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