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