]> sigrok.org Git - libsigrokdecode.git/blame - decoders/enc28j60/pd.py
enc28j60: Factor out self.putr().
[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
3fc120d9
UH
85 self.range_ss = None
86 self.range_es = None
a7df1ee4
JL
87 self.active = False
88 self.bsel0 = None
89 self.bsel1 = None
90
91 def start(self):
92 self.ann = self.register(srd.OUTPUT_ANN)
93
72db471e
UH
94 def putc(self, data):
95 self.put(self.cmd_ss, self.cmd_es, self.ann, data)
96
3fc120d9
UH
97 def putr(self, data):
98 self.put(self.range_ss, self.range_es, self.ann, data)
99
a7df1ee4
JL
100 def _process_command(self):
101 if len(self.mosi) == 0:
102 self.active = False
103 return
104
105 header = self.mosi[0]
106 opcode = header & OPCODE_MASK
107
108 if opcode not in OPCODE_HANDLERS:
109 self._put_command_warning("Unknown opcode.")
110 self.active = False
111 return
112
113 getattr(self, OPCODE_HANDLERS[opcode])()
114
115 self.active = False
116
117 def _get_register_name(self, reg_addr):
118 if (self.bsel0 is None) or (self.bsel1 is None):
119 # We don't know the bank we're in yet.
120 return None
121 else:
122 bank = (self.bsel1 << 1) + self.bsel0
123 return REGS[bank][reg_addr]
124
125 def _put_register_header(self):
126 reg_addr = self.mosi[0] & REG_ADDR_MASK
127 reg_name = self._get_register_name(reg_addr)
128
3fc120d9 129 self.range_ss, self.range_es = self.cmd_ss, self.ranges[1][0]
fbf652db 130
a7df1ee4
JL
131 if reg_name is None:
132 # We don't know the bank we're in yet.
3fc120d9 133 self.putr([
a7df1ee4
JL
134 ANN_REG_ADDR,
135 [
136 'Reg Bank ? Addr 0x{0:02X}'.format(reg_addr),
137 '?:{0:02X}'.format(reg_addr),
138 ]])
3fc120d9 139 self.putr([
a7df1ee4
JL
140 ANN_WARNING,
141 [
142 'Warning: Register bank not known yet.',
143 'Warning',
144 ]])
145 else:
3fc120d9 146 self.putr([
a7df1ee4
JL
147 ANN_REG_ADDR,
148 [
149 'Reg {0}'.format(reg_name),
150 '{0}'.format(reg_name),
151 ]])
152
153 if (reg_name == '-') or (reg_name == 'Reserved'):
3fc120d9 154 self.putr([
a7df1ee4
JL
155 ANN_WARNING,
156 [
157 'Warning: Invalid register accessed.',
158 'Warning',
159 ]])
160
161 def _put_data_byte(self, data, byte_index, binary=False):
3fc120d9 162 self.range_ss = self.ranges[byte_index][0]
a7df1ee4 163 if byte_index == len(self.mosi) - 1:
3fc120d9 164 self.range_es = self.cmd_es
a7df1ee4 165 else:
3fc120d9 166 self.range_es = self.ranges[byte_index + 1][0]
a7df1ee4
JL
167
168 if binary:
3fc120d9 169 self.putr([
a7df1ee4
JL
170 ANN_DATA,
171 [
172 'Data 0b{0:08b}'.format(data),
173 '{0:08b}'.format(data),
174 ]])
175 else:
3fc120d9 176 self.putr([
a7df1ee4
JL
177 ANN_DATA,
178 [
179 'Data 0x{0:02X}'.format(data),
180 '{0:02X}'.format(data),
181 ]])
182
183 def _put_command_warning(self, reason):
72db471e 184 self.putc([
a7df1ee4
JL
185 ANN_WARNING,
186 [
187 'Warning: {0}'.format(reason),
188 'Warning',
189 ]])
190
191 def _process_rcr(self):
72db471e 192 self.putc([ANN_RCR, ['Read Control Register', 'RCR']])
a7df1ee4
JL
193
194 if (len(self.mosi) != 2) and (len(self.mosi) != 3):
195 self._put_command_warning('Invalid command length.')
196 return
197
198 self._put_register_header()
199
200 reg_name = self._get_register_name(self.mosi[0] & REG_ADDR_MASK)
201 if reg_name is None:
202 # We can't tell if we're accessing MAC/MII registers or not
203 # Let's trust the user in this case.
204 pass
205 else:
206 if (reg_name[0] == 'M') and (len(self.mosi) != 3):
207 self._put_command_warning('Attempting to read a MAC/MII '
208 + 'register without using the dummy byte.')
209 return
210
211 if (reg_name[0] != 'M') and (len(self.mosi) != 2):
212 self._put_command_warning('Attempting to read a non-MAC/MII '
213 + 'register using the dummy byte.')
214 return
215
216 if len(self.mosi) == 2:
217 self._put_data_byte(self.miso[1], 1)
218 else:
3fc120d9
UH
219 self.range_ss, self.range_es = self.ranges[1][0], self.ranges[2][0]
220 self.putr([
a7df1ee4
JL
221 ANN_DATA,
222 [
223 'Dummy Byte',
224 'Dummy',
225 ]])
226 self._put_data_byte(self.miso[2], 2)
227
228 def _process_rbm(self):
229 if self.mosi[0] != 0b00111010:
230 self._put_command_warning('Invalid header byte.')
231 return
232
72db471e 233 self.putc([
a7df1ee4
JL
234 ANN_RBM,
235 [
236 'Read Buffer Memory: Length {0}'.format(
237 len(self.mosi) - 1),
238 'RBM',
239 ]])
240
241 for i in range(1, len(self.miso)):
242 self._put_data_byte(self.miso[i], i)
243
244 def _process_wcr(self):
72db471e 245 self.putc([ANN_WCR, ['Write Control Register', 'WCR']])
a7df1ee4
JL
246
247 if len(self.mosi) != 2:
248 self._put_command_warning('Invalid command length.')
249 return
250
251 self._put_register_header()
252 self._put_data_byte(self.mosi[1], 1)
253
254 if self.mosi[0] & REG_ADDR_MASK == REG_ADDR_ECON1:
255 self.bsel0 = (self.mosi[1] & BIT_ECON1_BSEL0) >> 0
256 self.bsel1 = (self.mosi[1] & BIT_ECON1_BSEL1) >> 1
257
258 def _process_wbm(self):
259 if self.mosi[0] != 0b01111010:
260 self._put_command_warning('Invalid header byte.')
261 return
262
72db471e 263 self.putc([
a7df1ee4
JL
264 ANN_WBM,
265 [
266 'Write Buffer Memory: Length {0}'.format(
267 len(self.mosi) - 1),
268 'WBM',
269 ]])
270
271 for i in range(1, len(self.mosi)):
272 self._put_data_byte(self.mosi[i], i)
273
274 def _process_bfc(self):
72db471e 275 self.putc([ANN_BFC, ['Bit Field Clear', 'BFC']])
a7df1ee4
JL
276
277 if len(self.mosi) != 2:
278 self._put_command_warning('Invalid command length.')
279 return
280
281 self._put_register_header()
282 self._put_data_byte(self.mosi[1], 1, True)
283
284 if self.mosi[0] & REG_ADDR_MASK == REG_ADDR_ECON1:
285 if self.mosi[1] & BIT_ECON1_BSEL0:
286 self.bsel0 = 0
287 if self.mosi[1] & BIT_ECON1_BSEL1:
288 self.bsel1 = 0
289
290 def _process_bfs(self):
72db471e 291 self.putc([ANN_BFS, ['Bit Field Set', 'BFS']])
a7df1ee4
JL
292
293 if len(self.mosi) != 2:
294 self._put_command_warning('Invalid command length.')
295 return
296
297 self._put_register_header()
298 self._put_data_byte(self.mosi[1], 1, True)
299
300 if self.mosi[0] & REG_ADDR_MASK == REG_ADDR_ECON1:
301 if self.mosi[1] & BIT_ECON1_BSEL0:
302 self.bsel0 = 1
303 if self.mosi[1] & BIT_ECON1_BSEL1:
304 self.bsel1 = 1
305
306 def _process_src(self):
72db471e 307 self.putc([ANN_SRC, ['System Reset Command', 'SRC']])
a7df1ee4
JL
308
309 if len(self.mosi) != 1:
310 self._put_command_warning('Invalid command length.')
311 return
312
313 self.bsel0 = 0
314 self.bsel1 = 0
315
316 def decode(self, ss, es, data):
317 ptype, data1, data2 = data
318
319 if ptype == 'CS-CHANGE':
320 new_cs = data2
321
322 if new_cs == 0:
323 self.active = True
fbf652db 324 self.cmd_ss = ss
a7df1ee4
JL
325 self.mosi = []
326 self.miso = []
327 self.ranges = []
328 elif new_cs == 1:
329 if self.active:
fbf652db 330 self.cmd_es = es
a7df1ee4
JL
331 self._process_command()
332 elif ptype == 'DATA':
333 mosi, miso = data1, data2
334
335 self.mosi.append(mosi)
336 self.miso.append(miso)
337 self.ranges.append((ss, es))