]> sigrok.org Git - libsigrokdecode.git/blob - decoders/lpc/lpc.py
Initial LPC protocol decoder implementation.
[libsigrokdecode.git] / decoders / lpc / lpc.py
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
23 import sigrokdecode as srd
24
25 # Annotation feed formats
26 ANN_ASCII = 0
27
28 # ...
29 fields = {
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
78 class 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