7fc5ca77fd2491b8b329c1cb8b46ac9892ceb1ac
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, ir_width
=2):
39 self
.clkgen
= JTAG_Clock(tck
, clk_period
)
47 if trst_n
is not None:
49 self
.period
= Timer(clk_period
)
52 # TODO: Make values configurable
53 self
.BYPASS
= [1 for _
in range(ir_width
)]
54 self
.IDCODE
= [1 if i
== ir_width
-1 else 0 for i
in range(ir_width
)]
55 self
.SAMPLEPRELOAD
= [1 if i
== ir_width
-2 else 0 for i
in range(ir_width
)]
56 self
.EXTEST
= [0 for _
in range(ir_width
)]
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
):
121 if isinstance(cmd
, BinaryValue
):
122 cmd_copy
= [int(c
) for c
in cmd
.binstr
]
125 result
= BinaryValue(bits
=len(cmd_copy
))
128 yield self
.change_to_run()
130 yield self
.change_state([0, 1, 1])
135 # In first iteration we enter SHIFT state and tdo is made active
136 yield self
.cycle_clock()
137 # For the last iteration tdi will be shifted when entering next state
138 self
.tdi
<= cmd_copy
.pop()
139 l_result
.insert(0, str(self
.tdo
))
142 yield self
.change_state([0, 1, 1])
148 Get the IDCODE from the device
149 result will contain the 32 bit IDCODE of the device
152 result
= BinaryValue(bits
=32)
155 # Keep tdi 0 for the whole run
158 yield self
.change_to_run()
160 # If TAP was not reset we have to load IDCODE command
161 yield self
.load_ir(self
.IDCODE
)
163 # Should be again in RUN state
164 assert(self
.state
== "Run")
167 yield self
.change_state([0, 0, 1])
169 # Enter Shift; run for 32 cycles
172 l_result
.insert(0, str(self
.tdo
))
173 yield self
.cycle_clock()
174 result
.binstr
= "".join(l_result
)
177 yield self
.change_state([0, 1, 1])
183 def shift_data(self
, data_in
):
185 Shift data in through the JTAG and capture the output
186 Input can be of type BinaryValue or an iterable value of 0 and 1s.
187 Last bit will be shifted in first.
188 result will contain the sample TDO with the same number of bits as the input
190 if isinstance(data_in
, BinaryValue
):
191 data_copy
= [int(c
) for c
in data_in
.binstr
]
193 data_copy
= list(data_in
)
194 result
= BinaryValue()
197 yield self
.change_to_run()
199 yield self
.change_state([0, 1])
204 yield self
.cycle_clock()
205 self
.tdi
<= data_copy
.pop()
206 l_result
.insert(0, str(self
.tdo
))
207 result
.binstr
= "".join(l_result
)
210 yield self
.change_state([0, 1, 1])