]> sigrok.org Git - libsigrokdecode.git/blob - decoders/eeprom24xx/pd.py
avr_isp: Add more parts
[libsigrokdecode.git] / decoders / eeprom24xx / pd.py
1 ##
2 ## This file is part of the libsigrokdecode project.
3 ##
4 ## Copyright (C) 2014 Uwe Hermann <uwe@hermann-uwe.de>
5 ##
6 ## This program is free software; you can redistribute it and/or modify
7 ## it under the terms of the GNU General Public License as published by
8 ## the Free Software Foundation; either version 2 of the License, or
9 ## (at your option) any later version.
10 ##
11 ## This program is distributed in the hope that it will be useful,
12 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 ## GNU General Public License for more details.
15 ##
16 ## You should have received a copy of the GNU General Public License
17 ## along with this program; if not, see <http://www.gnu.org/licenses/>.
18 ##
19
20 import copy
21 import sigrokdecode as srd
22 from .lists import *
23
24 class Decoder(srd.Decoder):
25     api_version = 3
26     id = 'eeprom24xx'
27     name = '24xx EEPROM'
28     longname = '24xx I²C EEPROM'
29     desc = '24xx series I²C EEPROM protocol.'
30     license = 'gplv2+'
31     inputs = ['i2c']
32     outputs = []
33     tags = ['IC', 'Memory']
34     options = (
35         {'id': 'chip', 'desc': 'Chip', 'default': 'generic',
36             'values': tuple(chips.keys())},
37         {'id': 'addr_counter', 'desc': 'Initial address counter value',
38             'default': 0},
39     )
40     annotations = (
41         # Warnings
42         ('warning', 'Warning'),
43         # Bits/bytes
44         ('control-code', 'Control code'),
45         ('address-pin', 'Address pin (A0/A1/A2)'),
46         ('rw-bit', 'Read/write bit'),
47         ('word-addr-byte', 'Word address byte'),
48         ('data-byte', 'Data byte'),
49         # Fields
50         ('control-word', 'Control word'),
51         ('word-addr', 'Word address'),
52         ('data', 'Data'),
53         # Operations
54         ('byte-write', 'Byte write'),
55         ('page-write', 'Page write'),
56         ('cur-addr-read', 'Current address read'),
57         ('random-read', 'Random read'),
58         ('seq-random-read', 'Sequential random read'),
59         ('seq-cur-addr-read', 'Sequential current address read'),
60         ('ack-polling', 'Acknowledge polling'),
61         ('set-bank-addr', 'Set bank address'), # SBA. Only 34AA04.
62         ('read-bank-addr', 'Read bank address'), # RBA. Only 34AA04.
63         ('set-wp', 'Set write protection'), # SWP
64         ('clear-all-wp', 'Clear all write protection'), # CWP
65         ('read-wp', 'Read write protection status'), # RPS
66     )
67     annotation_rows = (
68         ('bits-bytes', 'Bits/bytes', (1, 2, 3, 4, 5)),
69         ('fields', 'Fields', (6, 7, 8)),
70         ('ops', 'Operations', tuple(range(9, 21))),
71         ('warnings', 'Warnings', (0,)),
72     )
73     binary = (
74         ('binary', 'Binary'),
75     )
76
77     def __init__(self):
78         self.reset()
79
80     def reset(self):
81         self.reset_variables()
82
83     def start(self):
84         self.out_ann = self.register(srd.OUTPUT_ANN)
85         self.out_binary = self.register(srd.OUTPUT_BINARY)
86         self.chip = chips[self.options['chip']]
87         self.addr_counter = self.options['addr_counter']
88
89     def putb(self, data):
90         self.put(self.ss_block, self.es_block, self.out_ann, data)
91
92     def putbin(self, data):
93         self.put(self.ss_block, self.es_block, self.out_binary, data)
94
95     def putbits(self, bit1, bit2, bits, data):
96         self.put(bits[bit1][1], bits[bit2][2], self.out_ann, data)
97
98     def reset_variables(self):
99         self.state = 'WAIT FOR START'
100         self.packets = []
101         self.bytebuf = []
102         self.is_cur_addr_read = False
103         self.is_random_access_read = False
104         self.is_seq_random_read = False
105         self.is_byte_write = False
106         self.is_page_write = False
107
108     def packet_append(self):
109         self.packets.append([self.ss, self.es, self.cmd, self.databyte, self.bits])
110         if self.cmd in ('DATA READ', 'DATA WRITE'):
111             self.bytebuf.append(self.databyte)
112
113     def hexbytes(self, idx):
114         return ' '.join(['%02X' % b for b in self.bytebuf[idx:]])
115
116     def put_control_word(self, bits):
117         s = ''.join(['%d' % b[0] for b in reversed(bits[4:])])
118         self.putbits(7, 4, bits, [1, ['Control code bits: ' + s,
119             'Control code: ' + s, 'Ctrl code: ' + s, 'Ctrl code', 'Ctrl', 'C']])
120         for i in reversed(range(self.chip['addr_pins'])):
121             self.putbits(i + 1, i + 1, bits,
122                 [2, ['Address bit %d: %d' % (i, bits[i + 1][0]),
123                      'Addr bit %d' % i, 'A%d' % i, 'A']])
124         s1 = 'read' if bits[0][0] == 1 else 'write'
125         s2 = 'R' if bits[0][0] == 1 else 'W'
126         self.putbits(0, 0, bits, [3, ['R/W bit: ' + s1, 'R/W', 'RW', s2]])
127         self.putbits(7, 0, bits, [6, ['Control word', 'Control', 'CW', 'C']])
128
129     def put_word_addr(self, p):
130         if self.chip['addr_bytes'] == 1:
131             a = p[1][3]
132             self.put(p[1][0], p[1][1], self.out_ann,
133                 [4, ['Word address byte: %02X' % a, 'Word addr byte: %02X' % a,
134                      'Addr: %02X' % a, 'A: %02X' % a, '%02X' % a]])
135             self.put(p[1][0], p[1][1], self.out_ann, [7, ['Word address',
136                      'Word addr', 'Addr', 'A']])
137             self.addr_counter = a
138         else:
139             a = p[1][3]
140             self.put(p[1][0], p[1][1], self.out_ann,
141                 [4, ['Word address high byte: %02X' % a,
142                      'Word addr high byte: %02X' % a,
143                      'Addr high: %02X' % a, 'AH: %02X' % a, '%02X' % a]])
144             a = p[2][3]
145             self.put(p[2][0], p[2][1], self.out_ann,
146                 [4, ['Word address low byte: %02X' % a,
147                      'Word addr low byte: %02X' % a,
148                      'Addr low: %02X' % a, 'AL: %02X' % a, '%02X' % a]])
149             self.put(p[1][0], p[2][1], self.out_ann, [7, ['Word address',
150                      'Word addr', 'Addr', 'A']])
151             self.addr_counter = (p[1][3] << 8) | p[2][3]
152
153     def put_data_byte(self, p):
154         if self.chip['addr_bytes'] == 1:
155             s = '%02X' % self.addr_counter
156         else:
157             s = '%04X' % self.addr_counter
158         self.put(p[0], p[1], self.out_ann, [5, ['Data byte %s: %02X' % \
159             (s, p[3]), 'Data byte: %02X' % p[3], \
160             'Byte: %02X' % p[3], 'DB: %02X' % p[3], '%02X' % p[3]]])
161
162     def put_data_bytes(self, idx, cls, s):
163         for p in self.packets[idx:]:
164             self.put_data_byte(p)
165             self.addr_counter += 1
166         self.put(self.packets[idx][0], self.packets[-1][1], self.out_ann,
167             [8, ['Data', 'D']])
168         a = ''.join(['%s' % c[0] for c in s.split()]).upper()
169         self.putb([cls, ['%s (%s): %s' % (s, self.addr_and_len(), \
170                   self.hexbytes(self.chip['addr_bytes'])),
171                   '%s (%s)' % (s, self.addr_and_len()), s, a, s[0]]])
172         self.putbin([0, bytes(self.bytebuf[self.chip['addr_bytes']:])])
173
174     def addr_and_len(self):
175         if self.chip['addr_bytes'] == 1:
176             a = '%02X' % self.bytebuf[0]
177         else:
178             a = '%02X%02X' % tuple(self.bytebuf[:2])
179         num_data_bytes = len(self.bytebuf) - self.chip['addr_bytes']
180         d = '%d bytes' % num_data_bytes
181         if num_data_bytes <= 1:
182             d = d[:-1]
183         return 'addr=%s, %s' % (a, d)
184
185     def decide_on_seq_or_rnd_read(self):
186         if len(self.bytebuf) < 2:
187             self.reset_variables()
188             return
189         if len(self.bytebuf) == 2:
190             self.is_random_access_read = True
191         else:
192             self.is_seq_random_read = True
193
194     def put_operation(self):
195         idx = 1 + self.chip['addr_bytes']
196         if self.is_byte_write:
197             # Byte write: word address, one data byte.
198             self.put_word_addr(self.packets)
199             self.put_data_bytes(idx, 9, 'Byte write')
200         elif self.is_page_write:
201             # Page write: word address, two or more data bytes.
202             self.put_word_addr(self.packets)
203             intitial_addr = self.addr_counter
204             self.put_data_bytes(idx, 10, 'Page write')
205             num_bytes_to_write = len(self.packets[idx:])
206             if num_bytes_to_write > self.chip['page_size']:
207                 self.putb([0, ['Warning: Wrote %d bytes but page size is '
208                                'only %d bytes!' % (num_bytes_to_write,
209                                self.chip['page_size'])]])
210             page1 = int(intitial_addr / self.chip['page_size'])
211             page2 = int((self.addr_counter - 1) / self.chip['page_size'])
212             if page1 != page2:
213                 self.putb([0, ['Warning: Page write crossed page boundary '
214                                'from page %d to %d!' % (page1, page2)]])
215         elif self.is_cur_addr_read:
216             # Current address read: no word address, one data byte.
217             self.put_data_byte(self.packets[1])
218             self.put(self.packets[1][0], self.packets[-1][1], self.out_ann,
219                 [8, ['Data', 'D']])
220             self.putb([11, ['Current address read: %02X' % self.bytebuf[0],
221                        'Current address read', 'Cur addr read', 'CAR', 'C']])
222             self.putbin([0, bytes([self.bytebuf[0]])])
223             self.addr_counter += 1
224         elif self.is_random_access_read:
225             # Random access read: word address, one data byte.
226             self.put_control_word(self.packets[idx][4])
227             self.put_word_addr(self.packets)
228             self.put_data_bytes(idx + 1, 12, 'Random access read')
229         elif self.is_seq_random_read:
230             # Sequential random read: word address, two or more data bytes.
231             self.put_control_word(self.packets[idx][4])
232             self.put_word_addr(self.packets)
233             self.put_data_bytes(idx + 1, 13, 'Sequential random read')
234
235     def handle_wait_for_start(self):
236         # Wait for an I²C START condition.
237         if self.cmd not in ('START', 'START REPEAT'):
238             return
239         self.ss_block = self.ss
240         self.state = 'GET CONTROL WORD'
241
242     def handle_get_control_word(self):
243         # The packet after START must be an ADDRESS READ or ADDRESS WRITE.
244         if self.cmd not in ('ADDRESS READ', 'ADDRESS WRITE'):
245             self.reset_variables()
246             return
247         self.packet_append()
248         self.put_control_word(self.bits)
249         self.state = '%s GET ACK NACK AFTER CONTROL WORD' % self.cmd[8]
250
251     def handle_r_get_ack_nack_after_control_word(self):
252         if self.cmd == 'ACK':
253             self.state = 'R GET WORD ADDR OR BYTE'
254         elif self.cmd == 'NACK':
255             self.es_block = self.es
256             self.putb([0, ['Warning: No reply from slave!']])
257             self.reset_variables()
258         else:
259             self.reset_variables()
260
261     def handle_r_get_word_addr_or_byte(self):
262         if self.cmd == 'STOP':
263             self.es_block = self.es
264             self.putb([0, ['Warning: Slave replied, but master aborted!']])
265             self.reset_variables()
266             return
267         elif self.cmd != 'DATA READ':
268             self.reset_variables()
269             return
270         self.packet_append()
271         self.state = 'R GET ACK NACK AFTER WORD ADDR OR BYTE'
272
273     def handle_r_get_ack_nack_after_word_addr_or_byte(self):
274         if self.cmd == 'ACK':
275             self.state = 'R GET RESTART'
276         elif self.cmd == 'NACK':
277             self.is_cur_addr_read = True
278             self.state = 'GET STOP AFTER LAST BYTE'
279         else:
280             self.reset_variables()
281
282     def handle_r_get_restart(self):
283         if self.cmd == 'RESTART':
284             self.state = 'R READ BYTE'
285         else:
286             self.reset_variables()
287
288     def handle_r_read_byte(self):
289         if self.cmd == 'DATA READ':
290             self.packet_append()
291             self.state = 'R GET ACK NACK AFTER BYTE WAS READ'
292         else:
293             self.reset_variables()
294
295     def handle_r_get_ack_nack_after_byte_was_read(self):
296         if self.cmd == 'ACK':
297             self.state = 'R READ BYTE'
298         elif self.cmd == 'NACK':
299             # It's either a RANDOM READ or a SEQUENTIAL READ.
300             self.state = 'GET STOP AFTER LAST BYTE'
301         else:
302             self.reset_variables()
303
304     def handle_w_get_ack_nack_after_control_word(self):
305         if self.cmd == 'ACK':
306             self.state = 'W GET WORD ADDR'
307         elif self.cmd == 'NACK':
308             self.es_block = self.es
309             self.putb([0, ['Warning: No reply from slave!']])
310             self.reset_variables()
311         else:
312             self.reset_variables()
313
314     def handle_w_get_word_addr(self):
315         if self.cmd == 'STOP':
316             self.es_block = self.es
317             self.putb([0, ['Warning: Slave replied, but master aborted!']])
318             self.reset_variables()
319             return
320         elif self.cmd != 'DATA WRITE':
321             self.reset_variables()
322             return
323         self.packet_append()
324         self.state = 'W GET ACK AFTER WORD ADDR'
325
326     def handle_w_get_ack_after_word_addr(self):
327         if self.cmd == 'ACK':
328             self.state = 'W DETERMINE EEPROM READ OR WRITE'
329         else:
330             self.reset_variables()
331
332     def handle_w_determine_eeprom_read_or_write(self):
333         if self.cmd == 'START REPEAT':
334             # It's either a RANDOM ACCESS READ or SEQUENTIAL RANDOM READ.
335             self.state = 'R2 GET CONTROL WORD'
336         elif self.cmd == 'DATA WRITE':
337             self.packet_append()
338             self.state = 'W GET ACK NACK AFTER BYTE WAS WRITTEN'
339         else:
340             self.reset_variables()
341
342     def handle_w_write_byte(self):
343         if self.cmd == 'DATA WRITE':
344             self.packet_append()
345             self.state = 'W GET ACK NACK AFTER BYTE WAS WRITTEN'
346         elif self.cmd == 'STOP':
347             if len(self.bytebuf) < 2:
348                 self.reset_variables()
349                 return
350             self.es_block = self.es
351             if len(self.bytebuf) == 2:
352                 self.is_byte_write = True
353             else:
354                 self.is_page_write = True
355             self.put_operation()
356             self.reset_variables()
357         elif self.cmd == 'START REPEAT':
358             # It's either a RANDOM ACCESS READ or SEQUENTIAL RANDOM READ.
359             self.state = 'R2 GET CONTROL WORD'
360         else:
361             self.reset_variables()
362
363     def handle_w_get_ack_nack_after_byte_was_written(self):
364         if self.cmd == 'ACK':
365             self.state = 'W WRITE BYTE'
366         else:
367             self.reset_variables()
368
369     def handle_r2_get_control_word(self):
370         if self.cmd == 'ADDRESS READ':
371             self.packet_append()
372             self.state = 'R2 GET ACK AFTER ADDR READ'
373         else:
374             self.reset_variables()
375
376     def handle_r2_get_ack_after_addr_read(self):
377         if self.cmd == 'ACK':
378             self.state = 'R2 READ BYTE'
379         else:
380             self.reset_variables()
381
382     def handle_r2_read_byte(self):
383         if self.cmd == 'DATA READ':
384             self.packet_append()
385             self.state = 'R2 GET ACK NACK AFTER BYTE WAS READ'
386         elif self.cmd == 'STOP':
387             self.decide_on_seq_or_rnd_read()
388             self.es_block = self.es
389             self.putb([0, ['Warning: STOP expected after a NACK (not ACK)']])
390             self.put_operation()
391             self.reset_variables()
392         else:
393             self.reset_variables()
394
395     def handle_r2_get_ack_nack_after_byte_was_read(self):
396         if self.cmd == 'ACK':
397             self.state = 'R2 READ BYTE'
398         elif self.cmd == 'NACK':
399             self.decide_on_seq_or_rnd_read()
400             self.state = 'GET STOP AFTER LAST BYTE'
401         else:
402             self.reset_variables()
403
404     def handle_get_stop_after_last_byte(self):
405         if self.cmd == 'STOP':
406             self.es_block = self.es
407             self.put_operation()
408             self.reset_variables()
409         elif self.cmd == 'START REPEAT':
410             self.es_block = self.es
411             self.putb([0, ['Warning: STOP expected (not RESTART)']])
412             self.put_operation()
413             self.reset_variables()
414             self.ss_block = self.ss
415             self.state = 'GET CONTROL WORD'
416         else:
417             self.reset_variables()
418
419     def decode(self, ss, es, data):
420         cmd, _ = data
421
422         # Collect the 'BITS' packet, then return. The next packet is
423         # guaranteed to belong to these bits we just stored.
424         if cmd == 'BITS':
425             _, databits = data
426             self.bits = copy.deepcopy(databits)
427             return
428
429         # Store the start/end samples of this I²C packet. Deep copy
430         # caller's data, assuming that implementation details of the
431         # above complex methods can access the data after returning
432         # from the .decode() invocation, with the data having become
433         # invalid by that time of access. This conservative approach
434         # can get weakened after close inspection of those methods.
435         self.ss, self.es = ss, es
436         _, databyte = data
437         databyte = copy.deepcopy(databyte)
438         self.cmd, self.databyte = cmd, databyte
439
440         # State machine.
441         s = 'handle_%s' % self.state.lower().replace(' ', '_')
442         handle_state = getattr(self, s)
443         handle_state()