2 ## This file is part of the sigrok project.
4 ## Copyright (C) 2012 Uwe Hermann <uwe@hermann-uwe.de>
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.
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.
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
21 # LPC protocol decoder
23 import sigrokdecode as srd
25 # Annotation feed formats
30 'START': { # LAD[3:0] values that are not listed are reserved.
31 0b0000: 'Start of cycle for a target',
33 0b0010: 'Grant for bus master 0',
34 0b0011: 'Grant for bus master 1',
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)',
48 'CT_DR': { # Bit 0 (LAD[0]) is unused.
51 0b0100: 'Memory read',
52 0b0110: 'Memory write',
68 0b1001: 'Ready more (DMA only)',
78 class Decoder(srd.Decoder):
82 longname = 'Low-Pin-Count'
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'},
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'},
106 ['ASCII', 'TODO: description'],
109 def __init__(self, **kwargs):
118 self.oldpins = (-1, -1, -1, -1, -1, -1, -1)
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')
127 def handle_get_start(self, lad, lframe):
128 # LAD[3:0]: START field (1 clock cycle).
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]])
137 # Output a warning if LAD[3:0] changes while LFRAME# is low.
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']])
144 # LFRAME# is asserted (low). Wait until it gets de-asserted again
145 # (the host is allowed to keep it asserted multiple clocks).
149 self.start_field = self.lad
150 self.state = 'GET CT/DR'
152 def handle_get_ct_dr(self, lad, lad_bits):
153 # LAD[3:0]: Cycle type / direction field (1 clock cycle).
155 self.cycle_type = fields['CT_DR'][lad]
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]])
163 self.put(0, 0, self.out_ann, [0, ['Cycle type: %s' % self.cycle_type]])
165 self.state = 'GET ADDR'
169 def handle_get_addr(self, lad, lad_bits):
170 # LAD[3:0]: ADDR field (4/8/0 clock cycles).
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.
179 addr_nibbles = 0 # TODO: How to handle later on?
181 # Data is driven MSN-first.
182 offset = ((addr_nibbles - 1) - self.cur_nibble) * 4
183 self.addr |= (lad << offset)
185 # Continue if we haven't seen all ADDR cycles, yet.
187 if (self.cur_nibble < addr_nibbles - 1):
191 self.put(0, 0, self.out_ann, [0, ['Address: %s' % hex(self.addr)]])
193 self.state = 'GET TAR'
196 def handle_get_tar(self, lad, lad_bits):
197 # LAD[3:0]: First TAR (turn-around) field (2 clock cycles).
199 self.put(0, 0, self.out_ann, [0, ['TAR, cycle %d: %s'
200 % (self.tarcount, lad_bits)]])
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)]])
211 if (self.tarcount != 2):
215 self.state = 'GET SYNC'
217 def handle_get_sync(self, lad, lad_bits):
218 # LAD[3:0]: SYNC field (1-n clock cycles).
220 self.sync_val = lad_bits
221 self.cycle_type = fields['SYNC'][lad]
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)]])
228 self.put(0, 0, self.out_ann, [0, ['SYNC, cycle %d: %s'
229 % (self.synccount, self.sync_val)]])
233 self.state = 'GET DATA'
236 def handle_get_data(self, lad, lad_bits):
237 # LAD[3:0]: DATA field (2 clock cycles).
239 if (self.cycle_count == 0):
241 elif (self.cycle_count == 1):
242 self.databyte |= (lad << 4)
246 if (self.cycle_count != 2):
247 self.cycle_count += 1
250 self.put(0, 0, self.out_ann, [0, ['DATA: %s' % hex(self.databyte)]])
252 self.state = 'GET TAR2'
254 def handle_get_tar2(self, lad, lad_bits):
255 # LAD[3:0]: Second TAR field (2 clock cycles).
257 self.put(0, 0, self.out_ann, [0, ['TAR, cycle %d: %s'
258 % (self.tarcount, lad_bits)]])
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)]])
269 if (self.tarcount != 2):
273 self.state = 'GET SYNC'
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:
279 # If none of the pins changed, there's nothing to do.
280 if self.oldpins == pins:
283 # Store current pin values for the next round.
286 # Get individual pin values into local variables.
287 # TODO: Handle optional pins.
288 (lframe, lreset, lclk, lad0, lad1, lad2, lad3) = pins
290 # Only look at the signals upon falling LCLK edges.
292 ## if not (self.oldlclk == 1 and lclk == 0)
293 ## self.oldlclk = lclk
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:]
303 if self.state == 'IDLE':
304 # A valid LPC cycle starts with LFRAME# being asserted (low).
308 self.state = 'GET START'
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)
326 raise Exception('Invalid state: %s' % self.state)