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