7e0df81ee8f33aec2562f99e0baa26e10e12c863
[soc.git] / src / soc / fu / cr / test / test_pipe_caller.py
1 from nmigen import Module, Signal
2
3 # NOTE: to use cxxsim, export NMIGEN_SIM_MODE=cxxsim from the shell
4 # Also, check out the cxxsim nmigen branch, and latest yosys from git
5 from nmutil.sim_tmp_alternative import Simulator, Settle
6
7 from nmigen.cli import rtlil
8 import unittest
9 from soc.decoder.isa.caller import ISACaller, special_sprs
10 from soc.decoder.power_decoder import (create_pdecode)
11 from soc.decoder.power_decoder2 import (PowerDecode2)
12 from soc.decoder.power_enums import (XER_bits, Function)
13 from soc.decoder.selectable_int import SelectableInt
14 from soc.simulator.program import Program
15 from soc.decoder.isa.all import ISA
16 from soc.config.endian import bigendian
17
18 from soc.fu.test.common import TestAccumulatorBase, TestCase, ALUHelpers
19 from soc.fu.test.common import mask_extend
20 from soc.fu.cr.pipeline import CRBasePipe
21 from soc.fu.cr.pipe_data import CRPipeSpec
22 import random
23
24
25 # This test bench is a bit different than is usual. Initially when I
26 # was writing it, I had all of the tests call a function to create a
27 # device under test and simulator, initialize the dut, run the
28 # simulation for ~2 cycles, and assert that the dut output what it
29 # should have. However, this was really slow, since it needed to
30 # create and tear down the dut and simulator for every test case.
31
32 # Now, instead of doing that, every test case in ALUTestCase puts some
33 # data into the test_data list below, describing the instructions to
34 # be tested and the initial state. Once all the tests have been run,
35 # test_data gets passed to TestRunner which then sets up the DUT and
36 # simulator once, runs all the data through it, and asserts that the
37 # results match the pseudocode sim at every cycle.
38
39 # By doing this, I've reduced the time it takes to run the test suite
40 # massively. Before, it took around 1 minute on my computer, now it
41 # takes around 3 seconds
42
43
44 class CRTestCase(TestAccumulatorBase):
45
46 def case_crop(self):
47 insns = ["crand", "cror", "crnand", "crnor", "crxor", "creqv",
48 "crandc", "crorc"]
49 for i in range(40):
50 choice = random.choice(insns)
51 ba = random.randint(0, 31)
52 bb = random.randint(0, 31)
53 bt = random.randint(0, 31)
54 lst = [f"{choice} {ba}, {bb}, {bt}"]
55 cr = random.randint(0, (1 << 32)-1)
56 self.add_case(Program(lst, bigendian), initial_cr=cr)
57
58 def case_crand(self):
59 for i in range(20):
60 lst = ["crand 0, 11, 13"]
61 cr = random.randint(0, (1 << 32)-1)
62 self.add_case(Program(lst, bigendian), initial_cr=cr)
63
64 def case_1_mcrf(self):
65 for i in range(20):
66 src = random.randint(0, 7)
67 dst = random.randint(0, 7)
68 lst = [f"mcrf {src}, {dst}"]
69 cr = random.randint(0, (1 << 32)-1)
70 self.add_case(Program(lst, bigendian), initial_cr=cr)
71
72 def case_0_mcrf(self):
73 for i in range(8):
74 lst = [f"mcrf 5, {i}"]
75 cr = 0xfeff0001
76 self.add_case(Program(lst, bigendian), initial_cr=cr)
77
78 def case_mtcrf(self):
79 for i in range(1):
80 mask = random.randint(0, 255)
81 lst = [f"mtcrf {mask}, 2"]
82 cr = random.randint(0, (1 << 32)-1)
83 initial_regs = [0] * 32
84 initial_regs[2] = random.randint(0, (1 << 32)-1)
85 self.add_case(Program(lst, bigendian), initial_regs=initial_regs,
86 initial_cr=cr)
87
88 def case_mtocrf(self):
89 for i in range(20):
90 mask = 1 << random.randint(0, 7)
91 lst = [f"mtocrf {mask}, 2"]
92 cr = random.randint(0, (1 << 32)-1)
93 initial_regs = [0] * 32
94 initial_regs[2] = random.randint(0, (1 << 32)-1)
95 self.add_case(Program(lst, bigendian), initial_regs=initial_regs,
96 initial_cr=cr)
97
98 def case_mfcr(self):
99 for i in range(1):
100 lst = ["mfcr 2"]
101 cr = random.randint(0, (1 << 32)-1)
102 self.add_case(Program(lst, bigendian), initial_cr=cr)
103
104 def case_cror_regression(self):
105 """another bad hack!
106 """
107 dis = ["cror 28, 5, 11"]
108 lst = bytes([0x83, 0x5b, 0x75, 0x4f]) # 4f855b83
109 cr = 0x35055058
110 p = Program(lst, bigendian)
111 p.assembly = '\n'.join(dis)+'\n'
112 self.add_case(p, initial_cr=cr)
113
114 def case_mfocrf_regression(self):
115 """bit of a bad hack. comes from microwatt 1.bin instruction 0x106d0
116 as the mask is non-standard, gnu-as barfs. so we fake it up directly
117 from the binary
118 """
119 mask = 0b10000111
120 dis = [f"mfocrf 2, {mask}"]
121 lst = bytes([0x26, 0x78, 0xb8, 0x7c]) # 0x7cb87826
122 cr = 0x5F9E080E
123 p = Program(lst, bigendian)
124 p.assembly = '\n'.join(dis)+'\n'
125 self.add_case(p, initial_cr=cr)
126
127 def case_mtocrf_regression(self):
128 """microwatt 1.bin regression, same hack as above.
129 106b4: 21 d9 96 7d .long 0x7d96d921 # mtocrf 12, 0b01101101
130 """
131 mask = 0b01101101
132 dis = [f"mtocrf 12, {mask}"]
133 lst = bytes([0x21, 0xd9, 0x96, 0x7d]) # 0x7d96d921
134 cr = 0x529e08fe
135 initial_regs = [0] * 32
136 initial_regs[12] = 0xffffffffffffffff
137 p = Program(lst, bigendian)
138 p.assembly = '\n'.join(dis)+'\n'
139 self.add_case(p, initial_regs=initial_regs, initial_cr=cr)
140
141 def case_mtocrf_regression_2(self):
142 """microwatt 1.bin regression, zero fxm
143 mtocrf 0,16 14928: 21 09 10 7e .long 0x7e100921
144 """
145 dis = ["mtocrf 16, 0"]
146 lst = bytes([0x21, 0x09, 0x10, 0x7e]) # 0x7e100921
147 cr = 0x3F089F7F
148 initial_regs = [0] * 32
149 initial_regs[16] = 0x0001C020
150 p = Program(lst, bigendian)
151 p.assembly = '\n'.join(dis)+'\n'
152 self.add_case(p, initial_regs=initial_regs, initial_cr=cr)
153
154 def case_mfocrf_1(self):
155 lst = [f"mfocrf 2, 1"]
156 cr = 0x1234
157 self.add_case(Program(lst, bigendian), initial_cr=cr)
158
159 def case_mfocrf(self):
160 for i in range(1):
161 mask = 1 << random.randint(0, 7)
162 lst = [f"mfocrf 2, {mask}"]
163 cr = random.randint(0, (1 << 32)-1)
164 self.add_case(Program(lst, bigendian), initial_cr=cr)
165
166 def case_isel_0(self):
167 lst = [ "isel 4, 1, 2, 31"
168 ]
169 initial_regs = [0] * 32
170 initial_regs[1] = 0x1004
171 initial_regs[2] = 0x1008
172 cr= 0x1ee
173 self.add_case(Program(lst, bigendian),
174 initial_regs=initial_regs, initial_cr=cr)
175
176 def case_isel_1(self):
177 lst = [ "isel 4, 1, 2, 30"
178 ]
179 initial_regs = [0] * 32
180 initial_regs[1] = 0x1004
181 initial_regs[2] = 0x1008
182 cr= 0x1ee
183 self.add_case(Program(lst, bigendian),
184 initial_regs=initial_regs, initial_cr=cr)
185
186 def case_isel_2(self):
187 lst = [ "isel 4, 1, 2, 2"
188 ]
189 initial_regs = [0] * 32
190 initial_regs[1] = 0x1004
191 initial_regs[2] = 0x1008
192 cr= 0x1ee
193 self.add_case(Program(lst, bigendian),
194 initial_regs=initial_regs, initial_cr=cr)
195
196 def case_isel_3(self):
197 lst = [ "isel 1, 2, 3, 13"
198 ]
199 initial_regs = [0] * 32
200 initial_regs[2] = 0x1004
201 initial_regs[3] = 0x1008
202 cr= 0x5d677571b8229f1
203 cr= 0x1b8229f1
204 self.add_case(Program(lst, bigendian),
205 initial_regs=initial_regs, initial_cr=cr)
206
207 def case_isel(self):
208 for i in range(20):
209 bc = random.randint(0, 31)
210 lst = [f"isel 1, 2, 3, {bc}"]
211 cr = random.randint(0, (1 << 64)-1)
212 initial_regs = [0] * 32
213 #initial_regs[2] = random.randint(0, (1 << 64)-1)
214 #initial_regs[3] = random.randint(0, (1 << 64)-1)
215 initial_regs[2] = i*2+1
216 initial_regs[3] = i*2+2
217 self.add_case(Program(lst, bigendian),
218 initial_regs=initial_regs, initial_cr=cr)
219
220 def case_setb(self):
221 for i in range(20):
222 bfa = random.randint(0, 7)
223 lst = [f"setb 1, {bfa}"]
224 cr = random.randint(0, (1 << 32)-1)
225 self.add_case(Program(lst, bigendian), initial_cr=cr)
226
227 def case_regression_setb(self):
228 lst = [f"setb 1, 6"]
229 cr = random.randint(0, 0x66f6b106)
230 self.add_case(Program(lst, bigendian), initial_cr=cr)
231
232 def case_ilang(self):
233 pspec = CRPipeSpec(id_wid=2)
234 alu = CRBasePipe(pspec)
235 vl = rtlil.convert(alu, ports=alu.ports())
236 with open("cr_pipeline.il", "w") as f:
237 f.write(vl)
238
239
240 def get_cu_inputs(dec2, sim):
241 """naming (res) must conform to CRFunctionUnit input regspec
242 """
243 res = {}
244 full_reg = yield dec2.dec_cr_in.whole_reg.data
245 full_reg_ok = yield dec2.dec_cr_in.whole_reg.ok
246 full_cr_mask = mask_extend(full_reg, 8, 4)
247
248 # full CR
249 print(sim.cr.value)
250 if full_reg_ok:
251 res['full_cr'] = sim.cr.value & full_cr_mask
252 else:
253 yield from ALUHelpers.get_sim_cr_a(res, sim, dec2) # CR A
254 yield from ALUHelpers.get_sim_cr_b(res, sim, dec2) # CR B
255 yield from ALUHelpers.get_sim_cr_c(res, sim, dec2) # CR C
256
257 yield from ALUHelpers.get_sim_int_ra(res, sim, dec2) # RA
258 yield from ALUHelpers.get_sim_int_rb(res, sim, dec2) # RB
259
260 print("get inputs", res)
261 return res
262
263
264 class TestRunner(unittest.TestCase):
265 def __init__(self, test_data):
266 super().__init__("run_all")
267 self.test_data = test_data
268
269 def set_inputs(self, alu, dec2, simulator):
270 inp = yield from get_cu_inputs(dec2, simulator)
271 yield from ALUHelpers.set_full_cr(alu, dec2, inp)
272 yield from ALUHelpers.set_cr_a(alu, dec2, inp)
273 yield from ALUHelpers.set_cr_b(alu, dec2, inp)
274 yield from ALUHelpers.set_cr_c(alu, dec2, inp)
275 yield from ALUHelpers.set_int_ra(alu, dec2, inp)
276 yield from ALUHelpers.set_int_rb(alu, dec2, inp)
277
278 def assert_outputs(self, alu, dec2, simulator, code):
279 whole_reg_ok = yield dec2.dec_cr_out.whole_reg.ok
280 whole_reg_data = yield dec2.dec_cr_out.whole_reg.data
281 full_cr_mask = mask_extend(whole_reg_data, 8, 4)
282
283 cr_en = yield dec2.e.write_cr.ok
284 if whole_reg_ok:
285 full_cr = yield alu.n.data_o.full_cr.data & full_cr_mask
286 expected_cr = simulator.cr.value
287 print("CR whole: expected %x, actual: %x mask: %x" % \
288 (expected_cr, full_cr, full_cr_mask))
289 # HACK: only look at the bits that we expected to change
290 self.assertEqual(expected_cr & full_cr_mask, full_cr, code)
291 elif cr_en:
292 cr_sel = yield dec2.e.write_cr.data
293 expected_cr = simulator.cr.value
294 print(f"CR whole: {expected_cr:x}, sel {cr_sel}")
295 expected_cr = simulator.crl[cr_sel].get_range().value
296 real_cr = yield alu.n.data_o.cr.data
297 print(f"CR part: expected {expected_cr:x}, actual: {real_cr:x}")
298 self.assertEqual(expected_cr, real_cr, code)
299 alu_out = yield alu.n.data_o.o.data
300 out_reg_valid = yield dec2.e.write_reg.ok
301 if out_reg_valid:
302 write_reg_idx = yield dec2.e.write_reg.data
303 expected = simulator.gpr(write_reg_idx).value
304 print(f"expected {expected:x}, actual: {alu_out:x}")
305 self.assertEqual(expected, alu_out, code)
306
307 def execute(self, alu, instruction, pdecode2, test):
308 program = test.program
309 sim = ISA(pdecode2, test.regs, test.sprs, test.cr, test.mem,
310 test.msr,
311 bigendian=bigendian)
312 gen = program.generate_instructions()
313 instructions = list(zip(gen, program.assembly.splitlines()))
314
315 index = sim.pc.CIA.value//4
316 while index < len(instructions):
317 ins, code = instructions[index]
318
319 print("0x{:X}".format(ins & 0xffffffff))
320 print(code)
321
322 # ask the decoder to decode this binary data (endian'd)
323 yield pdecode2.dec.bigendian.eq(bigendian) # little / big?
324 yield instruction.eq(ins) # raw binary instr.
325 yield Settle()
326 yield from self.set_inputs(alu, pdecode2, sim)
327 yield alu.p.valid_i.eq(1)
328 fn_unit = yield pdecode2.e.do.fn_unit
329 self.assertEqual(fn_unit, Function.CR.value, code)
330 yield
331 opname = code.split(' ')[0]
332 yield from sim.call(opname)
333 index = sim.pc.CIA.value//4
334
335 vld = yield alu.n.valid_o
336 while not vld:
337 yield
338 vld = yield alu.n.valid_o
339 yield
340 yield from self.assert_outputs(alu, pdecode2, sim, code)
341
342 def run_all(self):
343 m = Module()
344 comb = m.d.comb
345 instruction = Signal(32)
346
347 fn_name = "CR"
348 opkls = CRPipeSpec.opsubsetkls
349
350 m.submodules.pdecode2 = pdecode2 = PowerDecode2(None, opkls, fn_name)
351 pdecode = pdecode2.dec
352
353 pspec = CRPipeSpec(id_wid=2)
354 m.submodules.alu = alu = CRBasePipe(pspec)
355
356 comb += alu.p.data_i.ctx.op.eq_from_execute1(pdecode2.e)
357 comb += alu.n.ready_i.eq(1)
358 comb += pdecode2.dec.raw_opcode_in.eq(instruction)
359 sim = Simulator(m)
360
361 sim.add_clock(1e-6)
362
363 def process():
364 for test in self.test_data:
365 print(test.name)
366 with self.subTest(test.name):
367 yield from self.execute(alu, instruction, pdecode2, test)
368
369 sim.add_sync_process(process)
370 with sim.write_vcd("cr_simulator.vcd"):
371 sim.run()
372
373
374 if __name__ == "__main__":
375 unittest.main(exit=False)
376 suite = unittest.TestSuite()
377 suite.addTest(TestRunner(CRTestCase().test_data))
378
379 runner = unittest.TextTestRunner()
380 runner.run(suite)