]> sigrok.org Git - libsigrokdecode.git/blame - decoders/enc28j60/pd.py
enc28j60: Use the common ss/es abbreviations.
[libsigrokdecode.git] / decoders / enc28j60 / pd.py
CommitLineData
a7df1ee4
JL
1##
2## This file is part of the libsigrokdecode project.
3##
4## Copyright (C) 2019 Jiahao Li <reg@ljh.me>
5##
6## Permission is hereby granted, free of charge, to any person obtaining a copy
7## of this software and associated documentation files (the "Software"), to deal
8## in the Software without restriction, including without limitation the rights
9## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10## copies of the Software, and to permit persons to whom the Software is
11## furnished to do so, subject to the following conditions:
12##
13## The above copyright notice and this permission notice shall be included in all
14## copies or substantial portions of the Software.
15##
16## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22## SOFTWARE.
23
24import sigrokdecode as srd
de49d11e 25from .lists import *
a7df1ee4
JL
26
27OPCODE_MASK = 0b11100000
28REG_ADDR_MASK = 0b00011111
29
30OPCODE_HANDLERS = {
31 0b00000000: '_process_rcr',
32 0b00100000: '_process_rbm',
33 0b01000000: '_process_wcr',
34 0b01100000: '_process_wbm',
35 0b10000000: '_process_bfs',
36 0b10100000: '_process_bfc',
37 0b11100000: '_process_src',
38}
39
acc08e51
UH
40(ANN_RCR, ANN_RBM, ANN_WCR, ANN_WBM, ANN_BFS, ANN_BFC, ANN_SRC, ANN_DATA,
41ANN_REG_ADDR, ANN_WARNING) = range(10)
a7df1ee4
JL
42
43REG_ADDR_ECON1 = 0x1F
44BIT_ECON1_BSEL0 = 0b00000001
45BIT_ECON1_BSEL1 = 0b00000010
46
a7df1ee4
JL
47class Decoder(srd.Decoder):
48 api_version = 3
49 id = 'enc28j60'
50 name = 'ENC28J60'
51 longname = 'Microchip ENC28J60'
52 desc = 'Microchip ENC28J60 10Base-T Ethernet controller protocol.'
53 license = 'mit'
54 inputs = ['spi']
052be6a7 55 outputs = []
2df02753 56 tags = ['Embedded/industrial', 'Networking']
a7df1ee4
JL
57 annotations = (
58 ('rcr', 'Read Control Register'),
59 ('rbm', 'Read Buffer Memory'),
60 ('wcr', 'Write Control Register'),
61 ('wbm', 'Write Buffer Memory'),
62 ('bfs', 'Bit Field Set'),
63 ('bfc', 'Bit Field Clear'),
64 ('src', 'System Reset Command'),
65 ('data', 'Data'),
66 ('reg-addr', 'Register Address'),
67 ('warning', 'Warning'),
68 )
69 annotation_rows = (
70 ('commands', 'Commands',
71 (ANN_RCR, ANN_RBM, ANN_WCR, ANN_WBM, ANN_BFS, ANN_BFC, ANN_SRC)),
72 ('fields', 'Fields', (ANN_DATA, ANN_REG_ADDR)),
73 ('warnings', 'Warnings', (ANN_WARNING,)),
74 )
75
76 def __init__(self):
77 self.reset()
78
79 def reset(self):
80 self.mosi = []
81 self.miso = []
82 self.ranges = []
fbf652db
UH
83 self.cmd_ss = None
84 self.cmd_es = None
a7df1ee4
JL
85 self.active = False
86 self.bsel0 = None
87 self.bsel1 = None
88
89 def start(self):
90 self.ann = self.register(srd.OUTPUT_ANN)
91
92 def _process_command(self):
93 if len(self.mosi) == 0:
94 self.active = False
95 return
96
97 header = self.mosi[0]
98 opcode = header & OPCODE_MASK
99
100 if opcode not in OPCODE_HANDLERS:
101 self._put_command_warning("Unknown opcode.")
102 self.active = False
103 return
104
105 getattr(self, OPCODE_HANDLERS[opcode])()
106
107 self.active = False
108
109 def _get_register_name(self, reg_addr):
110 if (self.bsel0 is None) or (self.bsel1 is None):
111 # We don't know the bank we're in yet.
112 return None
113 else:
114 bank = (self.bsel1 << 1) + self.bsel0
115 return REGS[bank][reg_addr]
116
117 def _put_register_header(self):
118 reg_addr = self.mosi[0] & REG_ADDR_MASK
119 reg_name = self._get_register_name(reg_addr)
120
fbf652db
UH
121 ss, es = self.cmd_ss, self.ranges[1][0]
122
a7df1ee4
JL
123 if reg_name is None:
124 # We don't know the bank we're in yet.
fbf652db 125 self.put(ss, es, self.ann, [
a7df1ee4
JL
126 ANN_REG_ADDR,
127 [
128 'Reg Bank ? Addr 0x{0:02X}'.format(reg_addr),
129 '?:{0:02X}'.format(reg_addr),
130 ]])
fbf652db 131 self.put(ss, es, self.ann, [
a7df1ee4
JL
132 ANN_WARNING,
133 [
134 'Warning: Register bank not known yet.',
135 'Warning',
136 ]])
137 else:
fbf652db 138 self.put(ss, es, self.ann, [
a7df1ee4
JL
139 ANN_REG_ADDR,
140 [
141 'Reg {0}'.format(reg_name),
142 '{0}'.format(reg_name),
143 ]])
144
145 if (reg_name == '-') or (reg_name == 'Reserved'):
fbf652db 146 self.put(ss, es, self.ann, [
a7df1ee4
JL
147 ANN_WARNING,
148 [
149 'Warning: Invalid register accessed.',
150 'Warning',
151 ]])
152
153 def _put_data_byte(self, data, byte_index, binary=False):
fbf652db 154 ss = self.ranges[byte_index][0]
a7df1ee4 155 if byte_index == len(self.mosi) - 1:
fbf652db 156 es = self.cmd_es
a7df1ee4 157 else:
fbf652db 158 es = self.ranges[byte_index + 1][0]
a7df1ee4
JL
159
160 if binary:
fbf652db 161 self.put(ss, es, self.ann, [
a7df1ee4
JL
162 ANN_DATA,
163 [
164 'Data 0b{0:08b}'.format(data),
165 '{0:08b}'.format(data),
166 ]])
167 else:
fbf652db 168 self.put(ss, es, self.ann, [
a7df1ee4
JL
169 ANN_DATA,
170 [
171 'Data 0x{0:02X}'.format(data),
172 '{0:02X}'.format(data),
173 ]])
174
175 def _put_command_warning(self, reason):
fbf652db 176 self.put(self.cmd_ss, self.cmd_es, self.ann, [
a7df1ee4
JL
177 ANN_WARNING,
178 [
179 'Warning: {0}'.format(reason),
180 'Warning',
181 ]])
182
183 def _process_rcr(self):
fbf652db 184 self.put(self.cmd_ss, self.cmd_es,
a7df1ee4
JL
185 self.ann, [ANN_RCR, ['Read Control Register', 'RCR']])
186
187 if (len(self.mosi) != 2) and (len(self.mosi) != 3):
188 self._put_command_warning('Invalid command length.')
189 return
190
191 self._put_register_header()
192
193 reg_name = self._get_register_name(self.mosi[0] & REG_ADDR_MASK)
194 if reg_name is None:
195 # We can't tell if we're accessing MAC/MII registers or not
196 # Let's trust the user in this case.
197 pass
198 else:
199 if (reg_name[0] == 'M') and (len(self.mosi) != 3):
200 self._put_command_warning('Attempting to read a MAC/MII '
201 + 'register without using the dummy byte.')
202 return
203
204 if (reg_name[0] != 'M') and (len(self.mosi) != 2):
205 self._put_command_warning('Attempting to read a non-MAC/MII '
206 + 'register using the dummy byte.')
207 return
208
209 if len(self.mosi) == 2:
210 self._put_data_byte(self.miso[1], 1)
211 else:
fbf652db
UH
212 ss, es = self.ranges[1][0], self.ranges[2][0]
213 self.put(ss, es, self.ann, [
a7df1ee4
JL
214 ANN_DATA,
215 [
216 'Dummy Byte',
217 'Dummy',
218 ]])
219 self._put_data_byte(self.miso[2], 2)
220
221 def _process_rbm(self):
222 if self.mosi[0] != 0b00111010:
223 self._put_command_warning('Invalid header byte.')
224 return
225
fbf652db 226 self.put(self.cmd_ss, self.cmd_es, self.ann, [
a7df1ee4
JL
227 ANN_RBM,
228 [
229 'Read Buffer Memory: Length {0}'.format(
230 len(self.mosi) - 1),
231 'RBM',
232 ]])
233
234 for i in range(1, len(self.miso)):
235 self._put_data_byte(self.miso[i], i)
236
237 def _process_wcr(self):
fbf652db 238 self.put(self.cmd_ss, self.cmd_es,
a7df1ee4
JL
239 self.ann, [ANN_WCR, ['Write Control Register', 'WCR']])
240
241 if len(self.mosi) != 2:
242 self._put_command_warning('Invalid command length.')
243 return
244
245 self._put_register_header()
246 self._put_data_byte(self.mosi[1], 1)
247
248 if self.mosi[0] & REG_ADDR_MASK == REG_ADDR_ECON1:
249 self.bsel0 = (self.mosi[1] & BIT_ECON1_BSEL0) >> 0
250 self.bsel1 = (self.mosi[1] & BIT_ECON1_BSEL1) >> 1
251
252 def _process_wbm(self):
253 if self.mosi[0] != 0b01111010:
254 self._put_command_warning('Invalid header byte.')
255 return
256
fbf652db 257 self.put(self.cmd_ss, self.cmd_es, self.ann, [
a7df1ee4
JL
258 ANN_WBM,
259 [
260 'Write Buffer Memory: Length {0}'.format(
261 len(self.mosi) - 1),
262 'WBM',
263 ]])
264
265 for i in range(1, len(self.mosi)):
266 self._put_data_byte(self.mosi[i], i)
267
268 def _process_bfc(self):
fbf652db 269 self.put(self.cmd_ss, self.cmd_es,
a7df1ee4
JL
270 self.ann, [ANN_BFC, ['Bit Field Clear', 'BFC']])
271
272 if len(self.mosi) != 2:
273 self._put_command_warning('Invalid command length.')
274 return
275
276 self._put_register_header()
277 self._put_data_byte(self.mosi[1], 1, True)
278
279 if self.mosi[0] & REG_ADDR_MASK == REG_ADDR_ECON1:
280 if self.mosi[1] & BIT_ECON1_BSEL0:
281 self.bsel0 = 0
282 if self.mosi[1] & BIT_ECON1_BSEL1:
283 self.bsel1 = 0
284
285 def _process_bfs(self):
fbf652db 286 self.put(self.cmd_ss, self.cmd_es,
a7df1ee4
JL
287 self.ann, [ANN_BFS, ['Bit Field Set', 'BFS']])
288
289 if len(self.mosi) != 2:
290 self._put_command_warning('Invalid command length.')
291 return
292
293 self._put_register_header()
294 self._put_data_byte(self.mosi[1], 1, True)
295
296 if self.mosi[0] & REG_ADDR_MASK == REG_ADDR_ECON1:
297 if self.mosi[1] & BIT_ECON1_BSEL0:
298 self.bsel0 = 1
299 if self.mosi[1] & BIT_ECON1_BSEL1:
300 self.bsel1 = 1
301
302 def _process_src(self):
fbf652db 303 self.put(self.cmd_ss, self.cmd_es,
a7df1ee4
JL
304 self.ann, [ANN_SRC, ['System Reset Command', 'SRC']])
305
306 if len(self.mosi) != 1:
307 self._put_command_warning('Invalid command length.')
308 return
309
310 self.bsel0 = 0
311 self.bsel1 = 0
312
313 def decode(self, ss, es, data):
314 ptype, data1, data2 = data
315
316 if ptype == 'CS-CHANGE':
317 new_cs = data2
318
319 if new_cs == 0:
320 self.active = True
fbf652db 321 self.cmd_ss = ss
a7df1ee4
JL
322 self.mosi = []
323 self.miso = []
324 self.ranges = []
325 elif new_cs == 1:
326 if self.active:
fbf652db 327 self.cmd_es = es
a7df1ee4
JL
328 self._process_command()
329 elif ptype == 'DATA':
330 mosi, miso = data1, data2
331
332 self.mosi.append(mosi)
333 self.miso.append(miso)
334 self.ranges.append((ss, es))