Allow the formal engine to perform a same-cycle result in the ALU
[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 openpower.decoder.power_decoder import (create_pdecode)
10 from openpower.decoder.power_decoder2 import (PowerDecode2)
11 from openpower.decoder.power_enums import Function
12 from openpower.decoder.isa.all import ISA
13 from openpower.endian import bigendian
14
15 from openpower.test.common import TestAccumulatorBase, ALUHelpers
16 from openpower.util import mask_extend
17 from soc.fu.cr.pipeline import CRBasePipe
18 from soc.fu.cr.pipe_data import CRPipeSpec
19 import random
20
21 from openpower.test.cr.cr_cases import CRTestCase
22
23
24 class CRIlangCase(TestAccumulatorBase):
25
26 def case_ilang(self):
27 pspec = CRPipeSpec(id_wid=2, parent_pspec=None)
28 alu = CRBasePipe(pspec)
29 vl = rtlil.convert(alu, ports=alu.ports())
30 with open("cr_pipeline.il", "w") as f:
31 f.write(vl)
32
33
34 def get_cu_inputs(dec2, sim):
35 """naming (res) must conform to CRFunctionUnit input regspec
36 """
37 res = {}
38 full_reg = yield dec2.dec_cr_in.whole_reg.data
39 full_reg_ok = yield dec2.dec_cr_in.whole_reg.ok
40 full_cr_mask = mask_extend(full_reg, 8, 4)
41
42 # full CR
43 print(sim.cr.value)
44 if full_reg_ok:
45 res['full_cr'] = sim.cr.value & full_cr_mask
46 else:
47 yield from ALUHelpers.get_sim_cr_a(res, sim, dec2) # CR A
48 yield from ALUHelpers.get_sim_cr_b(res, sim, dec2) # CR B
49 yield from ALUHelpers.get_sim_cr_c(res, sim, dec2) # CR C
50
51 yield from ALUHelpers.get_sim_int_ra(res, sim, dec2) # RA
52 yield from ALUHelpers.get_sim_int_rb(res, sim, dec2) # RB
53
54 print("get inputs", res)
55 return res
56
57
58 class TestRunner(unittest.TestCase):
59 def __init__(self, test_data):
60 super().__init__("run_all")
61 self.test_data = test_data
62
63 def set_inputs(self, alu, dec2, simulator):
64 inp = yield from get_cu_inputs(dec2, simulator)
65 yield from ALUHelpers.set_full_cr(alu, dec2, inp)
66 yield from ALUHelpers.set_cr_a(alu, dec2, inp)
67 yield from ALUHelpers.set_cr_b(alu, dec2, inp)
68 yield from ALUHelpers.set_cr_c(alu, dec2, inp)
69 yield from ALUHelpers.set_int_ra(alu, dec2, inp)
70 yield from ALUHelpers.set_int_rb(alu, dec2, inp)
71
72 def assert_outputs(self, alu, dec2, simulator, code):
73 whole_reg_ok = yield dec2.dec_cr_out.whole_reg.ok
74 whole_reg_data = yield dec2.dec_cr_out.whole_reg.data
75 full_cr_mask = mask_extend(whole_reg_data, 8, 4)
76
77 cr_en = yield dec2.e.write_cr.ok
78 if whole_reg_ok:
79 full_cr = yield alu.n.o_data.full_cr.data & full_cr_mask
80 expected_cr = simulator.cr.value
81 print("CR whole: expected %x, actual: %x mask: %x" %
82 (expected_cr, full_cr, full_cr_mask))
83 # HACK: only look at the bits that we expected to change
84 self.assertEqual(expected_cr & full_cr_mask, full_cr, code)
85 elif cr_en:
86 cr_sel = yield dec2.e.write_cr.data
87 expected_cr = simulator.cr.value
88 print(f"CR whole: {expected_cr:x}, sel {cr_sel}")
89 expected_cr = simulator.crl[cr_sel].get_range().value
90 real_cr = yield alu.n.o_data.cr.data
91 print(f"CR part: expected {expected_cr:x}, actual: {real_cr:x}")
92 self.assertEqual(expected_cr, real_cr, code)
93 alu_out = yield alu.n.o_data.o.data
94 out_reg_valid = yield dec2.e.write_reg.ok
95 if out_reg_valid:
96 write_reg_idx = yield dec2.e.write_reg.data
97 expected = simulator.gpr(write_reg_idx).value
98 print(f"expected {expected:x}, actual: {alu_out:x}")
99 self.assertEqual(expected, alu_out, code)
100
101 def execute(self, alu, instruction, pdecode2, test):
102 program = test.program
103 sim = ISA(pdecode2, test.regs, test.sprs, test.cr, test.mem,
104 test.msr,
105 bigendian=bigendian)
106 gen = program.generate_instructions()
107 instructions = list(zip(gen, program.assembly.splitlines()))
108
109 index = sim.pc.CIA.value//4
110 while index < len(instructions):
111 ins, code = instructions[index]
112
113 print("0x{:X}".format(ins & 0xffffffff))
114 print(code)
115
116 # ask the decoder to decode this binary data (endian'd)
117 yield pdecode2.dec.bigendian.eq(bigendian) # little / big?
118 yield instruction.eq(ins) # raw binary instr.
119 yield Settle()
120 yield from self.set_inputs(alu, pdecode2, sim)
121 yield alu.p.i_valid.eq(1)
122 fn_unit = yield pdecode2.e.do.fn_unit
123 self.assertEqual(fn_unit, Function.CR.value, code)
124 yield
125 opname = code.split(' ')[0]
126 yield from sim.call(opname)
127 index = sim.pc.CIA.value//4
128
129 vld = yield alu.n.o_valid
130 while not vld:
131 yield
132 vld = yield alu.n.o_valid
133 yield
134 yield from self.assert_outputs(alu, pdecode2, sim, code)
135
136 def run_all(self):
137 m = Module()
138 comb = m.d.comb
139 instruction = Signal(32)
140
141 fn_name = "CR"
142 opkls = CRPipeSpec.opsubsetkls
143
144 m.submodules.pdecode2 = pdecode2 = PowerDecode2(None, opkls, fn_name)
145 pdecode = pdecode2.dec
146
147 pspec = CRPipeSpec(id_wid=2, parent_pspec=None)
148 m.submodules.alu = alu = CRBasePipe(pspec)
149
150 comb += alu.p.i_data.ctx.op.eq_from_execute1(pdecode2.do)
151 comb += alu.n.i_ready.eq(1)
152 comb += pdecode2.dec.raw_opcode_in.eq(instruction)
153 sim = Simulator(m)
154
155 sim.add_clock(1e-6)
156
157 def process():
158 for test in self.test_data:
159 print(test.name)
160 with self.subTest(test.name):
161 yield from self.execute(alu, instruction, pdecode2, test)
162
163 sim.add_sync_process(process)
164 with sim.write_vcd("cr_simulator.vcd"):
165 sim.run()
166
167
168 if __name__ == "__main__":
169 unittest.main(exit=False)
170 suite = unittest.TestSuite()
171 suite.addTest(TestRunner(CRTestCase().test_data))
172 suite.addTest(TestRunner(CRIlangCase().test_data))
173
174 runner = unittest.TextTestRunner()
175 runner.run(suite)