add first cut at wishbone jtag unit test
[soc-cocotb-sim.git] / ls180 / pre_pnr / test.py
1 from itertools import chain
2
3 import cocotb
4 from cocotb.clock import Clock
5 from cocotb.triggers import Timer
6 from cocotb.utils import get_sim_steps
7 from cocotb.binary import BinaryValue
8
9 from c4m.nmigen.jtag.tap import IOType
10 from c4m.cocotb.jtag.c4m_jtag import JTAG_Master
11 from c4m.cocotb.jtag.c4m_jtag_svfcocotb import SVF_Executor
12
13 from soc.config.pinouts import get_pinspecs
14 from soc.debug.jtag import Pins
15
16
17 #
18 # Helper functions
19 #
20
21 class DUTWrapper:
22 def __init__(self, dut):
23 self.dut = dut
24 try:
25 ti = dut.test_issuer
26 except AttributeError:
27 ti = dut
28 ti._discover_all()
29 self.ti = ti
30 self.clk = ti.clk
31 self.rst = ti.rst
32 self.tck = ti.TAP_bus__tck
33 self.tms = ti.TAP_bus__tms
34 self.tdi = ti.TAP_bus__tdi
35 self.tdo = ti.TAP_bus__tdo
36
37 def info(self, *args, **kwargs):
38 return self.dut._log.info(*args, **kwargs)
39
40
41 class JTAGPin:
42 def __init__(self, pin):
43 self.type_ = pin[2]
44 self.name = pin[3]
45
46 def log(self, wrap):
47 if self.type_ == IOType.In:
48 core_i = getattr(wrap.ti, f"{self.name}__core__i").value
49 pad_i = getattr(wrap.ti, f"{self.name}__pad__i").value
50 wrap.info(f"{self.name}: core.i={core_i}, pad.i={pad_i}")
51 elif self.type_ == IOType.Out:
52 core_o = getattr(wrap.ti, f"{self.name}__core__o").value
53 pad_o = getattr(wrap.ti, f"{self.name}__pad__o").value
54 wrap.info(f"{self.name}: core.o={core_o}, pad.o={pad_o}")
55 elif self.type_ == IOType.TriOut:
56 core_o = getattr(wrap.ti, f"{self.name}__core__o").value
57 core_oe = getattr(wrap.ti, f"{self.name}__core__oe").value
58 pad_o = getattr(wrap.ti, f"{self.name}__pad__o").value
59 pad_oe = getattr(wrap.ti, f"{self.name}__pad__oe").value
60 wrap.info(f"{self.name}: core.(o={core_o}, oe={core_oe}), " \
61 "pad.(o={pad_o}, oe={pad_oe})")
62 elif self.type_ == IOType.InTriOut:
63 core_i = getattr(wrap.ti, f"{self.name}__core__i").value
64 core_o = getattr(wrap.ti, f"{self.name}__core__o").value
65 core_oe = getattr(wrap.ti, f"{self.name}__core__oe").value
66 pad_i = getattr(wrap.ti, f"{self.name}__pad__i").value
67 pad_o = getattr(wrap.ti, f"{self.name}__pad__o").value
68 pad_oe = getattr(wrap.ti, f"{self.name}__pad__oe").value
69 wrap.info(f"{self.name}: core.(i={core_i}, o={core_o}, " \
70 "oe={core_oe}), pad.(i={core_i}, o={pad_o}, " \
71 "oe={pad_oe})")
72 else:
73 raise ValueError(f"Unsupported pin type {self.type_}")
74
75 def data(self, *, i=None, o=None, oe=None):
76 if self.type_ == IOType.In:
77 assert i is not None
78 return [i]
79 elif self.type_ == IOType.Out:
80 assert o is not None
81 return [o]
82 elif self.type_ == IOType.TriOut:
83 assert (o is not None) and (oe is not None)
84 return [o, oe]
85 elif self.type_ == IOType.InTriOut:
86 assert (i is not None) and(o is not None) and (oe is not None)
87 return [i, o, oe]
88 else:
89 raise ValueError(f"Unsupported pin type {self.type_}")
90
91 def check(self, *, wrap, i=None, o=None, oe=None):
92 if self.type_ in (IOType.In, IOType.InTriOut):
93 sig = f"{self.name}__core__i"
94 val = getattr(wrap.ti, sig).value
95 if val != i:
96 raise ValueError(f"'{sig}' should be {i}, not {val}")
97 if self.type_ in (IOType.Out, IOType.TriOut, IOType.InTriOut):
98 sig = f"{self.name}__pad__o"
99 val = getattr(wrap.ti, sig).value
100 if val != o:
101 raise ValueError(f"'{sig}' should be {o}, not {val}")
102 if self.type_ in (IOType.TriOut, IOType.InTriOut):
103 sig = f"{self.name}__pad__oe"
104 val = getattr(wrap.ti, sig).value
105 if val != oe:
106 raise ValueError(f"'{sig}' should be {oe}, not {val}")
107
108
109 def log_pins(wrap, pins):
110 for pin in pins:
111 pin.log(wrap)
112
113
114 def get_jtag_boundary():
115 """gets the list of information for jtag boundary scan
116 """
117 # currently only a subset of pins is enabled. nuisance
118 subset = ['uart',
119 'mtwi',
120 'eint', 'gpio', 'mspi0',
121 # 'mspi1', - disabled for now
122 # 'pwm', 'sd0', - disabled for now
123 'sdr']
124 pins = tuple(JTAGPin(pin) for pin in Pins(get_pinspecs(subset=subset)))
125 return pins
126
127
128 def setup_sim(dut, *, info, clk_period, run):
129 """Initialize CPU and setup clock"""
130
131 wrap = DUTWrapper(dut)
132 wrap.info(info)
133
134 clk_steps = get_sim_steps(clk_period, "ns")
135 cocotb.fork(Clock(wrap.clk, clk_steps).start())
136
137 wrap.rst <= 1
138 wrap.clk <= 0
139 if run:
140 yield Timer(int(10.5*clk_steps))
141 wrap.rst <= 0
142 yield Timer(int(5*clk_steps))
143
144 return wrap
145
146
147 def setup_jtag(wrap, *, tck_period):
148 # TODO: Make this a generator
149 if False:
150 yield Timer(0)
151 return JTAG_Master(wrap.tck, wrap.tms, wrap.tdi, wrap.tdo,
152 clk_period=tck_period,
153 ir_width=4)
154
155 def execute_svf(wrap, *, jtag, svf_filename):
156 yield jtag.reset()
157
158 jtag_svf = SVF_Executor(jtag)
159 with open(svf_filename, "r") as f:
160 svf_deck = f.read()
161 yield jtag_svf.run(svf_deck, p=wrap.info)
162
163 #
164 # IDCODE using JTAG_master
165 #
166
167 def idcode(wrap, *, jtag):
168 yield jtag.idcode()
169 result1 = jtag.result
170 wrap.info("IDCODE1: {}".format(result1))
171 assert(result1 == BinaryValue("00000000000000000001100011111111"))
172
173 yield jtag.idcode()
174 result2 = jtag.result
175 wrap.info("IDCODE2: {}".format(result2))
176
177 assert(result1 == result2)
178
179
180 @cocotb.test()
181 def idcode_reset(dut):
182 clk_period = 100 # 10MHz
183 tck_period = 300 # 3MHz
184
185 info = "Running IDCODE test; cpu in reset..."
186 wrap = yield from setup_sim(dut, info=info, clk_period=clk_period,
187 run=False)
188 jtag = yield from setup_jtag(wrap, tck_period = tck_period)
189
190 yield from idcode(wrap, jtag=jtag)
191
192 wrap.info("IDCODE test completed")
193
194
195 @cocotb.test()
196 def idcode_run(dut):
197 clk_period = 100 # 10MHz
198 tck_period = 300 # 3MHz
199
200 info = "Running IDCODE test; cpu running..."
201 wrap = yield from setup_sim(dut, info=info, clk_period=clk_period,
202 run=True)
203 jtag = yield from setup_jtag(wrap, tck_period = tck_period)
204
205 yield from idcode(wrap, jtag=jtag)
206
207 wrap.info("IDCODE test completed")
208
209 #
210 # Read IDCODE from SVF file
211 #
212
213 @cocotb.test()
214 def idcodesvf_reset(dut):
215 clk_period = 100 # 10MHz
216 tck_period = 300 # 3MHz
217
218 info = "Running IDCODE through SVF test; cpu in reset..."
219 wrap = yield from setup_sim(dut, info=info, clk_period=clk_period,
220 run=False)
221 jtag = yield from setup_jtag(wrap, tck_period = tck_period)
222
223 yield from execute_svf(wrap, jtag=jtag, svf_filename="idcode.svf")
224
225 wrap.info("IDCODE test completed")
226
227
228 @cocotb.test()
229 def idcodesvf_run(dut):
230 clk_period = 100 # 10MHz
231 tck_period = 300 # 3MHz
232
233 info = "Running IDCODE through SVF test; cpu running..."
234 wrap = yield from setup_sim(dut, info=info, clk_period=clk_period,
235 run=True)
236 jtag = yield from setup_jtag(wrap, tck_period = tck_period)
237
238 yield from execute_svf(wrap, jtag=jtag, svf_filename="idcode.svf")
239
240 wrap.info("IDCODE test completed")
241
242 #
243 # Boundary scan
244 #
245
246 def boundary_scan(wrap, *, jtag):
247 pins = get_jtag_boundary()
248
249 yield jtag.reset()
250
251 wrap.info("")
252 wrap.info("Before scan")
253 log_pins(wrap, pins)
254
255 yield jtag.load_ir([0, 0, 0, 0])
256 pinsdata = tuple(pin.data(i=i%2, o=((i%3)%2), oe=((i%5)%2))
257 for i, pin in enumerate(pins))
258 yield jtag.shift_data(chain(*pinsdata))
259
260 wrap.info("")
261 wrap.info("After scan")
262 log_pins(wrap, pins)
263 for i, pin in enumerate(pins):
264 pin.check(wrap=wrap, i=i%2, o=((i%3)%2), oe=((i%5)%2))
265
266 yield jtag.reset()
267
268 wrap.info("")
269 wrap.info("After reset")
270 log_pins(wrap, pins)
271
272
273 @cocotb.test()
274 def boundary_scan_reset(dut):
275 clk_period = 100 # 10MHz
276 tck_period = 300 # 3MHz
277
278 info = "Running boundary scan test; cpu in reset..."
279 wrap = yield from setup_sim(dut, info=info, clk_period=clk_period,
280 run=False)
281 jtag = yield from setup_jtag(wrap, tck_period = tck_period)
282
283 yield from boundary_scan(wrap, jtag=jtag)
284
285 wrap.info("IDCODE test completed")
286
287
288 @cocotb.test()
289 def boundary_scan_run(dut):
290 clk_period = 100 # 10MHz
291 tck_period = 300 # 3MHz
292
293 info = "Running boundary scan test; cpu running..."
294 wrap = yield from setup_sim(dut, info=info, clk_period=clk_period,
295 run=True)
296 jtag = yield from setup_jtag(wrap, tck_period = tck_period)
297
298 yield from boundary_scan(wrap, jtag=jtag)
299
300 wrap.info("IDCODE test completed")
301
302
303 @cocotb.test()
304 def test05_wishbone(dut):
305 """
306 Test of an added Wishbone interface
307 """
308 data_in = BinaryValue()
309 # these have to match with soc.debug.jtag.JTAG ircodes
310 cmd_MEMADDRESS = BinaryValue("0101") # 5
311 cmd_MEMREAD = BinaryValue("0110") # 6
312 cmd_MEMREADWRITE = BinaryValue("0111") # 7
313
314 # Run JTAG @ 1MHz
315 jtagclk_period = get_sim_steps(1, "us")
316 master = JTAG_Master(
317 dut.tap_bus__tck, dut.tap_bus__tms, dut.tap_bus__tdi, dut.tap_bus__tdo,
318 clk_period=jtagclk_period, ir_width=3,
319 )
320 # Run main chip @ 10MHz; need to be clocked for WB interface to function
321 cocotb.fork(Clock(dut.clk, 100, "ns").start())
322
323 # Load the memory address
324 yield master.load_ir(cmd_MEMADDRESS)
325 dut._log.info("Loading address")
326
327 data_in.binstr = "00000000000000000000000000001"
328 dut._log.info(" input: {}".format(data_in.binstr))
329 yield master.shift_data(data_in)
330 dut._log.info(" output: {}".format(master.result.binstr))
331
332 # Do write
333 yield master.load_ir(cmd_MEMREADWRITE)
334 dut._log.info("Writing memory")
335
336 data_in.binstr = "01010101"
337 dut._log.info(" input: {}".format(data_in.binstr))
338 yield master.shift_data(data_in)
339 dut._log.info(" output: {}".format(master.result.binstr))
340
341 data_in.binstr = "10101010"
342 dut._log.info(" input: {}".format(data_in.binstr))
343 yield master.shift_data(data_in)
344 dut._log.info(" output: {}".format(master.result.binstr))
345
346 # Load the memory address
347 yield master.load_ir(cmd_MEMADDRESS)
348 dut._log.info("Loading address")
349
350 data_in.binstr = "00000000000000000000000000001"
351 dut._log.info(" input: {}".format(data_in.binstr))
352 yield master.shift_data(data_in)
353 dut._log.info(" output: {}".format(master.result.binstr))
354 assert master.result.binstr == "1100000000000010"
355
356 # Do read and write
357 yield master.load_ir(cmd_MEMREADWRITE)
358 dut._log.info("Reading and writing memory")
359
360 data_in.binstr = "10101010" * 8
361 dut._log.info(" input: {}".format(data_in.binstr))
362 yield master.shift_data(data_in)
363 dut._log.info(" output: {}".format(master.result.binstr))
364 assert master.result.binstr == "01010101" * 8
365
366 data_in.binstr = "01010101" * 8
367 dut._log.info(" input: {}".format(data_in.binstr))
368 yield master.shift_data(data_in)
369 dut._log.info(" output: {}".format(master.result.binstr))
370 assert master.result.binstr == "10101010" * 8
371
372 # Load the memory address
373 yield master.load_ir(cmd_MEMADDRESS)
374 dut._log.info("Loading address")
375
376 data_in.binstr = "00000000000000000000000000001"
377 dut._log.info(" input: {}".format(data_in.binstr))
378 yield master.shift_data(data_in)
379 dut._log.info(" output: {}".format(master.result.binstr))
380 assert master.result.binstr == "1100000000000010"
381
382 # Do read
383 yield master.load_ir(cmd_MEMREAD)
384 dut._log.info("Reading memory")
385 data_in.binstr = "00000000" * 8
386
387 dut._log.info(" input: {}".format(data_in.binstr))
388 yield master.shift_data(data_in)
389 dut._log.info(" output: {}".format(master.result.binstr))
390 assert master.result.binstr == "10101010" * 8
391
392 dut._log.info(" input: {}".format(data_in.binstr))
393 yield master.shift_data(data_in)
394 dut._log.info(" output: {}".format(master.result.binstr))
395 assert master.result.binstr == "01010101" * 8
396
397 # Load the memory address
398 yield master.load_ir(cmd_MEMADDRESS) # MEMADDR
399 dut._log.info("Loading address")
400
401 data_in.binstr = "00000000000000000000000000001"
402 dut._log.info(" input: {}".format(data_in.binstr))
403 yield master.shift_data(data_in)
404 dut._log.info(" output: {}".format(master.result.binstr))
405 assert master.result.binstr == "1100000000000010"
406
407 # Do read
408 yield master.load_ir(cmd_MEMREAD) # MEMREAD
409 dut._log.info("Reading memory")
410 data_in.binstr = "00000000" * 8
411
412 dut._log.info(" input: {}".format(data_in.binstr))
413 yield master.shift_data(data_in)
414 dut._log.info(" output: {}".format(master.result.binstr))
415 assert master.result.binstr == "10101010" * 8
416
417 dut._log.info(" input: {}".format(data_in.binstr))
418 yield master.shift_data(data_in)
419 dut._log.info(" output: {}".format(master.result.binstr))
420 assert master.result.binstr == "01010101" * 8
421
422 dut._log.info("{!r}".format(wbmem))
423 # demo / debug how to get boundary scan names. run "python3 test.py"
424 if __name__ == '__main__':
425 pinouts = get_jtag_boundary()
426 for pin in pinouts:
427 # example: ('eint', '2', <IOType.In: 1>, 'eint_2', 125)
428 print (pin)