CR FXM becomes a full mask.
[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 nmigen.cli import rtlil
4 import unittest
5 from soc.decoder.isa.caller import ISACaller, special_sprs
6 from soc.decoder.power_decoder import (create_pdecode)
7 from soc.decoder.power_decoder2 import (PowerDecode2)
8 from soc.decoder.power_enums import (XER_bits, Function)
9 from soc.decoder.selectable_int import SelectableInt
10 from soc.simulator.program import Program
11 from soc.decoder.isa.all import ISA
12 from soc.config.endian import bigendian
13
14 from soc.fu.test.common import TestAccumulatorBase, TestCase, ALUHelpers
15 from soc.fu.test.common import mask_extend
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(TestAccumulatorBase):
41
42 def cse_crop(self):
43 insns = ["crand", "cror", "crnand", "crnor", "crxor", "creqv",
44 "crandc", "crorc"]
45 for i in range(40):
46 choice = random.choice(insns)
47 ba = random.randint(0, 31)
48 bb = random.randint(0, 31)
49 bt = random.randint(0, 31)
50 lst = [f"{choice} {ba}, {bb}, {bt}"]
51 cr = random.randint(0, (1 << 32)-1)
52 self.add_case(Program(lst, bigendian), initial_cr=cr)
53
54 def cse_crand(self):
55 for i in range(20):
56 lst = ["crand 0, 11, 13"]
57 cr = random.randint(0, (1 << 32)-1)
58 self.add_case(Program(lst, bigendian), initial_cr=cr)
59
60 def cse_1_mcrf(self):
61 for i in range(20):
62 src = random.randint(0, 7)
63 dst = random.randint(0, 7)
64 lst = [f"mcrf {src}, {dst}"]
65 cr = random.randint(0, (1 << 32)-1)
66 self.add_case(Program(lst, bigendian), initial_cr=cr)
67
68 def cse_0_mcrf(self):
69 for i in range(8):
70 lst = [f"mcrf 5, {i}"]
71 cr = 0xfeff0001
72 self.add_case(Program(lst, bigendian), initial_cr=cr)
73
74 def case_mtcrf(self):
75 for i in range(1):
76 mask = random.randint(0, 255)
77 lst = [f"mtcrf {mask}, 2"]
78 cr = random.randint(0, (1 << 32)-1)
79 initial_regs = [0] * 32
80 initial_regs[2] = random.randint(0, (1 << 32)-1)
81 self.add_case(Program(lst, bigendian), initial_regs=initial_regs,
82 initial_cr=cr)
83
84 def case_mtocrf(self):
85 for i in range(20):
86 mask = 1 << random.randint(0, 7)
87 lst = [f"mtocrf {mask}, 2"]
88 cr = random.randint(0, (1 << 32)-1)
89 initial_regs = [0] * 32
90 initial_regs[2] = random.randint(0, (1 << 32)-1)
91 self.add_case(Program(lst, bigendian), initial_regs=initial_regs,
92 initial_cr=cr)
93
94 def cse_mfcr(self):
95 for i in range(1):
96 lst = ["mfcr 2"]
97 cr = random.randint(0, (1 << 32)-1)
98 self.add_case(Program(lst, bigendian), initial_cr=cr)
99
100 def case_mfocrf(self):
101 for i in range(1):
102 mask = 1 << random.randint(0, 7)
103 lst = [f"mfocrf 2, {mask}"]
104 cr = random.randint(0, (1 << 32)-1)
105 self.add_case(Program(lst, bigendian), initial_cr=cr)
106
107 def cse_isel(self):
108 for i in range(20):
109 bc = random.randint(0, 31)
110 lst = [f"isel 1, 2, 3, {bc}"]
111 cr = random.randint(0, (1 << 64)-1)
112 initial_regs = [0] * 32
113 initial_regs[2] = random.randint(0, (1 << 64)-1)
114 initial_regs[3] = random.randint(0, (1 << 64)-1)
115 #initial_regs[2] = i*2
116 #initial_regs[3] = i*2+1
117 self.add_case(Program(lst, bigendian),
118 initial_regs=initial_regs, initial_cr=cr)
119
120 def cse_setb(self):
121 for i in range(20):
122 bfa = random.randint(0, 7)
123 lst = [f"setb 1, {bfa}"]
124 cr = random.randint(0, (1 << 32)-1)
125 self.add_case(Program(lst, bigendian), initial_cr=cr)
126
127 def cse_regression_setb(self):
128 lst = [f"setb 1, 6"]
129 cr = random.randint(0, 0x66f6b106)
130 self.add_case(Program(lst, bigendian), initial_cr=cr)
131
132 def cse_ilang(self):
133 pspec = CRPipeSpec(id_wid=2)
134 alu = CRBasePipe(pspec)
135 vl = rtlil.convert(alu, ports=alu.ports())
136 with open("cr_pipeline.il", "w") as f:
137 f.write(vl)
138
139
140 def get_cu_inputs(dec2, sim):
141 """naming (res) must conform to CRFunctionUnit input regspec
142 """
143 res = {}
144 full_reg = yield dec2.e.do.read_cr_whole.data
145 full_reg_ok = yield dec2.e.do.read_cr_whole.ok
146 full_cr_mask = mask_extend(full_reg, 8, 4)
147
148 # full CR
149 print(sim.cr.get_range().value)
150 if full_reg_ok:
151 res['full_cr'] = sim.cr.get_range().value & full_cr_mask
152 else:
153 # CR A
154 cr1_en = yield dec2.e.read_cr1.ok
155 if cr1_en:
156 cr1_sel = yield dec2.e.read_cr1.data
157 res['cr_a'] = sim.crl[cr1_sel].get_range().value
158 cr2_en = yield dec2.e.read_cr2.ok
159 # CR B
160 if cr2_en:
161 cr2_sel = yield dec2.e.read_cr2.data
162 res['cr_b'] = sim.crl[cr2_sel].get_range().value
163 cr3_en = yield dec2.e.read_cr3.ok
164 # CR C
165 if cr3_en:
166 cr3_sel = yield dec2.e.read_cr3.data
167 res['cr_c'] = sim.crl[cr3_sel].get_range().value
168
169 # RA/RC
170 reg1_ok = yield dec2.e.read_reg1.ok
171 if reg1_ok:
172 data1 = yield dec2.e.read_reg1.data
173 res['ra'] = sim.gpr(data1).value
174
175 # RB (or immediate)
176 reg2_ok = yield dec2.e.read_reg2.ok
177 if reg2_ok:
178 data2 = yield dec2.e.read_reg2.data
179 res['rb'] = sim.gpr(data2).value
180
181 print("get inputs", res)
182 return res
183
184
185 class TestRunner(unittest.TestCase):
186 def __init__(self, test_data):
187 super().__init__("run_all")
188 self.test_data = test_data
189
190 def set_inputs(self, alu, dec2, simulator):
191 inp = yield from get_cu_inputs(dec2, simulator)
192 yield from ALUHelpers.set_full_cr(alu, dec2, inp)
193 yield from ALUHelpers.set_cr_a(alu, dec2, inp)
194 yield from ALUHelpers.set_cr_b(alu, dec2, inp)
195 yield from ALUHelpers.set_cr_c(alu, dec2, inp)
196 yield from ALUHelpers.set_int_ra(alu, dec2, inp)
197 yield from ALUHelpers.set_int_rb(alu, dec2, inp)
198
199 def assert_outputs(self, alu, dec2, simulator, code):
200 whole_reg_ok = yield dec2.e.do.write_cr_whole.ok
201 whole_reg_data = yield dec2.e.do.write_cr_whole.data
202 full_cr_mask = mask_extend(whole_reg_data, 8, 4)
203
204 cr_en = yield dec2.e.write_cr.ok
205 if whole_reg_ok:
206 full_cr = yield alu.n.data_o.full_cr.data & full_cr_mask
207 expected_cr = simulator.cr.get_range().value
208 print("CR whole: expected %x, actual: %x mask: %x" % \
209 (expected_cr, full_cr, full_cr_mask))
210 # HACK: only look at the bits that we expected to change
211 self.assertEqual(expected_cr & full_cr_mask, full_cr, code)
212 elif cr_en:
213 cr_sel = yield dec2.e.write_cr.data
214 expected_cr = simulator.cr.get_range().value
215 print(f"CR whole: {expected_cr:x}, sel {cr_sel}")
216 expected_cr = simulator.crl[cr_sel].get_range().value
217 real_cr = yield alu.n.data_o.cr.data
218 print(f"CR part: expected {expected_cr:x}, actual: {real_cr:x}")
219 self.assertEqual(expected_cr, real_cr, code)
220 alu_out = yield alu.n.data_o.o.data
221 out_reg_valid = yield dec2.e.write_reg.ok
222 if out_reg_valid:
223 write_reg_idx = yield dec2.e.write_reg.data
224 expected = simulator.gpr(write_reg_idx).value
225 print(f"expected {expected:x}, actual: {alu_out:x}")
226 self.assertEqual(expected, alu_out, code)
227
228 def execute(self, alu, instruction, pdecode2, test):
229 program = test.program
230 sim = ISA(pdecode2, test.regs, test.sprs, test.cr, test.mem,
231 test.msr,
232 bigendian=bigendian)
233 gen = program.generate_instructions()
234 instructions = list(zip(gen, program.assembly.splitlines()))
235
236 index = sim.pc.CIA.value//4
237 while index < len(instructions):
238 ins, code = instructions[index]
239
240 print("0x{:X}".format(ins & 0xffffffff))
241 print(code)
242
243 # ask the decoder to decode this binary data (endian'd)
244 yield pdecode2.dec.bigendian.eq(bigendian) # little / big?
245 yield instruction.eq(ins) # raw binary instr.
246 yield Settle()
247 yield from self.set_inputs(alu, pdecode2, sim)
248 yield alu.p.valid_i.eq(1)
249 fn_unit = yield pdecode2.e.do.fn_unit
250 self.assertEqual(fn_unit, Function.CR.value, code)
251 yield
252 opname = code.split(' ')[0]
253 yield from sim.call(opname)
254 index = sim.pc.CIA.value//4
255
256 vld = yield alu.n.valid_o
257 while not vld:
258 yield
259 vld = yield alu.n.valid_o
260 yield
261 yield from self.assert_outputs(alu, pdecode2, sim, code)
262
263 def run_all(self):
264 m = Module()
265 comb = m.d.comb
266 instruction = Signal(32)
267
268 pdecode = create_pdecode()
269
270 m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode)
271
272 pspec = CRPipeSpec(id_wid=2)
273 m.submodules.alu = alu = CRBasePipe(pspec)
274
275 comb += alu.p.data_i.ctx.op.eq_from_execute1(pdecode2.e)
276 comb += alu.n.ready_i.eq(1)
277 comb += pdecode2.dec.raw_opcode_in.eq(instruction)
278 sim = Simulator(m)
279
280 sim.add_clock(1e-6)
281
282 def process():
283 for test in self.test_data:
284 print(test.name)
285 with self.subTest(test.name):
286 yield from self.execute(alu, instruction, pdecode2, test)
287
288 sim.add_sync_process(process)
289 with sim.write_vcd("cr_simulator.vcd"):
290 sim.run()
291
292
293 if __name__ == "__main__":
294 unittest.main(exit=False)
295 suite = unittest.TestSuite()
296 suite.addTest(TestRunner(CRTestCase().test_data))
297
298 runner = unittest.TextTestRunner()
299 runner.run(suite)