cffa0316e04eb7cfa6ed7f7414eecb94c06d3c1e
[soc.git] / src / soc / fu / compunits / test / test_compunit.py
1 from nmigen import Module, Signal, ResetSignal
2 from nmigen.back.pysim import Simulator, Delay, Settle
3 from nmutil.formaltest import FHDLTestCase
4 from nmigen.cli import rtlil
5 import unittest
6 from soc.decoder.power_decoder import (create_pdecode)
7 from soc.decoder.power_decoder2 import (PowerDecode2)
8 from soc.decoder.power_enums import Function
9 from soc.decoder.isa.all import ISA
10
11 from soc.experiment.compalu_multi import find_ok # hack
12 from soc.config.test.test_loadstore import TestMemPspec
13
14 def set_cu_input(cu, idx, data):
15 rdop = cu.get_in_name(idx)
16 yield cu.src_i[idx].eq(data)
17 while True:
18 rd_rel_o = yield cu.rd.rel[idx]
19 print ("rd_rel %d wait HI" % idx, rd_rel_o, rdop, hex(data))
20 if rd_rel_o:
21 break
22 yield
23 yield cu.rd.go[idx].eq(1)
24 while True:
25 yield
26 rd_rel_o = yield cu.rd.rel[idx]
27 if rd_rel_o:
28 break
29 print ("rd_rel %d wait HI" % idx, rd_rel_o)
30 yield
31 yield cu.rd.go[idx].eq(0)
32 yield cu.src_i[idx].eq(0)
33
34
35 def get_cu_output(cu, idx, code):
36 wrmask = yield cu.wrmask
37 wrop = cu.get_out_name(idx)
38 wrok = cu.get_out(idx)
39 fname = find_ok(wrok.fields)
40 wrok = yield getattr(wrok, fname)
41 print ("wr_rel mask", repr(code), idx, wrop, bin(wrmask), fname, wrok)
42 assert wrmask & (1<<idx), \
43 "get_cu_output '%s': mask bit %d not set\n" \
44 "write-operand '%s' Data.ok likely not set (%s)" \
45 % (code, idx, wrop, hex(wrok))
46 while True:
47 wr_relall_o = yield cu.wr.rel
48 wr_rel_o = yield cu.wr.rel[idx]
49 print ("wr_rel %d wait" % idx, hex(wr_relall_o), wr_rel_o)
50 if wr_rel_o:
51 break
52 yield
53 yield cu.wr.go[idx].eq(1)
54 yield Settle()
55 result = yield cu.dest[idx]
56 yield
57 yield cu.wr.go[idx].eq(0)
58 print ("result", repr(code), idx, wrop, wrok, hex(result))
59
60 return result
61
62
63 def set_cu_inputs(cu, inp):
64 print ("set_cu_inputs", inp)
65 for idx, data in inp.items():
66 yield from set_cu_input(cu, idx, data)
67
68
69 def set_operand(cu, dec2, sim):
70 yield from cu.oper_i.eq_from_execute1(dec2.e)
71 yield cu.issue_i.eq(1)
72 yield
73 yield cu.issue_i.eq(0)
74 yield
75
76
77 def get_cu_outputs(cu, code):
78 res = {}
79 wrmask = yield cu.wrmask
80 print ("get_cu_outputs", cu.n_dst, wrmask)
81 if not wrmask: # no point waiting (however really should doublecheck wr.rel)
82 return {}
83 # wait for at least one result
84 while True:
85 wr_rel_o = yield cu.wr.rel
86 if wr_rel_o:
87 break
88 yield
89 for i in range(cu.n_dst):
90 wr_rel_o = yield cu.wr.rel[i]
91 if wr_rel_o:
92 result = yield from get_cu_output(cu, i, code)
93 wrop = cu.get_out_name(i)
94 print ("output", i, wrop, hex(result))
95 res[wrop] = result
96 return res
97
98
99 def get_inp_indexed(cu, inp):
100 res = {}
101 for i in range(cu.n_src):
102 wrop = cu.get_in_name(i)
103 if wrop in inp:
104 res[i] = inp[wrop]
105 return res
106
107 def get_l0_mem(l0): # BLECH!
108 if hasattr(l0.pimem, 'lsui'):
109 return l0.pimem.lsui.mem
110 return l0.pimem.mem.mem
111
112 def setup_test_memory(l0, sim):
113 mem = get_l0_mem(l0)
114 print ("before, init mem", mem.depth, mem.width, mem)
115 for i in range(mem.depth):
116 data = sim.mem.ld(i*8, 8, False)
117 print ("init ", i, hex(data))
118 yield mem._array[i].eq(data)
119 yield Settle()
120 for k, v in sim.mem.mem.items():
121 print (" %6x %016x" % (k, v))
122 print ("before, nmigen mem dump")
123 for i in range(mem.depth):
124 actual_mem = yield mem._array[i]
125 print (" %6i %016x" % (i, actual_mem))
126
127
128 def dump_sim_memory(dut, l0, sim, code):
129 mem = get_l0_mem(l0)
130 print ("sim mem dump")
131 for k, v in sim.mem.mem.items():
132 print (" %6x %016x" % (k, v))
133 print ("nmigen mem dump")
134 for i in range(mem.depth):
135 actual_mem = yield mem._array[i]
136 print (" %6i %016x" % (i, actual_mem))
137
138
139 def check_sim_memory(dut, l0, sim, code):
140 mem = get_l0_mem(l0)
141
142 for i in range(mem.depth):
143 expected_mem = sim.mem.ld(i*8, 8, False)
144 actual_mem = yield mem._array[i]
145 dut.assertEqual(expected_mem, actual_mem,
146 "%s %d %x %x" % (code, i,
147 expected_mem, actual_mem))
148
149 class TestRunner(FHDLTestCase):
150 def __init__(self, test_data, fukls, iodef, funit):
151 super().__init__("run_all")
152 self.test_data = test_data
153 self.fukls = fukls
154 self.iodef = iodef
155 self.funit = funit
156
157 def run_all(self):
158 m = Module()
159 comb = m.d.comb
160 instruction = Signal(32)
161
162 pdecode = create_pdecode()
163 m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode)
164
165 # copy of the decoder for simulator
166 simdec = create_pdecode()
167 simdec2 = PowerDecode2(simdec)
168 m.submodules.simdec2 = simdec2 # pain in the neck
169
170 if self.funit == Function.LDST:
171 from soc.experiment.l0_cache import TstL0CacheBuffer
172 pspec = TestMemPspec(ldst_ifacetype='test_bare_wb',
173 addr_wid=48,
174 mask_wid=8,
175 reg_wid=64)
176 m.submodules.l0 = l0 = TstL0CacheBuffer(pspec, n_units=1)
177 pi = l0.l0.dports[0]
178 m.submodules.cu = cu = self.fukls(pi, idx=0, awid=3)
179 m.d.comb += cu.ad.go.eq(cu.ad.rel) # link addr-go direct to rel
180 m.d.comb += cu.st.go.eq(cu.st.rel) # link store-go direct to rel
181 else:
182 m.submodules.cu = cu = self.fukls(0)
183
184 comb += pdecode2.dec.raw_opcode_in.eq(instruction)
185 sim = Simulator(m)
186
187 sim.add_clock(1e-6)
188
189 def process():
190 yield cu.issue_i.eq(0)
191 yield
192
193 for test in self.test_data:
194 print(test.name)
195 program = test.program
196 self.subTest(test.name)
197 print ("test", test.name, test.mem)
198 gen = list(program.generate_instructions())
199 insncode = program.assembly.splitlines()
200 instructions = list(zip(gen, insncode))
201 sim = ISA(simdec2, test.regs, test.sprs, test.cr, test.mem,
202 test.msr,
203 initial_insns=gen, respect_pc=False,
204 disassembly=insncode,
205 bigendian=False)
206
207 # initialise memory
208 if self.funit == Function.LDST:
209 yield from setup_test_memory(l0, sim)
210
211 index = sim.pc.CIA.value//4
212 while True:
213 try:
214 yield from sim.setup_one()
215 except KeyError: # indicates instruction not in imem: stop
216 break
217 yield Settle()
218 ins, code = instructions[index]
219 print(index, code)
220
221 # ask the decoder to decode this binary data (endian'd)
222 yield pdecode2.dec.bigendian.eq(0) # little / big?
223 yield instruction.eq(ins) # raw binary instr.
224 yield Settle()
225 fn_unit = yield pdecode2.e.do.fn_unit
226 fuval = self.funit.value
227 self.assertEqual(fn_unit & fuval, fuval)
228
229 # set operand and get inputs
230 yield from set_operand(cu, pdecode2, sim)
231 yield Settle()
232 iname = yield from self.iodef.get_cu_inputs(pdecode2, sim)
233 inp = get_inp_indexed(cu, iname)
234
235 # reset read-operand mask
236 rdmask = pdecode2.rdflags(cu)
237 #print ("hardcoded rdmask", cu.rdflags(pdecode2.e))
238 #print ("decoder rdmask", rdmask)
239 yield cu.rdmaskn.eq(~rdmask)
240
241 # reset write-operand mask
242 for idx in range(cu.n_dst):
243 wrok = cu.get_out(idx)
244 fname = find_ok(wrok.fields)
245 yield getattr(wrok, fname).eq(0)
246
247 yield Settle()
248
249 # set inputs into CU
250 rd_rel_o = yield cu.rd.rel
251 wr_rel_o = yield cu.wr.rel
252 print ("before inputs, rd_rel, wr_rel: ",
253 bin(rd_rel_o), bin(wr_rel_o))
254 assert wr_rel_o == 0, "wr.rel %s must be zero. "\
255 "previous instr not written all regs\n"\
256 "respec %s" % \
257 (bin(wr_rel_o), cu.rwid[1])
258 yield from set_cu_inputs(cu, inp)
259 rd_rel_o = yield cu.rd.rel
260 wr_rel_o = yield cu.wr.rel
261 wrmask = yield cu.wrmask
262 print ("after inputs, rd_rel, wr_rel, wrmask: ",
263 bin(rd_rel_o), bin(wr_rel_o), bin(wrmask))
264
265 # call simulated operation
266 yield from sim.execute_one()
267 yield Settle()
268 index = sim.pc.CIA.value//4
269
270 # get all outputs (one by one, just "because")
271 res = yield from get_cu_outputs(cu, code)
272 wrmask = yield cu.wrmask
273 rd_rel_o = yield cu.rd.rel
274 wr_rel_o = yield cu.wr.rel
275 print ("after got outputs, rd_rel, wr_rel, wrmask: ",
276 bin(rd_rel_o), bin(wr_rel_o), bin(wrmask))
277
278 # wait for busy to go low
279 while True:
280 busy_o = yield cu.busy_o
281 print ("busy", busy_o)
282 if not busy_o:
283 break
284 yield
285
286 if self.funit == Function.LDST:
287 yield from dump_sim_memory(self, l0, sim, code)
288
289
290 # sigh. hard-coded. test memory
291 if self.funit == Function.LDST:
292 yield from check_sim_memory(self, l0, sim, code)
293 yield from self.iodef.check_cu_outputs(res, pdecode2,
294 sim, cu,
295 code)
296 else:
297 yield from self.iodef.check_cu_outputs(res, pdecode2,
298 sim, cu.alu,
299 code)
300
301
302 sim.add_sync_process(process)
303
304 name = self.funit.name.lower()
305 with sim.write_vcd("%s_simulator.vcd" % name,
306 "%s_simulator.gtkw" % name,
307 traces=[]):
308 sim.run()
309
310