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