Function is a generator.
[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 if False:
149 # Yield is never executed but it makes this function a generator
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 wishbone_basic(dut):
305 """Test of an added Wishbone interface
306
307 for this test the soc JTAG TAP address width is 29 bits and data is 64
308 JTAG has access to the *full* memory range, including peripherals,
309 as defined by the litex setup.
310 """
311 clk_period = 100 # 10MHz
312 tck_period = 300 # 3MHz
313
314 data_in = BinaryValue()
315 # these have to match with soc.debug.jtag.JTAG ircodes
316 cmd_MEMADDRESS = BinaryValue("0101") # 5
317 cmd_MEMREAD = BinaryValue("0110") # 6
318 cmd_MEMREADWRITE = BinaryValue("0111") # 7
319
320 info = "Running Wishbone basic test"
321 wrap = yield from setup_sim(dut, info=info, clk_period=clk_period,
322 run=False)
323 master = yield from setup_jtag(wrap, tck_period = tck_period)
324
325 # Load the memory address
326 yield master.load_ir(cmd_MEMADDRESS)
327 dut._log.info("Loading address")
328
329 # WBaddresses in soc.debug.jtag.JTAG are 29 bits
330 data_in.binstr = "00000000000000000000000000001"
331 dut._log.info(" input: {}".format(data_in.binstr))
332 yield master.shift_data(data_in)
333 dut._log.info(" output: {}".format(master.result.binstr))
334
335 # Do write
336 yield master.load_ir(cmd_MEMREADWRITE)
337 dut._log.info("Writing memory")
338
339 # data is 64-bit
340 data_in.binstr = "01010101" * 8
341 dut._log.info(" input: {}".format(data_in.binstr))
342 yield master.shift_data(data_in)
343 dut._log.info(" output: {}".format(master.result.binstr))
344
345 data_in.binstr = "10101010" * 8
346 dut._log.info(" input: {}".format(data_in.binstr))
347 yield master.shift_data(data_in)
348 dut._log.info(" output: {}".format(master.result.binstr))
349
350 # Load the memory address
351 yield master.load_ir(cmd_MEMADDRESS)
352 dut._log.info("Loading address")
353
354 data_in.binstr = "00000000000000000000000000001"
355 dut._log.info(" input: {}".format(data_in.binstr))
356 yield master.shift_data(data_in)
357 dut._log.info(" output: {}".format(master.result.binstr))
358 assert master.result.binstr == "00000000000000000000000000000"
359
360 # Do read and write
361 yield master.load_ir(cmd_MEMREADWRITE)
362 dut._log.info("Reading and writing memory")
363
364 data_in.binstr = "10101010" * 8
365 dut._log.info(" input: {}".format(data_in.binstr))
366 yield master.shift_data(data_in)
367 dut._log.info(" output: {}".format(master.result.binstr))
368 assert master.result.binstr == "01010101" * 8
369
370 data_in.binstr = "01010101" * 8
371 dut._log.info(" input: {}".format(data_in.binstr))
372 yield master.shift_data(data_in)
373 dut._log.info(" output: {}".format(master.result.binstr))
374 assert master.result.binstr == "10101010" * 8
375
376 # Load the memory address
377 yield master.load_ir(cmd_MEMADDRESS)
378 dut._log.info("Loading address")
379
380 data_in.binstr = "00000000000000000000000000001"
381 dut._log.info(" input: {}".format(data_in.binstr))
382 yield master.shift_data(data_in)
383 dut._log.info(" output: {}".format(master.result.binstr))
384 assert master.result.binstr == "00000000000000000000000000010"
385
386 # Do read
387 yield master.load_ir(cmd_MEMREAD)
388 dut._log.info("Reading memory")
389 data_in.binstr = "00000000" * 8
390
391 dut._log.info(" input: {}".format(data_in.binstr))
392 yield master.shift_data(data_in)
393 dut._log.info(" output: {}".format(master.result.binstr))
394 assert master.result.binstr == "10101010" * 8
395
396 dut._log.info(" input: {}".format(data_in.binstr))
397 yield master.shift_data(data_in)
398 dut._log.info(" output: {}".format(master.result.binstr))
399 assert master.result.binstr == "01010101" * 8
400
401 # Load the memory address
402 yield master.load_ir(cmd_MEMADDRESS) # MEMADDR
403 dut._log.info("Loading address")
404
405 data_in.binstr = "00000000000000000000000000001"
406 dut._log.info(" input: {}".format(data_in.binstr))
407 yield master.shift_data(data_in)
408 dut._log.info(" output: {}".format(master.result.binstr))
409 assert master.result.binstr == "00000000000000000000000000010"
410
411 # Do read
412 yield master.load_ir(cmd_MEMREAD) # MEMREAD
413 dut._log.info("Reading memory")
414 data_in.binstr = "00000000" * 8
415
416 dut._log.info(" input: {}".format(data_in.binstr))
417 yield master.shift_data(data_in)
418 dut._log.info(" output: {}".format(master.result.binstr))
419 assert master.result.binstr == "10101010" * 8
420
421 dut._log.info(" input: {}".format(data_in.binstr))
422 yield master.shift_data(data_in)
423 dut._log.info(" output: {}".format(master.result.binstr))
424 assert master.result.binstr == "01010101" * 8
425
426 dut._log.info("{!r}".format(wbmem))
427
428
429 # demo / debug how to get boundary scan names. run "python3 test.py"
430 if __name__ == '__main__':
431 pinouts = get_jtag_boundary()
432 for pin in pinouts:
433 # example: ('eint', '2', <IOType.In: 1>, 'eint_2', 125)
434 print (pin)