use git submodule soclayout for source files, rather than
[soc-cocotb-sim.git] / ls180 / post_pnr / cocotb / test_add_boundary.py
1 import cocotb
2 from cocotb.clock import Clock
3 from cocotb.triggers import Timer
4 from cocotb.utils import get_sim_steps
5 from cocotb.binary import BinaryValue
6
7 from c4m.cocotb.jtag.c4m_jtag import JTAG_Master
8 from c4m.cocotb.jtag.c4m_jtag_svfcocotb import SVF_Executor
9
10 from itertools import chain
11
12 import cocotb
13 from cocotb.clock import Clock
14 from cocotb.triggers import Timer
15 from cocotb.utils import get_sim_steps
16 from cocotb.binary import BinaryValue
17
18 from c4m.nmigen.jtag.tap import IOType
19 from c4m.cocotb.jtag.c4m_jtag import JTAG_Master
20 from c4m.cocotb.jtag.c4m_jtag_svfcocotb import SVF_Executor
21
22 from itertools import chain
23
24 from c4m.nmigen.jtag.tap import IOType
25
26 #
27 # Helper functions
28 #
29
30 class DUTWrapper:
31 def __init__(self, dut):
32 self.dut = dut
33 ti = dut.instance_corona.core.subckt_22_jtag
34 ti._discover_all()
35 self.ti = ti
36 self.sys_clk = dut.sys_clk
37 self.sys_rst = dut.sys_rst
38 self.jtag_tck = dut.jtag_tck
39 self.jtag_tms = dut.jtag_tms
40 self.jtag_tdi = dut.jtag_tdi
41 self.jtag_tdo = dut.jtag_tdo
42 self.vdd = dut.vdd
43 self.vss = dut.vss
44 self.iovdd = dut.iovdd
45 self.iovss = dut.iovss
46
47 def info(self, *args, **kwargs):
48 return self.dut._log.info(*args, **kwargs)
49
50
51 def setup_sim(dut, *, info, clk_period, run):
52 """Initialize CPU and setup clock"""
53
54 wrap = DUTWrapper(dut)
55 wrap.info(info)
56
57 clk_steps = get_sim_steps(clk_period, "ns")
58 cocotb.fork(Clock(wrap.sys_clk, clk_steps).start())
59
60 wrap.vdd <= 1
61 wrap.vss <= 0
62 wrap.iovdd <= 1
63 wrap.iovss <= 0
64 wrap.sys_rst <= 1
65 wrap.sys_clk <= 0
66 # adder test (ignore this)
67 dut.a <= 3
68 dut.b <= 2
69
70 if run:
71 yield Timer(int(10.5*clk_steps))
72 wrap.sys_rst <= 0
73 yield Timer(int(5*clk_steps))
74
75 return wrap
76
77 def setup_jtag(dut, *, tck_period):
78 # Make this a generator
79 if False:
80 yield Timer(0)
81 clk_steps = get_sim_steps(tck_period, "ns")
82 return JTAG_Master(dut.jtag_tck, dut.jtag_tms,
83 dut.jtag_tdi, dut.jtag_tdo,
84 clk_period=clk_steps,
85 ir_width=4)
86
87
88 # demo / debug how to get boundary scan names. run "python3 test.py"
89 if __name__ == '__main__':
90 pinouts = get_jtag_boundary()
91 for pin in pinouts:
92 # example: ('eint', '2', <IOType.In: 1>, 'eint_2', 125)
93 print (pin)
94
95
96 #
97 # Helper functions
98 #
99
100 class JTAGPin:
101 def __init__(self, pin):
102 self.pin = pin
103 self.type_ = pin[2]
104 self.name = pin[3]
105
106 def __repr__(self):
107 return str(self.pin)
108
109 def log(self, wrap):
110 if self.type_ == IOType.In:
111 core_i = getattr(wrap.ti, f"{self.name}_core_i").value
112 pad_i = getattr(wrap.ti, f"{self.name}_pad_i").value
113 wrap.info(f"{self.name}: core.i={core_i}, pad.i={pad_i}")
114 elif self.type_ == IOType.Out:
115 core_o = getattr(wrap.ti, f"{self.name}_core_o").value
116 pad_o = getattr(wrap.ti, f"{self.name}_pad_o").value
117 wrap.info(f"{self.name}: core.o={core_o}, pad.o={pad_o}")
118 elif self.type_ == IOType.TriOut:
119 core_o = getattr(wrap.ti, f"{self.name}_core_o").value
120 core_oe = getattr(wrap.ti, f"{self.name}_core_oe").value
121 pad_o = getattr(wrap.ti, f"{self.name}_pad_o").value
122 pad_oe = getattr(wrap.ti, f"{self.name}_pad_oe").value
123 wrap.info(f"{self.name}: core.(o={core_o}, oe={core_oe}), " \
124 "pad.(o={pad_o}, oe={pad_oe})")
125 elif self.type_ == IOType.InTriOut:
126 core_i = getattr(wrap.ti, f"{self.name}_core_i").value
127 core_o = getattr(wrap.ti, f"{self.name}_core_o").value
128 core_oe = getattr(wrap.ti, f"{self.name}_core_oe").value
129 pad_i = getattr(wrap.ti, f"{self.name}_pad_i").value
130 pad_o = getattr(wrap.ti, f"{self.name}_pad_o").value
131 pad_oe = getattr(wrap.ti, f"{self.name}_pad_oe").value
132 wrap.info(f"{self.name}: core.(i={core_i}, o={core_o}, " \
133 "oe={core_oe}), pad.(i={core_i}, o={pad_o}, " \
134 "oe={pad_oe})")
135 else:
136 raise ValueError(f"Unsupported pin type {self.type_}")
137
138 def data(self, *, i=None, o=None, oe=None):
139 if self.type_ == IOType.In:
140 assert i is not None
141 return [i]
142 elif self.type_ == IOType.Out:
143 assert o is not None
144 return [o]
145 elif self.type_ == IOType.TriOut:
146 assert (o is not None) and (oe is not None)
147 return [o, oe]
148 elif self.type_ == IOType.InTriOut:
149 assert (i is not None) and(o is not None) and (oe is not None)
150 return [i, o, oe]
151 else:
152 raise ValueError(f"Unsupported pin type {self.type_}")
153
154 def check(self, *, wrap, i=None, o=None, oe=None):
155 if self.type_ in (IOType.In, IOType.InTriOut):
156 sig = f"{self.name}_core_i"
157 val = getattr(wrap.ti, sig).value
158 if val != i:
159 raise ValueError(f"'{sig}' should be {i}, not {val}")
160 if self.type_ in (IOType.Out, IOType.TriOut, IOType.InTriOut):
161 sig = f"{self.name}_pad_o"
162 val = getattr(wrap.ti, sig).value
163 if val != o:
164 raise ValueError(f"'{sig}' should be {o}, not {val}")
165 if self.type_ in (IOType.TriOut, IOType.InTriOut):
166 sig = f"{self.name}_pad_oe"
167 val = getattr(wrap.ti, sig).value
168 if val != oe:
169 raise ValueError(f"'{sig}' should be {oe}, not {val}")
170
171
172 def log_pins(wrap, pins):
173 for pin in pins:
174 pin.log(wrap)
175
176
177 def get_jtag_boundary():
178 """gets the list of information for jtag boundary scan
179 """
180 pins = []
181 for pname in ["a_0", "a_1", "a_2", "a_3",
182 "b_0", "b_1", "b_2", "b_3",
183 "f_0", "f_1", "f_2", "f_3"]:
184 if pname.startswith('f'):
185 ptype = IOType.Out
186 else:
187 ptype = IOType.In
188 pin = (None, None, ptype, pname)
189 pins.append(JTAGPin(pin))
190 return pins
191
192
193 #
194 # Boundary scan
195 #
196
197 def boundary_scan(wrap, *, jtag):
198 pins = get_jtag_boundary()
199
200 yield jtag.reset()
201
202 wrap.info("")
203 wrap.info("Before scan")
204 log_pins(wrap, pins)
205
206 yield jtag.load_ir([0, 0, 0, 0])
207 pinsdata = tuple(pin.data(i=i%2, o=((i%3)%2), oe=((i%5)%2))
208 for i, pin in enumerate(pins))
209 yield jtag.shift_data(chain(*pinsdata))
210
211 wrap.info("")
212 wrap.info("After scan")
213 log_pins(wrap, pins)
214 for i, pin in enumerate(pins):
215 pin.check(wrap=wrap, i=i%2, o=((i%3)%2), oe=((i%5)%2))
216
217 yield jtag.reset()
218
219 wrap.info("")
220 wrap.info("After reset")
221 log_pins(wrap, pins)
222
223
224 @cocotb.test()
225 def boundary_scan_reset(dut):
226 clk_period = 100 # 10MHz
227 tck_period = 300 # 3MHz
228
229 info = "Running boundary scan 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 boundary_scan(wrap, jtag=jtag)
235
236 wrap.info("IDCODE test completed")
237
238