]> sigrok.org Git - libsigrokdecode.git/blob - decoders/avr_pdi/pd.py
fcb73af88b945f079a03da306bbbd87983483b04
[libsigrokdecode.git] / decoders / avr_pdi / pd.py
1 ##
2 ## This file is part of the libsigrokdecode project.
3 ##
4 ## Copyright (C) 2011-2014 Uwe Hermann <uwe@hermann-uwe.de>
5 ## Copyright (C) 2016 Gerhard Sittig <gerhard.sittig@gmx.net>
6 ##
7 ## This program is free software; you can redistribute it and/or modify
8 ## it under the terms of the GNU General Public License as published by
9 ## the Free Software Foundation; either version 2 of the License, or
10 ## (at your option) any later version.
11 ##
12 ## This program is distributed in the hope that it will be useful,
13 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 ## GNU General Public License for more details.
16 ##
17 ## You should have received a copy of the GNU General Public License
18 ## along with this program; if not, see <http://www.gnu.org/licenses/>.
19 ##
20
21 # Note the implementation details:
22 #
23 # Although the Atmel literature suggests (does not explicitly mandate,
24 # but shows in diagrams) that two stop bits are used in the protocol,
25 # the decoder loses synchronization with ATxmega generated responses
26 # when it expects more than one stop bit. Since the chip's hardware is
27 # fixed, this is not an implementation error in some programmer software.
28 # Since this is a protocol decoder which does not participate in the
29 # communication (does not actively send data), we can read the data
30 # stream with one stop bit, and transparently keep working when two
31 # are used.
32 #
33 # Annotations in the UART fields level differ from Atmel literature.
34 # Wrong parity bits are referred to as "parity error". Low stop bits are
35 # referred to as "frame error".
36 #
37 # The PDI component in the device starts disabled. Enabling PDI
38 # communication is done by raising DATA and clocking RESET with a
39 # minimum frequency. PDI communication automatically gets disabled when
40 # RESET "is inactive" for a certain period of time. The specific timing
41 # conditions are rather fuzzy in the literature (phrased weakly), and
42 # are device dependent (refer to the minumum RESET pulse width). This
43 # protocol decoder implementation internally prepares for but currently
44 # does not support these enable and disable phases. On the one hand it
45 # avoids excess external dependencies or wrong results for legal input
46 # data. On the other hand the decoder works when input streams start in
47 # the middle of an established connection.
48 #
49 # Communication peers detect physical collisions. The decoder can't.
50 # Upon collisions, a peer will cease any subsequent transmission, until
51 # a BREAK is seen. Synchronization can get enforced by sending two BREAK
52 # conditions. The first will cause a collision, the second will re-enable
53 # the peer. The decoder has no concept of physical collisions. It stops
54 # the interpretation of instructions when BREAK is seen, and assumes
55 # that a new instruction will start after BREAK.
56 #
57 # This protocol decoder only supports PDI communication over UART frames.
58 # It lacks support for PDI over JTAG. This would require separation into
59 # multiple protocol decoder layers (UART physical, JTAG physical, PDI
60 # instructions, optionally device support on top of PDI. There is some
61 # more potential for future extensions:
62 # - The JTAG physical has dedicated TX and RX directions. This decoder
63 #   only picks up communicated bytes but does not check which "line"
64 #   they are communicated on (not applicable to half duplex UART).
65 # - PDI over JTAG uses "special frame error" conditions to communicate
66 #   additional symbols: BREAK (0xBB with parity 1), DELAY (0xDB with
67 #   parity 1), and EMPTY (0xEB with parity 1).
68 # - Another "device support" layer might interpret device specific
69 #   timings, and might map addresses used in memory access operations
70 #   to component names, or even register names and bit fields(?). It's
71 #   quite deep a rabbithole though...
72
73 import sigrokdecode as srd
74 from collections import namedtuple
75
76 class Ann:
77     '''Annotation and binary output classes.'''
78     (
79         BIT, START, DATA, PARITY_OK, PARITY_ERR,
80         STOP_OK, STOP_ERR, BREAK,
81         OPCODE, DATA_PROG, DATA_DEV, PDI_BREAK,
82         ENABLE, DISABLE, COMMAND,
83     ) = range(15)
84     (
85         BIN_BYTES,
86     ) = range(1)
87
88 Bit = namedtuple('Bit', 'val ss es')
89
90 class PDI:
91     '''PDI protocol instruction opcodes, and operand formats.'''
92     (
93         OP_LDS, OP_LD, OP_STS, OP_ST,
94         OP_LDCS, OP_REPEAT, OP_STCS, OP_KEY,
95     ) = range(8)
96     pointer_format_nice = [
97         '*(ptr)',
98         '*(ptr++)',
99         'ptr',
100         'ptr++ (rsv)',
101     ]
102     pointer_format_terse = [
103         '*p',
104         '*p++',
105         'p',
106         '(rsv)',
107     ]
108     ctrl_reg_name = {
109         0: 'status',
110         1: 'reset',
111         2: 'ctrl',
112     }
113
114 class Decoder(srd.Decoder):
115     api_version = 3
116     id = 'avr_pdi'
117     name = 'AVR PDI'
118     longname = 'Atmel Program and Debug Interface'
119     desc = 'Atmel proprietary interface for the ATxmega MCU.'
120     license = 'gplv2+'
121     inputs = ['logic']
122     outputs = ['pdi']
123     channels = (
124         {'id': 'reset', 'name': 'RESET', 'desc': 'RESET / PDI_CLK'},
125         {'id': 'data', 'name': 'DATA', 'desc': 'PDI_DATA'},
126     )
127     annotations = (
128         ('uart-bit', 'UART bit'),
129         ('start-bit', 'Start bit'),
130         ('data-bit', 'Data bit'),
131         ('parity-ok', 'Parity OK bit'),
132         ('parity-err', 'Parity error bit'),
133         ('stop-ok', 'Stop OK bit'),
134         ('stop-err', 'Stop error bit'),
135         ('break', 'BREAK condition'),
136         ('opcode', 'Instruction opcode'),
137         ('data-prog', 'Programmer data'),
138         ('data-dev', 'Device data'),
139         ('pdi-break', 'BREAK at PDI level'),
140         ('enable', 'Enable PDI'),
141         ('disable', 'Disable PDI'),
142         ('cmd-data', 'PDI command with data'),
143     )
144     annotation_rows = (
145         ('uart_bits', 'UART bits', (Ann.BIT,)),
146         ('uart_fields', 'UART fields', (Ann.START, Ann.DATA, Ann.PARITY_OK,
147             Ann.PARITY_ERR, Ann.STOP_OK, Ann.STOP_ERR, Ann.BREAK)),
148         ('pdi_fields', 'PDI fields', (Ann.OPCODE, Ann.DATA_PROG, Ann.DATA_DEV,
149             Ann.PDI_BREAK)),
150         ('pdi_cmds', 'PDI Cmds', (Ann.ENABLE, Ann.DISABLE, Ann.COMMAND)),
151     )
152     binary = (
153         ('bytes', 'PDI protocol bytes'),
154     )
155
156     def __init__(self):
157         self.samplerate = None
158         self.clear_state()
159
160     def clear_state(self):
161         # Track bit times and bit values.
162         self.ss_last_fall = None
163         self.data_sample = None
164         self.ss_curr_fall = None
165         # Collect UART frame bits into byte values.
166         self.bits = []
167         self.zero_count = 0
168         self.zero_ss = None
169         self.break_ss = None
170         self.break_es = None
171         self.clear_insn()
172
173     def clear_insn(self):
174         # Collect instructions and their arguments,
175         # properties of the current instructions.
176         self.insn_rep_count = 0
177         self.insn_opcode = None
178         self.insn_wr_counts = []
179         self.insn_rd_counts = []
180         # Accumulation of data items as bytes pass by.
181         self.insn_dat_bytes = []
182         self.insn_dat_count = 0
183         self.insn_ss_data = None
184         # Next layer "commands", instructions plus operands.
185         self.cmd_ss = None
186         self.cmd_insn_parts_nice = []
187         self.cmd_insn_parts_terse = []
188
189     def metadata(self, key, value):
190         if key == srd.SRD_CONF_SAMPLERATE:
191             self.samplerate = value
192
193     def start(self):
194         self.out_ann = self.register(srd.OUTPUT_ANN)
195         self.out_binary = self.register(srd.OUTPUT_BINARY)
196
197     def put_ann_bit(self, bit_nr, ann_idx):
198         b = self.bits[bit_nr]
199         self.put(b.ss, b.es, self.out_ann, [ann_idx, [str(b.val)]])
200
201     def put_ann_data(self, bit_nr, ann_data):
202         b = self.bits[bit_nr]
203         self.put(b.ss, b.es, self.out_ann, ann_data)
204
205     def put_ann_row_val(self, ss, es, row, value):
206         self.put(ss, es, self.out_ann, [row, value])
207
208     def put_bin_bytes(self, ss, es, row, value):
209         self.put(ss, es, self.out_binary, [row, value])
210
211     def handle_byte(self, ss, es, byteval):
212         '''Handle a byte at the PDI protocol layer.'''
213
214         # Handle BREAK conditions, which will abort any
215         # potentially currently executing instruction.
216         is_break = byteval is None
217         if is_break:
218             self.cmd_insn_parts_nice.append('BREAK')
219             self.cmd_insn_parts_terse.append('BRK')
220             self.insn_rep_count = 0
221             # Will FALLTHROUGH to "end of instruction" below.
222
223         # Decode instruction opcodes and argument sizes
224         # from the first byte of a transaction.
225         if self.insn_opcode is None and not is_break:
226             opcode = (byteval & 0xe0) >> 5
227             arg30 = byteval & 0x0f
228             arg32 = (byteval & 0x0c) >> 2
229             arg10 = byteval & 0x03
230             self.insn_opcode = opcode
231             self.cmd_ss = ss
232             mnemonics = None
233             if opcode == PDI.OP_LDS:
234                 # LDS: load data, direct addressing.
235                 # Writes an address, reads a data item.
236                 width_addr = arg32 + 1
237                 width_data = arg10 + 1
238                 self.insn_wr_counts = [width_addr]
239                 self.insn_rd_counts = [width_data]
240                 mnemonics = [
241                     'Insn: LDS a{:d}, m{:d}'.format(width_addr, width_data),
242                     'LDS a{:d}, m{:d}'.format(width_addr, width_data), 'LDS',
243                 ]
244                 self.cmd_insn_parts_nice = ['LDS']
245                 self.cmd_insn_parts_terse = ['LDS']
246             elif opcode == PDI.OP_LD:
247                 # LD: load data, indirect addressing.
248                 # Reads a data item, with optional repeat.
249                 ptr_txt = PDI.pointer_format_nice[arg32]
250                 ptr_txt_terse = PDI.pointer_format_terse[arg32]
251                 width_data = arg10 + 1
252                 self.insn_wr_counts = []
253                 self.insn_rd_counts = [width_data]
254                 if self.insn_rep_count:
255                     self.insn_rd_counts.extend(self.insn_rep_count * [width_data])
256                     self.insn_rep_count = 0
257                 mnemonics = [
258                     'Insn: LD {:s} m{:d}'.format(ptr_txt, width_data),
259                     'LD {:s} m{:d}'.format(ptr_txt, width_data), 'LD',
260                 ]
261                 self.cmd_insn_parts_nice = ['LD', ptr_txt]
262                 self.cmd_insn_parts_terse = ['LD', ptr_txt_terse]
263             elif opcode == PDI.OP_STS:
264                 # STS: store data, direct addressing.
265                 # Writes an address, writes a data item.
266                 width_addr = arg32 + 1
267                 width_data = arg10 + 1
268                 self.insn_wr_counts = [width_addr, width_data]
269                 self.insn_rd_counts = []
270                 mnemonics = [
271                     'Insn: STS a{:d}, i{:d}'.format(width_addr, width_data),
272                     'STS a{:d}, i{:d}'.format(width_addr, width_data), 'STS',
273                 ]
274                 self.cmd_insn_parts_nice = ['STS']
275                 self.cmd_insn_parts_terse = ['STS']
276             elif opcode == PDI.OP_ST:
277                 # ST: store data, indirect addressing.
278                 # Writes a data item, with optional repeat.
279                 ptr_txt = PDI.pointer_format_nice[arg32]
280                 ptr_txt_terse = PDI.pointer_format_terse[arg32]
281                 width_data = arg10 + 1
282                 self.insn_wr_counts = [width_data]
283                 self.insn_rd_counts = []
284                 if self.insn_rep_count:
285                     self.insn_wr_counts.extend(self.insn_rep_count * [width_data])
286                     self.insn_rep_count = 0
287                 mnemonics = [
288                     'Insn: ST {:s} i{:d}'.format(ptr_txt, width_data),
289                     'ST {:s} i{:d}'.format(ptr_txt, width_data), 'ST',
290                 ]
291                 self.cmd_insn_parts_nice = ['ST', ptr_txt]
292                 self.cmd_insn_parts_terse = ['ST', ptr_txt_terse]
293             elif opcode == PDI.OP_LDCS:
294                 # LDCS: load control/status.
295                 # Loads exactly one byte.
296                 reg_num = arg30
297                 reg_txt = PDI.ctrl_reg_name.get(reg_num, 'r{:d}'.format(reg_num))
298                 reg_txt_terse = '{:d}'.format(reg_num)
299                 self.insn_wr_counts = []
300                 self.insn_rd_counts = [1]
301                 mnemonics = [
302                     'Insn: LDCS {:s}, m1'.format(reg_txt),
303                     'LDCS {:s}, m1'.format(reg_txt), 'LDCS',
304                 ]
305                 self.cmd_insn_parts_nice = ['LDCS', reg_txt]
306                 self.cmd_insn_parts_terse = ['LDCS', reg_txt_terse]
307             elif opcode == PDI.OP_STCS:
308                 # STCS: store control/status.
309                 # Writes exactly one byte.
310                 reg_num = arg30
311                 reg_txt = PDI.ctrl_reg_name.get(reg_num, 'r{:d}'.format(reg_num))
312                 reg_txt_terse = '{:d}'.format(reg_num)
313                 self.insn_wr_counts = [1]
314                 self.insn_rd_counts = []
315                 mnemonics = [
316                     'Insn: STCS {:s}, i1'.format(reg_txt),
317                     'STCS {:s}, i1'.format(reg_txt), 'STCS',
318                 ]
319                 self.cmd_insn_parts_nice = ['STCS', reg_txt]
320                 self.cmd_insn_parts_terse = ['STCS', reg_txt_terse]
321             elif opcode == PDI.OP_REPEAT:
322                 # REPEAT: sets repeat count for the next instruction.
323                 # Reads repeat count from following bytes.
324                 width_data = arg10 + 1
325                 self.insn_wr_counts = [width_data]
326                 self.insn_rd_counts = []
327                 mnemonics = [
328                     'Insn: REPEAT i{:d}'.format(width_data),
329                     'REPEAT i{:d}'.format(width_data), 'REP',
330                 ]
331                 self.cmd_insn_parts_nice = ['REPEAT']
332                 self.cmd_insn_parts_terse = ['REP']
333             elif opcode == PDI.OP_KEY:
334                 # KEY: set activation key (enables PDIBUS mmap access).
335                 # Writes a sequence of 8 bytes, fixed length.
336                 width_data = 8
337                 self.insn_wr_counts = [width_data]
338                 self.insn_rd_counts = []
339                 mnemonics = [
340                     'Insn: KEY i{:d}'.format(width_data),
341                     'KEY i{:d}'.format(width_data), 'KEY',
342                 ]
343                 self.cmd_insn_parts_nice = ['KEY']
344                 self.cmd_insn_parts_terse = ['KEY']
345
346             # Emit an annotation for the instruction opcode.
347             self.put_ann_row_val(ss, es, Ann.OPCODE, mnemonics)
348
349             # Prepare to write/read operands/data bytes.
350             self.insn_dat_bytes = []
351             if self.insn_wr_counts:
352                 self.insn_dat_count = self.insn_wr_counts[0]
353                 return
354             if self.insn_rd_counts:
355                 self.insn_dat_count = self.insn_rd_counts[0]
356                 return
357             # FALLTHROUGH.
358             # When there are no operands or data bytes to read,
359             # then fall through to the end of the instruction
360             # handling below (which emits annotations).
361
362         # Read bytes which carry operands (addresses, immediates)
363         # or data values for memory access.
364         if self.insn_dat_count and not is_break:
365
366             # Accumulate received bytes until another multi byte
367             # data item is complete.
368             if not self.insn_dat_bytes:
369                 self.insn_ss_data = ss
370             self.insn_dat_bytes.append(byteval)
371             self.insn_dat_count -= 1
372             if self.insn_dat_count:
373                 return
374
375             # Determine the data item's duration and direction,
376             # "consume" its length spec (to simplify later steps).
377             data_ss = self.insn_ss_data
378             data_es = es
379             if self.insn_wr_counts:
380                 data_ann = Ann.DATA_PROG
381                 data_width = self.insn_wr_counts.pop(0)
382             elif self.insn_rd_counts:
383                 data_ann = Ann.DATA_DEV
384                 data_width = self.insn_rd_counts.pop(0)
385
386             # PDI communicates multi-byte data items in little endian
387             # order. Get a nice textual representation of the number,
388             # wide and narrow for several zoom levels.
389             self.insn_dat_bytes.reverse()
390             data_txt_digits = ''.join(['{:02x}'.format(b) for b in self.insn_dat_bytes])
391             data_txt_hex = '0x' + data_txt_digits
392             data_txt_prefix = 'Data: ' + data_txt_hex
393             data_txts = [data_txt_prefix, data_txt_hex, data_txt_digits]
394             self.insn_dat_bytes = []
395
396             # Emit an annotation for the data value.
397             self.put_ann_row_val(data_ss, data_es, data_ann, data_txts)
398
399             # Collect detailled information which describes the whole
400             # command when combined (for a next layer annotation,
401             # spanning the complete command).
402             self.cmd_insn_parts_nice.append(data_txt_hex)
403             self.cmd_insn_parts_terse.append(data_txt_digits)
404
405             # Send out write data first until exhausted,
406             # then drain expected read data.
407             if self.insn_wr_counts:
408                 self.insn_dat_count = self.insn_wr_counts[0]
409                 return
410             if self.insn_rd_counts:
411                 self.insn_dat_count = self.insn_rd_counts[0]
412                 return
413
414             # FALLTHROUGH.
415             # When all operands and data bytes were seen,
416             # terminate the inspection of the instruction.
417
418         # Postprocess the instruction after its operands were seen.
419         cmd_es = es
420         cmd_txt_nice = ' '.join(self.cmd_insn_parts_nice)
421         cmd_txt_terse = ' '.join(self.cmd_insn_parts_terse)
422         cmd_txts = [cmd_txt_nice, cmd_txt_terse]
423         self.put_ann_row_val(self.cmd_ss, cmd_es, Ann.COMMAND, cmd_txts)
424         if self.insn_opcode == PDI.OP_REPEAT and not is_break:
425             # The last communicated data item is the repeat
426             # count for the next instruction (i.e. it will
427             # execute N+1 times when "REPEAT N" is specified).
428             count = int(self.cmd_insn_parts_nice[-1], 0)
429             self.insn_rep_count = count
430
431         # Have the state for instruction decoding cleared, but make sure
432         # to carry over REPEAT count specs between instructions. They
433         # start out as zero, will be setup by REPEAT instructions, need
434         # to get passed to the instruction which follows REPEAT. The
435         # instruction which sees a non-zero repeat count which will
436         # consume the counter and drop it to zero, then the counter
437         # remains at zero until the next REPEAT instruction.
438         save_rep_count = self.insn_rep_count
439         self.clear_insn()
440         self.insn_rep_count = save_rep_count
441
442     def handle_bits(self, ss, es, bitval):
443         '''Handle a bit at the UART layer.'''
444
445         # Concentrate annotation literals here for easier maintenance.
446         ann_class_text = {
447             Ann.START: ['Start bit', 'Start', 'S'],
448             Ann.PARITY_OK: ['Parity OK', 'Par OK', 'P'],
449             Ann.PARITY_ERR: ['Parity error', 'Par ERR', 'PE'],
450             Ann.STOP_OK: ['Stop bit', 'Stop', 'T'],
451             Ann.STOP_ERR: ['Stop bit error', 'Stop ERR', 'TE'],
452             Ann.BREAK: ['Break condition', 'BREAK', 'BRK'],
453         }
454         def put_uart_field(bitpos, annclass):
455             self.put_ann_data(bitpos, [annclass, ann_class_text[annclass]])
456
457         # The number of bits which form one UART frame. Note that
458         # the decoder operates with only one stop bit.
459         frame_bitcount = 1 + 8 + 1 + 1
460
461         # Detect adjacent runs of all-zero bits. This is meant
462         # to cope when BREAK conditions appear at any arbitrary
463         # position, it need not be "aligned" to an UART frame.
464         if bitval == 1:
465             self.zero_count = 0
466         elif bitval == 0:
467             if not self.zero_count:
468                 self.zero_ss = ss
469             self.zero_count += 1
470             if self.zero_count == frame_bitcount:
471                 self.break_ss = self.zero_ss
472
473         # BREAK conditions are _at_minimum_ the length of a UART frame, but
474         # can span an arbitrary number of bit times. Track the "end sample"
475         # value of the last low bit we have seen, and emit the annotation only
476         # after the line went idle (high) again. Pass BREAK to the upper layer
477         # as well. When the line is low, BREAK still is pending. When the line
478         # is high, the current bit cannot be START, thus return from here.
479         if self.break_ss is not None:
480             if bitval == '0':
481                 self.break_es = es
482                 return
483             self.put(self.break_ss, self.break_es, self.out_ann,
484                  [Ann.BREAK, ann_class_text[Ann.BREAK]])
485             self.handle_byte(self.break_ss, self.break_es, None)
486             self.break_ss = None
487             self.break_es = None
488             self.bits = []
489             return
490
491         # Ignore high bits when waiting for START.
492         if not self.bits and bitval == 1:
493             return
494
495         # Store individual bits and their start/end sample numbers,
496         # until a complete frame was received.
497         self.bits.append(Bit(bitval, ss, es))
498         if len(self.bits) < frame_bitcount:
499             return
500
501         # Get individual fields of the UART frame.
502         bits_num = sum([b.val << pos for pos, b in enumerate(self.bits)])
503         if False:
504             # This logic could detect BREAK conditions which are aligned to
505             # UART frames. Which was obsoleted by the above detection at
506             # arbitrary positions. The code still can be useful to detect
507             # "other kinds of frame errors" which carry valid symbols for
508             # upper layers (the Atmel literature suggests "break", "delay",
509             # and "empty" symbols when PDI is communicated over different
510             # physical layers).
511             if bits_num == 0: # BREAK
512                 self.break_ss = self.bits[0].ss
513                 self.break_es = es
514                 self.bits = []
515                 return
516         start_bit = bits_num & 0x01; bits_num >>= 1
517         data_val = bits_num & 0xff; bits_num >>= 8
518         data_text = '{:02x}'.format(data_val)
519         parity_bit = bits_num & 0x01; bits_num >>= 1
520         stop_bit = bits_num & 0x01; bits_num >>= 1
521
522         # Check for frame errors. START _must_ have been low
523         # according to the above accumulation logic.
524         parity_ok = (bin(data_val).count('1') + parity_bit) % 2 == 0
525         stop_ok = stop_bit == 1
526         valid_frame = parity_ok and stop_ok
527
528         # Emit annotations.
529         for idx in range(frame_bitcount):
530             self.put_ann_bit(idx, Ann.BIT)
531         put_uart_field(0, Ann.START)
532         self.put(self.bits[1].ss, self.bits[8].es, self.out_ann,
533              [Ann.DATA, ['Data: ' + data_text, 'D: ' + data_text, data_text]])
534         put_uart_field(9, Ann.PARITY_OK if parity_ok else Ann.PARITY_ERR)
535         put_uart_field(10, Ann.STOP_OK if stop_ok else Ann.STOP_ERR)
536
537         # Emit binary data stream. Have bytes interpreted at higher layers.
538         if valid_frame:
539             byte_ss, byte_es = self.bits[0].ss, self.bits[-1].es
540             self.put_bin_bytes(byte_ss, byte_es, Ann.BIN_BYTES, bytes([data_val]))
541             self.handle_byte(byte_ss, byte_es, data_val)
542
543         # Reset internal state for the next frame.
544         self.bits = []
545
546     def handle_clk_edge(self, clock_pin, data_pin):
547         # Sample the data line on rising clock edges. Always, for TX and for
548         # RX bytes alike.
549         if clock_pin == 1:
550             self.data_sample = data_pin
551             return
552
553         # Falling clock edges are boundaries for bit slots. Inspect previously
554         # sampled bits on falling clock edges, when the start and end sample
555         # numbers were determined. Only inspect bit slots of known clock
556         # periods (avoid interpreting the DATA line when the "enabled" state
557         # has not yet been determined).
558         self.ss_last_fall = self.ss_curr_fall
559         self.ss_curr_fall = self.samplenum
560         if self.ss_last_fall is None:
561             return
562
563         # Have the past bit slot processed.
564         bit_ss, bit_es = self.ss_last_fall, self.ss_curr_fall
565         bit_val = self.data_sample
566         self.handle_bits(bit_ss, bit_es, bit_val)
567
568     def decode(self):
569         while True:
570             self.handle_clk_edge(*self.wait({0: 'e'}))