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