]>
Commit | Line | Data |
---|---|---|
1 | ## | |
2 | ## This file is part of the libsigrokdecode project. | |
3 | ## | |
4 | ## Copyright (C) 2017 Marcus Comstedt <marcus@mc.pp.se> | |
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 | import sigrokdecode as srd | |
21 | ||
22 | ann = [ | |
23 | ['Size', 'L'], | |
24 | ['SrcAP', 'S'], | |
25 | ['DstAP', 'D'], | |
26 | ['Cmd', 'C'], | |
27 | ['Data'], | |
28 | ['Cksum', 'K'], | |
29 | ] | |
30 | ||
31 | class Decoder(srd.Decoder): | |
32 | api_version = 3 | |
33 | id = 'maple_bus' | |
34 | name = 'Maple bus' | |
35 | longname = 'SEGA Maple bus' | |
36 | desc = 'Maple bus peripheral protocol for SEGA Dreamcast.' | |
37 | license = 'gplv2+' | |
38 | inputs = ['logic'] | |
39 | outputs = [] | |
40 | tags = ['Retro computing'] | |
41 | channels = ( | |
42 | {'id': 'sdcka', 'name': 'SDCKA', 'desc': 'Data/clock line A'}, | |
43 | {'id': 'sdckb', 'name': 'SDCKB', 'desc': 'Data/clock line B'}, | |
44 | ) | |
45 | annotations = ( | |
46 | ('start', 'Start pattern'), | |
47 | ('end', 'End pattern'), | |
48 | ('start-with-crc', 'Start pattern with CRC'), | |
49 | ('occupancy', 'SDCKB occupancy pattern'), | |
50 | ('reset', 'RESET pattern'), | |
51 | ('bit', 'Bit'), | |
52 | ('size', 'Data size'), | |
53 | ('source', 'Source AP'), | |
54 | ('dest', 'Destination AP'), | |
55 | ('command', 'Command'), | |
56 | ('data', 'Data'), | |
57 | ('checksum', 'Checksum'), | |
58 | ('frame-error', 'Frame error'), | |
59 | ('checksum-error', 'Checksum error'), | |
60 | ('size-error', 'Size error'), | |
61 | ) | |
62 | annotation_rows = ( | |
63 | ('bits', 'Bits', (0, 1, 2, 3, 4, 5)), | |
64 | ('fields', 'Fields', (6, 7, 8, 9, 10, 11)), | |
65 | ('warnings', 'Warnings', (12, 13, 14)), | |
66 | ) | |
67 | binary = ( | |
68 | ('size', 'Data size'), | |
69 | ('source', 'Source AP'), | |
70 | ('dest', 'Destination AP'), | |
71 | ('command', 'Command code'), | |
72 | ('data', 'Data'), | |
73 | ('checksum', 'Checksum'), | |
74 | ) | |
75 | ||
76 | def __init__(self): | |
77 | self.reset() | |
78 | ||
79 | def reset(self): | |
80 | pass | |
81 | ||
82 | def start(self): | |
83 | self.out_ann = self.register(srd.OUTPUT_ANN) | |
84 | self.out_binary = self.register(srd.OUTPUT_BINARY) | |
85 | self.pending_bit_pos = None | |
86 | ||
87 | def putx(self, data): | |
88 | self.put(self.ss, self.es, self.out_ann, data) | |
89 | ||
90 | def putb(self, data): | |
91 | self.put(self.ss, self.es, self.out_binary, data) | |
92 | ||
93 | def byte_annotation(self, bintype, d): | |
94 | return [bintype + 6, | |
95 | ['%s: %02X' % (name, d) for name in ann[bintype]] + ['%02X' % d]] | |
96 | ||
97 | def got_start(self): | |
98 | self.putx([0, ['Start pattern', 'Start', 'S']]) | |
99 | ||
100 | def got_end(self): | |
101 | self.putx([1, ['End pattern', 'End', 'E']]) | |
102 | if self.length != self.expected_length + 1: | |
103 | self.putx([14, ['Size error', 'L error', 'LE']]) | |
104 | ||
105 | def got_start_with_crc(self): | |
106 | self.putx([2, ['Start pattern with CRC', 'Start CRC', 'SC']]) | |
107 | ||
108 | def got_occupancy(self): | |
109 | self.putx([3, ['SDCKB occupancy pattern', 'Occupancy', 'O']]) | |
110 | ||
111 | def got_reset(self): | |
112 | self.putx([4, ['RESET pattern', 'RESET', 'R']]) | |
113 | ||
114 | def output_pending_bit(self): | |
115 | if self.pending_bit_pos: | |
116 | self.put(self.pending_bit_pos, self.pending_bit_pos, self.out_ann, [5, ['Bit: %d' % self.pending_bit, '%d' % self.pending_bit]]) | |
117 | ||
118 | def got_bit(self, n): | |
119 | self.output_pending_bit() | |
120 | self.data = self.data * 2 + n | |
121 | self.pending_bit = n | |
122 | self.pending_bit_pos = self.samplenum | |
123 | ||
124 | def got_byte(self): | |
125 | self.output_pending_bit() | |
126 | bintype = 4 | |
127 | if self.length < 4: | |
128 | if self.length == 0: | |
129 | self.expected_length = 4 * (self.data + 1) | |
130 | bintype = self.length | |
131 | elif self.length == self.expected_length: | |
132 | bintype = 5 | |
133 | if self.data != self.checksum: | |
134 | self.putx([13, ['Cksum error', 'K error', 'KE']]) | |
135 | self.length = self.length + 1 | |
136 | self.checksum = self.checksum ^ self.data | |
137 | self.putx(self.byte_annotation(bintype, self.data)) | |
138 | self.putb([bintype, bytes([self.data])]) | |
139 | self.pending_bit_pos = None | |
140 | ||
141 | def frame_error(self): | |
142 | self.putx([7, ['Frame error', 'F error', 'FE']]) | |
143 | ||
144 | def handle_start(self): | |
145 | self.wait({0: 'l', 1: 'h'}) | |
146 | self.ss = self.samplenum | |
147 | count = 0 | |
148 | while True: | |
149 | sdcka, sdckb = self.wait([{1: 'f'}, {0: 'r'}]) | |
150 | if self.matched[0]: | |
151 | count = count + 1 | |
152 | if self.matched[1]: | |
153 | self.es = self.samplenum | |
154 | if sdckb == 1: | |
155 | if count == 4: | |
156 | self.got_start() | |
157 | return True | |
158 | elif count == 6: | |
159 | self.got_start_with_crc() | |
160 | return True | |
161 | elif count == 8: | |
162 | self.got_occupancy() | |
163 | return False | |
164 | elif count >= 14: | |
165 | self.got_reset() | |
166 | return False | |
167 | self.frame_error() | |
168 | return False | |
169 | ||
170 | def handle_byte_or_stop(self): | |
171 | self.ss = self.samplenum | |
172 | self.pending_bit_pos = None | |
173 | initial = True | |
174 | counta = 0 | |
175 | countb = 0 | |
176 | self.data = 0 | |
177 | while countb < 4: | |
178 | sdcka, sdckb = self.wait([{0: 'f'}, {1: 'f'}]) | |
179 | self.es = self.samplenum | |
180 | if self.matched[0]: | |
181 | if counta == countb: | |
182 | self.got_bit(sdckb) | |
183 | counta = counta + 1 | |
184 | elif counta == 1 and countb == 0 and self.data == 0 and sdckb == 0: | |
185 | self.wait([{0: 'h', 1: 'h'}, {0: 'f'}, {1: 'f'}]) | |
186 | self.es = self.samplenum | |
187 | if self.matched[0]: | |
188 | self.got_end() | |
189 | else: | |
190 | self.frame_error() | |
191 | return False | |
192 | else: | |
193 | self.frame_error() | |
194 | return False | |
195 | elif self.matched[1]: | |
196 | if counta == countb + 1: | |
197 | self.got_bit(sdcka) | |
198 | countb = countb + 1 | |
199 | elif counta == 0 and countb == 0 and sdcka == 1 and initial: | |
200 | self.ss = self.samplenum | |
201 | initial = False | |
202 | else: | |
203 | self.frame_error() | |
204 | return False | |
205 | self.wait({0: 'h'}) | |
206 | self.es = self.samplenum | |
207 | self.got_byte() | |
208 | return True | |
209 | ||
210 | def decode(self): | |
211 | while True: | |
212 | while not self.handle_start(): | |
213 | pass | |
214 | self.length = 0 | |
215 | self.expected_length = 4 | |
216 | self.checksum = 0 | |
217 | while self.handle_byte_or_stop(): | |
218 | pass |