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