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