whitespace
[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 # Helper functions
18 #
19
20 class DUTWrapper:
21 def __init__(self, dut):
22 self.dut = dut
23 try:
24 ti = dut.test_issuer
25 except AttributeError:
26 ti = dut
27 ti._discover_all()
28 self.ti = ti
29 self.clk = ti.clk
30 self.rst = ti.rst
31 self.tck = ti.TAP_bus__tck
32 self.tms = ti.TAP_bus__tms
33 self.tdi = ti.TAP_bus__tdi
34 self.tdo = ti.TAP_bus__tdo
35
36 def info(self, *args, **kwargs):
37 return self.dut._log.info(*args, **kwargs)
38
39
40 class JTAGPin:
41 def __init__(self, pin):
42 self.type_ = pin[2]
43 self.name = pin[3]
44
45 def log(self, wrap):
46 if self.type_ == IOType.In:
47 core_i = getattr(wrap.ti, f"{self.name}__core__i").value
48 pad_i = getattr(wrap.ti, f"{self.name}__pad__i").value
49 wrap.info(f"{self.name}: core.i={core_i}, pad.i={pad_i}")
50 elif self.type_ == IOType.Out:
51 core_o = getattr(wrap.ti, f"{self.name}__core__o").value
52 pad_o = getattr(wrap.ti, f"{self.name}__pad__o").value
53 wrap.info(f"{self.name}: core.o={core_o}, pad.o={pad_o}")
54 elif self.type_ == IOType.TriOut:
55 core_o = getattr(wrap.ti, f"{self.name}__core__o").value
56 core_oe = getattr(wrap.ti, f"{self.name}__core__oe").value
57 pad_o = getattr(wrap.ti, f"{self.name}__pad__o").value
58 pad_oe = getattr(wrap.ti, f"{self.name}__pad__oe").value
59 wrap.info(f"{self.name}: core.(o={core_o}, oe={core_oe}), " \
60 "pad.(o={pad_o}, oe={pad_oe})")
61 elif self.type_ == IOType.InTriOut:
62 core_i = getattr(wrap.ti, f"{self.name}__core__i").value
63 core_o = getattr(wrap.ti, f"{self.name}__core__o").value
64 core_oe = getattr(wrap.ti, f"{self.name}__core__oe").value
65 pad_i = getattr(wrap.ti, f"{self.name}__pad__i").value
66 pad_o = getattr(wrap.ti, f"{self.name}__pad__o").value
67 pad_oe = getattr(wrap.ti, f"{self.name}__pad__oe").value
68 wrap.info(f"{self.name}: core.(i={core_i}, o={core_o}, " \
69 "oe={core_oe}), pad.(i={core_i}, o={pad_o}, " \
70 "oe={pad_oe})")
71 else:
72 raise ValueError(f"Unsupported pin type {self.type_}")
73
74 def data(self, *, i=None, o=None, oe=None):
75 if self.type_ == IOType.In:
76 assert i is not None
77 return [i]
78 elif self.type_ == IOType.Out:
79 assert o is not None
80 return [o]
81 elif self.type_ == IOType.TriOut:
82 assert (o is not None) and (oe is not None)
83 return [o, oe]
84 elif self.type_ == IOType.InTriOut:
85 assert (i is not None) and(o is not None) and (oe is not None)
86 return [i, o, oe]
87 else:
88 raise ValueError(f"Unsupported pin type {self.type_}")
89
90 def check(self, *, wrap, i=None, o=None, oe=None):
91 if self.type_ in (IOType.In, IOType.InTriOut):
92 sig = f"{self.name}__core__i"
93 val = getattr(wrap.ti, sig).value
94 if val != i:
95 raise ValueError(f"'{sig}' should be {i}, not {val}")
96 if self.type_ in (IOType.Out, IOType.TriOut, IOType.InTriOut):
97 sig = f"{self.name}__pad__o"
98 val = getattr(wrap.ti, sig).value
99 if val != o:
100 raise ValueError(f"'{sig}' should be {o}, not {val}")
101 if self.type_ in (IOType.TriOut, IOType.InTriOut):
102 sig = f"{self.name}__pad__oe"
103 val = getattr(wrap.ti, sig).value
104 if val != oe:
105 raise ValueError(f"'{sig}' should be {oe}, not {val}")
106
107
108 def log_pins(wrap, pins):
109 for pin in pins:
110 pin.log(wrap)
111
112
113 def get_jtag_boundary():
114 """gets the list of information for jtag boundary scan
115 """
116 # currently only a subset of pins is enabled. nuisance
117 subset = ['uart',
118 'mtwi',
119 'eint', 'gpio', 'mspi0',
120 # 'mspi1', - disabled for now
121 # 'pwm', 'sd0', - disabled for now
122 'sdr']
123 pins = tuple(JTAGPin(pin) for pin in Pins(get_pinspecs(subset=subset)))
124 return pins
125
126
127 def setup_sim(dut, *, info, clk_period, run):
128 """Initialize CPU and setup clock"""
129
130 wrap = DUTWrapper(dut)
131 wrap.info(info)
132
133 clk_steps = get_sim_steps(clk_period, "ns")
134 cocotb.fork(Clock(wrap.clk, clk_steps).start())
135
136 wrap.rst <= 1
137 wrap.clk <= 0
138 if run:
139 yield Timer(int(10.5*clk_steps))
140 wrap.rst <= 0
141 yield Timer(int(5*clk_steps))
142
143 return wrap
144
145
146 def setup_jtag(wrap, *, tck_period):
147 # TODO: Make this a generator
148 if False:
149 yield Timer(0)
150 return JTAG_Master(wrap.tck, wrap.tms, wrap.tdi, wrap.tdo,
151 clk_period=tck_period,
152 ir_width=4)
153
154 def execute_svf(wrap, *, jtag, svf_filename):
155 yield jtag.reset()
156
157 jtag_svf = SVF_Executor(jtag)
158 with open(svf_filename, "r") as f:
159 svf_deck = f.read()
160 yield jtag_svf.run(svf_deck, p=wrap.info)
161
162 #
163 # IDCODE using JTAG_master
164 #
165
166 def idcode(wrap, *, jtag):
167 yield jtag.idcode()
168 result1 = jtag.result
169 wrap.info("IDCODE1: {}".format(result1))
170 assert(result1 == BinaryValue("00000000000000000001100011111111"))
171
172 yield jtag.idcode()
173 result2 = jtag.result
174 wrap.info("IDCODE2: {}".format(result2))
175
176 assert(result1 == result2)
177
178
179 @cocotb.test()
180 def idcode_reset(dut):
181 clk_period = 100 # 10MHz
182 tck_period = 300 # 3MHz
183
184 info = "Running IDCODE test; cpu in reset..."
185 wrap = yield from setup_sim(dut, info=info, clk_period=clk_period,
186 run=False)
187 jtag = yield from setup_jtag(wrap, tck_period = tck_period)
188
189 yield from idcode(wrap, jtag=jtag)
190
191 wrap.info("IDCODE test completed")
192
193
194 @cocotb.test()
195 def idcode_run(dut):
196 clk_period = 100 # 10MHz
197 tck_period = 300 # 3MHz
198
199 info = "Running IDCODE test; cpu running..."
200 wrap = yield from setup_sim(dut, info=info, clk_period=clk_period,
201 run=True)
202 jtag = yield from setup_jtag(wrap, tck_period = tck_period)
203
204 yield from idcode(wrap, jtag=jtag)
205
206 wrap.info("IDCODE test completed")
207
208 #
209 # Read IDCODE from SVF file
210 #
211
212 @cocotb.test()
213 def idcodesvf_reset(dut):
214 clk_period = 100 # 10MHz
215 tck_period = 300 # 3MHz
216
217 info = "Running IDCODE through SVF test; cpu in reset..."
218 wrap = yield from setup_sim(dut, info=info, clk_period=clk_period,
219 run=False)
220 jtag = yield from setup_jtag(wrap, tck_period = tck_period)
221
222 yield from execute_svf(wrap, jtag=jtag, svf_filename="idcode.svf")
223
224 wrap.info("IDCODE test completed")
225
226
227 @cocotb.test()
228 def idcodesvf_run(dut):
229 clk_period = 100 # 10MHz
230 tck_period = 300 # 3MHz
231
232 info = "Running IDCODE through SVF test; cpu running..."
233 wrap = yield from setup_sim(dut, info=info, clk_period=clk_period,
234 run=True)
235 jtag = yield from setup_jtag(wrap, tck_period = tck_period)
236
237 yield from execute_svf(wrap, jtag=jtag, svf_filename="idcode.svf")
238
239 wrap.info("IDCODE test completed")
240
241 #
242 # Boundary scan
243 #
244
245 def boundary_scan(wrap, *, jtag):
246 pins = get_jtag_boundary()
247
248 yield jtag.reset()
249
250 wrap.info("")
251 wrap.info("Before scan")
252 log_pins(wrap, pins)
253
254 yield jtag.load_ir([0, 0, 0, 0])
255 pinsdata = tuple(pin.data(i=i%2, o=((i%3)%2), oe=((i%5)%2))
256 for i, pin in enumerate(pins))
257 yield jtag.shift_data(chain(*pinsdata))
258
259 wrap.info("")
260 wrap.info("After scan")
261 log_pins(wrap, pins)
262 for i, pin in enumerate(pins):
263 pin.check(wrap=wrap, i=i%2, o=((i%3)%2), oe=((i%5)%2))
264
265 yield jtag.reset()
266
267 wrap.info("")
268 wrap.info("After reset")
269 log_pins(wrap, pins)
270
271
272 @cocotb.test()
273 def boundary_scan_reset(dut):
274 clk_period = 100 # 10MHz
275 tck_period = 300 # 3MHz
276
277 info = "Running boundary scan test; cpu in reset..."
278 wrap = yield from setup_sim(dut, info=info, clk_period=clk_period,
279 run=False)
280 jtag = yield from setup_jtag(wrap, tck_period = tck_period)
281
282 yield from boundary_scan(wrap, jtag=jtag)
283
284 wrap.info("IDCODE test completed")
285
286
287 @cocotb.test()
288 def boundary_scan_run(dut):
289 clk_period = 100 # 10MHz
290 tck_period = 300 # 3MHz
291
292 info = "Running boundary scan test; cpu running..."
293 wrap = yield from setup_sim(dut, info=info, clk_period=clk_period,
294 run=True)
295 jtag = yield from setup_jtag(wrap, tck_period = tck_period)
296
297 yield from boundary_scan(wrap, jtag=jtag)
298
299 wrap.info("IDCODE test completed")
300
301
302 # demo / debug how to get boundary scan names. run "python3 test.py"
303 if __name__ == '__main__':
304 pinouts = get_jtag_boundary()
305 for pin in pinouts:
306 # example: ('eint', '2', <IOType.In: 1>, 'eint_2', 125)
307 print (pin)