2 from cocotb
.triggers
import Timer
3 from cocotb
.binary
import BinaryValue
6 class JTAGException(Exception):
10 class JTAG_Clock(object):
12 Class for the JTAG clock, run cycle by cycle
14 def __init__(self
, signal
, period
):
16 self
.t
= Timer(period
/4)
19 def Cycle(self
, cycles
=1):
22 Cycle start in middle of 0 pulse of the clock
24 for i
in range(cycles
):
34 class JTAG_Master(object):
36 Class that will run JTAG commands, shift in and out data
38 #TODO: Handle a JTAG chain with more than one device
40 def __init__(self
, tck
, tms
, tdi
, tdo
, trst_n
=None, clk_period
=1000, ir_width
=2):
42 self
.clkgen
= JTAG_Clock(tck
, clk_period
)
50 if trst_n
is not None:
52 self
.period
= Timer(clk_period
)
55 # TODO: Make values configurable
56 self
.BYPASS
= [1 for _
in range(ir_width
)]
57 self
.IDCODE
= [1 if i
== ir_width
-1 else 0 for i
in range(ir_width
)]
58 self
.SAMPLEPRELOAD
= [1 if i
== ir_width
-2 else 0 for i
in range(ir_width
)]
59 self
.EXTEST
= [0 for _
in range(ir_width
)]
61 # After command we always leave the controller in reset or runidle state
62 # If value is None we will always reset the interface
65 # The methods of this class are coroutines. The results will be stored
70 def cycle_clock(self
, cycles
=1):
71 if self
.state
== "Run" and self
.tms
== 1:
73 yield self
.clkgen
.Cycle(cycles
)
77 if not self
.trst_n
is None:
78 # Enable reset signal for one clock period
83 # 5 cycles with tms on 1 should reset the JTAG TAP controller
85 yield self
.cycle_clock(5)
92 def change_state(self
, tms_list
):
94 Put TAP in other state by giving a TMS sequence
95 This function does not detect if one ends up in reset or run
96 state afterwards, self.state has to be updated by caller
99 tms_copy
= list(tms_list
)
101 self
.tms
<= tms_copy
.pop()
102 yield self
.cycle_clock()
106 def change_to_run(self
):
108 Put TAP in RunTestIdle state
109 self.result is bool and true if TAP went through reset state
112 if self
.state
is None:
114 if self
.state
== "Reset":
117 yield self
.cycle_clock()
119 assert(self
.state
== "Run")
120 self
.result
= isreset
123 def load_ir(self
, cmd
):
124 if isinstance(cmd
, BinaryValue
):
125 cmd_copy
= [int(c
) for c
in cmd
.binstr
]
128 result
= BinaryValue(n_bits
=len(cmd_copy
))
131 yield self
.change_to_run()
133 yield self
.change_state([0, 1, 1])
138 # In first iteration we enter SHIFT state and tdo is made active
139 yield self
.cycle_clock()
140 # For the last iteration tdi will be shifted when entering next state
141 self
.tdi
<= cmd_copy
.pop()
142 l_result
.insert(0, str(self
.tdo
))
145 yield self
.change_state([0, 1, 1])
151 Get the IDCODE from the device
152 result will contain the 32 bit IDCODE of the device
155 result
= BinaryValue(n_bits
=32)
158 # Keep tdi 0 for the whole run
161 yield self
.change_to_run()
163 # If TAP was not reset we have to load IDCODE command
164 yield self
.load_ir(self
.IDCODE
)
166 # Should be again in RUN state
167 assert(self
.state
== "Run")
170 yield self
.change_state([0, 0, 1])
172 # Enter Shift; run for 32 cycles
175 l_result
.insert(0, str(self
.tdo
))
176 yield self
.cycle_clock()
177 result
.binstr
= "".join(l_result
)
180 yield self
.change_state([0, 1, 1])
186 def shift_data(self
, data_in
):
188 Shift data in through the JTAG and capture the output
189 Input can be of type BinaryValue or an iterable value of 0 and 1s.
190 Last bit will be shifted in first.
191 result will contain the sample TDO with the same number of bits as the input
193 if isinstance(data_in
, BinaryValue
):
194 data_copy
= [int(c
) for c
in data_in
.binstr
]
196 data_copy
= list(data_in
)
197 result
= BinaryValue()
200 yield self
.change_to_run()
202 yield self
.change_state([0, 1])
207 yield self
.cycle_clock()
208 self
.tdi
<= data_copy
.pop()
209 l_result
.insert(0, str(self
.tdo
))
210 result
.binstr
= "".join(l_result
)
213 yield self
.change_state([0, 1, 1])