whitespace
[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),
155 initial_regs, initial_sprs)
156
157 def test_cmp(self):
158 lst = ["subf. 1, 6, 7",
159 "cmp cr2, 1, 6, 7"]
160 initial_regs = [0] * 32
161 initial_regs[6] = 0x10
162 initial_regs[7] = 0x05
163 self.run_tst_program(Program(lst, bigendian), initial_regs, {})
164
165 def test_extsb(self):
166 insns = ["extsb", "extsh", "extsw"]
167 for i in range(10):
168 choice = random.choice(insns)
169 lst = [f"{choice} 3, 1"]
170 print(lst)
171 initial_regs = [0] * 32
172 initial_regs[1] = random.randint(0, (1<<64)-1)
173 self.run_tst_program(Program(lst, bigendian), initial_regs)
174
175 def test_cmpeqb(self):
176 lst = ["cmpeqb cr1, 1, 2"]
177 for i in range(20):
178 initial_regs = [0] * 32
179 initial_regs[1] = i
180 initial_regs[2] = 0x0001030507090b0f
181 self.run_tst_program(Program(lst, bigendian), initial_regs, {})
182
183 def test_ilang(self):
184 pspec = ALUPipeSpec(id_wid=2)
185 alu = ALUBasePipe(pspec)
186 vl = rtlil.convert(alu, ports=alu.ports())
187 with open("alu_pipeline.il", "w") as f:
188 f.write(vl)
189
190
191 class TestRunner(FHDLTestCase):
192 def __init__(self, test_data):
193 super().__init__("run_all")
194 self.test_data = test_data
195
196 def run_all(self):
197 m = Module()
198 comb = m.d.comb
199 instruction = Signal(32)
200
201 pdecode = create_pdecode()
202
203 m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode)
204
205 pspec = ALUPipeSpec(id_wid=2)
206 m.submodules.alu = alu = ALUBasePipe(pspec)
207
208 comb += alu.p.data_i.ctx.op.eq_from_execute1(pdecode2.e)
209 comb += alu.p.valid_i.eq(1)
210 comb += alu.n.ready_i.eq(1)
211 comb += pdecode2.dec.raw_opcode_in.eq(instruction)
212 sim = Simulator(m)
213
214 sim.add_clock(1e-6)
215 def process():
216 for test in self.test_data:
217 print(test.name)
218 program = test.program
219 self.subTest(test.name)
220 sim = ISA(pdecode2, test.regs, test.sprs, test.cr,
221 test.mem, test.msr,
222 bigendian=bigendian)
223 gen = program.generate_instructions()
224 instructions = list(zip(gen, program.assembly.splitlines()))
225
226 index = sim.pc.CIA.value//4
227 while index < len(instructions):
228 ins, code = instructions[index]
229
230 print("instruction: 0x{:X}".format(ins & 0xffffffff))
231 print(code)
232 if 'XER' in sim.spr:
233 so = 1 if sim.spr['XER'][XER_bits['SO']] else 0
234 ov = 1 if sim.spr['XER'][XER_bits['OV']] else 0
235 ov32 = 1 if sim.spr['XER'][XER_bits['OV32']] else 0
236 print ("before: so/ov/32", so, ov, ov32)
237
238 # ask the decoder to decode this binary data (endian'd)
239 yield pdecode2.dec.bigendian.eq(bigendian) # little / big?
240 yield instruction.eq(ins) # raw binary instr.
241 yield Settle()
242 fn_unit = yield pdecode2.e.do.fn_unit
243 self.assertEqual(fn_unit, Function.ALU.value)
244 yield from set_alu_inputs(alu, pdecode2, sim)
245 yield
246 opname = code.split(' ')[0]
247 yield from sim.call(opname)
248 index = sim.pc.CIA.value//4
249
250 vld = yield alu.n.valid_o
251 while not vld:
252 yield
253 vld = yield alu.n.valid_o
254 yield
255
256 yield from self.check_alu_outputs(alu, pdecode2, sim, code)
257
258 sim.add_sync_process(process)
259 sim.write_vcd("alu_simulator.vcd")
260 sim.run()
261
262 def check_alu_outputs(self, alu, dec2, sim, code):
263
264 rc = yield dec2.e.do.rc.data
265 cridx_ok = yield dec2.e.write_cr.ok
266 cridx = yield dec2.e.write_cr.data
267
268 print ("check extra output", repr(code), cridx_ok, cridx)
269 if rc:
270 self.assertEqual(cridx, 0, code)
271
272 oe = yield dec2.e.do.oe.oe
273 oe_ok = yield dec2.e.do.oe.ok
274 if not oe or not oe_ok:
275 # if OE not enabled, XER SO and OV must correspondingly be false
276 so_ok = yield alu.n.data_o.xer_so.ok
277 ov_ok = yield alu.n.data_o.xer_ov.ok
278 self.assertEqual(so_ok, False, code)
279 self.assertEqual(ov_ok, False, code)
280
281 sim_o = {}
282 res = {}
283
284 yield from ALUHelpers.get_cr_a(res, alu, dec2)
285 yield from ALUHelpers.get_xer_ov(res, alu, dec2)
286 yield from ALUHelpers.get_xer_ca(res, alu, dec2)
287 yield from ALUHelpers.get_int_o(res, alu, dec2)
288 yield from ALUHelpers.get_xer_so(res, alu, dec2)
289
290 yield from ALUHelpers.get_sim_int_o(sim_o, sim, dec2)
291 yield from ALUHelpers.get_wr_sim_cr_a(sim_o, sim, dec2)
292 yield from ALUHelpers.get_sim_xer_ov(sim_o, sim, dec2)
293 yield from ALUHelpers.get_wr_sim_xer_ca(sim_o, sim, dec2)
294 yield from ALUHelpers.get_sim_xer_so(sim_o, sim, dec2)
295
296 ALUHelpers.check_cr_a(self, res, sim_o, "CR%d %s" % (cridx, code))
297 ALUHelpers.check_xer_ov(self, res, sim_o, code)
298 ALUHelpers.check_xer_ca(self, res, sim_o, code)
299 ALUHelpers.check_int_o(self, res, sim_o, code)
300 ALUHelpers.check_xer_so(self, res, sim_o, code)
301
302
303 if __name__ == "__main__":
304 unittest.main(exit=False)
305 suite = unittest.TestSuite()
306 suite.addTest(TestRunner(ALUTestCase.test_data))
307
308 runner = unittest.TextTestRunner()
309 runner.run(suite)