56d3fed6961abf07dc4c0774d28c733baebfc17c
[soc.git] / src / soc / fu / mul / test / test_pipe_caller.py
1 from nmigen import Module, Signal
2 from nmigen.back.pysim import Simulator, Delay, Settle
3 from nmutil.formaltest import FHDLTestCase
4 from nmigen.cli import rtlil
5 import unittest
6 from soc.decoder.isa.caller import ISACaller, special_sprs
7 from soc.decoder.power_decoder import (create_pdecode)
8 from soc.decoder.power_decoder2 import (PowerDecode2)
9 from soc.decoder.power_enums import (XER_bits, Function, MicrOp, CryIn)
10 from soc.decoder.selectable_int import SelectableInt
11 from soc.simulator.program import Program
12 from soc.decoder.isa.all import ISA
13 from soc.config.endian import bigendian
14
15 from soc.fu.test.common import (TestCase, ALUHelpers)
16 from soc.fu.mul.pipeline import MulBasePipe
17 from soc.fu.mul.pipe_data import MulPipeSpec
18 import random
19
20
21 def get_cu_inputs(dec2, sim):
22 """naming (res) must conform to MulFunctionUnit input regspec
23 """
24 res = {}
25
26 yield from ALUHelpers.get_sim_int_ra(res, sim, dec2) # RA
27 yield from ALUHelpers.get_sim_int_rb(res, sim, dec2) # RB
28 yield from ALUHelpers.get_sim_xer_so(res, sim, dec2) # XER.so
29
30 print ("alu get_cu_inputs", res)
31
32 return res
33
34
35
36 def set_alu_inputs(alu, dec2, sim):
37 # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43
38 # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok))
39 # and place it into data_i.b
40
41 inp = yield from get_cu_inputs(dec2, sim)
42 print ("set alu inputs", inp)
43 yield from ALUHelpers.set_int_ra(alu, dec2, inp)
44 yield from ALUHelpers.set_int_rb(alu, dec2, inp)
45
46 yield from ALUHelpers.set_xer_so(alu, dec2, inp)
47
48
49 # This test bench is a bit different than is usual. Initially when I
50 # was writing it, I had all of the tests call a function to create a
51 # device under test and simulator, initialize the dut, run the
52 # simulation for ~2 cycles, and assert that the dut output what it
53 # should have. However, this was really slow, since it needed to
54 # create and tear down the dut and simulator for every test case.
55
56 # Now, instead of doing that, every test case in MulTestCase puts some
57 # data into the test_data list below, describing the instructions to
58 # be tested and the initial state. Once all the tests have been run,
59 # test_data gets passed to TestRunner which then sets up the DUT and
60 # simulator once, runs all the data through it, and asserts that the
61 # results match the pseudocode sim at every cycle.
62
63 # By doing this, I've reduced the time it takes to run the test suite
64 # massively. Before, it took around 1 minute on my computer, now it
65 # takes around 3 seconds
66
67
68 class MulTestCase(FHDLTestCase):
69 test_data = []
70
71 def __init__(self, name):
72 super().__init__(name)
73 self.test_name = name
74
75 def run_tst_program(self, prog, initial_regs=None, initial_sprs=None):
76 tc = TestCase(prog, self.test_name, initial_regs, initial_sprs)
77 self.test_data.append(tc)
78
79 def test_0_mullw(self):
80 lst = [f"mullw 3, 1, 2"]
81 initial_regs = [0] * 32
82 #initial_regs[1] = 0xffffffffffffffff
83 #initial_regs[2] = 0xffffffffffffffff
84 initial_regs[1] = 0x2ffffffff
85 initial_regs[2] = 0x2
86 self.run_tst_program(Program(lst, bigendian), initial_regs)
87
88 def test_1_mullwo_(self):
89 lst = [f"mullwo. 3, 1, 2"]
90 initial_regs = [0] * 32
91 initial_regs[1] = 0x3b34b06f
92 initial_regs[2] = 0xfdeba998
93 self.run_tst_program(Program(lst, bigendian), initial_regs)
94
95 def test_2_mullwo(self):
96 lst = [f"mullwo 3, 1, 2"]
97 initial_regs = [0] * 32
98 initial_regs[1] = 0xffffffffffffa988 # -5678
99 initial_regs[2] = 0xffffffffffffedcc # -1234
100 self.run_tst_program(Program(lst, bigendian), initial_regs)
101
102 def test_3_mullw(self):
103 lst = ["mullw 3, 1, 2",
104 "mullw 3, 1, 2"]
105 initial_regs = [0] * 32
106 initial_regs[1] = 0x6
107 initial_regs[2] = 0xe
108 self.run_tst_program(Program(lst, bigendian), initial_regs)
109
110 def test_4_mullw_rand(self):
111 for i in range(40):
112 lst = ["mullw 3, 1, 2"]
113 initial_regs = [0] * 32
114 initial_regs[1] = random.randint(0, (1<<64)-1)
115 initial_regs[2] = random.randint(0, (1<<64)-1)
116 self.run_tst_program(Program(lst, bigendian), initial_regs)
117
118 def test_4_mullw_nonrand(self):
119 for i in range(40):
120 lst = ["mullw 3, 1, 2"]
121 initial_regs = [0] * 32
122 initial_regs[1] = i+1
123 initial_regs[2] = i+20
124 self.run_tst_program(Program(lst, bigendian), initial_regs)
125
126 def test_mulhw__regression_1(self):
127 lst = ["mulhw. 3, 1, 2"
128 ]
129 initial_regs = [0] * 32
130 initial_regs[1] = 0x7745b36eca6646fa
131 initial_regs[2] = 0x47dfba3a63834ba2
132 self.run_tst_program(Program(lst, bigendian), initial_regs)
133
134 def test_4_mullw_rand(self):
135 for i in range(40):
136 lst = ["mullw 3, 1, 2"]
137 initial_regs = [0] * 32
138 initial_regs[1] = random.randint(0, (1<<64)-1)
139 initial_regs[2] = random.randint(0, (1<<64)-1)
140 self.run_tst_program(Program(lst, bigendian), initial_regs)
141
142 def test_rand_mul_lh(self):
143 insns = ["mulhw", "mulhw.", "mulhwu", "mulhwu."]
144 for i in range(40):
145 choice = random.choice(insns)
146 lst = [f"{choice} 3, 1, 2"]
147 initial_regs = [0] * 32
148 initial_regs[1] = random.randint(0, (1<<64)-1)
149 initial_regs[2] = random.randint(0, (1<<64)-1)
150 self.run_tst_program(Program(lst, bigendian), initial_regs)
151
152 def test_rand_mullw(self):
153 insns = ["mullw", "mullw.", "mullwo", "mullwo."]
154 for i in range(40):
155 choice = random.choice(insns)
156 lst = [f"{choice} 3, 1, 2"]
157 initial_regs = [0] * 32
158 initial_regs[1] = random.randint(0, (1<<64)-1)
159 initial_regs[2] = random.randint(0, (1<<64)-1)
160 self.run_tst_program(Program(lst, bigendian), initial_regs)
161
162 def test_rand_mulld(self):
163 insns = ["mulld", "mulld.", "mulldo", "mulldo."]
164 for i in range(40):
165 choice = random.choice(insns)
166 lst = [f"{choice} 3, 1, 2"]
167 initial_regs = [0] * 32
168 initial_regs[1] = random.randint(0, (1<<64)-1)
169 initial_regs[2] = random.randint(0, (1<<64)-1)
170 self.run_tst_program(Program(lst, bigendian), initial_regs)
171
172 def test_rand_mulhd(self):
173 insns = ["mulhd", "mulhd."]
174 for i in range(40):
175 choice = random.choice(insns)
176 lst = [f"{choice} 3, 1, 2"]
177 initial_regs = [0] * 32
178 initial_regs[1] = random.randint(0, (1<<64)-1)
179 initial_regs[2] = random.randint(0, (1<<64)-1)
180 self.run_tst_program(Program(lst, bigendian), initial_regs)
181
182 def test_ilang(self):
183 pspec = MulPipeSpec(id_wid=2)
184 alu = MulBasePipe(pspec)
185 vl = rtlil.convert(alu, ports=alu.ports())
186 with open("mul_pipeline.il", "w") as f:
187 f.write(vl)
188
189
190 class TestRunner(FHDLTestCase):
191 def __init__(self, test_data):
192 super().__init__("run_all")
193 self.test_data = test_data
194
195 def run_all(self):
196 m = Module()
197 comb = m.d.comb
198 instruction = Signal(32)
199
200 pdecode = create_pdecode()
201
202 m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode)
203
204 pspec = MulPipeSpec(id_wid=2)
205 m.submodules.alu = alu = MulBasePipe(pspec)
206
207 comb += alu.p.data_i.ctx.op.eq_from_execute1(pdecode2.e)
208 comb += alu.n.ready_i.eq(1)
209 comb += pdecode2.dec.raw_opcode_in.eq(instruction)
210 sim = Simulator(m)
211
212 sim.add_clock(1e-6)
213 def process():
214 for test in self.test_data:
215 print(test.name)
216 program = test.program
217 self.subTest(test.name)
218 sim = ISA(pdecode2, test.regs, test.sprs, test.cr,
219 test.mem, test.msr,
220 bigendian=bigendian)
221 gen = program.generate_instructions()
222 instructions = list(zip(gen, program.assembly.splitlines()))
223 yield Settle()
224
225 index = sim.pc.CIA.value//4
226 while index < len(instructions):
227 ins, code = instructions[index]
228
229 print("instruction: 0x{:X}".format(ins & 0xffffffff))
230 print(code)
231 if 'XER' in sim.spr:
232 so = 1 if sim.spr['XER'][XER_bits['SO']] else 0
233 ov = 1 if sim.spr['XER'][XER_bits['OV']] else 0
234 ov32 = 1 if sim.spr['XER'][XER_bits['OV32']] else 0
235 print ("before: so/ov/32", so, ov, ov32)
236
237 # ask the decoder to decode this binary data (endian'd)
238 yield pdecode2.dec.bigendian.eq(bigendian) # little / big?
239 yield instruction.eq(ins) # raw binary instr.
240 yield Settle()
241 fn_unit = yield pdecode2.e.do.fn_unit
242 self.assertEqual(fn_unit, Function.MUL.value)
243 yield from set_alu_inputs(alu, pdecode2, sim)
244
245 # set valid for one cycle, propagate through pipeline...
246 yield alu.p.valid_i.eq(1)
247 yield
248 yield alu.p.valid_i.eq(0)
249
250 opname = code.split(' ')[0]
251 yield from sim.call(opname)
252 index = sim.pc.CIA.value//4
253
254 # ...wait for valid to pop out the end
255 vld = yield alu.n.valid_o
256 while not vld:
257 yield
258 vld = yield alu.n.valid_o
259 yield
260
261 yield from self.check_alu_outputs(alu, pdecode2, sim, code)
262 yield Settle()
263
264 sim.add_sync_process(process)
265 with sim.write_vcd("mul_simulator.vcd", "mul_simulator.gtkw",
266 traces=[]):
267 sim.run()
268
269 def check_alu_outputs(self, alu, dec2, sim, code):
270
271 rc = yield dec2.e.do.rc.data
272 cridx_ok = yield dec2.e.write_cr.ok
273 cridx = yield dec2.e.write_cr.data
274
275 print ("check extra output", repr(code), cridx_ok, cridx)
276 if rc:
277 self.assertEqual(cridx, 0, code)
278
279 oe = yield dec2.e.do.oe.oe
280 oe_ok = yield dec2.e.do.oe.ok
281 if not oe or not oe_ok:
282 # if OE not enabled, XER SO and OV must correspondingly be false
283 so_ok = yield alu.n.data_o.xer_so.ok
284 ov_ok = yield alu.n.data_o.xer_ov.ok
285 self.assertEqual(so_ok, False, code)
286 self.assertEqual(ov_ok, False, code)
287
288 sim_o = {}
289 res = {}
290
291 yield from ALUHelpers.get_cr_a(res, alu, dec2)
292 yield from ALUHelpers.get_xer_ov(res, alu, dec2)
293 yield from ALUHelpers.get_int_o(res, alu, dec2)
294 yield from ALUHelpers.get_xer_so(res, alu, dec2)
295
296 yield from ALUHelpers.get_sim_int_o(sim_o, sim, dec2)
297 yield from ALUHelpers.get_wr_sim_cr_a(sim_o, sim, dec2)
298 yield from ALUHelpers.get_sim_xer_ov(sim_o, sim, dec2)
299 yield from ALUHelpers.get_sim_xer_so(sim_o, sim, dec2)
300
301 ALUHelpers.check_int_o(self, res, sim_o, code)
302 ALUHelpers.check_xer_ov(self, res, sim_o, code)
303 ALUHelpers.check_xer_so(self, res, sim_o, code)
304 ALUHelpers.check_cr_a(self, res, sim_o, "CR%d %s" % (cridx, code))
305
306
307 if __name__ == "__main__":
308 unittest.main(exit=False)
309 suite = unittest.TestSuite()
310 suite.addTest(TestRunner(MulTestCase.test_data))
311
312 runner = unittest.TextTestRunner()
313 runner.run(suite)