sorting out bigendian/littleendian including in qemu
[soc.git] / src / soc / fu / cr / 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)
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.cr.pipeline import CRBasePipe
17 from soc.fu.cr.pipe_data import CRPipeSpec
18 import random
19
20
21
22 # This test bench is a bit different than is usual. Initially when I
23 # was writing it, I had all of the tests call a function to create a
24 # device under test and simulator, initialize the dut, run the
25 # simulation for ~2 cycles, and assert that the dut output what it
26 # should have. However, this was really slow, since it needed to
27 # create and tear down the dut and simulator for every test case.
28
29 # Now, instead of doing that, every test case in ALUTestCase puts some
30 # data into the test_data list below, describing the instructions to
31 # be tested and the initial state. Once all the tests have been run,
32 # test_data gets passed to TestRunner which then sets up the DUT and
33 # simulator once, runs all the data through it, and asserts that the
34 # results match the pseudocode sim at every cycle.
35
36 # By doing this, I've reduced the time it takes to run the test suite
37 # massively. Before, it took around 1 minute on my computer, now it
38 # takes around 3 seconds
39
40
41 class CRTestCase(FHDLTestCase):
42 test_data = []
43 def __init__(self, name):
44 super().__init__(name)
45 self.test_name = name
46
47 def run_tst_program(self, prog, initial_regs=None, initial_sprs=None,
48 initial_cr=0):
49 tc = TestCase(prog, self.test_name,
50 regs=initial_regs, sprs=initial_sprs, cr=initial_cr)
51 self.test_data.append(tc)
52
53 def test_crop(self):
54 insns = ["crand", "cror", "crnand", "crnor", "crxor", "creqv",
55 "crandc", "crorc"]
56 for i in range(40):
57 choice = random.choice(insns)
58 ba = random.randint(0, 31)
59 bb = random.randint(0, 31)
60 bt = random.randint(0, 31)
61 lst = [f"{choice} {ba}, {bb}, {bt}"]
62 cr = random.randint(0, (1<<32)-1)
63 self.run_tst_program(Program(lst, bigendian), initial_cr=cr)
64
65 def test_crand(self):
66 for i in range(20):
67 lst = ["crand 0, 11, 13"]
68 cr = random.randint(0, (1<<32)-1)
69 self.run_tst_program(Program(lst, bigendian), initial_cr=cr)
70
71 def test_1_mcrf(self):
72 for i in range(20):
73 src = random.randint(0, 7)
74 dst = random.randint(0, 7)
75 lst = [f"mcrf {src}, {dst}"]
76 cr = random.randint(0, (1<<32)-1)
77 self.run_tst_program(Program(lst, bigendian), initial_cr=cr)
78
79 def test_0_mcrf(self):
80 for i in range(8):
81 lst = [f"mcrf 5, {i}"]
82 cr = 0xfeff0001
83 self.run_tst_program(Program(lst, bigendian), initial_cr=cr)
84
85 def test_mtcrf(self):
86 for i in range(20):
87 mask = random.randint(0, 255)
88 lst = [f"mtcrf {mask}, 2"]
89 cr = random.randint(0, (1<<32)-1)
90 initial_regs = [0] * 32
91 initial_regs[2] = random.randint(0, (1<<32)-1)
92 self.run_tst_program(Program(lst, bigendian), initial_regs=initial_regs,
93 initial_cr=cr)
94 def test_mtocrf(self):
95 for i in range(20):
96 mask = 1<<random.randint(0, 7)
97 lst = [f"mtocrf {mask}, 2"]
98 cr = random.randint(0, (1<<32)-1)
99 initial_regs = [0] * 32
100 initial_regs[2] = random.randint(0, (1<<32)-1)
101 self.run_tst_program(Program(lst, bigendian), initial_regs=initial_regs,
102 initial_cr=cr)
103
104 def test_mfcr(self):
105 for i in range(5):
106 lst = ["mfcr 2"]
107 cr = random.randint(0, (1<<32)-1)
108 self.run_tst_program(Program(lst, bigendian), initial_cr=cr)
109
110 def test_mfocrf(self):
111 for i in range(20):
112 mask = 1<<random.randint(0, 7)
113 lst = [f"mfocrf 2, {mask}"]
114 cr = random.randint(0, (1<<32)-1)
115 self.run_tst_program(Program(lst, bigendian), initial_cr=cr)
116
117 def test_isel(self):
118 for i in range(20):
119 bc = random.randint(0, 31)
120 lst = [f"isel 1, 2, 3, {bc}"]
121 cr = random.randint(0, (1<<32)-1)
122 initial_regs = [0] * 32
123 initial_regs[2] = random.randint(0, (1<<64)-1)
124 initial_regs[3] = random.randint(0, (1<<64)-1)
125 #initial_regs[2] = i*2
126 #initial_regs[3] = i*2+1
127 self.run_tst_program(Program(lst, bigendian),
128 initial_regs=initial_regs, initial_cr=cr)
129
130 def test_setb(self):
131 for i in range(20):
132 bfa = random.randint(0, 7)
133 lst = [f"setb 1, {bfa}"]
134 cr = random.randint(0, (1<<32)-1)
135 self.run_tst_program(Program(lst, bigendian), initial_cr=cr)
136
137 def test_ilang(self):
138 pspec = CRPipeSpec(id_wid=2)
139 alu = CRBasePipe(pspec)
140 vl = rtlil.convert(alu, ports=alu.ports())
141 with open("cr_pipeline.il", "w") as f:
142 f.write(vl)
143
144
145 def get_cu_inputs(dec2, sim):
146 """naming (res) must conform to CRFunctionUnit input regspec
147 """
148 res = {}
149 full_reg = yield dec2.e.do.read_cr_whole
150
151 # full CR
152 print(sim.cr.get_range().value)
153 if full_reg:
154 res['full_cr'] = sim.cr.get_range().value
155 else:
156 # CR A
157 cr1_en = yield dec2.e.read_cr1.ok
158 if cr1_en:
159 cr1_sel = yield dec2.e.read_cr1.data
160 res['cr_a'] = sim.crl[cr1_sel].get_range().value
161 cr2_en = yield dec2.e.read_cr2.ok
162 # CR B
163 if cr2_en:
164 cr2_sel = yield dec2.e.read_cr2.data
165 res['cr_b'] = sim.crl[cr2_sel].get_range().value
166 cr3_en = yield dec2.e.read_cr3.ok
167 # CR C
168 if cr3_en:
169 cr3_sel = yield dec2.e.read_cr3.data
170 res['cr_c'] = sim.crl[cr3_sel].get_range().value
171
172 # RA/RC
173 reg1_ok = yield dec2.e.read_reg1.ok
174 if reg1_ok:
175 data1 = yield dec2.e.read_reg1.data
176 res['ra'] = sim.gpr(data1).value
177
178 # RB (or immediate)
179 reg2_ok = yield dec2.e.read_reg2.ok
180 if reg2_ok:
181 data2 = yield dec2.e.read_reg2.data
182 res['rb'] = sim.gpr(data2).value
183
184 print ("get inputs", res)
185 return res
186
187
188 class TestRunner(FHDLTestCase):
189 def __init__(self, test_data):
190 super().__init__("run_all")
191 self.test_data = test_data
192
193 def set_inputs(self, alu, dec2, simulator):
194 inp = yield from get_cu_inputs(dec2, simulator)
195 yield from ALUHelpers.set_full_cr(alu, dec2, inp)
196 yield from ALUHelpers.set_cr_a(alu, dec2, inp)
197 yield from ALUHelpers.set_cr_b(alu, dec2, inp)
198 yield from ALUHelpers.set_cr_c(alu, dec2, inp)
199 yield from ALUHelpers.set_int_ra(alu, dec2, inp)
200 yield from ALUHelpers.set_int_rb(alu, dec2, inp)
201
202 def assert_outputs(self, alu, dec2, simulator, code):
203 whole_reg = yield dec2.e.do.write_cr_whole
204 cr_en = yield dec2.e.write_cr.ok
205 if whole_reg:
206 full_cr = yield alu.n.data_o.full_cr.data
207 expected_cr = simulator.cr.get_range().value
208 print(f"CR whole: expected {expected_cr:x}, actual: {full_cr:x}")
209 self.assertEqual(expected_cr, full_cr, code)
210 elif cr_en:
211 cr_sel = yield dec2.e.write_cr.data
212 expected_cr = simulator.cr.get_range().value
213 print(f"CR whole: {expected_cr:x}, sel {cr_sel}")
214 expected_cr = simulator.crl[cr_sel].get_range().value
215 real_cr = yield alu.n.data_o.cr.data
216 print(f"CR part: expected {expected_cr:x}, actual: {real_cr:x}")
217 self.assertEqual(expected_cr, real_cr, code)
218 alu_out = yield alu.n.data_o.o.data
219 out_reg_valid = yield dec2.e.write_reg.ok
220 if out_reg_valid:
221 write_reg_idx = yield dec2.e.write_reg.data
222 expected = simulator.gpr(write_reg_idx).value
223 print(f"expected {expected:x}, actual: {alu_out:x}")
224 self.assertEqual(expected, alu_out, code)
225
226 def run_all(self):
227 m = Module()
228 comb = m.d.comb
229 instruction = Signal(32)
230
231 pdecode = create_pdecode()
232
233 m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode)
234
235 pspec = CRPipeSpec(id_wid=2)
236 m.submodules.alu = alu = CRBasePipe(pspec)
237
238 comb += alu.p.data_i.ctx.op.eq_from_execute1(pdecode2.e)
239 comb += alu.n.ready_i.eq(1)
240 comb += pdecode2.dec.raw_opcode_in.eq(instruction)
241 sim = Simulator(m)
242
243 sim.add_clock(1e-6)
244 def process():
245 for test in self.test_data:
246 print(test.name)
247 program = test.program
248 self.subTest(test.name)
249 sim = ISA(pdecode2, test.regs, test.sprs, test.cr, test.mem,
250 test.msr,
251 bigendian=bigendian)
252 gen = program.generate_instructions()
253 instructions = list(zip(gen, program.assembly.splitlines()))
254
255 index = sim.pc.CIA.value//4
256 while index < len(instructions):
257 ins, code = instructions[index]
258
259 print("0x{:X}".format(ins & 0xffffffff))
260 print(code)
261
262 # ask the decoder to decode this binary data (endian'd)
263 yield pdecode2.dec.bigendian.eq(bigendian) # little / big?
264 yield instruction.eq(ins) # raw binary instr.
265 yield Settle()
266 yield from self.set_inputs(alu, pdecode2, sim)
267 yield alu.p.valid_i.eq(1)
268 fn_unit = yield pdecode2.e.do.fn_unit
269 self.assertEqual(fn_unit, Function.CR.value, code)
270 yield
271 opname = code.split(' ')[0]
272 yield from sim.call(opname)
273 index = sim.pc.CIA.value//4
274
275 vld = yield alu.n.valid_o
276 while not vld:
277 yield
278 vld = yield alu.n.valid_o
279 yield
280 yield from self.assert_outputs(alu, pdecode2, sim, code)
281
282 sim.add_sync_process(process)
283 with sim.write_vcd("simulator.vcd", "simulator.gtkw",
284 traces=[]):
285 sim.run()
286
287
288 if __name__ == "__main__":
289 unittest.main(exit=False)
290 suite = unittest.TestSuite()
291 suite.addTest(TestRunner(CRTestCase.test_data))
292
293 runner = unittest.TextTestRunner()
294 runner.run(suite)