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