make cxxsim optional and print warning
[soc.git] / src / soc / fu / alu / test / test_pipe_caller.py
1 from nmigen import Module, Signal
2 from nmigen.back.pysim import Delay, Settle
3 # NOTE: to use this (set to True), at present it is necessary to check
4 # out the cxxsim nmigen branch
5 cxxsim = False
6 if cxxsim:
7 try:
8 from nmigen.sim.cxxsim import Simulator
9 except ImportError:
10 print("nope, sorry, have to use nmigen cxxsim branch for now")
11 cxxsim = False
12 from nmigen.back.pysim import Simulator
13 else:
14 from nmigen.back.pysim import Simulator
15
16 from nmutil.formaltest import FHDLTestCase
17 from nmigen.cli import rtlil
18 import unittest
19 from soc.decoder.isa.caller import ISACaller, special_sprs
20 from soc.decoder.power_decoder import (create_pdecode)
21 from soc.decoder.power_decoder2 import (PowerDecode2)
22 from soc.decoder.power_enums import (XER_bits, Function, MicrOp, CryIn)
23 from soc.decoder.selectable_int import SelectableInt
24 from soc.simulator.program import Program
25 from soc.decoder.isa.all import ISA
26 from soc.config.endian import bigendian
27
28 from soc.fu.test.common import (TestCase, ALUHelpers)
29 from soc.fu.alu.pipeline import ALUBasePipe
30 from soc.fu.alu.pipe_data import ALUPipeSpec
31 import random
32
33
34 def get_cu_inputs(dec2, sim):
35 """naming (res) must conform to ALUFunctionUnit input regspec
36 """
37 res = {}
38
39 yield from ALUHelpers.get_sim_int_ra(res, sim, dec2) # RA
40 yield from ALUHelpers.get_sim_int_rb(res, sim, dec2) # RB
41 yield from ALUHelpers.get_rd_sim_xer_ca(res, sim, dec2) # XER.ca
42 yield from ALUHelpers.get_sim_xer_so(res, sim, dec2) # XER.so
43
44 print ("alu get_cu_inputs", res)
45
46 return res
47
48
49
50 def set_alu_inputs(alu, dec2, sim):
51 # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43
52 # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok))
53 # and place it into data_i.b
54
55 inp = yield from get_cu_inputs(dec2, sim)
56 yield from ALUHelpers.set_int_ra(alu, dec2, inp)
57 yield from ALUHelpers.set_int_rb(alu, dec2, inp)
58
59 yield from ALUHelpers.set_xer_ca(alu, dec2, inp)
60 yield from ALUHelpers.set_xer_so(alu, dec2, inp)
61
62
63 # This test bench is a bit different than is usual. Initially when I
64 # was writing it, I had all of the tests call a function to create a
65 # device under test and simulator, initialize the dut, run the
66 # simulation for ~2 cycles, and assert that the dut output what it
67 # should have. However, this was really slow, since it needed to
68 # create and tear down the dut and simulator for every test case.
69
70 # Now, instead of doing that, every test case in ALUTestCase puts some
71 # data into the test_data list below, describing the instructions to
72 # be tested and the initial state. Once all the tests have been run,
73 # test_data gets passed to TestRunner which then sets up the DUT and
74 # simulator once, runs all the data through it, and asserts that the
75 # results match the pseudocode sim at every cycle.
76
77 # By doing this, I've reduced the time it takes to run the test suite
78 # massively. Before, it took around 1 minute on my computer, now it
79 # takes around 3 seconds
80
81
82 class ALUTestCase(FHDLTestCase):
83 test_data = []
84
85 def __init__(self, name):
86 super().__init__(name)
87 self.test_name = name
88
89 def run_tst_program(self, prog, initial_regs=None, initial_sprs=None):
90 tc = TestCase(prog, self.test_name, initial_regs, initial_sprs)
91 self.test_data.append(tc)
92
93 def test_1_regression(self):
94 lst = [f"extsw 3, 1"]
95 initial_regs = [0] * 32
96 initial_regs[1] = 0xb6a1fc6c8576af91
97 self.run_tst_program(Program(lst, bigendian), initial_regs)
98 lst = [f"subf 3, 1, 2"]
99 initial_regs = [0] * 32
100 initial_regs[1] = 0x3d7f3f7ca24bac7b
101 initial_regs[2] = 0xf6b2ac5e13ee15c2
102 self.run_tst_program(Program(lst, bigendian), initial_regs)
103 lst = [f"subf 3, 1, 2"]
104 initial_regs = [0] * 32
105 initial_regs[1] = 0x833652d96c7c0058
106 initial_regs[2] = 0x1c27ecff8a086c1a
107 self.run_tst_program(Program(lst, bigendian), initial_regs)
108 lst = [f"extsb 3, 1"]
109 initial_regs = [0] * 32
110 initial_regs[1] = 0x7f9497aaff900ea0
111 self.run_tst_program(Program(lst, bigendian), initial_regs)
112 lst = [f"add. 3, 1, 2"]
113 initial_regs = [0] * 32
114 initial_regs[1] = 0xc523e996a8ff6215
115 initial_regs[2] = 0xe1e5b9cc9864c4a8
116 self.run_tst_program(Program(lst, bigendian), initial_regs)
117 lst = [f"add 3, 1, 2"]
118 initial_regs = [0] * 32
119 initial_regs[1] = 0x2e08ae202742baf8
120 initial_regs[2] = 0x86c43ece9efe5baa
121 self.run_tst_program(Program(lst, bigendian), initial_regs)
122
123 def test_rand(self):
124 insns = ["add", "add.", "subf"]
125 for i in range(40):
126 choice = random.choice(insns)
127 lst = [f"{choice} 3, 1, 2"]
128 initial_regs = [0] * 32
129 initial_regs[1] = random.randint(0, (1<<64)-1)
130 initial_regs[2] = random.randint(0, (1<<64)-1)
131 self.run_tst_program(Program(lst, bigendian), initial_regs)
132
133 def test_rand_imm(self):
134 insns = ["addi", "addis", "subfic"]
135 for i in range(10):
136 choice = random.choice(insns)
137 imm = random.randint(-(1<<15), (1<<15)-1)
138 lst = [f"{choice} 3, 1, {imm}"]
139 print(lst)
140 initial_regs = [0] * 32
141 initial_regs[1] = random.randint(0, (1<<64)-1)
142 self.run_tst_program(Program(lst, bigendian), initial_regs)
143
144 def test_0_adde(self):
145 lst = ["adde. 5, 6, 7"]
146 for i in range(10):
147 initial_regs = [0] * 32
148 initial_regs[6] = random.randint(0, (1<<64)-1)
149 initial_regs[7] = random.randint(0, (1<<64)-1)
150 initial_sprs = {}
151 xer = SelectableInt(0, 64)
152 xer[XER_bits['CA']] = 1
153 initial_sprs[special_sprs['XER']] = xer
154 self.run_tst_program(Program(lst, bigendian), initial_regs, initial_sprs)
155
156 def test_cmp(self):
157 lst = ["subf. 1, 6, 7",
158 "cmp cr2, 1, 6, 7"]
159 initial_regs = [0] * 32
160 initial_regs[6] = 0x10
161 initial_regs[7] = 0x05
162 self.run_tst_program(Program(lst, bigendian), initial_regs, {})
163
164 def test_extsb(self):
165 insns = ["extsb", "extsh", "extsw"]
166 for i in range(10):
167 choice = random.choice(insns)
168 lst = [f"{choice} 3, 1"]
169 print(lst)
170 initial_regs = [0] * 32
171 initial_regs[1] = random.randint(0, (1<<64)-1)
172 self.run_tst_program(Program(lst, bigendian), initial_regs)
173
174 def test_cmpeqb(self):
175 lst = ["cmpeqb cr1, 1, 2"]
176 for i in range(20):
177 initial_regs = [0] * 32
178 initial_regs[1] = i
179 initial_regs[2] = 0x0001030507090b0f
180 self.run_tst_program(Program(lst, bigendian), initial_regs, {})
181
182 def test_ilang(self):
183 pspec = ALUPipeSpec(id_wid=2)
184 alu = ALUBasePipe(pspec)
185 vl = rtlil.convert(alu, ports=alu.ports())
186 with open("alu_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 = ALUPipeSpec(id_wid=2)
205 m.submodules.alu = alu = ALUBasePipe(pspec)
206
207 comb += alu.p.data_i.ctx.op.eq_from_execute1(pdecode2.e)
208 comb += alu.p.valid_i.eq(1)
209 comb += alu.n.ready_i.eq(1)
210 comb += pdecode2.dec.raw_opcode_in.eq(instruction)
211 sim = Simulator(m)
212
213 sim.add_clock(1e-6)
214 def process():
215 for test in self.test_data:
216 print(test.name)
217 program = test.program
218 self.subTest(test.name)
219 sim = ISA(pdecode2, test.regs, test.sprs, test.cr,
220 test.mem, test.msr,
221 bigendian=bigendian)
222 gen = program.generate_instructions()
223 instructions = list(zip(gen, program.assembly.splitlines()))
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.ALU.value)
243 yield from set_alu_inputs(alu, pdecode2, sim)
244 yield
245 opname = code.split(' ')[0]
246 yield from sim.call(opname)
247 index = sim.pc.CIA.value//4
248
249 vld = yield alu.n.valid_o
250 while not vld:
251 yield
252 vld = yield alu.n.valid_o
253 yield
254
255 yield from self.check_alu_outputs(alu, pdecode2, sim, code)
256
257 sim.add_sync_process(process)
258 sim.write_vcd("alu_simulator.vcd")
259 sim.run()
260
261 def check_alu_outputs(self, alu, dec2, sim, code):
262
263 rc = yield dec2.e.do.rc.data
264 cridx_ok = yield dec2.e.write_cr.ok
265 cridx = yield dec2.e.write_cr.data
266
267 print ("check extra output", repr(code), cridx_ok, cridx)
268 if rc:
269 self.assertEqual(cridx, 0, code)
270
271 oe = yield dec2.e.do.oe.oe
272 oe_ok = yield dec2.e.do.oe.ok
273 if not oe or not oe_ok:
274 # if OE not enabled, XER SO and OV must correspondingly be false
275 so_ok = yield alu.n.data_o.xer_so.ok
276 ov_ok = yield alu.n.data_o.xer_ov.ok
277 self.assertEqual(so_ok, False, code)
278 self.assertEqual(ov_ok, False, code)
279
280 sim_o = {}
281 res = {}
282
283 yield from ALUHelpers.get_cr_a(res, alu, dec2)
284 yield from ALUHelpers.get_xer_ov(res, alu, dec2)
285 yield from ALUHelpers.get_xer_ca(res, alu, dec2)
286 yield from ALUHelpers.get_int_o(res, alu, dec2)
287 yield from ALUHelpers.get_xer_so(res, alu, dec2)
288
289 yield from ALUHelpers.get_sim_int_o(sim_o, sim, dec2)
290 yield from ALUHelpers.get_wr_sim_cr_a(sim_o, sim, dec2)
291 yield from ALUHelpers.get_sim_xer_ov(sim_o, sim, dec2)
292 yield from ALUHelpers.get_wr_sim_xer_ca(sim_o, sim, dec2)
293 yield from ALUHelpers.get_sim_xer_so(sim_o, sim, dec2)
294
295 ALUHelpers.check_cr_a(self, res, sim_o, "CR%d %s" % (cridx, code))
296 ALUHelpers.check_xer_ov(self, res, sim_o, code)
297 ALUHelpers.check_xer_ca(self, res, sim_o, code)
298 ALUHelpers.check_int_o(self, res, sim_o, code)
299 ALUHelpers.check_xer_so(self, res, sim_o, code)
300
301
302 if __name__ == "__main__":
303 unittest.main(exit=False)
304 suite = unittest.TestSuite()
305 suite.addTest(TestRunner(ALUTestCase.test_data))
306
307 runner = unittest.TextTestRunner()
308 runner.run(suite)