3 based on Staf Verhaegen (Chips4Makers) wishbone TAP
6 from nmigen
import (Module
, Signal
, Elaboratable
, Const
)
7 from nmigen
.cli
import rtlil
8 from c4m
.nmigen
.jtag
.tap
import TAP
, IOType
9 from soc
.debug
.dmi
import DMIInterface
, DBGCore
11 from nmigen
.back
.pysim
import Simulator
, Delay
, Settle
, Tick
12 from nmutil
.util
import wrap
15 # JTAG to DMI interface
20 # req : ____/------------\_____
24 # din : xxxxxxxxxxxx< >xxx
25 # ack : ____________/------\___
27 # * addr/dout set along with req, can be latched on same cycle by slave
28 # * ack & din remain up until req is dropped by master, the slave must
29 # provide a stable output on din on reads during that time.
30 # * req remains low at until at least one sysclk after ack seen down.
34 def __init__(self
, *args
, **kwargs
):
35 super().__init
__(*args
, **kwargs
)
38 def elaborate(self
, platform
):
39 m
= super().elaborate(platform
)
40 self
._elaborate
_dmis
(m
)
43 def add_dmi(self
, *, ircodes
, address_width
=8, data_width
=64,
44 domain
="sync", name
=None):
45 """Add a DMI interface
47 * writing to DMIADDR will automatically trigger a DMI READ.
48 the DMI address does not alter (so writes can be done at that addr)
49 * reading from DMIREAD triggers a DMI READ at the current DMI addr
50 the address is automatically incremented by 1 after.
51 * writing to DMIWRITE triggers a DMI WRITE at the current DMI addr
52 the address is automatically incremented by 1 after.
56 ircodes: sequence of three integer for the JTAG IR codes;
57 they represent resp. DMIADDR, DMIREAD and DMIWRITE.
58 First code has a shift register of length 'address_width',
59 the two other codes share a shift register of length
62 address_width: width of the address
63 data_width: width of the data
66 dmi: soc.debug.dmi.DMIInterface
70 raise ValueError("3 IR Codes have to be provided")
73 name
= "dmi" + str(len(self
._dmis
))
75 # add 2 shift registers: one for addr, one for data.
76 sr_addr
= self
.add_shiftreg(ircode
=ircodes
[0], length
=address_width
,
77 domain
=domain
, name
=name
+"_addrsr")
78 sr_data
= self
.add_shiftreg(ircode
=ircodes
[1:], length
=data_width
,
79 domain
=domain
, name
=name
+"_datasr")
81 dmi
= DMIInterface(name
=name
)
82 self
._dmis
.append((sr_addr
, sr_data
, dmi
, domain
))
86 def _elaborate_dmis(self
, m
):
87 for sr_addr
, sr_data
, dmi
, domain
in self
._dmis
:
89 m
.d
.comb
+= sr_addr
.i
.eq(dmi
.addr_i
)
91 with m
.FSM(domain
=domain
) as ds
:
93 # detect mode based on whether jtag addr or data read/written
95 with m
.If(sr_addr
.oe
): # DMIADDR code
96 cd
+= dmi
.addr_i
.eq(sr_addr
.o
)
98 with m
.Elif(sr_data
.oe
[0]): # DMIREAD code
100 cd
+= dmi
.addr_i
.eq(dmi
.addr_i
+ 1)
102 with m
.Elif(sr_data
.oe
[1]): # DMIWRITE code
103 cd
+= dmi
.din
.eq(sr_data
.o
)
106 # req_i raises for 1 clock
107 with m
.State("READ"):
111 with m
.State("READACK"):
112 with m
.If(dmi
.ack_o
):
113 # Store read data in sr_data.i hold till next read
114 cd
+= sr_data
.i
.eq(dmi
.dout
)
117 # req_i raises for 1 clock
118 with m
.State("WRRD"):
122 with m
.State("WRRDACK"):
123 with m
.If(dmi
.ack_o
):
124 cd
+= dmi
.addr_i
.eq(dmi
.addr_i
+ 1)
125 m
.next
= "READ" # for readwrite
127 # set DMI req and write-enable based on ongoing FSM states
129 dmi
.req_i
.eq(ds
.ongoing("READ") | ds
.ongoing("WRRD")),
130 dmi
.we_i
.eq(ds
.ongoing("WRRD")),
134 def tms_state_set(dut
, bits
):
136 yield dut
.bus
.tck
.eq(1)
137 yield dut
.bus
.tms
.eq(bit
)
139 yield dut
.bus
.tck
.eq(0)
141 yield dut
.bus
.tms
.eq(0)
144 def tms_data_getset(dut
, tms
, d_len
, d_in
=0):
146 yield dut
.bus
.tms
.eq(tms
)
147 for i
in range(d_len
):
148 tdi
= 1 if (d_in
& (1<<i
)) else 0
149 yield dut
.bus
.tck
.eq(1)
150 res |
= (1<<i
) if (yield dut
.bus
.tdo
) else 0
152 yield dut
.bus
.tdi
.eq(tdi
)
153 yield dut
.bus
.tck
.eq(0)
155 yield dut
.bus
.tdi
.eq(0)
156 yield dut
.bus
.tms
.eq(0)
161 def jtag_set_reset(dut
):
162 yield from tms_state_set(dut
, [1, 1, 1, 1, 1])
164 def jtag_set_shift_dr(dut
):
165 yield from tms_state_set(dut
, [1, 0, 0])
167 def jtag_set_shift_ir(dut
):
168 yield from tms_state_set(dut
, [1, 1, 0])
170 def jtag_set_run(dut
):
171 yield from tms_state_set(dut
, [0])
173 def jtag_set_idle(dut
):
174 yield from tms_state_set(dut
, [1, 1, 0])
177 def jtag_read_write_reg(dut
, addr
, d_len
, d_in
=0):
178 yield from jtag_set_run(dut
)
179 yield from jtag_set_shift_ir(dut
)
180 yield from tms_data_getset(dut
, 0, dut
._ir
_width
, addr
)
181 yield from jtag_set_idle(dut
)
183 yield from jtag_set_shift_dr(dut
)
184 result
= yield from tms_data_getset(dut
, 0, d_len
, d_in
)
185 yield from jtag_set_idle(dut
)
194 ctrl_reg
= 0b100 # terminated
199 req
= yield dmi
.req_i
204 # check read/write and address
206 addr
= yield dmi
.addr_i
207 print (" dmi wen, addr", wen
, addr
)
208 if addr
== DBGCore
.CTRL
and wen
== 0:
209 print (" read ctrl reg", ctrl_reg
)
210 yield dmi
.dout
.eq(ctrl_reg
)
211 yield dmi
.ack_o
.eq(1)
213 yield dmi
.ack_o
.eq(0)
214 elif addr
== DBGCore
.CTRL
and wen
== 1:
215 ctrl_reg
= (yield dmi
.din
)
216 print (" write ctrl reg", ctrl_reg
)
217 yield dmi
.ack_o
.eq(1)
219 yield dmi
.ack_o
.eq(0)
220 elif addr
== DBGCore
.MSR
and wen
== 0:
221 print (" read msr reg")
222 yield dmi
.dout
.eq(0xdeadbeef) # test MSR value
223 yield dmi
.ack_o
.eq(1)
225 yield dmi
.ack_o
.eq(0)
227 # do nothing but just ack it
228 yield dmi
.ack_o
.eq(1)
230 yield dmi
.ack_o
.eq(0)
232 # JTAG-ircodes for accessing DMI
241 yield from jtag_set_reset(dut
)
242 idcode
= yield from jtag_read_write_reg(dut
, 0b1, 32)
243 print ("idcode", hex(idcode
))
244 assert idcode
== 0x18ff
247 yield from jtag_read_write_reg(dut
, 0b101, 8, DBGCore
.CTRL
)
249 # read DMI CTRL register
250 status
= yield from jtag_read_write_reg(dut
, 0b110, 64)
251 print ("dmi ctrl status", hex(status
))
255 yield from jtag_read_write_reg(dut
, 0b101, 8, 0)
257 # write DMI CTRL register
258 status
= yield from jtag_read_write_reg(dut
, 0b111, 64, 0b101)
259 print ("dmi ctrl status", hex(status
))
260 assert status
== 4 # returned old value (nice! cool feature!)
263 yield from jtag_read_write_reg(dut
, 0b101, 8, DBGCore
.CTRL
)
265 # read DMI CTRL register
266 status
= yield from jtag_read_write_reg(dut
, 0b110, 64)
267 print ("dmi ctrl status", hex(status
))
270 # write DMI MSR address
271 yield from jtag_read_write_reg(dut
, 0b101, 8, DBGCore
.MSR
)
273 # read DMI MSR register
274 msr
= yield from jtag_read_write_reg(dut
, 0b110, 64)
275 print ("dmi msr", hex(msr
))
276 assert msr
== 0xdeadbeef
283 if __name__
== '__main__':
284 dut
= DMITAP(ir_width
=4)
285 iotypes
= (IOType
.In
, IOType
.Out
, IOType
.TriOut
, IOType
.InTriOut
)
286 ios
= [dut
.add_io(iotype
=iotype
) for iotype
in iotypes
]
287 dut
.sr
= dut
.add_shiftreg(ircode
=4, length
=3) # test loopback register
288 dut
.dmi
= dut
.add_dmi(ircodes
=[DMI_ADDR
, DMI_READ
, DMI_WRITE
])
291 m
.submodules
.ast
= dut
292 m
.d
.comb
+= dut
.sr
.i
.eq(dut
.sr
.o
) # loopback
295 sim
.add_clock(1e-6, domain
="sync") # standard clock
297 sim
.add_sync_process(wrap(jtag_sim(dut
)))
298 sim
.add_sync_process(wrap(dmi_sim(dut
)))
300 with sim
.write_vcd("dmi2jtag_test.vcd"):