2 from cocotb
.triggers
import Timer
3 from cocotb
.utils
import get_sim_steps
4 from cocotb
.binary
import BinaryValue
6 class JTAG_Clock(object):
8 Class for the JTAG clock, run cycle by cycle
10 def __init__(self
, signal
, period
):
12 self
.t
= Timer(period
/4)
15 def Cycle(self
, cycles
=1):
18 Cycle start in middle of 0 pulse of the clock
20 for i
in range(cycles
):
29 class JTAG_Master(object):
31 Class that will run JTAG commands, shift in and out data
33 #TODO: Handle a JTAG chain with more than one device
35 def __init__(self
, tck
, tms
, tdi
, tdo
, trst_n
=None, clk_period
=1000):
37 self
.clkgen
= JTAG_Clock(tck
, clk_period
)
46 self
.period
= Timer(clk_period
)
49 # TODO: make IR length configurable; now 2 is assumed
52 self
.SAMPLEPRELOAD
= [1, 0]
55 # After command we always leave the controller in reset or runidle state
56 # If value is None we will always reset the interface
59 # The methods of this class are coroutines. The results will be stored
64 def cycle_clock(self
, cycles
=1):
65 if self
.state
== "Run" and self
.tms
== 1:
67 yield self
.clkgen
.Cycle(cycles
)
71 if not self
.trst_n
is None:
72 # Enable reset signal for one clock period
77 # 5 cycles with tms on 1 should reset the JTAG TAP controller
79 yield self
.cycle_clock(5)
86 def change_state(self
, tms_list
):
88 Put TAP in other state by giving a TMS sequence
89 This function does not detect if one ends up in reset or run
90 state afterwards, self.state has to be updated by caller
93 tms_copy
= list(tms_list
)
95 self
.tms
<= tms_copy
.pop()
96 yield self
.cycle_clock()
100 def change_to_run(self
):
102 Put TAP in RunTestIdle state
103 self.result is bool and true if TAP went through reset state
106 if self
.state
is None:
108 if self
.state
is "Reset":
111 yield self
.cycle_clock()
113 assert(self
.state
== "Run")
114 self
.result
= isreset
117 def load_ir(self
, cmd
):
119 result
= BinaryValue(bits
=len(cmd_copy
))
122 yield self
.change_to_run()
124 yield self
.change_state([0, 1, 1])
129 # In first iteration we enter SHIFT state and tdo is made active
130 yield self
.cycle_clock()
131 # For the last iteration tdi will be shifted when entering next state
132 self
.tdi
<= cmd_copy
.pop()
133 l_result
.insert(0, str(self
.tdo
))
136 yield self
.change_state([0, 1, 1])
142 Get the IDCODE from the device
143 result will contain the 32 bit IDCODE of the device
146 result
= BinaryValue(bits
=32)
149 # Keep tdi 0 for the whole run
152 yield self
.change_to_run()
154 # If TAP was not reset we have to load IDCODE command
155 yield self
.load_ir(self
.IDCODE
)
157 # Should be again in RUN state
158 assert(self
.state
== "Run")
161 yield self
.change_state([0, 0, 1])
163 # Enter Shift; run for 32 cycles
166 l_result
.insert(0, str(self
.tdo
))
167 yield self
.cycle_clock()
168 result
.binstr
= "".join(l_result
)
171 yield self
.change_state([0, 1, 1])
177 def shift_data(self
, data_in
):
179 Shift data in through the JTAG and capture the output
180 Input can be of type BinaryValue or an iterable value of 0 and 1s.
181 Last bit will be shifted in first.
182 result will contain the sample TDO with the same number of bits as the input
184 if isinstance(data_in
, BinaryValue
):
185 data_copy
= [int(c
) for c
in data_in
.binstr
]
187 data_copy
= list(data_in
)
188 result
= BinaryValue()
191 yield self
.change_to_run()
193 yield self
.change_state([0, 1])
198 yield self
.cycle_clock()
199 self
.tdi
<= data_copy
.pop()
200 l_result
.insert(0, str(self
.tdo
))
201 result
.binstr
= "".join(l_result
)
204 yield self
.change_state([0, 1, 1])