]> sigrok.org Git - libsigrokdecode.git/blob - decoders/avr_pdi/pd.py
Add PD tags handling and some tags
[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     tags = ['Logic', 'MCU Debugging']
124     channels = (
125         {'id': 'reset', 'name': 'RESET', 'desc': 'RESET / PDI_CLK'},
126         {'id': 'data', 'name': 'DATA', 'desc': 'PDI_DATA'},
127     )
128     annotations = (
129         ('uart-bit', 'UART bit'),
130         ('start-bit', 'Start bit'),
131         ('data-bit', 'Data bit'),
132         ('parity-ok', 'Parity OK bit'),
133         ('parity-err', 'Parity error bit'),
134         ('stop-ok', 'Stop OK bit'),
135         ('stop-err', 'Stop error bit'),
136         ('break', 'BREAK condition'),
137         ('opcode', 'Instruction opcode'),
138         ('data-prog', 'Programmer data'),
139         ('data-dev', 'Device data'),
140         ('pdi-break', 'BREAK at PDI level'),
141         ('enable', 'Enable PDI'),
142         ('disable', 'Disable PDI'),
143         ('cmd-data', 'PDI command with data'),
144     )
145     annotation_rows = (
146         ('uart_bits', 'UART bits', (Ann.BIT,)),
147         ('uart_fields', 'UART fields', (Ann.START, Ann.DATA, Ann.PARITY_OK,
148             Ann.PARITY_ERR, Ann.STOP_OK, Ann.STOP_ERR, Ann.BREAK)),
149         ('pdi_fields', 'PDI fields', (Ann.OPCODE, Ann.DATA_PROG, Ann.DATA_DEV,
150             Ann.PDI_BREAK)),
151         ('pdi_cmds', 'PDI Cmds', (Ann.ENABLE, Ann.DISABLE, Ann.COMMAND)),
152     )
153     binary = (
154         ('bytes', 'PDI protocol bytes'),
155     )
156
157     def __init__(self):
158         self.reset()
159
160     def reset(self):
161         self.samplerate = None
162         self.clear_state()
163
164     def clear_state(self):
165         # Track bit times and bit values.
166         self.ss_last_fall = None
167         self.data_sample = None
168         self.ss_curr_fall = None
169         # Collect UART frame bits into byte values.
170         self.bits = []
171         self.zero_count = 0
172         self.zero_ss = None
173         self.break_ss = None
174         self.break_es = None
175         self.clear_insn()
176
177     def clear_insn(self):
178         # Collect instructions and their arguments,
179         # properties of the current instructions.
180         self.insn_rep_count = 0
181         self.insn_opcode = None
182         self.insn_wr_counts = []
183         self.insn_rd_counts = []
184         # Accumulation of data items as bytes pass by.
185         self.insn_dat_bytes = []
186         self.insn_dat_count = 0
187         self.insn_ss_data = None
188         # Next layer "commands", instructions plus operands.
189         self.cmd_ss = None
190         self.cmd_insn_parts_nice = []
191         self.cmd_insn_parts_terse = []
192
193     def metadata(self, key, value):
194         if key == srd.SRD_CONF_SAMPLERATE:
195             self.samplerate = value
196
197     def start(self):
198         self.out_ann = self.register(srd.OUTPUT_ANN)
199         self.out_binary = self.register(srd.OUTPUT_BINARY)
200
201     def put_ann_bit(self, bit_nr, ann_idx):
202         b = self.bits[bit_nr]
203         self.put(b.ss, b.es, self.out_ann, [ann_idx, [str(b.val)]])
204
205     def put_ann_data(self, bit_nr, ann_data):
206         b = self.bits[bit_nr]
207         self.put(b.ss, b.es, self.out_ann, ann_data)
208
209     def put_ann_row_val(self, ss, es, row, value):
210         self.put(ss, es, self.out_ann, [row, value])
211
212     def put_bin_bytes(self, ss, es, row, value):
213         self.put(ss, es, self.out_binary, [row, value])
214
215     def handle_byte(self, ss, es, byteval):
216         '''Handle a byte at the PDI protocol layer.'''
217
218         # Handle BREAK conditions, which will abort any
219         # potentially currently executing instruction.
220         is_break = byteval is None
221         if is_break:
222             self.cmd_insn_parts_nice.append('BREAK')
223             self.cmd_insn_parts_terse.append('BRK')
224             self.insn_rep_count = 0
225             # Will FALLTHROUGH to "end of instruction" below.
226
227         # Decode instruction opcodes and argument sizes
228         # from the first byte of a transaction.
229         if self.insn_opcode is None and not is_break:
230             opcode = (byteval & 0xe0) >> 5
231             arg30 = byteval & 0x0f
232             arg32 = (byteval & 0x0c) >> 2
233             arg10 = byteval & 0x03
234             self.insn_opcode = opcode
235             self.cmd_ss = ss
236             mnemonics = None
237             if opcode == PDI.OP_LDS:
238                 # LDS: load data, direct addressing.
239                 # Writes an address, reads a data item.
240                 width_addr = arg32 + 1
241                 width_data = arg10 + 1
242                 self.insn_wr_counts = [width_addr]
243                 self.insn_rd_counts = [width_data]
244                 mnemonics = [
245                     'Insn: LDS a{:d}, m{:d}'.format(width_addr, width_data),
246                     'LDS a{:d}, m{:d}'.format(width_addr, width_data), 'LDS',
247                 ]
248                 self.cmd_insn_parts_nice = ['LDS']
249                 self.cmd_insn_parts_terse = ['LDS']
250             elif opcode == PDI.OP_LD:
251                 # LD: load data, indirect addressing.
252                 # Reads a data item, with optional repeat.
253                 ptr_txt = PDI.pointer_format_nice[arg32]
254                 ptr_txt_terse = PDI.pointer_format_terse[arg32]
255                 width_data = arg10 + 1
256                 self.insn_wr_counts = []
257                 self.insn_rd_counts = [width_data]
258                 if self.insn_rep_count:
259                     self.insn_rd_counts.extend(self.insn_rep_count * [width_data])
260                     self.insn_rep_count = 0
261                 mnemonics = [
262                     'Insn: LD {:s} m{:d}'.format(ptr_txt, width_data),
263                     'LD {:s} m{:d}'.format(ptr_txt, width_data), 'LD',
264                 ]
265                 self.cmd_insn_parts_nice = ['LD', ptr_txt]
266                 self.cmd_insn_parts_terse = ['LD', ptr_txt_terse]
267             elif opcode == PDI.OP_STS:
268                 # STS: store data, direct addressing.
269                 # Writes an address, writes a data item.
270                 width_addr = arg32 + 1
271                 width_data = arg10 + 1
272                 self.insn_wr_counts = [width_addr, width_data]
273                 self.insn_rd_counts = []
274                 mnemonics = [
275                     'Insn: STS a{:d}, i{:d}'.format(width_addr, width_data),
276                     'STS a{:d}, i{:d}'.format(width_addr, width_data), 'STS',
277                 ]
278                 self.cmd_insn_parts_nice = ['STS']
279                 self.cmd_insn_parts_terse = ['STS']
280             elif opcode == PDI.OP_ST:
281                 # ST: store data, indirect addressing.
282                 # Writes a data item, with optional repeat.
283                 ptr_txt = PDI.pointer_format_nice[arg32]
284                 ptr_txt_terse = PDI.pointer_format_terse[arg32]
285                 width_data = arg10 + 1
286                 self.insn_wr_counts = [width_data]
287                 self.insn_rd_counts = []
288                 if self.insn_rep_count:
289                     self.insn_wr_counts.extend(self.insn_rep_count * [width_data])
290                     self.insn_rep_count = 0
291                 mnemonics = [
292                     'Insn: ST {:s} i{:d}'.format(ptr_txt, width_data),
293                     'ST {:s} i{:d}'.format(ptr_txt, width_data), 'ST',
294                 ]
295                 self.cmd_insn_parts_nice = ['ST', ptr_txt]
296                 self.cmd_insn_parts_terse = ['ST', ptr_txt_terse]
297             elif opcode == PDI.OP_LDCS:
298                 # LDCS: load control/status.
299                 # Loads exactly one byte.
300                 reg_num = arg30
301                 reg_txt = PDI.ctrl_reg_name.get(reg_num, 'r{:d}'.format(reg_num))
302                 reg_txt_terse = '{:d}'.format(reg_num)
303                 self.insn_wr_counts = []
304                 self.insn_rd_counts = [1]
305                 mnemonics = [
306                     'Insn: LDCS {:s}, m1'.format(reg_txt),
307                     'LDCS {:s}, m1'.format(reg_txt), 'LDCS',
308                 ]
309                 self.cmd_insn_parts_nice = ['LDCS', reg_txt]
310                 self.cmd_insn_parts_terse = ['LDCS', reg_txt_terse]
311             elif opcode == PDI.OP_STCS:
312                 # STCS: store control/status.
313                 # Writes exactly one byte.
314                 reg_num = arg30
315                 reg_txt = PDI.ctrl_reg_name.get(reg_num, 'r{:d}'.format(reg_num))
316                 reg_txt_terse = '{:d}'.format(reg_num)
317                 self.insn_wr_counts = [1]
318                 self.insn_rd_counts = []
319                 mnemonics = [
320                     'Insn: STCS {:s}, i1'.format(reg_txt),
321                     'STCS {:s}, i1'.format(reg_txt), 'STCS',
322                 ]
323                 self.cmd_insn_parts_nice = ['STCS', reg_txt]
324                 self.cmd_insn_parts_terse = ['STCS', reg_txt_terse]
325             elif opcode == PDI.OP_REPEAT:
326                 # REPEAT: sets repeat count for the next instruction.
327                 # Reads repeat count from following bytes.
328                 width_data = arg10 + 1
329                 self.insn_wr_counts = [width_data]
330                 self.insn_rd_counts = []
331                 mnemonics = [
332                     'Insn: REPEAT i{:d}'.format(width_data),
333                     'REPEAT i{:d}'.format(width_data), 'REP',
334                 ]
335                 self.cmd_insn_parts_nice = ['REPEAT']
336                 self.cmd_insn_parts_terse = ['REP']
337             elif opcode == PDI.OP_KEY:
338                 # KEY: set activation key (enables PDIBUS mmap access).
339                 # Writes a sequence of 8 bytes, fixed length.
340                 width_data = 8
341                 self.insn_wr_counts = [width_data]
342                 self.insn_rd_counts = []
343                 mnemonics = [
344                     'Insn: KEY i{:d}'.format(width_data),
345                     'KEY i{:d}'.format(width_data), 'KEY',
346                 ]
347                 self.cmd_insn_parts_nice = ['KEY']
348                 self.cmd_insn_parts_terse = ['KEY']
349
350             # Emit an annotation for the instruction opcode.
351             self.put_ann_row_val(ss, es, Ann.OPCODE, mnemonics)
352
353             # Prepare to write/read operands/data bytes.
354             self.insn_dat_bytes = []
355             if self.insn_wr_counts:
356                 self.insn_dat_count = self.insn_wr_counts[0]
357                 return
358             if self.insn_rd_counts:
359                 self.insn_dat_count = self.insn_rd_counts[0]
360                 return
361             # FALLTHROUGH.
362             # When there are no operands or data bytes to read,
363             # then fall through to the end of the instruction
364             # handling below (which emits annotations).
365
366         # Read bytes which carry operands (addresses, immediates)
367         # or data values for memory access.
368         if self.insn_dat_count and not is_break:
369
370             # Accumulate received bytes until another multi byte
371             # data item is complete.
372             if not self.insn_dat_bytes:
373                 self.insn_ss_data = ss
374             self.insn_dat_bytes.append(byteval)
375             self.insn_dat_count -= 1
376             if self.insn_dat_count:
377                 return
378
379             # Determine the data item's duration and direction,
380             # "consume" its length spec (to simplify later steps).
381             data_ss = self.insn_ss_data
382             data_es = es
383             if self.insn_wr_counts:
384                 data_ann = Ann.DATA_PROG
385                 data_width = self.insn_wr_counts.pop(0)
386             elif self.insn_rd_counts:
387                 data_ann = Ann.DATA_DEV
388                 data_width = self.insn_rd_counts.pop(0)
389
390             # PDI communicates multi-byte data items in little endian
391             # order. Get a nice textual representation of the number,
392             # wide and narrow for several zoom levels.
393             self.insn_dat_bytes.reverse()
394             data_txt_digits = ''.join(['{:02x}'.format(b) for b in self.insn_dat_bytes])
395             data_txt_hex = '0x' + data_txt_digits
396             data_txt_prefix = 'Data: ' + data_txt_hex
397             data_txts = [data_txt_prefix, data_txt_hex, data_txt_digits]
398             self.insn_dat_bytes = []
399
400             # Emit an annotation for the data value.
401             self.put_ann_row_val(data_ss, data_es, data_ann, data_txts)
402
403             # Collect detailled information which describes the whole
404             # command when combined (for a next layer annotation,
405             # spanning the complete command).
406             self.cmd_insn_parts_nice.append(data_txt_hex)
407             self.cmd_insn_parts_terse.append(data_txt_digits)
408
409             # Send out write data first until exhausted,
410             # then drain expected read data.
411             if self.insn_wr_counts:
412                 self.insn_dat_count = self.insn_wr_counts[0]
413                 return
414             if self.insn_rd_counts:
415                 self.insn_dat_count = self.insn_rd_counts[0]
416                 return
417
418             # FALLTHROUGH.
419             # When all operands and data bytes were seen,
420             # terminate the inspection of the instruction.
421
422         # Postprocess the instruction after its operands were seen.
423         cmd_es = es
424         cmd_txt_nice = ' '.join(self.cmd_insn_parts_nice)
425         cmd_txt_terse = ' '.join(self.cmd_insn_parts_terse)
426         cmd_txts = [cmd_txt_nice, cmd_txt_terse]
427         self.put_ann_row_val(self.cmd_ss, cmd_es, Ann.COMMAND, cmd_txts)
428         if self.insn_opcode == PDI.OP_REPEAT and not is_break:
429             # The last communicated data item is the repeat
430             # count for the next instruction (i.e. it will
431             # execute N+1 times when "REPEAT N" is specified).
432             count = int(self.cmd_insn_parts_nice[-1], 0)
433             self.insn_rep_count = count
434
435         # Have the state for instruction decoding cleared, but make sure
436         # to carry over REPEAT count specs between instructions. They
437         # start out as zero, will be setup by REPEAT instructions, need
438         # to get passed to the instruction which follows REPEAT. The
439         # instruction which sees a non-zero repeat count which will
440         # consume the counter and drop it to zero, then the counter
441         # remains at zero until the next REPEAT instruction.
442         save_rep_count = self.insn_rep_count
443         self.clear_insn()
444         self.insn_rep_count = save_rep_count
445
446     def handle_bits(self, ss, es, bitval):
447         '''Handle a bit at the UART layer.'''
448
449         # Concentrate annotation literals here for easier maintenance.
450         ann_class_text = {
451             Ann.START: ['Start bit', 'Start', 'S'],
452             Ann.PARITY_OK: ['Parity OK', 'Par OK', 'P'],
453             Ann.PARITY_ERR: ['Parity error', 'Par ERR', 'PE'],
454             Ann.STOP_OK: ['Stop bit', 'Stop', 'T'],
455             Ann.STOP_ERR: ['Stop bit error', 'Stop ERR', 'TE'],
456             Ann.BREAK: ['Break condition', 'BREAK', 'BRK'],
457         }
458         def put_uart_field(bitpos, annclass):
459             self.put_ann_data(bitpos, [annclass, ann_class_text[annclass]])
460
461         # The number of bits which form one UART frame. Note that
462         # the decoder operates with only one stop bit.
463         frame_bitcount = 1 + 8 + 1 + 1
464
465         # Detect adjacent runs of all-zero bits. This is meant
466         # to cope when BREAK conditions appear at any arbitrary
467         # position, it need not be "aligned" to an UART frame.
468         if bitval == 1:
469             self.zero_count = 0
470         elif bitval == 0:
471             if not self.zero_count:
472                 self.zero_ss = ss
473             self.zero_count += 1
474             if self.zero_count == frame_bitcount:
475                 self.break_ss = self.zero_ss
476
477         # BREAK conditions are _at_minimum_ the length of a UART frame, but
478         # can span an arbitrary number of bit times. Track the "end sample"
479         # value of the last low bit we have seen, and emit the annotation only
480         # after the line went idle (high) again. Pass BREAK to the upper layer
481         # as well. When the line is low, BREAK still is pending. When the line
482         # is high, the current bit cannot be START, thus return from here.
483         if self.break_ss is not None:
484             if bitval == '0':
485                 self.break_es = es
486                 return
487             self.put(self.break_ss, self.break_es, self.out_ann,
488                  [Ann.BREAK, ann_class_text[Ann.BREAK]])
489             self.handle_byte(self.break_ss, self.break_es, None)
490             self.break_ss = None
491             self.break_es = None
492             self.bits = []
493             return
494
495         # Ignore high bits when waiting for START.
496         if not self.bits and bitval == 1:
497             return
498
499         # Store individual bits and their start/end sample numbers,
500         # until a complete frame was received.
501         self.bits.append(Bit(bitval, ss, es))
502         if len(self.bits) < frame_bitcount:
503             return
504
505         # Get individual fields of the UART frame.
506         bits_num = sum([b.val << pos for pos, b in enumerate(self.bits)])
507         if False:
508             # This logic could detect BREAK conditions which are aligned to
509             # UART frames. Which was obsoleted by the above detection at
510             # arbitrary positions. The code still can be useful to detect
511             # "other kinds of frame errors" which carry valid symbols for
512             # upper layers (the Atmel literature suggests "break", "delay",
513             # and "empty" symbols when PDI is communicated over different
514             # physical layers).
515             if bits_num == 0: # BREAK
516                 self.break_ss = self.bits[0].ss
517                 self.break_es = es
518                 self.bits = []
519                 return
520         start_bit = bits_num & 0x01; bits_num >>= 1
521         data_val = bits_num & 0xff; bits_num >>= 8
522         data_text = '{:02x}'.format(data_val)
523         parity_bit = bits_num & 0x01; bits_num >>= 1
524         stop_bit = bits_num & 0x01; bits_num >>= 1
525
526         # Check for frame errors. START _must_ have been low
527         # according to the above accumulation logic.
528         parity_ok = (bin(data_val).count('1') + parity_bit) % 2 == 0
529         stop_ok = stop_bit == 1
530         valid_frame = parity_ok and stop_ok
531
532         # Emit annotations.
533         for idx in range(frame_bitcount):
534             self.put_ann_bit(idx, Ann.BIT)
535         put_uart_field(0, Ann.START)
536         self.put(self.bits[1].ss, self.bits[8].es, self.out_ann,
537              [Ann.DATA, ['Data: ' + data_text, 'D: ' + data_text, data_text]])
538         put_uart_field(9, Ann.PARITY_OK if parity_ok else Ann.PARITY_ERR)
539         put_uart_field(10, Ann.STOP_OK if stop_ok else Ann.STOP_ERR)
540
541         # Emit binary data stream. Have bytes interpreted at higher layers.
542         if valid_frame:
543             byte_ss, byte_es = self.bits[0].ss, self.bits[-1].es
544             self.put_bin_bytes(byte_ss, byte_es, Ann.BIN_BYTES, bytes([data_val]))
545             self.handle_byte(byte_ss, byte_es, data_val)
546
547         # Reset internal state for the next frame.
548         self.bits = []
549
550     def handle_clk_edge(self, clock_pin, data_pin):
551         # Sample the data line on rising clock edges. Always, for TX and for
552         # RX bytes alike.
553         if clock_pin == 1:
554             self.data_sample = data_pin
555             return
556
557         # Falling clock edges are boundaries for bit slots. Inspect previously
558         # sampled bits on falling clock edges, when the start and end sample
559         # numbers were determined. Only inspect bit slots of known clock
560         # periods (avoid interpreting the DATA line when the "enabled" state
561         # has not yet been determined).
562         self.ss_last_fall = self.ss_curr_fall
563         self.ss_curr_fall = self.samplenum
564         if self.ss_last_fall is None:
565             return
566
567         # Have the past bit slot processed.
568         bit_ss, bit_es = self.ss_last_fall, self.ss_curr_fall
569         bit_val = self.data_sample
570         self.handle_bits(bit_ss, bit_es, bit_val)
571
572     def decode(self):
573         while True:
574             self.handle_clk_edge(*self.wait({0: 'e'}))