1dd13b1ee0d1a0c3e47859421735bc27db5dd0a5
2 from cocotb
.triggers
import Timer
3 from cocotb
.binary
import BinaryValue
5 class JTAGException(Exception):
8 class JTAG_Clock(object):
10 Class for the JTAG clock, run cycle by cycle
12 def __init__(self
, signal
, period
):
14 self
.t
= Timer(period
/4)
17 def Cycle(self
, cycles
=1):
20 Cycle start in middle of 0 pulse of the clock
22 for i
in range(cycles
):
31 class JTAG_Master(object):
33 Class that will run JTAG commands, shift in and out data
35 #TODO: Handle a JTAG chain with more than one device
37 def __init__(self
, tck
, tms
, tdi
, tdo
, trst_n
=None, clk_period
=1000):
39 self
.clkgen
= JTAG_Clock(tck
, clk_period
)
47 if trst_n
is not None:
49 self
.period
= Timer(clk_period
)
52 # TODO: make IR length configurable; now 2 is assumed
55 self
.SAMPLEPRELOAD
= [1, 0]
58 # After command we always leave the controller in reset or runidle state
59 # If value is None we will always reset the interface
62 # The methods of this class are coroutines. The results will be stored
67 def cycle_clock(self
, cycles
=1):
68 if self
.state
== "Run" and self
.tms
== 1:
70 yield self
.clkgen
.Cycle(cycles
)
74 if not self
.trst_n
is None:
75 # Enable reset signal for one clock period
80 # 5 cycles with tms on 1 should reset the JTAG TAP controller
82 yield self
.cycle_clock(5)
89 def change_state(self
, tms_list
):
91 Put TAP in other state by giving a TMS sequence
92 This function does not detect if one ends up in reset or run
93 state afterwards, self.state has to be updated by caller
96 tms_copy
= list(tms_list
)
98 self
.tms
<= tms_copy
.pop()
99 yield self
.cycle_clock()
103 def change_to_run(self
):
105 Put TAP in RunTestIdle state
106 self.result is bool and true if TAP went through reset state
109 if self
.state
is None:
111 if self
.state
is "Reset":
114 yield self
.cycle_clock()
116 assert(self
.state
== "Run")
117 self
.result
= isreset
120 def load_ir(self
, cmd
):
122 result
= BinaryValue(bits
=len(cmd_copy
))
125 yield self
.change_to_run()
127 yield self
.change_state([0, 1, 1])
132 # In first iteration we enter SHIFT state and tdo is made active
133 yield self
.cycle_clock()
134 # For the last iteration tdi will be shifted when entering next state
135 self
.tdi
<= cmd_copy
.pop()
136 l_result
.insert(0, str(self
.tdo
))
139 yield self
.change_state([0, 1, 1])
145 Get the IDCODE from the device
146 result will contain the 32 bit IDCODE of the device
149 result
= BinaryValue(bits
=32)
152 # Keep tdi 0 for the whole run
155 yield self
.change_to_run()
157 # If TAP was not reset we have to load IDCODE command
158 yield self
.load_ir(self
.IDCODE
)
160 # Should be again in RUN state
161 assert(self
.state
== "Run")
164 yield self
.change_state([0, 0, 1])
166 # Enter Shift; run for 32 cycles
169 l_result
.insert(0, str(self
.tdo
))
170 yield self
.cycle_clock()
171 result
.binstr
= "".join(l_result
)
174 yield self
.change_state([0, 1, 1])
180 def shift_data(self
, data_in
):
182 Shift data in through the JTAG and capture the output
183 Input can be of type BinaryValue or an iterable value of 0 and 1s.
184 Last bit will be shifted in first.
185 result will contain the sample TDO with the same number of bits as the input
187 if isinstance(data_in
, BinaryValue
):
188 data_copy
= [int(c
) for c
in data_in
.binstr
]
190 data_copy
= list(data_in
)
191 result
= BinaryValue()
194 yield self
.change_to_run()
196 yield self
.change_state([0, 1])
201 yield self
.cycle_clock()
202 self
.tdi
<= data_copy
.pop()
203 l_result
.insert(0, str(self
.tdo
))
204 result
.binstr
= "".join(l_result
)
207 yield self
.change_state([0, 1, 1])