]>
Commit | Line | Data |
---|---|---|
93b92702 GS |
1 | ## |
2 | ## This file is part of the libsigrokdecode project. | |
3 | ## | |
4 | ## Copyright (C) 2017 Gerhard Sittig <gerhard.sittig@gmx.net> | |
5 | ## | |
6 | ## This program is free software; you can redistribute it and/or modify | |
7 | ## it under the terms of the GNU General Public License as published by | |
8 | ## the Free Software Foundation; either version 2 of the License, or | |
9 | ## (at your option) any later version. | |
10 | ## | |
11 | ## This program is distributed in the hope that it will be useful, | |
12 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | ## GNU General Public License for more details. | |
15 | ## | |
16 | ## You should have received a copy of the GNU General Public License | |
17 | ## along with this program; if not, see <http://www.gnu.org/licenses/>. | |
18 | ## | |
19 | ||
20 | # This implementation is incomplete. TODO items: | |
21 | # - Support the optional RESET# pin, detect cold and warm reset. | |
22 | # - Split slot values into audio samples of their respective width and | |
23 | # frequency (either on user provided parameters, or from inspection of | |
24 | # decoded register access). | |
25 | ||
26 | import sigrokdecode as srd | |
27 | ||
28 | class ChannelError(Exception): | |
29 | pass | |
30 | ||
31 | class Pins: | |
32 | (SYNC, BIT_CLK, SDATA_OUT, SDATA_IN, RESET) = range(5) | |
33 | ||
34 | class Ann: | |
35 | ( | |
36 | BITS_OUT, BITS_IN, | |
37 | SLOT_OUT_RAW, SLOT_OUT_TAG, SLOT_OUT_ADDR, SLOT_OUT_DATA, | |
38 | SLOT_OUT_03, SLOT_OUT_04, SLOT_OUT_05, SLOT_OUT_06, | |
39 | SLOT_OUT_07, SLOT_OUT_08, SLOT_OUT_09, SLOT_OUT_10, | |
40 | SLOT_OUT_11, SLOT_OUT_IO, | |
41 | SLOT_IN_RAW, SLOT_IN_TAG, SLOT_IN_ADDR, SLOT_IN_DATA, | |
42 | SLOT_IN_03, SLOT_IN_04, SLOT_IN_05, SLOT_IN_06, | |
43 | SLOT_IN_07, SLOT_IN_08, SLOT_IN_09, SLOT_IN_10, | |
44 | SLOT_IN_11, SLOT_IN_IO, | |
45 | WARN, ERROR, | |
46 | ) = range(32) | |
47 | ( | |
48 | BIN_FRAME_OUT, | |
49 | BIN_FRAME_IN, | |
50 | BIN_SLOT_RAW_OUT, | |
51 | BIN_SLOT_RAW_IN, | |
52 | ) = range(4) | |
53 | ||
54 | class Decoder(srd.Decoder): | |
55 | api_version = 3 | |
56 | id = 'ac97' | |
57 | name = "AC '97" | |
58 | longname = "Audio Codec '97" | |
59 | desc = 'Audio and modem control for PC systems.' | |
60 | license = 'gplv2+' | |
61 | inputs = ['logic'] | |
6cbba91f | 62 | outputs = [] |
d6d8a8a4 | 63 | tags = ['Audio', 'PC'] |
93b92702 GS |
64 | channels = ( |
65 | {'id': 'sync', 'name': 'SYNC', 'desc': 'Frame synchronization'}, | |
66 | {'id': 'clk', 'name': 'BIT_CLK', 'desc': 'Data bits clock'}, | |
67 | ) | |
68 | optional_channels = ( | |
69 | {'id': 'out', 'name': 'SDATA_OUT', 'desc': 'Data output'}, | |
70 | {'id': 'in', 'name': 'SDATA_IN', 'desc': 'Data input'}, | |
71 | {'id': 'rst', 'name': 'RESET#', 'desc': 'Reset line'}, | |
72 | ) | |
73 | annotations = ( | |
74 | ('bit-out', 'Output bits'), | |
75 | ('bit-in', 'Input bits'), | |
76 | ('slot-out-raw', 'Output raw value'), | |
77 | ('slot-out-tag', 'Output TAG'), | |
78 | ('slot-out-cmd-addr', 'Output command address'), | |
79 | ('slot-out-cmd-data', 'Output command data'), | |
80 | ('slot-out-03', 'Output slot 3'), | |
81 | ('slot-out-04', 'Output slot 4'), | |
82 | ('slot-out-05', 'Output slot 5'), | |
83 | ('slot-out-06', 'Output slot 6'), | |
84 | ('slot-out-07', 'Output slot 7'), | |
85 | ('slot-out-08', 'Output slot 8'), | |
86 | ('slot-out-09', 'Output slot 9'), | |
87 | ('slot-out-10', 'Output slot 10'), | |
88 | ('slot-out-11', 'Output slot 11'), | |
89 | ('slot-out-io-ctrl', 'Output I/O control'), | |
90 | ('slot-in-raw', 'Input raw value'), | |
91 | ('slot-in-tag', 'Input TAG'), | |
92 | ('slot-in-sts-addr', 'Input status address'), | |
93 | ('slot-in-sts-data', 'Input status data'), | |
94 | ('slot-in-03', 'Input slot 3'), | |
95 | ('slot-in-04', 'Input slot 4'), | |
96 | ('slot-in-05', 'Input slot 5'), | |
97 | ('slot-in-06', 'Input slot 6'), | |
98 | ('slot-in-07', 'Input slot 7'), | |
99 | ('slot-in-08', 'Input slot 8'), | |
100 | ('slot-in-09', 'Input slot 9'), | |
101 | ('slot-in-10', 'Input slot 10'), | |
102 | ('slot-in-11', 'Input slot 11'), | |
103 | ('slot-in-io-sts', 'Input I/O status'), | |
104 | # TODO: Add more annotation classes: | |
105 | # TAG: 'ready', 'valid', 'id', 'rsv' | |
106 | # CMD ADDR: 'r/w', 'addr', 'unused' | |
107 | # CMD DATA: 'data', 'unused' | |
108 | # 3-11: 'data', 'unused', 'double data' | |
109 | ('warning', 'Warning'), | |
110 | ('error', 'Error'), | |
111 | ) | |
112 | annotation_rows = ( | |
113 | ('bits-out', 'Output bits', (Ann.BITS_OUT,)), | |
114 | ('slots-out-raw', 'Output numbers', (Ann.SLOT_OUT_RAW,)), | |
115 | ('slots-out', 'Output slots', ( | |
116 | Ann.SLOT_OUT_TAG, Ann.SLOT_OUT_ADDR, Ann.SLOT_OUT_DATA, | |
117 | Ann.SLOT_OUT_03, Ann.SLOT_OUT_04, Ann.SLOT_OUT_05, Ann.SLOT_OUT_06, | |
118 | Ann.SLOT_OUT_07, Ann.SLOT_OUT_08, Ann.SLOT_OUT_09, Ann.SLOT_OUT_10, | |
119 | Ann.SLOT_OUT_11, Ann.SLOT_OUT_IO,)), | |
120 | ('bits-in', 'Input bits', (Ann.BITS_IN,)), | |
121 | ('slots-in-raw', 'Input numbers', (Ann.SLOT_IN_RAW,)), | |
122 | ('slots-in', 'Input slots', ( | |
123 | Ann.SLOT_IN_TAG, Ann.SLOT_IN_ADDR, Ann.SLOT_IN_DATA, | |
124 | Ann.SLOT_IN_03, Ann.SLOT_IN_04, Ann.SLOT_IN_05, Ann.SLOT_IN_06, | |
125 | Ann.SLOT_IN_07, Ann.SLOT_IN_08, Ann.SLOT_IN_09, Ann.SLOT_IN_10, | |
126 | Ann.SLOT_IN_11, Ann.SLOT_IN_IO,)), | |
127 | ('warnings', 'Warnings', (Ann.WARN,)), | |
128 | ('errors', 'Errors', (Ann.ERROR,)), | |
129 | ) | |
130 | binary = ( | |
131 | ('frame-out', 'Frame bits, output data'), | |
132 | ('frame-in', 'Frame bits, input data'), | |
133 | ('slot-raw-out', 'Raw slot bits, output data'), | |
134 | ('slot-raw-in', 'Raw slot bits, input data'), | |
135 | # TODO: Which (other) binary classes to implement? | |
136 | # - Are binary annotations per audio slot useful? | |
137 | # - Assume 20bit per slot, in 24bit units? Or assume 16bit | |
138 | # audio samples? Observe register access and derive width | |
139 | # of the audio data? Dump channels 3-11 or 1-12? | |
140 | ) | |
141 | ||
142 | def putx(self, ss, es, cls, data): | |
143 | self.put(ss, es, self.out_ann, [cls, data]) | |
144 | ||
145 | def putf(self, frombit, bitcount, cls, data): | |
146 | ss = self.frame_ss_list[frombit] | |
147 | es = self.frame_ss_list[frombit + bitcount] | |
148 | self.putx(ss, es, cls, data) | |
149 | ||
150 | def putb(self, frombit, bitcount, cls, data): | |
151 | ss = self.frame_ss_list[frombit] | |
152 | es = self.frame_ss_list[frombit + bitcount] | |
153 | self.put(ss, es, self.out_binary, [cls, data]) | |
154 | ||
155 | def __init__(self): | |
156 | self.out_binary = None | |
157 | self.out_ann = None | |
158 | self.reset() | |
159 | ||
160 | def reset(self): | |
161 | self.frame_ss_list = None | |
162 | self.frame_slot_lens = [0, 16] + [16 + 20 * i for i in range(1, 13)] | |
163 | self.frame_total_bits = self.frame_slot_lens[-1] | |
164 | self.handle_slots = { | |
165 | 0: self.handle_slot_00, | |
166 | 1: self.handle_slot_01, | |
167 | 2: self.handle_slot_02, | |
168 | } | |
169 | ||
170 | def start(self): | |
171 | if not self.out_binary: | |
172 | self.out_binary = self.register(srd.OUTPUT_BINARY) | |
173 | if not self.out_ann: | |
174 | self.out_ann = self.register(srd.OUTPUT_ANN) | |
175 | ||
176 | def metadata(self, key, value): | |
177 | if key == srd.SRD_CONF_SAMPLERATE: | |
178 | self.samplerate = value | |
179 | ||
180 | def bits_to_int(self, bits): | |
181 | # Convert MSB-first bit sequence to integer value. | |
182 | if not bits: | |
183 | return 0 | |
184 | count = len(bits) | |
185 | value = sum([2 ** (count - 1 - i) for i in range(count) if bits[i]]) | |
186 | return value | |
187 | ||
188 | def bits_to_bin_ann(self, bits): | |
189 | # Convert MSB-first bit sequence to binary annotation data. | |
190 | # It's assumed that the number of bits does not (in useful ways) | |
191 | # fit into an integer, and we need to create an array of bytes | |
192 | # from the data afterwards, anyway. Hence the separate routine | |
193 | # and the conversion of eight bits each. | |
194 | out = [] | |
195 | count = len(bits) | |
196 | while count > 0: | |
197 | count -= 8 | |
198 | by, bits = bits[:8], bits[8:] | |
199 | by = self.bits_to_int(by) | |
200 | out.append(by) | |
201 | out = bytes(out) | |
202 | return out | |
203 | ||
204 | def int_to_nibble_text(self, value, bitcount): | |
205 | # Convert number to hex digits for given bit count. | |
206 | digits = (bitcount + 3) // 4 | |
207 | text = '{{:0{:d}x}}'.format(digits).format(value) | |
208 | return text | |
209 | ||
210 | def get_bit_field(self, data, size, off, count): | |
211 | shift = size - off - count | |
212 | data >>= shift | |
213 | mask = (1 << count) - 1 | |
214 | data &= mask | |
215 | return data | |
216 | ||
217 | def flush_frame_bits(self): | |
218 | # Flush raw frame bits to binary annotation. | |
219 | anncls = Ann.BIN_FRAME_OUT | |
220 | data = self.frame_bits_out[:] | |
221 | count = len(data) | |
222 | data = self.bits_to_bin_ann(data) | |
223 | self.putb(0, count, anncls, data) | |
224 | ||
225 | anncls = Ann.BIN_FRAME_IN | |
226 | data = self.frame_bits_in[:] | |
227 | count = len(data) | |
228 | data = self.bits_to_bin_ann(data) | |
229 | self.putb(0, count, anncls, data) | |
230 | ||
231 | def start_frame(self, ss): | |
232 | # Mark the start of a frame. | |
233 | if self.frame_ss_list: | |
234 | # Flush bits if we had a frame before the frame which is | |
235 | # starting here. | |
236 | self.flush_frame_bits() | |
237 | self.frame_ss_list = [ss] | |
238 | self.frame_bits_out = [] | |
239 | self.frame_bits_in = [] | |
240 | self.frame_slot_data_out = [] | |
241 | self.frame_slot_data_in = [] | |
242 | self.have_slots = {True: None, False: None} | |
243 | ||
244 | def handle_slot_dummy(self, slotidx, bitidx, bitcount, is_out, data): | |
245 | # Handle slot x, default/fallback handler. | |
246 | # Only process data of slots 1-12 when slot 0 says "valid". | |
247 | if not self.have_slots[is_out]: | |
248 | return | |
249 | if not self.have_slots[is_out][slotidx]: | |
250 | return | |
251 | ||
252 | # Emit a naive annotation with just the data bits that we saw | |
253 | # for the slot (hex nibbles for density). For audio data this | |
254 | # can be good enough. Slots with special meaning should not end | |
255 | # up calling the dummy handler. | |
256 | text = self.int_to_nibble_text(data, bitcount) | |
257 | anncls = Ann.SLOT_OUT_TAG if is_out else Ann.SLOT_IN_TAG | |
258 | self.putf(bitidx, bitcount, anncls + slotidx, [text]) | |
259 | ||
260 | # Emit binary output for the data that is contained in slots | |
261 | # which end up calling the default handler. This transparently | |
262 | # should translate to "the slots with audio data", as other | |
263 | # slots which contain management data should have their specific | |
264 | # handler routines. In the present form, this approach might be | |
265 | # good enough to get a (header-less) audio stream for typical | |
266 | # setups where only line-in or line-out are in use. | |
267 | # | |
268 | # TODO: Improve this early prototype implementation. For now the | |
269 | # decoder just exports the upper 16 bits of each audio channel | |
270 | # that happens to be valid. For an improved implementation, it | |
271 | # either takes user provided specs or more smarts like observing | |
272 | # register access (if the capture includes it). | |
273 | anncls = Ann.BIN_SLOT_RAW_OUT if is_out else Ann.BIN_SLOT_RAW_IN | |
274 | data_bin = data >> 4 | |
275 | data_bin &= 0xffff | |
276 | data_bin = data_bin.to_bytes(2, byteorder = 'big') | |
277 | self.putb(bitidx, bitcount, anncls, data_bin) | |
278 | ||
279 | def handle_slot_00(self, slotidx, bitidx, bitcount, is_out, data): | |
280 | # Handle slot 0, TAG. | |
281 | slotpos = self.frame_slot_lens[slotidx] | |
282 | fieldoff = 0 | |
283 | anncls = Ann.SLOT_OUT_TAG if is_out else Ann.SLOT_IN_TAG | |
284 | ||
285 | fieldlen = 1 | |
286 | ready = self.get_bit_field(data, bitcount, fieldoff, fieldlen) | |
287 | text = ['READY: 1', 'READY', 'RDY', 'R'] if ready else ['ready: 0', 'rdy', '-'] | |
288 | self.putf(slotpos + fieldoff, fieldlen, anncls, text) | |
289 | fieldoff += fieldlen | |
290 | ||
291 | fieldlen = 12 | |
292 | valid = self.get_bit_field(data, bitcount, fieldoff, fieldlen) | |
293 | text = ['VALID: {:3x}'.format(valid), '{:3x}'.format(valid)] | |
294 | self.putf(slotpos + fieldoff, fieldlen, anncls, text) | |
295 | have_slots = [True] + [False] * 12 | |
296 | for idx in range(12): | |
297 | have_slots[idx + 1] = bool(valid & (1 << (11 - idx))) | |
298 | self.have_slots[is_out] = have_slots | |
299 | fieldoff += fieldlen | |
300 | ||
301 | fieldlen = 1 | |
302 | rsv = self.get_bit_field(data, bitcount, fieldoff, fieldlen) | |
303 | if rsv != 0: | |
304 | text = ['reserved bit error', 'rsv error', 'rsv'] | |
305 | self.putf(slotpos + fieldoff, fieldlen, Ann.ERROR, text) | |
306 | fieldoff += fieldlen | |
307 | ||
308 | # TODO: Will input slot 0 have a Codec ID, or 3 reserved bits? | |
309 | fieldlen = 2 | |
310 | codec = self.get_bit_field(data, bitcount, fieldoff, fieldlen) | |
311 | text = ['CODEC: {:1x}'.format(codec), '{:1x}'.format(codec)] | |
312 | self.putf(slotpos + fieldoff, fieldlen, anncls, text) | |
313 | fieldoff += fieldlen | |
314 | ||
315 | def handle_slot_01(self, slotidx, bitidx, bitcount, is_out, data): | |
316 | # Handle slot 1, command/status address. | |
317 | slotpos = self.frame_slot_lens[slotidx] | |
318 | if not self.have_slots[is_out]: | |
319 | return | |
320 | if not self.have_slots[is_out][slotidx]: | |
321 | return | |
322 | fieldoff = 0 | |
323 | anncls = Ann.SLOT_OUT_TAG if is_out else Ann.SLOT_IN_TAG | |
324 | anncls += slotidx | |
325 | ||
326 | fieldlen = 1 | |
327 | if is_out: | |
328 | is_read = self.get_bit_field(data, bitcount, fieldoff, fieldlen) | |
329 | text = ['READ', 'RD', 'R'] if is_read else ['WRITE', 'WR', 'W'] | |
330 | self.putf(slotpos + fieldoff, fieldlen, anncls, text) | |
331 | # TODO: Check for the "atomic" constraint? Some operations | |
332 | # involve address _and_ data, which cannot be spread across | |
333 | # several frames. Slot 0 and 1 _must_ be provided within the | |
334 | # same frame (the test should occur in the handler for slot | |
335 | # 2 of course, in slot 1 we don't know what will follow). | |
336 | else: | |
337 | rsv = self.get_bit_field(data, bitcount, fieldoff, fieldlen) | |
338 | if rsv != 0: | |
339 | text = ['reserved bit error', 'rsv error', 'rsv'] | |
340 | self.putf(slotpos + fieldoff, fieldlen, Ann.ERROR, text) | |
341 | fieldoff += fieldlen | |
342 | ||
343 | fieldlen = 7 | |
344 | regaddr = self.get_bit_field(data, bitcount, fieldoff, fieldlen) | |
345 | # TODO: Present 0-63 or 0-126 as the address of the 16bit register? | |
346 | text = ['ADDR: {:2x}'.format(regaddr), '{:2x}'.format(regaddr)] | |
347 | self.putf(slotpos + fieldoff, fieldlen, anncls, text) | |
348 | if regaddr & 0x01: | |
349 | text = ['odd register address', 'odd reg addr', 'odd addr', 'odd'] | |
350 | self.putf(slotpos + fieldoff, fieldlen, Ann.ERROR, text) | |
351 | fieldoff += fieldlen | |
352 | ||
353 | # Strictly speaking there are 10 data request bits and 2 reserved | |
354 | # bits for input slots, and 12 reserved bits for output slots. We | |
355 | # test for 10 and 2 bits, to simplify the logic. Only in case of | |
356 | # non-zero reserved bits for outputs this will result in "a little | |
357 | # strange" an annotation. This is a cosmetic issue, we don't mind. | |
358 | fieldlen = 10 | |
359 | reqdata = self.get_bit_field(data, bitcount, fieldoff, fieldlen) | |
360 | if is_out and reqdata != 0: | |
361 | text = ['reserved bit error', 'rsv error', 'rsv'] | |
362 | self.putf(slotpos + fieldoff, fieldlen, Ann.ERROR, text) | |
363 | if not is_out: | |
364 | text = ['REQ: {:3x}'.format(reqdata), '{:3x}'.format(reqdata)] | |
365 | self.putf(slotpos + fieldoff, fieldlen, anncls, text) | |
366 | fieldoff += fieldlen | |
367 | ||
368 | fieldlen = 2 | |
369 | rsv = self.get_bit_field(data, bitcount, fieldoff, fieldlen) | |
370 | if rsv != 0: | |
371 | text = ['reserved bit error', 'rsv error', 'rsv'] | |
372 | self.putf(slotpos + fieldoff, fieldlen, Ann.ERROR, text) | |
373 | fieldoff += fieldlen | |
374 | ||
375 | def handle_slot_02(self, slotidx, bitidx, bitcount, is_out, data): | |
376 | # Handle slot 2, command/status data. | |
377 | slotpos = self.frame_slot_lens[slotidx] | |
378 | if not self.have_slots[is_out]: | |
379 | return | |
380 | if not self.have_slots[is_out][slotidx]: | |
381 | return | |
382 | fieldoff = 0 | |
383 | anncls = Ann.SLOT_OUT_TAG if is_out else Ann.SLOT_IN_TAG | |
384 | anncls += slotidx | |
385 | ||
386 | fieldlen = 16 | |
387 | rwdata = self.get_bit_field(data, bitcount, fieldoff, fieldlen) | |
388 | # TODO: Check for zero output data when the operation is a read. | |
389 | # TODO: Check for the "atomic" constraint. | |
390 | text = ['DATA: {:4x}'.format(rwdata), '{:4x}'.format(rwdata)] | |
391 | self.putf(slotpos + fieldoff, fieldlen, anncls, text) | |
392 | fieldoff += fieldlen | |
393 | ||
394 | fieldlen = 4 | |
395 | rsv = self.get_bit_field(data, bitcount, fieldoff, fieldlen) | |
396 | if rsv != 0: | |
397 | text = ['reserved bits error', 'rsv error', 'rsv'] | |
398 | self.putf(slotpos + fieldoff, fieldlen, Ann.ERROR, text) | |
399 | fieldoff += fieldlen | |
400 | ||
401 | # TODO: Implement other slots. | |
402 | # - 1: cmd/status addr (check status vs command) | |
403 | # - 2: cmd/status data (check status vs command) | |
404 | # - 3-11: audio out/in | |
405 | # - 12: io control/status (modem GPIO(?)) | |
406 | ||
407 | def handle_slot(self, slotidx, data_out, data_in): | |
408 | # Process a received slot of a frame. | |
409 | func = self.handle_slots.get(slotidx, self.handle_slot_dummy) | |
410 | bitidx = self.frame_slot_lens[slotidx] | |
411 | bitcount = self.frame_slot_lens[slotidx + 1] - bitidx | |
412 | if data_out is not None: | |
413 | func(slotidx, bitidx, bitcount, True, data_out) | |
414 | if data_in is not None: | |
415 | func(slotidx, bitidx, bitcount, False, data_in) | |
416 | ||
417 | def handle_bits(self, ss, es, bit_out, bit_in): | |
418 | # Process a received pair of bits. | |
419 | # Emit the bits' annotations. Only interpret the data when we | |
420 | # are in a frame (have seen the start of the frame, and don't | |
421 | # exceed the expected number of bits in a frame). | |
422 | if bit_out is not None: | |
423 | self.putx(ss, es, Ann.BITS_OUT, ['{:d}'.format(bit_out)]) | |
424 | if bit_in is not None: | |
425 | self.putx(ss, es, Ann.BITS_IN, ['{:d}'.format(bit_in)]) | |
426 | if self.frame_ss_list is None: | |
427 | return | |
428 | self.frame_ss_list.append(es) | |
429 | have_len = len(self.frame_ss_list) - 1 | |
430 | if have_len > self.frame_total_bits: | |
431 | return | |
432 | ||
433 | # Accumulate the bits within the frame, until one slot of the | |
434 | # frame has become available. | |
435 | slot_idx = 0 | |
436 | if bit_out is not None: | |
437 | self.frame_bits_out.append(bit_out) | |
438 | slot_idx = len(self.frame_slot_data_out) | |
439 | if bit_in is not None: | |
440 | self.frame_bits_in.append(bit_in) | |
441 | slot_idx = len(self.frame_slot_data_in) | |
442 | want_len = self.frame_slot_lens[slot_idx + 1] | |
443 | if have_len != want_len: | |
444 | return | |
445 | prev_len = self.frame_slot_lens[slot_idx] | |
446 | ||
447 | # Convert bits to integer values. This shall simplify extraction | |
448 | # of bit fields in multiple other locations. | |
449 | slot_data_out = None | |
450 | if bit_out is not None: | |
451 | slot_bits = self.frame_bits_out[prev_len:] | |
452 | slot_data = self.bits_to_int(slot_bits) | |
453 | self.frame_slot_data_out.append(slot_data) | |
454 | slot_data_out = slot_data | |
455 | slot_data_in = None | |
456 | if bit_in is not None: | |
457 | slot_bits = self.frame_bits_in[prev_len:] | |
458 | slot_data = self.bits_to_int(slot_bits) | |
459 | self.frame_slot_data_in.append(slot_data) | |
460 | slot_data_in = slot_data | |
461 | ||
462 | # Emit simple annotations for the integer values, until upper | |
463 | # layer decode stages will be implemented. | |
464 | slot_len = have_len - prev_len | |
465 | slot_ss = self.frame_ss_list[prev_len] | |
466 | slot_es = self.frame_ss_list[have_len] | |
467 | if slot_data_out is not None: | |
468 | slot_text = self.int_to_nibble_text(slot_data_out, slot_len) | |
469 | self.putx(slot_ss, slot_es, Ann.SLOT_OUT_RAW, [slot_text]) | |
470 | if slot_data_in is not None: | |
471 | slot_text = self.int_to_nibble_text(slot_data_in, slot_len) | |
472 | self.putx(slot_ss, slot_es, Ann.SLOT_IN_RAW, [slot_text]) | |
473 | ||
474 | self.handle_slot(slot_idx, slot_data_out, slot_data_in) | |
475 | ||
476 | def decode(self): | |
477 | have_sdo = self.has_channel(Pins.SDATA_OUT) | |
478 | have_sdi = self.has_channel(Pins.SDATA_IN) | |
479 | if not have_sdo and not have_sdi: | |
480 | raise ChannelError('Either SDATA_OUT or SDATA_IN (or both) are required.') | |
481 | have_reset = self.has_channel(Pins.RESET) | |
482 | ||
483 | # Data is sampled at falling CLK edges. Annotations need to span | |
484 | # the period between rising edges. SYNC rises one cycle _before_ | |
485 | # the start of a frame. Grab the earliest SYNC sample we can get | |
486 | # and advance to the start of a bit time. Then keep getting the | |
487 | # samples and the end of all subsequent bit times. | |
488 | prev_sync = [None, None, None] | |
489 | pins = self.wait({Pins.BIT_CLK: 'e'}) | |
490 | if pins[Pins.BIT_CLK] == 0: | |
491 | prev_sync[-1] = pins[Pins.SYNC] | |
492 | pins = self.wait({Pins.BIT_CLK: 'r'}) | |
493 | bit_ss = self.samplenum | |
494 | while True: | |
495 | pins = self.wait({Pins.BIT_CLK: 'f'}) | |
496 | prev_sync.pop(0) | |
497 | prev_sync.append(pins[Pins.SYNC]) | |
498 | self.wait({Pins.BIT_CLK: 'r'}) | |
499 | if prev_sync[0] == 0 and prev_sync[1] == 1: | |
500 | self.start_frame(bit_ss) | |
501 | self.handle_bits(bit_ss, self.samplenum, | |
502 | pins[Pins.SDATA_OUT] if have_sdo else None, | |
503 | pins[Pins.SDATA_IN] if have_sdi else None) | |
504 | bit_ss = self.samplenum |