b479398338d69563b15e914f0665d23c5808fc63
[libsigrokdecode.git] / decoders / jtag_ejtag / pd.py
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
20 import sigrokdecode as srd
21
22 class 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
40 class 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
51 class ControlReg(object):
52     PRACC             = (1 << 18)
53     PRNW              = (1 << 19)
54
55 class Ann(object):
56     INSTRUCTION       = 0
57     REGISTER          = 1
58     CONTROL_FIELD_IN  = 10
59     CONTROL_FIELD_OUT = 11
60     PRACC             = 12
61
62 ejtag_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
86 ejtag_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
98 ejtag_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
152 ejtag_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
161 def bin_to_int(s: str):
162     return int('0b' + s, 2)
163
164 class RegData(object):
165     def __init__(self):
166         self.ss = None
167         self.es = None
168         self.data = None
169
170 class LastData(object):
171     def __init__(self):
172         self.data_in = RegData()
173         self.data_out = RegData()
174
175 class 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
182         self.start_sample = 0
183         self.end_sample = 0
184
185     def __init__(self):
186         self.reset()
187
188 regs_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
193 class 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
248         start_sample = self.pracc_state.start_sample
249         end_sample = self.pracc_state.end_sample
250         pracc_write = (control_out & ControlReg.PRNW) != 0
251
252         display_string = 'PrAcc: '
253         display_string += 'Store' if pracc_write else 'Load/Fetch'
254
255         if pracc_write:
256             if self.pracc_state.address_out != None:
257                 display_string += ', A:' + ' 0x{:08X}'.format(self.pracc_state.address_out)
258             if self.pracc_state.data_out != None:
259                 display_string += ', D:' + ' 0x{:08X}'.format(self.pracc_state.data_out)
260         else:
261             if self.pracc_state.address_out != None:
262                 display_string += ', A:' + ' 0x{:08X}'.format(self.pracc_state.address_out)
263             if self.pracc_state.data_in != None:
264                 display_string += ', D:' + ' 0x{:08X}'.format(self.pracc_state.data_in)
265
266         self.pracc_state.reset()
267
268         display_data = [Ann.PRACC, [display_string]]
269         self.put_at(start_sample, end_sample, display_data)
270
271     def parse_control_reg(self, ann):
272         reg_write = ann == Ann.CONTROL_FIELD_IN
273         control_bit_positions = []
274         data_select = ''
275
276         if reg_write:
277             data_select = 'in'
278         else:
279             data_select = 'out'
280
281         control_bit_positions = self.last_data[data_select]['data'][1]
282         control_data = self.last_data[data_select]['data'][0]
283
284         # Annotate control register fields.
285         for field in ejtag_control_reg:
286             start_bit = 31 - field[1]
287             end_bit = 31 - field[0]
288             comment = field[2]
289             value_descriptions = []
290
291             if reg_write:
292                 if len(field[3]) < 2:
293                     continue
294                 value_descriptions = field[3][1]
295             else:
296                 value_descriptions = field[3][0]
297
298             start_sample = control_bit_positions[start_bit][0]
299             end_sample = control_bit_positions[end_bit][1]
300
301             value_str = control_data[end_bit : start_bit + 1]
302             value_index = bin_to_int(value_str)
303
304             short_desc = comment + ': ' + value_str
305             long_desc = value_descriptions[value_index] if len(value_descriptions) > value_index else '?'
306             display_data = [ann, [short_desc, long_desc]]
307
308             self.put_at(start_sample, end_sample, display_data)
309
310     def check_last_data(self):
311         if not hasattr(self, 'last_data'):
312             self.last_data = {'in': {}, 'out': {}}
313
314     def handle_fastdata(self, val, ann):
315         spracc_write_desc = {
316             0: ['0', 'SPrAcc: 0', 'Request completion of Fastdata access'],
317             1: ['1', 'SPrAcc: 1', 'No effect'],
318         }
319         spracc_read_desc = {
320             0: ['0', 'SPrAcc: 0', 'Fastdata access failure'],
321             1: ['1', 'SPrAcc: 1', 'Successful completion of Fastdata access'],
322         }
323
324         bitstring = val[0]
325         bit_sample_pos = val[1]
326         fastdata_state = bitstring[32]
327         data = bin_to_int(bitstring[0:32])
328
329         fastdata_bit_pos = bit_sample_pos[32]
330         data_pos = [bit_sample_pos[31][0], bit_sample_pos[0][1]]
331
332         fastdata_sample_start, fastdata_sample_end = fastdata_bit_pos
333         data_sample_start, data_sample_end = data_pos
334
335         display_data = [ann, ['0x{:08X}'.format(data)]]
336         spracc_display_data = []
337
338         if ann == Ann.CONTROL_FIELD_IN:
339             spracc_display_data = [ann, spracc_write_desc[int(fastdata_state)]]
340         elif ann == Ann.CONTROL_FIELD_OUT:
341             spracc_display_data = [ann, spracc_read_desc[int(fastdata_state)]]
342
343         self.put_at(fastdata_sample_start, fastdata_sample_end, spracc_display_data)
344         self.put_at(data_sample_start, data_sample_end, display_data)
345
346     def handle_dr_tdi(self, val):
347         value = bin_to_int(val[0])
348         self.check_last_data()
349         self.last_data['in'] = {'ss': self.ss, 'es': self.es, 'data': val}
350
351         self.pracc_state.start_sample = self.ss
352         self.pracc_state.end_sample = self.es
353
354         if self.state == State.ADDRESS:
355             self.pracc_state.address_in = value
356         elif self.state == State.DATA:
357             self.pracc_state.data_in = value
358         elif self.state == State.FASTDATA:
359             self.handle_fastdata(val, Ann.CONTROL_FIELD_IN)
360
361     def handle_dr_tdo(self, val):
362         value = bin_to_int(val[0])
363         self.check_last_data()
364         self.last_data['out'] = {'ss': self.ss, 'es': self.es, 'data': val}
365         if self.state == State.ADDRESS:
366             self.pracc_state.address_out = value
367         elif self.state == State.DATA:
368             self.pracc_state.data_out = value
369         elif self.state == State.FASTDATA:
370             self.handle_fastdata(val, Ann.CONTROL_FIELD_OUT)
371
372     def handle_ir_tdi(self, val):
373         code = bin_to_int(val[0])
374         hex = '0x{:02X}'.format(code)
375         if code in ejtag_insn:
376             # Format instruction name.
377             insn = ejtag_insn[code]
378             s_short = insn[0]
379             s_long = insn[0] + ': ' + insn[1] + ' (' + hex + ')'
380             # Display it and select data register.
381             self.put_current([Ann.INSTRUCTION, [s_short, s_long]])
382         else:
383             self.put_current([Ann.INSTRUCTION, [hex, 'IR TDI ({})'.format(hex)]])
384         self.select_reg(code)
385
386     def handle_new_state(self, new_state):
387         if new_state != 'UPDATE-DR' or not hasattr(self, 'last_data'):
388             return
389
390         if self.state == State.RESET:
391             return
392
393         reg_name = ejtag_reg[self.state]
394         ann_index = Ann.REGISTER + self.state
395         display_data = [ann_index, [reg_name]]
396         self.put_at(self.last_data['in']['ss'], self.last_data['in']['es'], display_data)
397
398         if self.state == State.CONTROL:
399             control_bit_positions = self.last_data['in']['data'][1]
400             bit_count = len(control_bit_positions)
401             # Check if control register data length is correct.
402             if bit_count != 32:
403                 error_display = [Ann.REGISTER, ['Error: length != 32']]
404                 self.put_at(self.last_data['in']['ss'], self.last_data['in']['es'], error_display)
405                 return
406             self.parse_control_reg(Ann.CONTROL_FIELD_IN)
407             self.parse_control_reg(Ann.CONTROL_FIELD_OUT)
408             self.parse_pracc()
409
410     def decode(self, ss: int, es: int, data):
411         cmd, val = data
412         self.ss, self.es = ss, es
413
414         if cmd == 'IR TDI':
415             self.handle_ir_tdi(val)
416         elif cmd == 'DR TDI':
417             self.handle_dr_tdi(val)
418         elif cmd == 'DR TDO':
419             self.handle_dr_tdo(val)
420         elif cmd == 'NEW STATE':
421             self.handle_new_state(val)