Fix forgotten test_pipe_caller changes from e0b4334c7d83dda41d5610239150079f30a2f713
[soc.git] / src / soc / fu / mul / test / test_pipe_caller_long.py
1 from nmigen import Module, Signal
2 from nmigen.sim.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, MicrOp, CryIn)
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.mul.pipeline import MulBasePipe
16 from soc.fu.mul.pipe_data import MulPipeSpec
17 import random
18
19
20 def get_cu_inputs(dec2, sim):
21 """naming (res) must conform to MulFunctionUnit input regspec
22 """
23 res = {}
24
25 yield from ALUHelpers.get_sim_int_ra(res, sim, dec2) # RA
26 yield from ALUHelpers.get_sim_int_rb(res, sim, dec2) # RB
27 yield from ALUHelpers.get_sim_xer_so(res, sim, dec2) # XER.so
28
29 print("alu get_cu_inputs", res)
30
31 return res
32
33
34 def set_alu_inputs(alu, dec2, sim):
35 # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43
36 # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok))
37 # and place it into data_i.b
38
39 inp = yield from get_cu_inputs(dec2, sim)
40 print("set alu inputs", inp)
41 yield from ALUHelpers.set_int_ra(alu, dec2, inp)
42 yield from ALUHelpers.set_int_rb(alu, dec2, inp)
43
44 yield from ALUHelpers.set_xer_so(alu, dec2, inp)
45
46
47 # This test bench is a bit different than is usual. Initially when I
48 # was writing it, I had all of the tests call a function to create a
49 # device under test and simulator, initialize the dut, run the
50 # simulation for ~2 cycles, and assert that the dut output what it
51 # should have. However, this was really slow, since it needed to
52 # create and tear down the dut and simulator for every test case.
53
54 # Now, instead of doing that, every test case in MulTestCase puts some
55 # data into the test_data list below, describing the instructions to
56 # be tested and the initial state. Once all the tests have been run,
57 # test_data gets passed to TestRunner which then sets up the DUT and
58 # simulator once, runs all the data through it, and asserts that the
59 # results match the pseudocode sim at every cycle.
60
61 # By doing this, I've reduced the time it takes to run the test suite
62 # massively. Before, it took around 1 minute on my computer, now it
63 # takes around 3 seconds
64
65
66 class MulTestCase(TestAccumulatorBase):
67
68 def case_all(self):
69 instrs = ["mulhw",
70 "mulhw.", "mullw",
71 "mullw.", "mullwo",
72 "mullwo.", "mulhwu",
73 "mulhwu.", "mulld",
74 "mulld.", "mulldo",
75 "mulldo.", "mulhd",
76 "mulhd.", "mulhdu",
77 "mulhdu."]
78
79 test_values = [
80 0x0,
81 0x1,
82 0x2,
83 0xFFFF_FFFF_FFFF_FFFF,
84 0xFFFF_FFFF_FFFF_FFFE,
85 0x7FFF_FFFF_FFFF_FFFF,
86 0x8000_0000_0000_0000,
87 0x1234_5678_0000_0000,
88 0x1234_5678_8000_0000,
89 0x1234_5678_FFFF_FFFF,
90 0x1234_5678_7FFF_FFFF,
91 0xffffffff,
92 0x7fffffff,
93 0x80000000,
94 0xfffffffe,
95 0xfffffffd
96 ]
97
98 for instr in instrs:
99 l = [f"{instr} 3, 1, 2"]
100 for ra in test_values:
101 for rb in test_values:
102 initial_regs = [0] * 32
103 initial_regs[1] = ra
104 initial_regs[2] = rb
105 # use "with" so as to close the files used
106 with Program(l, bigendian) as prog:
107 self.add_case(prog, initial_regs)
108
109 def case_all_rb_randint(self):
110 instrs = ["mulhw",
111 "mulhw.", "mullw",
112 "mullw.", "mullwo",
113 "mullwo.", "mulhwu",
114 "mulhwu.", "mulld",
115 "mulld.", "mulldo",
116 "mulldo.", "mulhd",
117 "mulhd.", "mulhdu",
118 "mulhdu."]
119
120 test_values = [
121 0x0,
122 0x1,
123 0x2,
124 0xFFFF_FFFF_FFFF_FFFF,
125 0xFFFF_FFFF_FFFF_FFFE,
126 0x7FFF_FFFF_FFFF_FFFF,
127 0x8000_0000_0000_0000,
128 0x1234_5678_0000_0000,
129 0x1234_5678_8000_0000,
130 0x1234_5678_FFFF_FFFF,
131 0x1234_5678_7FFF_FFFF,
132 0xffffffff,
133 0x7fffffff,
134 0x80000000,
135 0xfffffffe,
136 0xfffffffd
137 ]
138
139 for instr in instrs:
140 l = [f"{instr} 3, 1, 2"]
141 for ra in test_values:
142 initial_regs = [0] * 32
143 initial_regs[1] = ra
144 initial_regs[2] = random.randint(0, (1 << 64)-1)
145 # use "with" so as to close the files used
146 with Program(l, bigendian) as prog:
147 self.add_case(prog, initial_regs)
148
149 def case_all_rb_close_to_ov(self):
150 instrs = ["mulhw",
151 "mulhw.", "mullw",
152 "mullw.", "mullwo",
153 "mullwo.", "mulhwu",
154 "mulhwu.", "mulld",
155 "mulld.", "mulldo",
156 "mulldo.", "mulhd",
157 "mulhd.", "mulhdu",
158 "mulhdu."]
159
160 test_values = [
161 0x0,
162 0x1,
163 0x2,
164 0xFFFF_FFFF_FFFF_FFFF,
165 0xFFFF_FFFF_FFFF_FFFE,
166 0x7FFF_FFFF_FFFF_FFFF,
167 0x8000_0000_0000_0000,
168 0x1234_5678_0000_0000,
169 0x1234_5678_8000_0000,
170 0x1234_5678_FFFF_FFFF,
171 0x1234_5678_7FFF_FFFF,
172 0xffffffff,
173 0x7fffffff,
174 0x80000000,
175 0xfffffffe,
176 0xfffffffd
177 ]
178
179 for instr in instrs:
180 for i in range(20):
181 x = 0x7fffffff + random.randint((-1 << 31), (1 << 31) - 1)
182 ra = random.randint(0, (1 << 32)-1)
183 rb = x // ra
184
185 l = [f"{instr} 3, 1, 2"]
186 initial_regs = [0] * 32
187 initial_regs[1] = ra
188 initial_regs[2] = rb
189 # use "with" so as to close the files used
190 with Program(l, bigendian) as prog:
191 self.add_case(prog, initial_regs)
192
193 def case_mulli(self):
194
195 imm_values = [-32768, -32767, -32766, -2, -1, 0, 1, 2, 32766, 32767]
196
197 ra_values = [
198 0x0,
199 0x1,
200 0x2,
201 0xFFFF_FFFF_FFFF_FFFF,
202 0xFFFF_FFFF_FFFF_FFFE,
203 0x7FFF_FFFF_FFFF_FFFF,
204 0x8000_0000_0000_0000,
205 0x1234_5678_0000_0000,
206 0x1234_5678_8000_0000,
207 0x1234_5678_FFFF_FFFF,
208 0x1234_5678_7FFF_FFFF,
209 0xffffffff,
210 0x7fffffff,
211 0x80000000,
212 0xfffffffe,
213 0xfffffffd
214 ]
215
216 for i in range(20):
217 imm_values.append(random.randint(-1 << 15, (1 << 15) - 1))
218
219 for i in range(14):
220 ra_values.append(random.randint(0, (1 << 64) - 1))
221
222 for ra in ra_values:
223 for imm in imm_values:
224 l = [f"mulli 0, 1, {imm}"]
225 initial_regs = [0] * 32
226 initial_regs[1] = ra
227 # use "with" so as to close the files used
228 with Program(l, bigendian) as prog:
229 self.add_case(prog, initial_regs)
230
231 # TODO add test case for these 3 operand cases (madd
232 # needs to be implemented)
233 # "maddhd","maddhdu","maddld"
234
235 def case_ilang(self):
236 pspec = MulPipeSpec(id_wid=2)
237 alu = MulBasePipe(pspec)
238 vl = rtlil.convert(alu, ports=alu.ports())
239 with open("mul_pipeline.il", "w") as f:
240 f.write(vl)
241
242
243 class TestRunner(unittest.TestCase):
244 def __init__(self, test_data):
245 super().__init__("run_all")
246 self.test_data = test_data
247
248 def run_all(self):
249 m = Module()
250 comb = m.d.comb
251 instruction = Signal(32)
252
253 pdecode = create_pdecode()
254
255 m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode)
256
257 pspec = MulPipeSpec(id_wid=2)
258 m.submodules.alu = alu = MulBasePipe(pspec)
259
260 comb += alu.p.data_i.ctx.op.eq_from_execute1(pdecode2.do)
261 comb += alu.n.ready_i.eq(1)
262 comb += pdecode2.dec.raw_opcode_in.eq(instruction)
263 sim = Simulator(m)
264
265 sim.add_clock(1e-6)
266
267 def process():
268 for test in self.test_data:
269 print(test.name)
270 program = test.program
271 self.subTest(test.name)
272 sim = ISA(pdecode2, test.regs, test.sprs, test.cr,
273 test.mem, test.msr,
274 bigendian=bigendian)
275 gen = program.generate_instructions()
276 instructions = list(zip(gen, program.assembly.splitlines()))
277 yield Settle()
278
279 index = sim.pc.CIA.value//4
280 while index < len(instructions):
281 ins, code = instructions[index]
282
283 print("instruction: 0x{:X}".format(ins & 0xffffffff))
284 print(code)
285 if 'XER' in sim.spr:
286 so = 1 if sim.spr['XER'][XER_bits['SO']] else 0
287 ov = 1 if sim.spr['XER'][XER_bits['OV']] else 0
288 ov32 = 1 if sim.spr['XER'][XER_bits['OV32']] else 0
289 print("before: so/ov/32", so, ov, ov32)
290
291 # ask the decoder to decode this binary data (endian'd)
292 yield pdecode2.dec.bigendian.eq(bigendian) # little / big?
293 yield instruction.eq(ins) # raw binary instr.
294 yield Settle()
295 fn_unit = yield pdecode2.e.do.fn_unit
296 self.assertEqual(fn_unit, Function.MUL.value)
297 yield from set_alu_inputs(alu, pdecode2, sim)
298
299 # set valid for one cycle, propagate through pipeline...
300 yield alu.p.valid_i.eq(1)
301 yield
302 yield alu.p.valid_i.eq(0)
303
304 opname = code.split(' ')[0]
305 yield from sim.call(opname)
306 index = sim.pc.CIA.value//4
307
308 # ...wait for valid to pop out the end
309 vld = yield alu.n.valid_o
310 while not vld:
311 yield
312 vld = yield alu.n.valid_o
313 yield
314
315 yield from self.check_alu_outputs(alu, pdecode2, sim, code)
316 yield Settle()
317
318 sim.add_sync_process(process)
319 with sim.write_vcd("mul_simulator.vcd", "mul_simulator.gtkw",
320 traces=[]):
321 sim.run()
322
323 def check_alu_outputs(self, alu, dec2, sim, code):
324
325 rc = yield dec2.e.do.rc.data
326 cridx_ok = yield dec2.e.write_cr.ok
327 cridx = yield dec2.e.write_cr.data
328
329 print("check extra output", repr(code), cridx_ok, cridx)
330 if rc:
331 self.assertEqual(cridx, 0, code)
332
333 oe = yield dec2.e.do.oe.oe
334 oe_ok = yield dec2.e.do.oe.ok
335 if not oe or not oe_ok:
336 # if OE not enabled, XER SO and OV must correspondingly be false
337 so_ok = yield alu.n.data_o.xer_so.ok
338 ov_ok = yield alu.n.data_o.xer_ov.ok
339 self.assertEqual(so_ok, False, code)
340 self.assertEqual(ov_ok, False, code)
341
342 sim_o = {}
343 res = {}
344
345 yield from ALUHelpers.get_cr_a(res, alu, dec2)
346 yield from ALUHelpers.get_xer_ov(res, alu, dec2)
347 yield from ALUHelpers.get_int_o(res, alu, dec2)
348 yield from ALUHelpers.get_xer_so(res, alu, dec2)
349
350 yield from ALUHelpers.get_sim_int_o(sim_o, sim, dec2)
351 yield from ALUHelpers.get_wr_sim_cr_a(sim_o, sim, dec2)
352 yield from ALUHelpers.get_sim_xer_ov(sim_o, sim, dec2)
353 yield from ALUHelpers.get_sim_xer_so(sim_o, sim, dec2)
354
355 ALUHelpers.check_int_o(self, res, sim_o, code)
356 ALUHelpers.check_xer_ov(self, res, sim_o, code)
357 ALUHelpers.check_xer_so(self, res, sim_o, code)
358 ALUHelpers.check_cr_a(self, res, sim_o, "CR%d %s" % (cridx, code))
359
360
361 if __name__ == "__main__":
362 unittest.main(exit=False)
363 suite = unittest.TestSuite()
364 suite.addTest(TestRunner(MulTestCase().test_data))
365
366 runner = unittest.TextTestRunner()
367 runner.run(suite)