use pdecode2.do not pdecode2.e in test_pipe_caller tests
[soc.git] / src / soc / fu / mul / 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, Delay, 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, MicrOp, CryIn)
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.mul.pipeline import MulBasePipe
20 from soc.fu.mul.pipe_data import MulPipeSpec
21 import random
22
23
24 def get_cu_inputs(dec2, sim):
25 """naming (res) must conform to MulFunctionUnit input regspec
26 """
27 res = {}
28
29 yield from ALUHelpers.get_sim_int_ra(res, sim, dec2) # RA
30 yield from ALUHelpers.get_sim_int_rb(res, sim, dec2) # RB
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 data_i.b
42
43 inp = yield from get_cu_inputs(dec2, sim)
44 print("set alu inputs", inp)
45 yield from ALUHelpers.set_int_ra(alu, dec2, inp)
46 yield from ALUHelpers.set_int_rb(alu, dec2, inp)
47
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 MulTestCase 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 MulTestCase(TestAccumulatorBase):
71
72 def case_0_mullw(self):
73 lst = [f"mullw 3, 1, 2"]
74 initial_regs = [0] * 32
75 #initial_regs[1] = 0xffffffffffffffff
76 #initial_regs[2] = 0xffffffffffffffff
77 initial_regs[1] = 0x2ffffffff
78 initial_regs[2] = 0x2
79 self.add_case(Program(lst, bigendian), initial_regs)
80
81 def case_1_mullwo_(self):
82 lst = [f"mullwo. 3, 1, 2"]
83 initial_regs = [0] * 32
84 initial_regs[1] = 0x3b34b06f
85 initial_regs[2] = 0xfdeba998
86 self.add_case(Program(lst, bigendian), initial_regs)
87
88 def case_2_mullwo(self):
89 lst = [f"mullwo 3, 1, 2"]
90 initial_regs = [0] * 32
91 initial_regs[1] = 0xffffffffffffa988 # -5678
92 initial_regs[2] = 0xffffffffffffedcc # -1234
93 self.add_case(Program(lst, bigendian), initial_regs)
94
95 def case_3_mullw(self):
96 lst = ["mullw 3, 1, 2",
97 "mullw 3, 1, 2"]
98 initial_regs = [0] * 32
99 initial_regs[1] = 0x6
100 initial_regs[2] = 0xe
101 self.add_case(Program(lst, bigendian), initial_regs)
102
103 def case_4_mullw_rand(self):
104 for i in range(40):
105 lst = ["mullw 3, 1, 2"]
106 initial_regs = [0] * 32
107 initial_regs[1] = random.randint(0, (1 << 64)-1)
108 initial_regs[2] = random.randint(0, (1 << 64)-1)
109 self.add_case(Program(lst, bigendian), initial_regs)
110
111 def case_4_mullw_nonrand(self):
112 for i in range(40):
113 lst = ["mullw 3, 1, 2"]
114 initial_regs = [0] * 32
115 initial_regs[1] = i+1
116 initial_regs[2] = i+20
117 self.add_case(Program(lst, bigendian), initial_regs)
118
119 def case_mulhw__regression_1(self):
120 lst = ["mulhw. 3, 1, 2"
121 ]
122 initial_regs = [0] * 32
123 initial_regs[1] = 0x7745b36eca6646fa
124 initial_regs[2] = 0x47dfba3a63834ba2
125 self.add_case(Program(lst, bigendian), initial_regs)
126
127 def case_rand_mul_lh(self):
128 insns = ["mulhw", "mulhw.", "mulhwu", "mulhwu."]
129 for i in range(40):
130 choice = random.choice(insns)
131 lst = [f"{choice} 3, 1, 2"]
132 initial_regs = [0] * 32
133 initial_regs[1] = random.randint(0, (1 << 64)-1)
134 initial_regs[2] = random.randint(0, (1 << 64)-1)
135 self.add_case(Program(lst, bigendian), initial_regs)
136
137 def case_rand_mullw(self):
138 insns = ["mullw", "mullw.", "mullwo", "mullwo."]
139 for i in range(40):
140 choice = random.choice(insns)
141 lst = [f"{choice} 3, 1, 2"]
142 initial_regs = [0] * 32
143 initial_regs[1] = random.randint(0, (1 << 64)-1)
144 initial_regs[2] = random.randint(0, (1 << 64)-1)
145 self.add_case(Program(lst, bigendian), initial_regs)
146
147 def case_rand_mulld(self):
148 insns = ["mulld", "mulld.", "mulldo", "mulldo."]
149 for i in range(40):
150 choice = random.choice(insns)
151 lst = [f"{choice} 3, 1, 2"]
152 initial_regs = [0] * 32
153 initial_regs[1] = random.randint(0, (1 << 64)-1)
154 initial_regs[2] = random.randint(0, (1 << 64)-1)
155 self.add_case(Program(lst, bigendian), initial_regs)
156
157 def case_rand_mulhd(self):
158 insns = ["mulhd", "mulhd."]
159 for i in range(40):
160 choice = random.choice(insns)
161 lst = [f"{choice} 3, 1, 2"]
162 initial_regs = [0] * 32
163 initial_regs[1] = random.randint(0, (1 << 64)-1)
164 initial_regs[2] = random.randint(0, (1 << 64)-1)
165 self.add_case(Program(lst, bigendian), initial_regs)
166
167 def case_0_mullhw_regression(self):
168 lst = [f"mulhwu 3, 1, 2"]
169 initial_regs = [0] * 32
170 initial_regs[1] = 0x4000000000000000
171 initial_regs[2] = 0x0000000000000002
172 self.add_case(Program(lst, bigendian), initial_regs)
173
174 # TODO add test case for these 3 operand cases (madd
175 # needs to be implemented)
176 # "maddhd","maddhdu","maddld"
177
178 def case_ilang(self):
179 pspec = MulPipeSpec(id_wid=2)
180 alu = MulBasePipe(pspec)
181 vl = rtlil.convert(alu, ports=alu.ports())
182 with open("mul_pipeline.il", "w") as f:
183 f.write(vl)
184
185
186 class TestRunner(unittest.TestCase):
187 def __init__(self, test_data):
188 super().__init__("run_all")
189 self.test_data = test_data
190
191 def run_all(self):
192 m = Module()
193 comb = m.d.comb
194 instruction = Signal(32)
195
196 fn_name = "MUL"
197 opkls = MulPipeSpec.opsubsetkls
198
199 m.submodules.pdecode2 = pdecode2 = PowerDecode2(None, opkls, fn_name)
200 pdecode = pdecode2.dec
201
202 pspec = MulPipeSpec(id_wid=2)
203 m.submodules.alu = alu = MulBasePipe(pspec)
204
205 comb += alu.p.data_i.ctx.op.eq_from_execute1(pdecode2.do)
206 comb += alu.n.ready_i.eq(1)
207 comb += pdecode2.dec.raw_opcode_in.eq(instruction)
208 sim = Simulator(m)
209
210 sim.add_clock(1e-6)
211
212 def process():
213 for test in self.test_data:
214 print(test.name)
215 program = test.program
216 self.subTest(test.name)
217 sim = ISA(pdecode2, test.regs, test.sprs, test.cr,
218 test.mem, test.msr,
219 bigendian=bigendian)
220 gen = program.generate_instructions()
221 instructions = list(zip(gen, program.assembly.splitlines()))
222 yield Settle()
223
224 index = sim.pc.CIA.value//4
225 while index < len(instructions):
226 ins, code = instructions[index]
227
228 print("instruction: 0x{:X}".format(ins & 0xffffffff))
229 print(code)
230 if 'XER' in sim.spr:
231 so = 1 if sim.spr['XER'][XER_bits['SO']] else 0
232 ov = 1 if sim.spr['XER'][XER_bits['OV']] else 0
233 ov32 = 1 if sim.spr['XER'][XER_bits['OV32']] else 0
234 print("before: so/ov/32", so, ov, ov32)
235
236 # ask the decoder to decode this binary data (endian'd)
237 yield pdecode2.dec.bigendian.eq(bigendian) # little / big?
238 yield instruction.eq(ins) # raw binary instr.
239 yield Settle()
240 fn_unit = yield pdecode2.e.do.fn_unit
241 self.assertEqual(fn_unit, Function.MUL.value)
242 yield from set_alu_inputs(alu, pdecode2, sim)
243
244 # set valid for one cycle, propagate through pipeline...
245 yield alu.p.valid_i.eq(1)
246 yield
247 yield alu.p.valid_i.eq(0)
248
249 opname = code.split(' ')[0]
250 yield from sim.call(opname)
251 index = sim.pc.CIA.value//4
252
253 # ...wait for valid to pop out the end
254 vld = yield alu.n.valid_o
255 while not vld:
256 yield
257 vld = yield alu.n.valid_o
258 yield
259
260 yield from self.check_alu_outputs(alu, pdecode2, sim, code)
261 yield Settle()
262
263 sim.add_sync_process(process)
264 with sim.write_vcd("mul_simulator.vcd", "mul_simulator.gtkw",
265 traces=[]):
266 sim.run()
267
268 def check_alu_outputs(self, alu, dec2, sim, code):
269
270 rc = yield dec2.e.do.rc.rc
271 cridx_ok = yield dec2.e.write_cr.ok
272 cridx = yield dec2.e.write_cr.data
273
274 print("check extra output", repr(code), cridx_ok, cridx)
275 if rc:
276 self.assertEqual(cridx, 0, code)
277
278 oe = yield dec2.e.do.oe.oe
279 oe_ok = yield dec2.e.do.oe.ok
280 if not oe or not oe_ok:
281 # if OE not enabled, XER SO and OV must correspondingly be false
282 so_ok = yield alu.n.data_o.xer_so.ok
283 ov_ok = yield alu.n.data_o.xer_ov.ok
284 self.assertEqual(so_ok, False, code)
285 self.assertEqual(ov_ok, False, code)
286
287 sim_o = {}
288 res = {}
289
290 yield from ALUHelpers.get_cr_a(res, alu, dec2)
291 yield from ALUHelpers.get_xer_ov(res, alu, dec2)
292 yield from ALUHelpers.get_int_o(res, alu, dec2)
293 yield from ALUHelpers.get_xer_so(res, alu, dec2)
294
295 yield from ALUHelpers.get_sim_int_o(sim_o, sim, dec2)
296 yield from ALUHelpers.get_wr_sim_cr_a(sim_o, sim, dec2)
297 yield from ALUHelpers.get_sim_xer_ov(sim_o, sim, dec2)
298 yield from ALUHelpers.get_sim_xer_so(sim_o, sim, dec2)
299
300 ALUHelpers.check_int_o(self, res, sim_o, code)
301 ALUHelpers.check_xer_ov(self, res, sim_o, code)
302 ALUHelpers.check_xer_so(self, res, sim_o, code)
303 ALUHelpers.check_cr_a(self, res, sim_o, "CR%d %s" % (cridx, code))
304
305
306 if __name__ == "__main__":
307 unittest.main(exit=False)
308 suite = unittest.TestSuite()
309 suite.addTest(TestRunner(MulTestCase().test_data))
310
311 runner = unittest.TextTestRunner()
312 runner.run(suite)