Allow the formal engine to perform a same-cycle result in the ALU
[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_soc.wishbone.sram import SRAM
12 from nmigen import Memory, Signal, Module
13
14 from nmigen.back.pysim import Simulator, Delay, Settle, Tick
15 from nmutil.util import wrap
16
17
18 # JTAG to DMI interface
19 #
20 # DMI bus
21 #
22 # clk : | | | | | | |
23 # req : ____/------------\_____
24 # addr: xxxx< >xxxxx
25 # dout: xxxx< >xxxxx
26 # wr : xxxx< >xxxxx
27 # din : xxxxxxxxxxxx< >xxx
28 # ack : ____________/------\___
29 #
30 # * addr/dout set along with req, can be latched on same cycle by slave
31 # * ack & din remain up until req is dropped by master, the slave must
32 # provide a stable output on din on reads during that time.
33 # * req remains low at until at least one sysclk after ack seen down.
34
35
36 class DMITAP(TAP):
37 def __init__(self, *args, **kwargs):
38 super().__init__(*args, **kwargs)
39 self._dmis = []
40
41 def elaborate(self, platform):
42 m = super().elaborate(platform)
43 self._elaborate_dmis(m)
44 return m
45
46 def add_dmi(self, *, ircodes, address_width=8, data_width=64,
47 domain="sync", name=None):
48 """Add a DMI interface
49
50 * writing to DMIADDR will automatically trigger a DMI READ.
51 the DMI address does not alter (so writes can be done at that addr)
52 * reading from DMIREAD triggers a DMI READ at the current DMI addr
53 the address is automatically incremented by 1 after.
54 * writing to DMIWRITE triggers a DMI WRITE at the current DMI addr
55 the address is automatically incremented by 1 after.
56
57 Parameters:
58 -----------
59 ircodes: sequence of three integer for the JTAG IR codes;
60 they represent resp. DMIADDR, DMIREAD and DMIWRITE.
61 First code has a shift register of length 'address_width',
62 the two other codes share a shift register of length
63 data_width.
64
65 address_width: width of the address
66 data_width: width of the data
67
68 Returns:
69 dmi: soc.debug.dmi.DMIInterface
70 The DMI interface
71 """
72 if len(ircodes) != 3:
73 raise ValueError("3 IR Codes have to be provided")
74
75 if name is None:
76 name = "dmi" + str(len(self._dmis))
77
78 # add 2 shift registers: one for addr, one for data.
79 sr_addr = self.add_shiftreg(ircode=ircodes[0], length=address_width,
80 domain=domain, name=name+"_addrsr")
81 sr_data = self.add_shiftreg(ircode=ircodes[1:], length=data_width,
82 domain=domain, name=name+"_datasr")
83
84 dmi = DMIInterface(name=name)
85 self._dmis.append((sr_addr, sr_data, dmi, domain))
86
87 return dmi
88
89 def _elaborate_dmis(self, m):
90 for sr_addr, sr_data, dmi, domain in self._dmis:
91 cd = m.d[domain]
92 m.d.comb += sr_addr.i.eq(dmi.addr_i)
93
94 with m.FSM(domain=domain) as ds:
95
96 # detect mode based on whether jtag addr or data read/written
97 with m.State("IDLE"):
98 with m.If(sr_addr.oe): # DMIADDR code
99 cd += dmi.addr_i.eq(sr_addr.o)
100 m.next = "READ"
101 with m.Elif(sr_data.oe[0]): # DMIREAD code
102 # If data is
103 cd += dmi.addr_i.eq(dmi.addr_i + 1)
104 m.next = "READ"
105 with m.Elif(sr_data.oe[1]): # DMIWRITE code
106 cd += dmi.din.eq(sr_data.o)
107 m.next = "WRRD"
108
109 # req_i raises for 1 clock
110 with m.State("READ"):
111 m.next = "READACK"
112
113 # wait for read ack
114 with m.State("READACK"):
115 with m.If(dmi.ack_o):
116 # Store read data in sr_data.i hold till next read
117 cd += sr_data.i.eq(dmi.dout)
118 m.next = "IDLE"
119
120 # req_i raises for 1 clock
121 with m.State("WRRD"):
122 m.next = "WRRDACK"
123
124 # wait for write ack
125 with m.State("WRRDACK"):
126 with m.If(dmi.ack_o):
127 cd += dmi.addr_i.eq(dmi.addr_i + 1)
128 m.next = "READ" # for readwrite
129
130 # set DMI req and write-enable based on ongoing FSM states
131 m.d.comb += [
132 dmi.req_i.eq(ds.ongoing("READ") | ds.ongoing("WRRD")),
133 dmi.we_i.eq(ds.ongoing("WRRD")),
134 ]
135
136
137 def tms_state_set(dut, bits):
138 for bit in bits:
139 yield dut.bus.tck.eq(1)
140 yield dut.bus.tms.eq(bit)
141 yield
142 yield dut.bus.tck.eq(0)
143 yield
144 yield dut.bus.tms.eq(0)
145
146
147 def tms_data_getset(dut, tms, d_len, d_in=0):
148 res = 0
149 yield dut.bus.tms.eq(tms)
150 for i in range(d_len):
151 tdi = 1 if (d_in & (1<<i)) else 0
152 yield dut.bus.tck.eq(1)
153 res |= (1<<i) if (yield dut.bus.tdo) else 0
154 yield
155 yield dut.bus.tdi.eq(tdi)
156 yield dut.bus.tck.eq(0)
157 yield
158 yield dut.bus.tms.eq(0)
159
160 return res
161
162
163 def jtag_set_reset(dut):
164 yield from tms_state_set(dut, [1, 1, 1, 1, 1])
165
166 def jtag_set_shift_dr(dut):
167 yield from tms_state_set(dut, [1, 0, 0])
168
169 def jtag_set_shift_ir(dut):
170 yield from tms_state_set(dut, [1, 1, 0])
171
172 def jtag_set_run(dut):
173 yield from tms_state_set(dut, [0])
174
175 def jtag_set_idle(dut):
176 yield from tms_state_set(dut, [1, 1, 0])
177
178
179 def jtag_read_write_reg(dut, addr, d_len, d_in=0):
180 yield from jtag_set_run(dut)
181 yield from jtag_set_shift_ir(dut)
182 yield from tms_data_getset(dut, 0, dut._ir_width, addr)
183 yield from jtag_set_idle(dut)
184
185 yield from jtag_set_shift_dr(dut)
186 result = yield from tms_data_getset(dut, 0, d_len, d_in)
187 yield from jtag_set_idle(dut)
188 return result
189
190
191 stop = False
192
193 def dmi_sim(dut):
194 global stop
195
196 ctrl_reg = 0b100 # terminated
197
198 dmi = dut.dmi
199 while not stop:
200 # wait for req
201 req = yield dmi.req_i
202 if req == 0:
203 yield
204 continue
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 print (" read ctrl reg", ctrl_reg)
212 yield dmi.dout.eq(ctrl_reg)
213 yield dmi.ack_o.eq(1)
214 yield
215 yield dmi.ack_o.eq(0)
216 elif addr == DBGCore.CTRL and wen == 1:
217 ctrl_reg = (yield dmi.din)
218 print (" write ctrl reg", ctrl_reg)
219 yield dmi.ack_o.eq(1)
220 yield
221 yield dmi.ack_o.eq(0)
222 elif addr == DBGCore.MSR and wen == 0:
223 print (" read msr reg")
224 yield dmi.dout.eq(0xdeadbeef) # test MSR value
225 yield dmi.ack_o.eq(1)
226 yield
227 yield dmi.ack_o.eq(0)
228 else:
229 # do nothing but just ack it
230 yield dmi.ack_o.eq(1)
231 yield
232 yield dmi.ack_o.eq(0)
233
234 # JTAG-ircodes for accessing DMI
235 DMI_ADDR = 5
236 DMI_READ = 6
237 DMI_WRRD = 7
238
239 # JTAG-ircodes for accessing Wishbone
240 WB_ADDR = 8
241 WB_READ = 9
242 WB_WRRD = 10
243
244
245 def jtag_sim(dut):
246
247 ####### JTAGy stuff (IDCODE) ######
248
249 # read idcode
250 yield from jtag_set_reset(dut)
251 idcode = yield from jtag_read_write_reg(dut, 0b1, 32)
252 print ("idcode", hex(idcode))
253 assert idcode == 0x18ff
254
255 ####### JTAG to DMI ######
256
257 # write DMI address
258 yield from jtag_read_write_reg(dut, DMI_ADDR, 8, DBGCore.CTRL)
259
260 # read DMI CTRL register
261 status = yield from jtag_read_write_reg(dut, DMI_READ, 64)
262 print ("dmi ctrl status", hex(status))
263 assert status == 4
264
265 # write DMI address
266 yield from jtag_read_write_reg(dut, DMI_ADDR, 8, 0)
267
268 # write DMI CTRL register
269 status = yield from jtag_read_write_reg(dut, DMI_WRRD, 64, 0b101)
270 print ("dmi ctrl status", hex(status))
271 assert status == 4 # returned old value (nice! cool feature!)
272
273 # write DMI address
274 yield from jtag_read_write_reg(dut, DMI_ADDR, 8, DBGCore.CTRL)
275
276 # read DMI CTRL register
277 status = yield from jtag_read_write_reg(dut, DMI_READ, 64)
278 print ("dmi ctrl status", hex(status))
279 assert status == 5
280
281 # write DMI MSR address
282 yield from jtag_read_write_reg(dut, DMI_ADDR, 8, DBGCore.MSR)
283
284 # read DMI MSR register
285 msr = yield from jtag_read_write_reg(dut, DMI_READ, 64)
286 print ("dmi msr", hex(msr))
287 assert msr == 0xdeadbeef
288
289 ####### JTAG to Wishbone ######
290
291 # write Wishbone address
292 yield from jtag_read_write_reg(dut, WB_ADDR, 16, 0x18)
293
294 # write/read wishbone data
295 data = yield from jtag_read_write_reg(dut, WB_WRRD, 16, 0xfeef)
296 print ("wb write", hex(data))
297
298 # write Wishbone address
299 yield from jtag_read_write_reg(dut, WB_ADDR, 16, 0x18)
300
301 # write/read wishbone data
302 data = yield from jtag_read_write_reg(dut, WB_READ, 16, 0)
303 print ("wb read", hex(data))
304
305 ####### done - tell dmi_sim to stop (otherwise it won't) ########
306
307 global stop
308 stop = True
309
310
311 if __name__ == '__main__':
312 dut = DMITAP(ir_width=4)
313 iotypes = (IOType.In, IOType.Out, IOType.TriOut, IOType.InTriOut)
314 ios = [dut.add_io(iotype=iotype) for iotype in iotypes]
315 dut.sr = dut.add_shiftreg(ircode=4, length=3) # test loopback register
316
317 # create and connect wishbone SRAM (a quick way to do WB test)
318 dut.wb = dut.add_wishbone(ircodes=[WB_ADDR, WB_READ, WB_WRRD],
319 address_width=16, data_width=16)
320 memory = Memory(width=16, depth=16)
321 sram = SRAM(memory=memory, bus=dut.wb)
322
323 # create DMI2JTAG (goes through to dmi_sim())
324 dut.dmi = dut.add_dmi(ircodes=[DMI_ADDR, DMI_READ, DMI_WRRD])
325
326 m = Module()
327 m.submodules.ast = dut
328 m.submodules.sram = sram
329 m.d.comb += dut.sr.i.eq(dut.sr.o) # loopback
330
331 sim = Simulator(m)
332 sim.add_clock(1e-6, domain="sync") # standard clock
333
334 sim.add_sync_process(wrap(jtag_sim(dut))) # actual jtag tester
335 sim.add_sync_process(wrap(dmi_sim(dut))) # handles (pretends to be) DMI
336
337 with sim.write_vcd("dmi2jtag_test.vcd"):
338 sim.run()