add DMI JTAG test
[soc.git] / src / soc / debug / dmi2jtag.py
1 """DMI 2 JTAG
2
3 based on Staf Verhaegen (Chips4Makers) wishbone TAP
4 """
5
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
10
11 from nmigen.back.pysim import Simulator, Delay, Settle, Tick
12 from nmutil.util import wrap
13
14
15 # JTAG to DMI interface
16 #
17 # DMI bus
18 #
19 # clk : | | | | | | |
20 # req : ____/------------\_____
21 # addr: xxxx< >xxxxx
22 # dout: xxxx< >xxxxx
23 # wr : xxxx< >xxxxx
24 # din : xxxxxxxxxxxx< >xxx
25 # ack : ____________/------\___
26 #
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.
31
32
33 class DMITAP(TAP):
34 def __init__(self, *args, **kwargs):
35 super().__init__(*args, **kwargs)
36 self._dmis = []
37
38 def elaborate(self, platform):
39 m = super().elaborate(platform)
40 self._elaborate_dmis(m)
41 return m
42
43 def add_dmi(self, *, ircodes, address_width=8, data_width=64,
44 domain="sync", name=None):
45 """Add a DMI interface
46
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.
53
54 Parameters:
55 -----------
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
60 data_width.
61
62 address_width: width of the address
63 data_width: width of the data
64
65 Returns:
66 dmi: soc.debug.dmi.DMIInterface
67 The DMI interface
68 """
69 if len(ircodes) != 3:
70 raise ValueError("3 IR Codes have to be provided")
71
72 if name is None:
73 name = "dmi" + str(len(self._dmis))
74
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")
80
81 dmi = DMIInterface(name=name)
82 self._dmis.append((sr_addr, sr_data, dmi, domain))
83
84 return dmi
85
86 def _elaborate_dmis(self, m):
87 for sr_addr, sr_data, dmi, domain in self._dmis:
88 cd = m.d[domain]
89 m.d.comb += sr_addr.i.eq(dmi.addr_i)
90
91 with m.FSM(domain=domain) as ds:
92
93 # detect mode based on whether jtag addr or data read/written
94 with m.State("IDLE"):
95 with m.If(sr_addr.oe): # DMIADDR code
96 cd += dmi.addr_i.eq(sr_addr.o)
97 m.next = "READ"
98 with m.Elif(sr_data.oe[0]): # DMIREAD code
99 # If data is
100 cd += dmi.addr_i.eq(dmi.addr_i + 1)
101 m.next = "READ"
102 with m.Elif(sr_data.oe[1]): # DMIWRITE code
103 cd += dmi.din.eq(sr_data.o)
104 m.next = "WRITE"
105
106 # req_i raises for 1 clock
107 with m.State("READ"):
108 m.next = "READACK"
109
110 # wait for read ack
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)
115 m.next = "IDLE"
116
117 # req_i raises for 1 clock
118 with m.State("WRITE"):
119 m.next = "WRITEACK"
120
121 # wait for write ack
122 with m.State("WRITEACK"):
123 with m.If(dmi.ack_o):
124 cd += dmi.addr_i.eq(dmi.addr_i + 1)
125 m.next = "IDLE"
126 #m.next = "READ" - for readwrite
127
128 # set DMI req and write-enable based on ongoing FSM states
129 m.d.comb += [
130 dmi.req_i.eq(ds.ongoing("READ") | ds.ongoing("WRITE")),
131 dmi.we_i.eq(ds.ongoing("WRITE")),
132 ]
133
134
135 def tms_state_set(dut, bits):
136 for bit in bits:
137 yield dut.bus.tck.eq(1)
138 yield dut.bus.tms.eq(bit)
139 yield
140 yield dut.bus.tck.eq(0)
141 yield
142 yield dut.bus.tms.eq(0)
143
144
145 def tms_data_getset(dut, tms, d_len, d_in=0):
146 res = 0
147 yield dut.bus.tms.eq(tms)
148 for i in range(d_len):
149 tdi = 1 if (d_in & (1<<i)) else 0
150 yield dut.bus.tck.eq(1)
151 res |= (1<<i) if (yield dut.bus.tdo) else 0
152 yield
153 yield dut.bus.tdi.eq(tdi)
154 yield dut.bus.tck.eq(0)
155 yield
156 yield dut.bus.tdi.eq(0)
157 yield dut.bus.tms.eq(0)
158
159 return res
160
161
162 def jtag_set_reset(dut):
163 yield from tms_state_set(dut, [1, 1, 1, 1, 1])
164
165 def jtag_set_shift_dr(dut):
166 yield from tms_state_set(dut, [1, 0, 0])
167
168 def jtag_set_shift_ir(dut):
169 yield from tms_state_set(dut, [1, 1, 0])
170
171 def jtag_set_run(dut):
172 yield from tms_state_set(dut, [0])
173
174 def jtag_set_idle(dut):
175 yield from tms_state_set(dut, [1, 1, 0])
176
177
178 def jtag_read_write_reg(dut, addr, d_len, d_in=0):
179 yield from jtag_set_run(dut)
180 yield from jtag_set_shift_ir(dut)
181 yield from tms_data_getset(dut, 0, dut._ir_width, addr)
182 yield from jtag_set_idle(dut)
183
184 yield from jtag_set_shift_dr(dut)
185 result = yield from tms_data_getset(dut, 0, d_len, d_in)
186 yield from jtag_set_idle(dut)
187 return result
188
189
190 stop = False
191
192 def dmi_sim(dut):
193 global stop
194
195 ctrl_reg = 0b100 # terminated
196
197 dmi = dut.dmi
198 while not stop:
199 # wait for req
200 req = yield dmi.req_i
201 if req == 0:
202 yield
203 continue
204 print ("dmi req", req)
205
206 # check read/write and address
207 wen = yield dmi.we_i
208 addr = yield dmi.addr_i
209 print ("dmi wen, addr", wen, addr)
210 if addr == DBGCore.CTRL and wen == 0:
211 yield dmi.dout.eq(ctrl_reg)
212 yield dmi.ack_o.eq(1)
213 yield
214 yield dmi.ack_o.eq(0)
215 elif addr == DBGCore.CTRL and wen == 1:
216 ctrl_reg = (yield dmi.din)
217 print ("write ctrl reg", ctrl_reg)
218 yield dmi.ack_o.eq(1)
219 yield
220 yield dmi.ack_o.eq(0)
221 else:
222 # do nothing but just ack it
223 yield dmi.ack_o.eq(1)
224 yield
225 yield dmi.ack_o.eq(0)
226
227 # JTAG-ircodes for accessing DMI
228 DMI_ADDR = 5
229 DMI_READ = 6
230 DMI_WRITE = 7
231
232 def jtag_sim(dut):
233
234 if True:
235 # read idcode
236 yield from jtag_set_reset(dut)
237 idcode = yield from jtag_read_write_reg(dut, 0b1, 32)
238 print ("idcode", hex(idcode))
239 assert idcode == 0x18ff
240
241 # write DMI address
242 yield from jtag_read_write_reg(dut, 0b101, 8, DBGCore.CTRL)
243
244 # read DMI CTRL register
245 status = yield from jtag_read_write_reg(dut, 0b110, 64)
246 print ("dmi ctrl status", hex(status))
247
248 # write DMI address
249 yield from jtag_read_write_reg(dut, 0b101, 8, 0)
250
251 # write DMI CTRL register
252 status = yield from jtag_read_write_reg(dut, 0b111, 64, 0b101)
253 print ("dmi ctrl status", hex(status))
254
255 # write DMI address
256 yield from jtag_read_write_reg(dut, 0b1010, 8, DBGCore.CTRL)
257
258 # read DMI CTRL register
259 status = yield from jtag_read_write_reg(dut, 0b110, 64)
260 print ("dmi ctrl status", hex(status))
261
262 for i in range(64):
263 yield
264
265 global stop
266 stop = True
267
268 if __name__ == '__main__':
269 dut = DMITAP(ir_width=4)
270 iotypes = (IOType.In, IOType.Out, IOType.TriOut, IOType.InTriOut)
271 ios = [dut.add_io(iotype=iotype) for iotype in iotypes]
272 dut.sr = dut.add_shiftreg(ircode=4, length=3) # test loopback register
273 dut.dmi = dut.add_dmi(ircodes=[DMI_ADDR, DMI_READ, DMI_WRITE])
274
275 m = Module()
276 m.submodules.ast = dut
277 m.d.comb += dut.sr.i.eq(dut.sr.o) # loopback
278
279 sim = Simulator(m)
280 sim.add_clock(1e-6, domain="sync") # standard clock
281
282 sim.add_sync_process(wrap(jtag_sim(dut)))
283 sim.add_sync_process(wrap(dmi_sim(dut)))
284
285 with sim.write_vcd("dmi2jtag_test.vcd"):
286 sim.run()
287
288