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