]> sigrok.org Git - libsigrokdecode.git/blame - decoders/avr_pdi/pd.py
avr_pdi: Convert to PD API version 3.
[libsigrokdecode.git] / decoders / avr_pdi / pd.py
CommitLineData
f0349f7f
GS
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
73import sigrokdecode as srd
74from collections import namedtuple
75
76class 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
88Bit = namedtuple('Bit', 'val ss es')
89
90class 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
114class Decoder(srd.Decoder):
6a239714 115 api_version = 3
f0349f7f
GS
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
f0349f7f
GS
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
6a239714 546 def handle_clk_edge(self, samplenum, clock_pin, data_pin):
f0349f7f
GS
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 = 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
6a239714
GS
568 def decode(self):
569 while True:
570 clock_pin, data_pin = self.wait({0: 'e'})
571 self.handle_clk_edge(self.samplenum, clock_pin, data_pin)