a87bb89689bb293282435ab53689a86e62738ca7
[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_regression_setb(self):
138 lst = [f"setb 1, 6"]
139 cr = random.randint(0, 0x66f6b106)
140 self.run_tst_program(Program(lst, bigendian), initial_cr=cr)
141
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 def process():
251 for test in self.test_data:
252 print(test.name)
253 program = test.program
254 self.subTest(test.name)
255 sim = ISA(pdecode2, test.regs, test.sprs, test.cr, test.mem,
256 test.msr,
257 bigendian=bigendian)
258 gen = program.generate_instructions()
259 instructions = list(zip(gen, program.assembly.splitlines()))
260
261 index = sim.pc.CIA.value//4
262 while index < len(instructions):
263 ins, code = instructions[index]
264
265 print("0x{:X}".format(ins & 0xffffffff))
266 print(code)
267
268 # ask the decoder to decode this binary data (endian'd)
269 yield pdecode2.dec.bigendian.eq(bigendian) # little / big?
270 yield instruction.eq(ins) # raw binary instr.
271 yield Settle()
272 yield from self.set_inputs(alu, pdecode2, sim)
273 yield alu.p.valid_i.eq(1)
274 fn_unit = yield pdecode2.e.do.fn_unit
275 self.assertEqual(fn_unit, Function.CR.value, code)
276 yield
277 opname = code.split(' ')[0]
278 yield from sim.call(opname)
279 index = sim.pc.CIA.value//4
280
281 vld = yield alu.n.valid_o
282 while not vld:
283 yield
284 vld = yield alu.n.valid_o
285 yield
286 yield from self.assert_outputs(alu, pdecode2, sim, code)
287
288 sim.add_sync_process(process)
289 with sim.write_vcd("simulator.vcd", "simulator.gtkw",
290 traces=[]):
291 sim.run()
292
293
294 if __name__ == "__main__":
295 unittest.main(exit=False)
296 suite = unittest.TestSuite()
297 suite.addTest(TestRunner(CRTestCase.test_data))
298
299 runner = unittest.TextTestRunner()
300 runner.run(suite)