format code
[soc.git] / src / soc / fu / shift_rot / test / test_pipe_caller.py
1 import random
2 from soc.fu.shift_rot.pipe_data import ShiftRotPipeSpec
3 from soc.fu.shift_rot.pipeline import ShiftRotBasePipe
4 from openpower.test.common import TestAccumulatorBase, TestCase, ALUHelpers
5 from openpower.endian import bigendian
6 from openpower.decoder.isa.all import ISA
7 from openpower.simulator.program import Program
8 from openpower.decoder.power_enums import (XER_bits, Function, CryIn)
9 from openpower.decoder.power_decoder2 import (PowerDecode2)
10 from openpower.decoder.power_decoder import (create_pdecode)
11 import unittest
12 from nmigen.cli import rtlil
13 from nmigen import Module, Signal
14
15 # NOTE: to use cxxsim, export NMIGEN_SIM_MODE=cxxsim from the shell
16 # Also, check out the cxxsim nmigen branch, and latest yosys from git
17 from nmutil.sim_tmp_alternative import Simulator, Settle
18
19 from openpower.test.shift_rot.shift_rot_cases import ShiftRotTestCase
20
21
22 def get_cu_inputs(dec2, sim):
23 """naming (res) must conform to ShiftRotFunctionUnit input regspec
24 """
25 res = {}
26
27 yield from ALUHelpers.get_sim_int_ra(res, sim, dec2) # RA
28 yield from ALUHelpers.get_sim_int_rb(res, sim, dec2) # RB
29 yield from ALUHelpers.get_sim_int_rc(res, sim, dec2) # RC
30 yield from ALUHelpers.get_rd_sim_xer_ca(res, sim, dec2) # XER.ca
31 yield from ALUHelpers.get_sim_xer_so(res, sim, dec2) # XER.so
32
33 print("alu get_cu_inputs", res)
34
35 return res
36
37
38 def set_alu_inputs(alu, dec2, sim):
39 # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43
40 # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok))
41 # and place it into i_data.b
42
43 inp = yield from get_cu_inputs(dec2, sim)
44 yield from ALUHelpers.set_int_ra(alu, dec2, inp)
45 yield from ALUHelpers.set_int_rb(alu, dec2, inp)
46 yield from ALUHelpers.set_int_rc(alu, dec2, inp)
47 yield from ALUHelpers.set_xer_ca(alu, dec2, inp)
48 yield from ALUHelpers.set_xer_so(alu, dec2, inp)
49
50
51 # This test bench is a bit different than is usual. Initially when I
52 # was writing it, I had all of the tests call a function to create a
53 # device under test and simulator, initialize the dut, run the
54 # simulation for ~2 cycles, and assert that the dut output what it
55 # should have. However, this was really slow, since it needed to
56 # create and tear down the dut and simulator for every test case.
57
58 # Now, instead of doing that, every test case in ShiftRotTestCase puts some
59 # data into the test_data list below, describing the instructions to
60 # be tested and the initial state. Once all the tests have been run,
61 # test_data gets passed to TestRunner which then sets up the DUT and
62 # simulator once, runs all the data through it, and asserts that the
63 # results match the pseudocode sim at every cycle.
64
65 # By doing this, I've reduced the time it takes to run the test suite
66 # massively. Before, it took around 1 minute on my computer, now it
67 # takes around 3 seconds
68
69
70 class ShiftRotIlangCase(TestAccumulatorBase):
71
72 def case_ilang(self):
73 pspec = ShiftRotPipeSpec(id_wid=2)
74 alu = ShiftRotBasePipe(pspec)
75 vl = rtlil.convert(alu, ports=alu.ports())
76 with open("shift_rot_pipeline.il", "w") as f:
77 f.write(vl)
78
79
80 class TestRunner(unittest.TestCase):
81 def __init__(self, test_data):
82 super().__init__("run_all")
83 self.test_data = test_data
84
85 def execute(self, alu, instruction, pdecode2, test):
86 program = test.program
87 simulator = ISA(pdecode2, test.regs, test.sprs, test.cr,
88 test.mem, test.msr,
89 bigendian=bigendian)
90 gen = program.generate_instructions()
91 instructions = list(zip(gen, program.assembly.splitlines()))
92
93 index = simulator.pc.CIA.value//4
94 while index < len(instructions):
95 ins, code = instructions[index]
96
97 print("0x{:X}".format(ins & 0xffffffff))
98 print(code)
99
100 # ask the decoder to decode this binary data (endian'd)
101 yield pdecode2.dec.bigendian.eq(bigendian) # little / big?
102 yield instruction.eq(ins) # raw binary instr.
103 yield Settle()
104 fn_unit = yield pdecode2.e.do.fn_unit
105 self.assertEqual(fn_unit, Function.SHIFT_ROT.value)
106 yield from set_alu_inputs(alu, pdecode2, simulator)
107
108 # set valid for one cycle, propagate through pipeline...
109 yield alu.p.i_valid.eq(1)
110 yield
111 yield alu.p.i_valid.eq(0)
112
113 opname = code.split(' ')[0]
114 yield from simulator.call(opname)
115 index = simulator.pc.CIA.value//4
116
117 vld = yield alu.n.o_valid
118 while not vld:
119 yield
120 vld = yield alu.n.o_valid
121 yield
122 alu_out = yield alu.n.o_data.o.data
123
124 yield from self.check_alu_outputs(alu, pdecode2,
125 simulator, code)
126 yield Settle()
127
128 def run_all(self):
129 m = Module()
130 comb = m.d.comb
131 instruction = Signal(32)
132
133 fn_name = "SHIFT_ROT"
134 opkls = ShiftRotPipeSpec.opsubsetkls
135
136 m.submodules.pdecode2 = pdecode2 = PowerDecode2(None, opkls, fn_name)
137 pdecode = pdecode2.dec
138
139 pspec = ShiftRotPipeSpec(id_wid=2)
140 m.submodules.alu = alu = ShiftRotBasePipe(pspec)
141
142 comb += alu.p.i_data.ctx.op.eq_from_execute1(pdecode2.do)
143 comb += alu.n.i_ready.eq(1)
144 comb += pdecode2.dec.raw_opcode_in.eq(instruction)
145 sim = Simulator(m)
146
147 sim.add_clock(1e-6)
148
149 def process():
150 for test in self.test_data:
151 print(test.name)
152 program = test.program
153 with self.subTest(test.name):
154 yield from self.execute(alu, instruction, pdecode2, test)
155
156 sim.add_sync_process(process)
157 with sim.write_vcd("shift_rot_simulator.vcd"):
158 sim.run()
159
160 def check_alu_outputs(self, alu, dec2, sim, code):
161
162 rc = yield dec2.e.do.rc.rc
163 cridx_ok = yield dec2.e.write_cr.ok
164 cridx = yield dec2.e.write_cr.data
165
166 print("check extra output", repr(code), cridx_ok, cridx)
167 if rc:
168 self.assertEqual(cridx, 0, code)
169
170 sim_o = {}
171 res = {}
172
173 yield from ALUHelpers.get_cr_a(res, alu, dec2)
174 yield from ALUHelpers.get_xer_ca(res, alu, dec2)
175 yield from ALUHelpers.get_int_o(res, alu, dec2)
176
177 print("hw outputs", res)
178
179 yield from ALUHelpers.get_sim_int_o(sim_o, sim, dec2)
180 yield from ALUHelpers.get_wr_sim_cr_a(sim_o, sim, dec2)
181 yield from ALUHelpers.get_wr_sim_xer_ca(sim_o, sim, dec2)
182
183 print("sim outputs", sim_o)
184
185 ALUHelpers.check_cr_a(self, res, sim_o, "CR%d %s" % (cridx, code))
186 ALUHelpers.check_xer_ca(self, res, sim_o, code)
187 ALUHelpers.check_int_o(self, res, sim_o, code)
188
189
190 if __name__ == "__main__":
191 unittest.main(exit=False)
192 suite = unittest.TestSuite()
193 suite.addTest(TestRunner(ShiftRotTestCase().test_data))
194 suite.addTest(TestRunner(ShiftRotIlangCase().test_data))
195
196 runner = unittest.TextTestRunner()
197 runner.run(suite)