]> sigrok.org Git - libsigrokdecode.git/blame - decoders/lpc/lpc.py
srd: MXC6225XU: Bugfixes, add missing bits/registers.
[libsigrokdecode.git] / decoders / lpc / lpc.py
CommitLineData
271acd3b
UH
1##
2## This file is part of the sigrok project.
3##
4## Copyright (C) 2012 Uwe Hermann <uwe@hermann-uwe.de>
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, write to the Free Software
18## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19##
20
21# LPC protocol decoder
22
23import sigrokdecode as srd
24
25# Annotation feed formats
26ANN_ASCII = 0
27
28# ...
29fields = {
30 'START': { # LAD[3:0] values that are not listed are reserved.
31 0b0000: 'Start of cycle for a target',
32 0b0001: 'Reserved',
33 0b0010: 'Grant for bus master 0',
34 0b0011: 'Grant for bus master 1',
35 0b0100: 'Reserved',
36 0b0101: 'Reserved',
37 0b0110: 'Reserved',
38 0b0111: 'Reserved',
39 0b1000: 'Reserved',
40 0b1001: 'Reserved',
41 0b1010: 'Reserved',
42 0b1011: 'Reserved',
43 0b1100: 'Reserved',
44 0b1101: 'Start of cycle for a Firmware Memory Read cycle',
45 0b1110: 'Start of cycle for a Firmware Memory Write cycle',
46 0b1111: 'Stop/Abort (end of a cycle for a target)',
47 },
48 'CT_DR': { # Bit 0 (LAD[0]) is unused.
49 0b0000: 'I/O read',
50 0b0010: 'I/O write',
51 0b0100: 'Memory read',
52 0b0110: 'Memory write',
53 0b1000: 'DMA read',
54 0b1010: 'DMA write',
55 0b1100: 'Reserved',
56 0b1110: 'Reserved',
57 },
58 'SYNC': {
59 0b0000: 'Ready',
60 0b0001: 'Reserved',
61 0b0010: 'Reserved',
62 0b0011: 'Reserved',
63 0b0100: 'Reserved',
64 0b0101: 'Short wait',
65 0b0110: 'Long wait',
66 0b0111: 'Reserved',
67 0b1000: 'Reserved',
68 0b1001: 'Ready more (DMA only)',
69 0b1010: 'Error',
70 0b1011: 'Reserved',
71 0b1100: 'Reserved',
72 0b1101: 'Reserved',
73 0b1110: 'Reserved',
74 0b1111: 'Reserved',
75 },
76}
77
78class Decoder(srd.Decoder):
79 api_version = 1
80 id = 'lpc'
81 name = 'LPC'
82 longname = 'Low-Pin-Count'
83 desc = 'TODO.'
84 license = 'gplv2+'
85 inputs = ['logic']
86 outputs = ['lpc']
87 probes = [
88 {'id': 'lframe', 'name': 'LFRAME#', 'desc': 'TODO'},
89 {'id': 'lreset', 'name': 'LRESET#', 'desc': 'TODO'},
90 {'id': 'lclk', 'name': 'LCLK', 'desc': 'TODO'},
91 {'id': 'lad0', 'name': 'LAD[0]', 'desc': 'TODO'},
92 {'id': 'lad1', 'name': 'LAD[1]', 'desc': 'TODO'},
93 {'id': 'lad2', 'name': 'LAD[2]', 'desc': 'TODO'},
94 {'id': 'lad3', 'name': 'LAD[3]', 'desc': 'TODO'},
95 ]
96 optional_probes = [
97 {'id': 'ldrq', 'name': 'LDRQ#', 'desc': 'TODO'},
98 {'id': 'serirq', 'name': 'SERIRQ', 'desc': 'TODO'},
99 {'id': 'clkrun', 'name': 'CLKRUN#', 'desc': 'TODO'},
100 {'id': 'lpme', 'name': 'LPME#', 'desc': 'TODO'},
101 {'id': 'lpcpd', 'name': 'LPCPD#', 'desc': 'TODO'},
102 {'id': 'lsmi', 'name': 'LSMI#', 'desc': 'TODO'},
103 ]
104 options = {}
105 annotations = [
106 ['ASCII', 'TODO: description'],
107 ]
108
109 def __init__(self, **kwargs):
110 self.state = 'IDLE'
111 self.oldlclk = -1
112 self.samplenum = 0
113 self.clocknum = 0
114 self.lad = -1
115 self.addr = 0
116 self.cur_nibble = 0
117 self.cycle_type = -1
118 self.oldpins = (-1, -1, -1, -1, -1, -1, -1)
119
120 def start(self, metadata):
121 self.out_proto = self.add(srd.OUTPUT_PROTO, 'lpc')
122 self.out_ann = self.add(srd.OUTPUT_ANN, 'lpc')
123
124 def report(self):
125 pass
126
127 def handle_get_start(self, lad, lframe):
128 # LAD[3:0]: START field (1 clock cycle).
129
130 # The last value of LAD[3:0] before LFRAME# gets de-asserted is what
131 # the peripherals must use. However, the host can keep LFRAME# asserted
132 # multiple clocks, and we output all START fields that occur, even
133 # though the peripherals are supposed to ignore all but the last one.
134 s = fields['START'][lad]
135 self.put(0, 0, self.out_ann, [0, [s]])
136
137 # Output a warning if LAD[3:0] changes while LFRAME# is low.
138 # TODO
139 if (self.lad != -1 and self.lad != lad):
140 self.put(0, 0, self.out_ann,
141 [0, ['Warning: LAD[3:0] changed while '
142 'LFRAME# was asserted']])
143
144 # LFRAME# is asserted (low). Wait until it gets de-asserted again
145 # (the host is allowed to keep it asserted multiple clocks).
146 if lframe != 1:
147 return
148
149 self.start_field = self.lad
150 self.state = 'GET CT/DR'
151
152 def handle_get_ct_dr(self, lad, lad_bits):
153 # LAD[3:0]: Cycle type / direction field (1 clock cycle).
154
155 self.cycle_type = fields['CT_DR'][lad]
156
157 # TODO: Warning/error on invalid cycle types.
158 if self.cycle_type == 'Reserved':
159 self.put(0, 0, self.out_ann,
160 [0, ['Warning: Invalid cycle type (%s)' % lad_bits]])
161
162 # ...
163 self.put(0, 0, self.out_ann, [0, ['Cycle type: %s' % self.cycle_type]])
164
165 self.state = 'GET ADDR'
166 self.addr = 0
167 self.cur_nibble = 0
168
169 def handle_get_addr(self, lad, lad_bits):
170 # LAD[3:0]: ADDR field (4/8/0 clock cycles).
171
172 # I/O cycles: 4 ADDR clocks. Memory cycles: 8 ADDR clocks.
173 # DMA cycles: no ADDR clocks at all.
174 if self.cycle_type in ('I/O read', 'I/O write'):
175 addr_nibbles = 4 # Address is 16bits.
176 elif self.cycle_type in ('Memory read', 'Memory write'):
177 addr_nibbles = 8 # Address is 32bits.
178 else:
179 addr_nibbles = 0 # TODO: How to handle later on?
180
181 # Data is driven MSN-first.
182 offset = ((addr_nibbles - 1) - self.cur_nibble) * 4
183 self.addr |= (lad << offset)
184
185 # Continue if we haven't seen all ADDR cycles, yet.
186 # TODO: Off-by-one?
187 if (self.cur_nibble < addr_nibbles - 1):
188 self.cur_nibble += 1
189 return
190
191 self.put(0, 0, self.out_ann, [0, ['Address: %s' % hex(self.addr)]])
192
193 self.state = 'GET TAR'
194 self.tar_count = 0
195
196 def handle_get_tar(self, lad, lad_bits):
197 # LAD[3:0]: First TAR (turn-around) field (2 clock cycles).
198
199 self.put(0, 0, self.out_ann, [0, ['TAR, cycle %d: %s'
200 % (self.tarcount, lad_bits)]])
201
202 # On the first TAR clock cycle LAD[3:0] is driven to 1111 by
203 # either the host or peripheral. On the second clock cycle,
204 # the host or peripheral tri-states LAD[3:0], but its value
205 # should still be 1111, due to pull-ups on the LAD lines.
206 if lad_bits != '1111':
207 self.put(0, 0, self.out_ann,
208 [0, ['Warning: TAR, cycle %d: %s (expected 1111)'
209 % (self.tarcount, lad_bits)]])
210
211 if (self.tarcount != 2):
212 self.tarcount += 1
213 return
214
215 self.state = 'GET SYNC'
216
217 def handle_get_sync(self, lad, lad_bits):
218 # LAD[3:0]: SYNC field (1-n clock cycles).
219
220 self.sync_val = lad_bits
221 self.cycle_type = fields['SYNC'][lad]
222
223 # TODO: Warnings if reserved value are seen?
224 if self.cycle_type == 'Reserved':
225 self.put(0, 0, self.out_ann, [0, ['Warning: SYNC, cycle %d: %s '
226 '(reserved value)' % (self.synccount, self.sync_val)]])
227
228 self.put(0, 0, self.out_ann, [0, ['SYNC, cycle %d: %s'
229 % (self.synccount, self.sync_val)]])
230
231 # TODO
232
233 self.state = 'GET DATA'
234 self.cycle_count = 0
235
236 def handle_get_data(self, lad, lad_bits):
237 # LAD[3:0]: DATA field (2 clock cycles).
238
239 if (self.cycle_count == 0):
240 self.databyte = lad
241 elif (self.cycle_count == 1):
242 self.databyte |= (lad << 4)
243 else:
244 pass # TODO: Error?
245
246 if (self.cycle_count != 2):
247 self.cycle_count += 1
248 return
249
250 self.put(0, 0, self.out_ann, [0, ['DATA: %s' % hex(self.databyte)]])
251
252 self.state = 'GET TAR2'
253
254 def handle_get_tar2(self, lad, lad_bits):
255 # LAD[3:0]: Second TAR field (2 clock cycles).
256
257 self.put(0, 0, self.out_ann, [0, ['TAR, cycle %d: %s'
258 % (self.tarcount, lad_bits)]])
259
260 # On the first TAR clock cycle LAD[3:0] is driven to 1111 by
261 # either the host or peripheral. On the second clock cycle,
262 # the host or peripheral tri-states LAD[3:0], but its value
263 # should still be 1111, due to pull-ups on the LAD lines.
264 if lad_bits != '1111':
265 self.put(0, 0, self.out_ann,
266 [0, ['Warning: TAR, cycle %d: %s (expected 1111)'
267 % (self.tarcount, lad_bits)]])
268
269 if (self.tarcount != 2):
270 self.tarcount += 1
271 return
272
273 self.state = 'GET SYNC'
274
275 # TODO: At which edge of the clock is data latched? Falling?
276 def decode(self, ss, es, data):
277 for (samplenum, pins) in data:
278
279 # If none of the pins changed, there's nothing to do.
280 if self.oldpins == pins:
281 continue
282
283 # Store current pin values for the next round.
284 self.oldpins = pins
285
286 # Get individual pin values into local variables.
287 # TODO: Handle optional pins.
288 (lframe, lreset, lclk, lad0, lad1, lad2, lad3) = pins
289
290 # Only look at the signals upon falling LCLK edges.
291 # TODO: Rising?
292 ## if not (self.oldlclk == 1 and lclk == 0)
293 ## self.oldlclk = lclk
294 ## continue
295
296 # Store LAD[3:0] bit values (one nibble) in local variables.
297 # Most (but not all states needs this).
298 if self.state != 'IDLE':
299 lad = (lad3 << 3) | (lad2 << 2) | (lad1 << 1) | lad0
300 lad_bits = bin(lad)[2:]
301
302 # State machine
303 if self.state == 'IDLE':
304 # A valid LPC cycle starts with LFRAME# being asserted (low).
305 # TODO?
306 if lframe != 0:
307 continue
308 self.state = 'GET START'
309 self.lad = -1
310 # self.clocknum = 0
311 elif self.state == 'GET START':
312 handle_get_start(lad, lad_bits, lframe)
313 elif self.state == 'GET CT/DR':
314 handle_get_ct_dr(lad, lad_bits)
315 elif self.state == 'GET ADDR':
316 handle_get_addr(lad, lad_bits)
317 elif self.state == 'GET TAR':
318 handle_get_tar(lad, lad_bits)
319 elif self.state == 'GET SYNC':
320 handle_get_sync(lad, lad_bits)
321 elif self.state == 'GET DATA':
322 handle_get_data(lad, lad_bits)
323 elif self.state == 'GET TAR2':
324 handle_get_tar2(lad, lad_bits)
325 else:
326 raise Exception('Invalid state: %s' % self.state)
327