]> sigrok.org Git - libsigrokdecode.git/blob - decoders/cjtag/pd.py
912f072a46b8bf82d768ff36a63e6ccba55a7a96
[libsigrokdecode.git] / decoders / cjtag / pd.py
1 ##
2 ## This file is part of the libsigrokdecode project.
3 ##
4 ## Copyright (C) 2012-2015 Uwe Hermann <uwe@hermann-uwe.de>
5 ## Copyright (C) 2019 Zhiyuan Wan <dv.xw@qq.com>
6 ## Copyright (C) 2019 Kongou Hikari <hikari@iloli.bid>
7 ##
8 ## This program is free software; you can redistribute it and/or modify
9 ## it under the terms of the GNU General Public License as published by
10 ## the Free Software Foundation; either version 2 of the License, or
11 ## (at your option) any later version.
12 ##
13 ## This program is distributed in the hope that it will be useful,
14 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 ## GNU General Public License for more details.
17 ##
18 ## You should have received a copy of the GNU General Public License
19 ## along with this program; if not, see <http://www.gnu.org/licenses/>.
20 ##
21
22 import sigrokdecode as srd
23
24 '''
25 OUTPUT_PYTHON format:
26
27 Packet:
28 [<ptype>, <pdata>]
29
30 <ptype>:
31  - 'NEW STATE': <pdata> is the new state of the JTAG state machine.
32    Valid values: 'TEST-LOGIC-RESET', 'RUN-TEST/IDLE', 'SELECT-DR-SCAN',
33    'CAPTURE-DR', 'SHIFT-DR', 'EXIT1-DR', 'PAUSE-DR', 'EXIT2-DR', 'UPDATE-DR',
34    'SELECT-IR-SCAN', 'CAPTURE-IR', 'SHIFT-IR', 'EXIT1-IR', 'PAUSE-IR',
35    'EXIT2-IR', 'UPDATE-IR'.
36  - 'IR TDI': Bitstring that was clocked into the IR register.
37  - 'IR TDO': Bitstring that was clocked out of the IR register.
38  - 'DR TDI': Bitstring that was clocked into the DR register.
39  - 'DR TDO': Bitstring that was clocked out of the DR register.
40
41 All bitstrings are a list consisting of two items. The first is a sequence
42 of '1' and '0' characters (the right-most character is the LSB. Example:
43 '01110001', where 1 is the LSB). The second item is a list of ss/es values
44 for each bit that is in the bitstring.
45 '''
46
47 jtag_states = [
48         # Intro "tree"
49         'TEST-LOGIC-RESET', 'RUN-TEST/IDLE',
50         # DR "tree"
51         'SELECT-DR-SCAN', 'CAPTURE-DR', 'UPDATE-DR', 'PAUSE-DR',
52         'SHIFT-DR', 'EXIT1-DR', 'EXIT2-DR',
53         # IR "tree"
54         'SELECT-IR-SCAN', 'CAPTURE-IR', 'UPDATE-IR', 'PAUSE-IR',
55         'SHIFT-IR', 'EXIT1-IR', 'EXIT2-IR',
56 ]
57
58 class Decoder(srd.Decoder):
59     api_version = 3
60     id = 'cjtag'
61     name = 'cJTAG'
62     longname = 'Compact Joint Test Action Group (IEEE 1149.7)'
63     desc = 'Protocol for testing, debugging, and flashing ICs.'
64     license = 'gplv2+'
65     inputs = ['logic']
66     outputs = ['jtag']
67     tags = ['Debug/trace']
68     channels = (
69         {'id': 'tdi',  'name': 'TDI',  'desc': 'Test data input'},
70         {'id': 'tdo',  'name': 'TDO',  'desc': 'Test data output'},
71         {'id': 'tck',  'name': 'TCK',  'desc': 'Test clock'},
72         {'id': 'tms',  'name': 'TMS',  'desc': 'Test mode select'},
73     )
74     optional_channels = (
75         {'id': 'trst', 'name': 'TRST#', 'desc': 'Test reset'},
76         {'id': 'srst', 'name': 'SRST#', 'desc': 'System reset'},
77         {'id': 'rtck', 'name': 'RTCK',  'desc': 'Return clock signal'},
78     )
79     annotations = tuple([tuple([s.lower(), s]) for s in jtag_states]) + ( \
80         ('bit-tdi', 'Bit (TDI)'),
81         ('bit-tdo', 'Bit (TDO)'),
82         ('bitstring-tdi', 'Bitstring (TDI)'),
83         ('bitstring-tdo', 'Bitstring (TDO)'),
84         ('bit-tms', 'Bit (TMS)'),
85         ('state-tapc', 'TAPC state'),
86     )
87     annotation_rows = (
88         ('bits-tdi', 'Bits (TDI)', (16,)),
89         ('bits-tdo', 'Bits (TDO)', (17,)),
90         ('bitstrings-tdi', 'Bitstrings (TDI)', (18,)),
91         ('bitstrings-tdo', 'Bitstrings (TDO)', (19,)),
92         ('bits-tms', 'Bits (TMS)', (20,)),
93         ('states-tapc', 'TAPC states', (21,)),
94         ('states', 'States', tuple(range(15 + 1))),
95     )
96
97     def __init__(self):
98         self.reset()
99
100     def reset(self):
101         # self.state = 'TEST-LOGIC-RESET'
102         self.state = 'RUN-TEST/IDLE'
103         self.cjtagstate = '4-WIRE'
104         self.oldcjtagstate = None
105         self.escape_edges = 0
106         self.oaclen = 0
107         self.oldtms = 0
108         self.oacp = 0
109         self.oscan1cycle = 0
110         self.oldstate = None
111         self.bits_tdi = []
112         self.bits_tdo = []
113         self.bits_samplenums_tdi = []
114         self.bits_samplenums_tdo = []
115         self.ss_item = self.es_item = None
116         self.ss_bitstring = self.es_bitstring = None
117         self.saved_item = None
118         self.first = True
119         self.first_bit = True
120
121     def start(self):
122         self.out_python = self.register(srd.OUTPUT_PYTHON)
123         self.out_ann = self.register(srd.OUTPUT_ANN)
124
125     def putx(self, data):
126         self.put(self.ss_item, self.es_item, self.out_ann, data)
127
128     def putp(self, data):
129         self.put(self.ss_item, self.es_item, self.out_python, data)
130
131     def putx_bs(self, data):
132         self.put(self.ss_bitstring, self.es_bitstring, self.out_ann, data)
133
134     def putp_bs(self, data):
135         self.put(self.ss_bitstring, self.es_bitstring, self.out_python, data)
136
137     def advance_state_machine(self, tms):
138         self.oldstate = self.state
139
140         if self.cjtagstate.startswith('CJTAG-'):
141             self.oacp = self.oacp + 1
142             if (self.oacp > 4 and self.oaclen == 12):
143                 self.cjtagstate = 'CJTAG-EC'
144
145             if (self.oacp == 8 and tms == 0):
146                 self.oaclen = 36
147             if (self.oacp > 8 and self.oaclen == 36):
148                 self.cjtagstate = 'CJTAG-SPARE'
149             if (self.oacp > 13 and self.oaclen == 36):
150                 self.cjtagstate = 'CJTAG-TPDEL'
151             if (self.oacp > 16 and self.oaclen == 36):
152                 self.cjtagstate = 'CJTAG-TPREV'
153             if (self.oacp > 18 and self.oaclen == 36):
154                 self.cjtagstate = 'CJTAG-TPST'
155             if (self.oacp > 23 and self.oaclen == 36):
156                 self.cjtagstate = 'CJTAG-RDYC'
157             if (self.oacp > 25 and self.oaclen == 36):
158                 self.cjtagstate = 'CJTAG-DLYC'
159             if (self.oacp > 27 and self.oaclen == 36):
160                 self.cjtagstate = 'CJTAG-SCNFMT'
161
162             if (self.oacp > 8 and self.oaclen == 12):
163                 self.cjtagstate = 'CJTAG-CP'
164             if (self.oacp > 32 and self.oaclen == 36):
165                 self.cjtagstate = 'CJTAG-CP'
166
167             if (self.oacp > self.oaclen):
168                 self.cjtagstate = 'OSCAN1'
169                 self.oscan1cycle = 1
170                 # Because Nuclei cJTAG device asserts a reset during cJTAG
171                 # online activating.
172                 self.state = 'TEST-LOGIC-RESET'
173             return
174
175         # Intro "tree"
176         if self.state == 'TEST-LOGIC-RESET':
177             self.state = 'TEST-LOGIC-RESET' if (tms) else 'RUN-TEST/IDLE'
178         elif self.state == 'RUN-TEST/IDLE':
179             self.state = 'SELECT-DR-SCAN' if (tms) else 'RUN-TEST/IDLE'
180
181         # DR "tree"
182         elif self.state == 'SELECT-DR-SCAN':
183             self.state = 'SELECT-IR-SCAN' if (tms) else 'CAPTURE-DR'
184         elif self.state == 'CAPTURE-DR':
185             self.state = 'EXIT1-DR' if (tms) else 'SHIFT-DR'
186         elif self.state == 'SHIFT-DR':
187             self.state = 'EXIT1-DR' if (tms) else 'SHIFT-DR'
188         elif self.state == 'EXIT1-DR':
189             self.state = 'UPDATE-DR' if (tms) else 'PAUSE-DR'
190         elif self.state == 'PAUSE-DR':
191             self.state = 'EXIT2-DR' if (tms) else 'PAUSE-DR'
192         elif self.state == 'EXIT2-DR':
193             self.state = 'UPDATE-DR' if (tms) else 'SHIFT-DR'
194         elif self.state == 'UPDATE-DR':
195             self.state = 'SELECT-DR-SCAN' if (tms) else 'RUN-TEST/IDLE'
196
197         # IR "tree"
198         elif self.state == 'SELECT-IR-SCAN':
199             self.state = 'TEST-LOGIC-RESET' if (tms) else 'CAPTURE-IR'
200         elif self.state == 'CAPTURE-IR':
201             self.state = 'EXIT1-IR' if (tms) else 'SHIFT-IR'
202         elif self.state == 'SHIFT-IR':
203             self.state = 'EXIT1-IR' if (tms) else 'SHIFT-IR'
204         elif self.state == 'EXIT1-IR':
205             self.state = 'UPDATE-IR' if (tms) else 'PAUSE-IR'
206         elif self.state == 'PAUSE-IR':
207             self.state = 'EXIT2-IR' if (tms) else 'PAUSE-IR'
208         elif self.state == 'EXIT2-IR':
209             self.state = 'UPDATE-IR' if (tms) else 'SHIFT-IR'
210         elif self.state == 'UPDATE-IR':
211             self.state = 'SELECT-DR-SCAN' if (tms) else 'RUN-TEST/IDLE'
212
213     def handle_rising_tck_edge(self, tdi, tdo, tck, tms, trst, srst, rtck):
214
215         # Rising TCK edges always advance the state machine.
216         self.advance_state_machine(tms)
217
218         if self.first:
219             # Save the start sample and item for later (no output yet).
220             self.ss_item = self.samplenum
221             self.first = False
222         else:
223             # Output the saved item (from the last CLK edge to the current).
224             self.es_item = self.samplenum
225             # Output the old state (from last rising TCK edge to current one).
226             self.putx([jtag_states.index(self.oldstate), [self.oldstate]])
227             self.putp(['NEW STATE', self.state])
228
229             self.putx([21, [self.oldcjtagstate]])
230             if (self.oldcjtagstate.startswith('CJTAG-')):
231                 self.putx([20, [str(self.oldtms)]])
232         self.oldtms = tms
233
234         # Upon SHIFT-*/EXIT1-* collect the current TDI/TDO values.
235         if self.oldstate.startswith('SHIFT-') or \
236            self.oldstate.startswith('EXIT1-'):
237             if self.first_bit:
238                 self.ss_bitstring = self.samplenum
239                 self.first_bit = False
240             else:
241                 self.putx([16, [str(self.bits_tdi[0])]])
242                 self.putx([17, [str(self.bits_tdo[0])]])
243                 # Use self.samplenum as ES of the previous bit.
244                 self.bits_samplenums_tdi[0][1] = self.samplenum
245                 self.bits_samplenums_tdo[0][1] = self.samplenum
246
247             self.bits_tdi.insert(0, tdi)
248             self.bits_tdo.insert(0, tdo)
249
250             # Use self.samplenum as SS of the current bit.
251             self.bits_samplenums_tdi.insert(0, [self.samplenum, -1])
252             self.bits_samplenums_tdo.insert(0, [self.samplenum, -1])
253
254         # Output all TDI/TDO bits if we just switched to UPDATE-*.
255         if self.state.startswith('UPDATE-'):
256
257             self.es_bitstring = self.samplenum
258
259             t = self.state[-2:] + ' TDI'
260             b = ''.join(map(str, self.bits_tdi[1:]))
261             h = ' (0x%x' % int('0b0' + b, 2) + ')'
262             s = t + ': ' + b + h + ', ' + str(len(self.bits_tdi[1:])) + ' bits'
263             self.putx_bs([18, [s]])
264             self.putp_bs([t, [b, self.bits_samplenums_tdi[1:]]])
265             self.bits_tdi = []
266             self.bits_samplenums_tdi = []
267
268             t = self.state[-2:] + ' TDO'
269             b = ''.join(map(str, self.bits_tdo[1:]))
270             h = ' (0x%x' % int('0b0' + b, 2) + ')'
271             s = t + ': ' + b + h + ', ' + str(len(self.bits_tdo[1:])) + ' bits'
272             self.putx_bs([19, [s]])
273             self.putp_bs([t, [b, self.bits_samplenums_tdo[1:]]])
274             self.bits_tdo = []
275             self.bits_samplenums_tdo = []
276
277             self.first_bit = True
278
279             self.ss_bitstring = self.samplenum
280
281         self.ss_item = self.samplenum
282
283     def handle_tms_edge(self, tck, tms):
284         self.escape_edges = self.escape_edges + 1
285
286     def handle_tapc_state(self, tck, tms):
287         self.oldcjtagstate = self.cjtagstate
288
289         if self.escape_edges >= 8:
290             self.cjtagstate = '4-WIRE'
291         if self.escape_edges == 6:
292             self.cjtagstate = 'CJTAG-OAC'
293             self.oacp = 0
294             self.oaclen = 12
295
296         self.escape_edges = 0
297
298     def decode(self):
299         tdi_real = 0
300         tms_real = 0
301         tdo_real = 0
302
303         while True:
304             # Wait for a rising edge on TCK.
305             (tdi, tdo, tck, tms, trst, srst, rtck) = self.wait({2: 'r'})
306             self.handle_tapc_state(tck, tms)
307
308             if (self.cjtagstate == 'OSCAN1'):
309                 if (self.oscan1cycle == 0): # nTDI
310                     if (tms == 0):
311                         tdi_real = 1
312                     else:
313                         tdi_real = 0
314                     self.oscan1cycle = 1
315                 elif (self.oscan1cycle == 1): # TMS
316                     tms_real = tms
317                     self.oscan1cycle = 2
318                 elif (self.oscan1cycle == 2): # TDO
319                     tdo_real = tms
320                     self.handle_rising_tck_edge(tdi_real, tdo_real, tck, tms_real, trst, srst, rtck)
321                     self.oscan1cycle = 0
322             else:
323                 self.handle_rising_tck_edge(tdi, tdo, tck, tms, trst, srst, rtck)
324
325             while (tck == 1):
326                 (tdi, tdo, tck, tms_n, trst, srst, rtck) = self.wait([{2: 'f'}, {3: 'e'}])
327                 if (tms_n != tms):
328                     tms = tms_n
329                     self.handle_tms_edge(tck, tms)