]> sigrok.org Git - libsigrokdecode.git/blame - decoders/jtag_ejtag/pd.py
jtag_ejtag: Shorten variable names to ss/es.
[libsigrokdecode.git] / decoders / jtag_ejtag / pd.py
CommitLineData
4bfb9af7
VI
1##
2## This file is part of the libsigrokdecode project.
3##
4## Copyright (C) 2018 Vladislav Ivanov <vlad.ivanov@lab-systems.ru>
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
20import sigrokdecode as srd
21
22class Instruction(object):
23 IDCODE = 0x01
24 IMPCODE = 0x03
25 ADDRESS = 0x08
26 DATA = 0x09
27 CONTROL = 0x0A
28 ALL = 0x0B
29 EJTAGBOOT = 0x0C
30 NORMALBOOT = 0x0D
31 FASTDATA = 0x0E
32 TCBCONTROLA = 0x10
33 TCBCONTROLB = 0x11
34 TCBDATA = 0x12
35 TCBCONTROLC = 0x13
36 PCSAMPLE = 0x14
37 TCBCONTROLD = 0x15
38 TCBCONTROLE = 0x16
39
40class State(object):
41 RESET = 0
42 DEVICE_ID = 1
43 IMPLEMENTATION = 2
44 DATA = 3
45 ADDRESS = 4
46 CONTROL = 5
47 FASTDATA = 6
48 PC_SAMPLE = 7
49 BYPASS = 8
50
51class ControlReg(object):
52 PRACC = (1 << 18)
53 PRNW = (1 << 19)
54
55class Ann(object):
56 INSTRUCTION = 0
57 REGISTER = 1
58 CONTROL_FIELD_IN = 10
59 CONTROL_FIELD_OUT = 11
60 PRACC = 12
61
62ejtag_insn = {
63 0x00: ['Free', 'Boundary scan'],
64 0x01: ['IDCODE', 'Select Device Identification (ID) register'],
65 0x02: ['Free', 'Boundary scan'],
66 0x03: ['IMPCODE', 'Select Implementation register'],
67 0x08: ['ADDRESS', 'Select Address register'],
68 0x09: ['DATA', 'Select Data register'],
69 0x0A: ['CONTROL', 'Select EJTAG Control register'],
70 0x0B: ['ALL', 'Select the Address, Data and EJTAG Control registers'],
71 0x0C: ['EJTAGBOOT', 'Fetch code from the debug exception vector after reset'],
72 0x0D: ['NORMALBOOT', 'Execute the reset handler after reset'],
73 0x0E: ['FASTDATA', 'Select the Data and Fastdata registers'],
74 0x0F: ['Reserved', 'Reserved'],
75 0x10: ['TCBCONTROLA', 'Select the control register TCBTraceControl'],
76 0x11: ['TCBCONTROLB', 'Selects trace control block register B'],
77 0x12: ['TCBDATA', 'Access the registers specified by TCBCONTROLB'],
78 0x13: ['TCBCONTROLC', 'Select trace control block register C'],
79 0x14: ['PCSAMPLE', 'Select the PCsample register'],
80 0x15: ['TCBCONTROLD', 'Select trace control block register D'],
81 0x16: ['TCBCONTROLE', 'Select trace control block register E'],
82 0x17: ['FDC', 'Select Fast Debug Channel'],
83 0x1C: ['Free', 'Boundary scan'],
84}
85
86ejtag_reg = {
87 0x00: 'RESET',
88 0x01: 'DEVICE_ID',
89 0x02: 'IMPLEMENTATION',
90 0x03: 'DATA',
91 0x04: 'ADDRESS',
92 0x05: 'CONTROL',
93 0x06: 'FASTDATA',
94 0x07: 'PC_SAMPLE',
95 0x08: 'BYPASS',
96}
97
98ejtag_control_reg = [
99 [31, 31, 'Rocc', [
100 # Read
101 ['No reset ocurred', 'Reset ocurred'],
102 # Write
103 ['Acknowledge reset', 'No effect'],
104 ]],
105 [30, 29, 'Psz', [
106 ['Access: byte', 'Access: halfword', 'Access: word', 'Access: triple'],
107 ]],
108 [23, 23, 'VPED', [
109 ['VPE disabled', 'VPE enabled'],
110 ]],
111 [22, 22, 'Doze', [
112 ['Processor is not in low-power mode', 'Processor is in low-power mode'],
113 ]],
114 [21, 21, 'Halt', [
115 ['Internal system bus clock is running', 'Internal system bus clock is stopped'],
116 ]],
117 [20, 20, 'Per Rst', [
118 ['No peripheral reset applied', 'Peripheral reset applied'],
119 ['Deassert peripheral reset', 'Assert peripheral reset'],
120 ]],
121 [19, 19, 'PRn W', [
122 ['Read processor access', 'Write processor access'],
123 ]],
124 [18, 18, 'Pr Acc', [
125 ['No pending processor access', 'Pending processor access'],
126 ['Finish processor access', 'Don\'t finish processor access'],
127 ]],
128 [16, 16, 'Pr Rst', [
129 ['No processor reset applied', 'Processor reset applied'],
130 ['Deassert processor reset', 'Assert system reset'],
131 ]],
132 [15, 15, 'Prob En', [
133 ['Probe will not serve processor accesses', 'Probe will service processor accesses'],
134 ]],
135 [14, 14, 'Prob Trap', [
136 ['Default location', 'DMSEG fetch'],
137 ['Set to default location', 'Set to DMSEG fetch'],
138 ]],
139 [13, 13, 'ISA On Debug', [
140 ['MIPS32/MIPS64 ISA', 'microMIPS ISA'],
141 ['Set to MIPS32/MIPS64 ISA', 'Set to microMIPS ISA'],
142 ]],
143 [12, 12, 'EJTAG Brk', [
144 ['No pending debug interrupt', 'Pending debug interrupt'],
145 ['No effect', 'Request debug interrupt'],
146 ]],
147 [3, 3, 'DM', [
148 ['Not in debug mode', 'In debug mode'],
149 ]],
150]
151
152ejtag_state_map = {
153 Instruction.IDCODE: State.DEVICE_ID,
154 Instruction.IMPCODE: State.IMPLEMENTATION,
155 Instruction.DATA: State.DATA,
156 Instruction.ADDRESS: State.ADDRESS,
157 Instruction.CONTROL: State.CONTROL,
158 Instruction.FASTDATA: State.FASTDATA,
159}
160
161def bin_to_int(s: str):
162 return int('0b' + s, 2)
163
164class RegData(object):
165 def __init__(self):
166 self.ss = None
167 self.es = None
168 self.data = None
169
170class LastData(object):
171 def __init__(self):
172 self.data_in = RegData()
173 self.data_out = RegData()
174
175class PraccState(object):
176 def reset(self):
177 self.address_in = None
178 self.address_out = None
179 self.data_in = None
180 self.data_out = None
181 self.write = False
d1b7bd1b
UH
182 self.ss = 0
183 self.es = 0
4bfb9af7
VI
184
185 def __init__(self):
186 self.reset()
187
188regs_items = {
189 'ann': tuple([tuple([s.lower(), s]) for s in list(ejtag_reg.values())]),
190 'rows_range': tuple(range(1, 1 + 9)),
191}
192
193class Decoder(srd.Decoder):
194 api_version = 3
195 id = 'jtag_ejtag'
196 name = 'JTAG / EJTAG (MIPS)'
197 longname = 'Joint Test Action Group / EJTAG (MIPS)'
198 desc = 'MIPS EJTAG protocol.'
199 license = 'gplv2+'
200 inputs = ['jtag']
201 outputs = ['jtag_ejtag']
202 annotations = (
203 ('instruction', 'Instruction'),
204 ) + regs_items['ann'] + (
205 ('control_field_in', 'Control field in'),
206 ('control_field_out', 'Control field out'),
207 ('pracc', 'PrAcc'),
208 )
209 annotation_rows = (
210 ('instructions', 'Instructions', (0,)),
211 ('regs', 'Registers', regs_items['rows_range']),
212 ('control_fields_in', 'Control fields in', (10,)),
213 ('control_fields_out', 'Control fields out', (11,)),
214 ('pracc', 'PrAcc', (12,)),
215 )
216
217 def __init__(self):
218 self.reset()
219
220 def reset(self):
221 self.state = State.RESET
222 self.pracc_state = PraccState()
223
224 def put_current(self, data):
225 self.put(self.ss, self.es, self.out_ann, data)
226
227 def put_at(self, ss: int, es: int, data):
228 self.put(ss, es, self.out_ann, data);
229
230 def start(self):
231 self.out_ann = self.register(srd.OUTPUT_ANN)
232
233 def select_reg(self, ir_value: int):
234 if ir_value in ejtag_state_map:
235 self.state = ejtag_state_map[ir_value]
236 else:
237 self.state = State.RESET
238
239 def parse_pracc(self):
240 control_in = bin_to_int(self.last_data['in']['data'][0])
241 control_out = bin_to_int(self.last_data['out']['data'][0])
242
243 # Check if JTAG master acknowledges a pending PrAcc.
244 if not ((not (control_in & ControlReg.PRACC)) and \
245 (control_out & ControlReg.PRACC)):
246 return
247
d1b7bd1b 248 ss, es = self.pracc_state.ss, self.pracc_state.es
4bfb9af7
VI
249 pracc_write = (control_out & ControlReg.PRNW) != 0
250
251 display_string = 'PrAcc: '
252 display_string += 'Store' if pracc_write else 'Load/Fetch'
253
254 if pracc_write:
255 if self.pracc_state.address_out != None:
256 display_string += ', A:' + ' 0x{:08X}'.format(self.pracc_state.address_out)
257 if self.pracc_state.data_out != None:
258 display_string += ', D:' + ' 0x{:08X}'.format(self.pracc_state.data_out)
259 else:
260 if self.pracc_state.address_out != None:
261 display_string += ', A:' + ' 0x{:08X}'.format(self.pracc_state.address_out)
262 if self.pracc_state.data_in != None:
263 display_string += ', D:' + ' 0x{:08X}'.format(self.pracc_state.data_in)
264
265 self.pracc_state.reset()
266
267 display_data = [Ann.PRACC, [display_string]]
d1b7bd1b 268 self.put_at(ss, es, display_data)
4bfb9af7
VI
269
270 def parse_control_reg(self, ann):
271 reg_write = ann == Ann.CONTROL_FIELD_IN
272 control_bit_positions = []
273 data_select = ''
274
275 if reg_write:
276 data_select = 'in'
277 else:
278 data_select = 'out'
279
280 control_bit_positions = self.last_data[data_select]['data'][1]
281 control_data = self.last_data[data_select]['data'][0]
282
283 # Annotate control register fields.
284 for field in ejtag_control_reg:
285 start_bit = 31 - field[1]
286 end_bit = 31 - field[0]
287 comment = field[2]
288 value_descriptions = []
289
290 if reg_write:
291 if len(field[3]) < 2:
292 continue
293 value_descriptions = field[3][1]
294 else:
295 value_descriptions = field[3][0]
296
d1b7bd1b
UH
297 ss = control_bit_positions[start_bit][0]
298 es = control_bit_positions[end_bit][1]
4bfb9af7
VI
299
300 value_str = control_data[end_bit : start_bit + 1]
301 value_index = bin_to_int(value_str)
302
303 short_desc = comment + ': ' + value_str
304 long_desc = value_descriptions[value_index] if len(value_descriptions) > value_index else '?'
305 display_data = [ann, [short_desc, long_desc]]
306
d1b7bd1b 307 self.put_at(ss, es, display_data)
4bfb9af7
VI
308
309 def check_last_data(self):
310 if not hasattr(self, 'last_data'):
311 self.last_data = {'in': {}, 'out': {}}
312
313 def handle_fastdata(self, val, ann):
314 spracc_write_desc = {
315 0: ['0', 'SPrAcc: 0', 'Request completion of Fastdata access'],
316 1: ['1', 'SPrAcc: 1', 'No effect'],
317 }
318 spracc_read_desc = {
319 0: ['0', 'SPrAcc: 0', 'Fastdata access failure'],
320 1: ['1', 'SPrAcc: 1', 'Successful completion of Fastdata access'],
321 }
322
323 bitstring = val[0]
324 bit_sample_pos = val[1]
325 fastdata_state = bitstring[32]
326 data = bin_to_int(bitstring[0:32])
327
328 fastdata_bit_pos = bit_sample_pos[32]
329 data_pos = [bit_sample_pos[31][0], bit_sample_pos[0][1]]
330
d1b7bd1b
UH
331 ss_fastdata, es_fastdata = fastdata_bit_pos
332 ss_data, es_data = data_pos
4bfb9af7
VI
333
334 display_data = [ann, ['0x{:08X}'.format(data)]]
335 spracc_display_data = []
336
337 if ann == Ann.CONTROL_FIELD_IN:
338 spracc_display_data = [ann, spracc_write_desc[int(fastdata_state)]]
339 elif ann == Ann.CONTROL_FIELD_OUT:
340 spracc_display_data = [ann, spracc_read_desc[int(fastdata_state)]]
341
d1b7bd1b
UH
342 self.put_at(ss_fastdata, es_fastdata, spracc_display_data)
343 self.put_at(ss_data, es_data, display_data)
4bfb9af7
VI
344
345 def handle_dr_tdi(self, val):
346 value = bin_to_int(val[0])
347 self.check_last_data()
348 self.last_data['in'] = {'ss': self.ss, 'es': self.es, 'data': val}
349
d1b7bd1b 350 self.pracc_state.ss, self.pracc_state.es = self.ss, self.es
4bfb9af7
VI
351
352 if self.state == State.ADDRESS:
353 self.pracc_state.address_in = value
354 elif self.state == State.DATA:
355 self.pracc_state.data_in = value
356 elif self.state == State.FASTDATA:
357 self.handle_fastdata(val, Ann.CONTROL_FIELD_IN)
358
359 def handle_dr_tdo(self, val):
360 value = bin_to_int(val[0])
361 self.check_last_data()
362 self.last_data['out'] = {'ss': self.ss, 'es': self.es, 'data': val}
363 if self.state == State.ADDRESS:
364 self.pracc_state.address_out = value
365 elif self.state == State.DATA:
366 self.pracc_state.data_out = value
367 elif self.state == State.FASTDATA:
368 self.handle_fastdata(val, Ann.CONTROL_FIELD_OUT)
369
370 def handle_ir_tdi(self, val):
371 code = bin_to_int(val[0])
372 hex = '0x{:02X}'.format(code)
373 if code in ejtag_insn:
374 # Format instruction name.
375 insn = ejtag_insn[code]
376 s_short = insn[0]
377 s_long = insn[0] + ': ' + insn[1] + ' (' + hex + ')'
378 # Display it and select data register.
379 self.put_current([Ann.INSTRUCTION, [s_short, s_long]])
380 else:
381 self.put_current([Ann.INSTRUCTION, [hex, 'IR TDI ({})'.format(hex)]])
382 self.select_reg(code)
383
384 def handle_new_state(self, new_state):
385 if new_state != 'UPDATE-DR' or not hasattr(self, 'last_data'):
386 return
387
388 if self.state == State.RESET:
389 return
390
391 reg_name = ejtag_reg[self.state]
392 ann_index = Ann.REGISTER + self.state
393 display_data = [ann_index, [reg_name]]
394 self.put_at(self.last_data['in']['ss'], self.last_data['in']['es'], display_data)
395
396 if self.state == State.CONTROL:
397 control_bit_positions = self.last_data['in']['data'][1]
398 bit_count = len(control_bit_positions)
399 # Check if control register data length is correct.
400 if bit_count != 32:
401 error_display = [Ann.REGISTER, ['Error: length != 32']]
402 self.put_at(self.last_data['in']['ss'], self.last_data['in']['es'], error_display)
403 return
404 self.parse_control_reg(Ann.CONTROL_FIELD_IN)
405 self.parse_control_reg(Ann.CONTROL_FIELD_OUT)
406 self.parse_pracc()
407
408 def decode(self, ss: int, es: int, data):
409 cmd, val = data
410 self.ss, self.es = ss, es
411
412 if cmd == 'IR TDI':
413 self.handle_ir_tdi(val)
414 elif cmd == 'DR TDI':
415 self.handle_dr_tdi(val)
416 elif cmd == 'DR TDO':
417 self.handle_dr_tdo(val)
418 elif cmd == 'NEW STATE':
419 self.handle_new_state(val)