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