experiment set dmi msr read
[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 = "WRRD"
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("WRRD"):
119 m.next = "WRRDACK"
120
121 # wait for write ack
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
126
127 # set DMI req and write-enable based on ongoing FSM states
128 m.d.comb += [
129 dmi.req_i.eq(ds.ongoing("READ") | ds.ongoing("WRRD")),
130 dmi.we_i.eq(ds.ongoing("WRRD")),
131 ]
132
133
134 def tms_state_set(dut, bits):
135 for bit in bits:
136 yield dut.bus.tck.eq(1)
137 yield dut.bus.tms.eq(bit)
138 yield
139 yield dut.bus.tck.eq(0)
140 yield
141 yield dut.bus.tms.eq(0)
142
143
144 def tms_data_getset(dut, tms, d_len, d_in=0):
145 res = 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
151 yield
152 yield dut.bus.tdi.eq(tdi)
153 yield dut.bus.tck.eq(0)
154 yield
155 yield dut.bus.tdi.eq(0)
156 yield dut.bus.tms.eq(0)
157
158 return res
159
160
161 def jtag_set_reset(dut):
162 yield from tms_state_set(dut, [1, 1, 1, 1, 1])
163
164 def jtag_set_shift_dr(dut):
165 yield from tms_state_set(dut, [1, 0, 0])
166
167 def jtag_set_shift_ir(dut):
168 yield from tms_state_set(dut, [1, 1, 0])
169
170 def jtag_set_run(dut):
171 yield from tms_state_set(dut, [0])
172
173 def jtag_set_idle(dut):
174 yield from tms_state_set(dut, [1, 1, 0])
175
176
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)
182
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)
186 return result
187
188
189 stop = False
190
191 def dmi_sim(dut):
192 global stop
193
194 ctrl_reg = 0b100 # terminated
195
196 dmi = dut.dmi
197 while not stop:
198 # wait for req
199 req = yield dmi.req_i
200 if req == 0:
201 yield
202 continue
203
204 # check read/write and address
205 wen = yield dmi.we_i
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)
212 yield
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)
218 yield
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)
224 yield
225 yield dmi.ack_o.eq(0)
226 else:
227 # do nothing but just ack it
228 yield dmi.ack_o.eq(1)
229 yield
230 yield dmi.ack_o.eq(0)
231
232 # JTAG-ircodes for accessing DMI
233 DMI_ADDR = 5
234 DMI_READ = 6
235 DMI_WRITE = 7
236
237 def jtag_sim(dut):
238
239 if True:
240 # read idcode
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
245
246 # write DMI address
247 yield from jtag_read_write_reg(dut, 0b101, 8, DBGCore.CTRL)
248
249 # read DMI CTRL register
250 status = yield from jtag_read_write_reg(dut, 0b110, 64)
251 print ("dmi ctrl status", hex(status))
252 assert status == 4
253
254 # write DMI address
255 yield from jtag_read_write_reg(dut, 0b101, 8, 0)
256
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!)
261
262 # write DMI address
263 yield from jtag_read_write_reg(dut, 0b101, 8, DBGCore.CTRL)
264
265 # read DMI CTRL register
266 status = yield from jtag_read_write_reg(dut, 0b110, 64)
267 print ("dmi ctrl status", hex(status))
268 assert status == 5
269
270 # write DMI MSR address
271 yield from jtag_read_write_reg(dut, 0b101, 8, DBGCore.MSR)
272
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
277
278 yield
279
280 global stop
281 stop = True
282
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])
289
290 m = Module()
291 m.submodules.ast = dut
292 m.d.comb += dut.sr.i.eq(dut.sr.o) # loopback
293
294 sim = Simulator(m)
295 sim.add_clock(1e-6, domain="sync") # standard clock
296
297 sim.add_sync_process(wrap(jtag_sim(dut)))
298 sim.add_sync_process(wrap(dmi_sim(dut)))
299
300 with sim.write_vcd("dmi2jtag_test.vcd"):
301 sim.run()
302
303