]> sigrok.org Git - libsigrokdecode.git/blame - decoders/swd/pd.py
all decoders: introduce a reset() method
[libsigrokdecode.git] / decoders / swd / pd.py
CommitLineData
4afe4046
AG
1##
2## This file is part of the libsigrokdecode project.
3##
4## Copyright (C) 2014 Angus Gratton <gus@projectgus.com>
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
4539e9ca 17## along with this program; if not, see <http://www.gnu.org/licenses/>.
4afe4046
AG
18##
19
20import sigrokdecode as srd
dcfb60a1 21import re
4afe4046
AG
22
23'''
24OUTPUT_PYTHON format:
25
26Packet:
27[<ptype>, <pdata>]
28
29<ptype>:
30 - 'AP_READ' (AP read)
31 - 'DP_READ' (DP read)
32 - 'AP_WRITE' (AP write)
33 - 'DP_WRITE' (DP write)
34 - 'LINE_RESET' (line reset sequence)
35
36<pdata>:
37 - tuple of address, ack state, data for the given sequence
38'''
39
40swd_states = [
41 'IDLE', # Idle/unknown
42 'REQUEST', # Request phase (first 8 bits)
43 'ACK', # Ack phase (next 3 bits)
44 'READ', # Reading phase (next 32 bits for reads)
45 'WRITE', # Writing phase (next 32 bits for write)
46 'DPARITY', # Data parity phase
47]
48
49# Regexes for matching SWD data out of bitstring ('1' / '0' characters) format
50RE_SWDSWITCH = re.compile(bin(0xE79E)[:1:-1] + '$')
51RE_SWDREQ = re.compile(r'1(?P<apdp>.)(?P<rw>.)(?P<addr>..)(?P<parity>.)01$')
52RE_IDLE = re.compile('0' * 50 + '$')
53
54# Sample edges
55RISING = 1
56FALLING = 0
57
58ADDR_DP_SELECT = 0x8
59ADDR_DP_CTRLSTAT = 0x4
60
61BIT_SELECT_CTRLSEL = 1
62BIT_CTRLSTAT_ORUNDETECT = 1
63
64ANNOTATIONS = ['reset', 'enable', 'read', 'write', 'ack', 'data', 'parity']
65
66class Decoder(srd.Decoder):
e809f7bc 67 api_version = 3
4afe4046
AG
68 id = 'swd'
69 name = 'SWD'
70 longname = 'Serial Wire Debug'
71 desc = 'Two-wire protocol for debug access to ARM CPUs.'
72 license = 'gplv2+'
73 inputs = ['logic']
74 outputs = ['swd']
75 channels = (
76 {'id': 'swclk', 'name': 'SWCLK', 'desc': 'Master clock'},
77 {'id': 'swdio', 'name': 'SWDIO', 'desc': 'Data input/output'},
78 )
79 options = (
80 {'id': 'strict_start',
81 'desc': 'Wait for a line reset before starting to decode',
82 'default': 'no', 'values': ('yes', 'no')},
83 )
84 annotations = (
85 ('reset', 'RESET'),
86 ('enable', 'ENABLE'),
87 ('read', 'READ'),
88 ('write', 'WRITE'),
89 ('ack', 'ACK'),
90 ('data', 'DATA'),
91 ('parity', 'PARITY'),
92 )
93
92b7b49f 94 def __init__(self):
10aeb8ea
GS
95 self.reset()
96
97 def reset(self):
4afe4046
AG
98 # SWD data/clock state
99 self.state = 'UNKNOWN'
4afe4046
AG
100 self.sample_edge = RISING
101 self.ack = None # Ack state of the current phase
102 self.ss_req = 0 # Start sample of current req
103 self.turnaround = 0 # Number of turnaround edges to ignore before continuing
104 self.bits = '' # Bits from SWDIO are accumulated here, matched against expected sequences
105 self.samplenums = [] # Sample numbers that correspond to the samples in self.bits
106 self.linereset_count = 0
107
108 # SWD debug port state
109 self.data = None
110 self.addr = None
111 self.rw = None # Are we inside an SWD read or a write?
112 self.ctrlsel = 0 # 'ctrlsel' is bit 0 in the SELECT register.
113 self.orundetect = 0 # 'orundetect' is bit 0 in the CTRLSTAT register.
114
115 def start(self):
116 self.out_ann = self.register(srd.OUTPUT_ANN)
117 self.out_python = self.register(srd.OUTPUT_PYTHON)
118 if self.options['strict_start'] == 'no':
119 self.state = 'REQ' # No need to wait for a LINE RESET.
120
121 def putx(self, ann, length, data):
122 '''Output annotated data.'''
123 ann = ANNOTATIONS.index(ann)
124 try:
125 ss = self.samplenums[-length]
126 except IndexError:
127 ss = self.samplenums[0]
128 if self.state == 'REQ':
129 self.ss_req = ss
130 es = self.samplenum
131 self.put(ss, es, self.out_ann, [ann, [data]])
132
133 def putp(self, ptype, pdata):
134 self.put(self.ss_req, self.samplenum, self.out_python, [ptype, pdata])
135
136 def put_python_data(self):
137 '''Emit Python data item based on current SWD packet contents.'''
138 ptype = {
139 ('AP', 'R'): 'AP_READ',
140 ('AP', 'W'): 'AP_WRITE',
141 ('DP', 'R'): 'DP_READ',
142 ('DP', 'W'): 'DP_WRITE',
143 }[(self.apdp, self.rw)]
144 self.putp(ptype, (self.addr, self.data, self.ack))
145
e809f7bc
UH
146 def decode(self):
147 while True:
148 # Wait for any clock edge.
149 clk, dio = self.wait({0: 'e'})
4afe4046
AG
150
151 # Count rising edges with DIO held high,
152 # as a line reset (50+ high edges) can happen from any state.
153 if clk == RISING:
154 if dio == 1:
155 self.linereset_count += 1
156 else:
157 if self.linereset_count >= 50:
158 self.putx('reset', self.linereset_count, 'LINERESET')
159 self.putp('LINE_RESET', None)
160 self.reset_state()
161 self.linereset_count = 0
162
163 # Otherwise, we only care about either rising or falling edges
164 # (depending on sample_edge, set according to current state).
165 if clk != self.sample_edge:
166 continue
167
168 # Turnaround bits get skipped.
169 if self.turnaround > 0:
170 self.turnaround -= 1
171 continue
172
173 self.bits += str(dio)
174 self.samplenums.append(self.samplenum)
175 {
176 'UNKNOWN': self.handle_unknown_edge,
177 'REQ': self.handle_req_edge,
178 'ACK': self.handle_ack_edge,
179 'DATA': self.handle_data_edge,
180 'DPARITY': self.handle_dparity_edge,
181 }[self.state]()
182
183 def next_state(self):
184 '''Step to the next SWD state, reset internal counters accordingly.'''
185 self.bits = ''
186 self.samplenums = []
187 self.linereset_count = 0
188 if self.state == 'UNKNOWN':
189 self.state = 'REQ'
190 self.sample_edge = RISING
191 self.turnaround = 0
192 elif self.state == 'REQ':
193 self.state = 'ACK'
194 self.sample_edge = FALLING
195 self.turnaround = 1
196 elif self.state == 'ACK':
197 self.state = 'DATA'
198 self.sample_edge = RISING if self.rw == 'W' else FALLING
199 self.turnaround = 0 if self.rw == 'R' else 2
200 elif self.state == 'DATA':
201 self.state = 'DPARITY'
202 elif self.state == 'DPARITY':
203 self.put_python_data()
204 self.state = 'REQ'
205 self.sample_edge = RISING
206 self.turnaround = 1 if self.rw == 'R' else 0
207
208 def reset_state(self):
209 '''Line reset (or equivalent), wait for a new pending SWD request.'''
210 if self.state != 'REQ': # Emit a Python data item.
211 self.put_python_data()
212 # Clear state.
213 self.bits = ''
214 self.samplenums = []
215 self.linereset_count = 0
216 self.turnaround = 0
217 self.sample_edge = RISING
218 self.data = ''
219 self.ack = None
220 self.state = 'REQ'
221
222 def handle_unknown_edge(self):
223 '''
224 Clock edge in the UNKNOWN state.
225 In the unknown state, clock edges get ignored until we see a line
226 reset (which is detected in the decode method, not here.)
227 '''
228 pass
229
230 def handle_req_edge(self):
231 '''Clock edge in the REQ state (waiting for SWD r/w request).'''
232 # Check for a JTAG->SWD enable sequence.
233 m = re.search(RE_SWDSWITCH, self.bits)
234 if m is not None:
235 self.putx('enable', 16, 'JTAG->SWD')
236 self.reset_state()
237 return
238
239 # Or a valid SWD Request packet.
240 m = re.search(RE_SWDREQ, self.bits)
241 if m is not None:
242 calc_parity = sum([int(x) for x in m.group('rw') + m.group('apdp') + m.group('addr')]) % 2
243 parity = '' if str(calc_parity) == m.group('parity') else 'E'
244 self.rw = 'R' if m.group('rw') == '1' else 'W'
245 self.apdp = 'AP' if m.group('apdp') == '1' else 'DP'
246 self.addr = int(m.group('addr')[::-1], 2) << 2
247 self.putx('read' if self.rw == 'R' else 'write', 8, self.get_address_description())
248 self.next_state()
249 return
250
251 def handle_ack_edge(self):
252 '''Clock edge in the ACK state (waiting for complete ACK sequence).'''
253 if len(self.bits) < 3:
254 return
255 if self.bits == '100':
256 self.putx('ack', 3, 'OK')
257 self.ack = 'OK'
258 self.next_state()
259 elif self.bits == '001':
260 self.putx('ack', 3, 'FAULT')
261 self.ack = 'FAULT'
262 if self.orundetect == 1:
263 self.next_state()
264 else:
265 self.reset_state()
266 self.turnaround = 1
267 elif self.bits == '010':
268 self.putx('ack', 3, 'WAIT')
269 self.ack = 'WAIT'
270 if self.orundetect == 1:
271 self.next_state()
272 else:
273 self.reset_state()
274 self.turnaround = 1
275 elif self.bits == '111':
276 self.putx('ack', 3, 'NOREPLY')
277 self.ack = 'NOREPLY'
278 self.reset_state()
279 else:
280 self.putx('ack', 3, 'ERROR')
281 self.ack = 'ERROR'
282 self.reset_state()
283
284 def handle_data_edge(self):
285 '''Clock edge in the DATA state (waiting for 32 bits to clock past).'''
286 if len(self.bits) < 32:
287 return
288 self.data = 0
289 self.dparity = 0
290 for x in range(32):
291 if self.bits[x] == '1':
292 self.data += (1 << x)
293 self.dparity += 1
294 self.dparity = self.dparity % 2
295
296 self.putx('data', 32, '0x%08x' % self.data)
297 self.next_state()
298
299 def handle_dparity_edge(self):
300 '''Clock edge in the DPARITY state (clocking in parity bit).'''
301 if str(self.dparity) != self.bits:
302 self.putx('parity', 1, str(self.dparity) + self.bits) # PARITY ERROR
303 elif self.rw == 'W':
304 self.handle_completed_write()
305 self.next_state()
306
307 def handle_completed_write(self):
308 '''
309 Update internal state of the debug port based on a completed
310 write operation.
311 '''
312 if self.apdp != 'DP':
313 return
314 elif self.addr == ADDR_DP_SELECT:
315 self.ctrlsel = self.data & BIT_SELECT_CTRLSEL
316 elif self.addr == ADDR_DP_CTRLSTAT and self.ctrlsel == 0:
317 self.orundetect = self.data & BIT_CTRLSTAT_ORUNDETECT
318
319 def get_address_description(self):
320 '''
321 Return a human-readable description of the currently selected address,
322 for annotated results.
323 '''
324 if self.apdp == 'DP':
325 if self.rw == 'R':
326 # Tables 2-4 & 2-5 in ADIv5.2 spec ARM document IHI 0031C
327 return {
328 0: 'IDCODE',
329 0x4: 'R CTRL/STAT' if self.ctrlsel == 0 else 'R DLCR',
330 0x8: 'RESEND',
331 0xC: 'RDBUFF'
332 }[self.addr]
333 elif self.rw == 'W':
334 # Tables 2-4 & 2-5 in ADIv5.2 spec ARM document IHI 0031C
335 return {
336 0: 'W ABORT',
337 0x4: 'W CTRL/STAT' if self.ctrlsel == 0 else 'W DLCR',
338 0x8: 'W SELECT',
339 0xC: 'W RESERVED'
340 }[self.addr]
341 elif self.apdp == 'AP':
342 if self.rw == 'R':
1483fb22 343 return 'R AP%x' % self.addr
4afe4046
AG
344 elif self.rw == 'W':
345 return 'W AP%x' % self.addr
346
347 # Any legitimate operations shouldn't fall through to here, probably
348 # a decoder bug.
349 return '? %s%s%x' % (self.rw, self.apdp, self.addr)