skip Decode2ToOperand from PowerDecodeSubset
[soc.git] / src / soc / fu / trap / test / test_pipe_caller.py
1 from nmigen import Module, Signal
2
3 # NOTE: to use cxxsim, export NMIGEN_SIM_MODE=cxxsim from the shell
4 # Also, check out the cxxsim nmigen branch, and latest yosys from git
5 from nmutil.sim_tmp_alternative import Simulator, Settle
6
7 from nmutil.formaltest import FHDLTestCase
8 from nmigen.cli import rtlil
9 import unittest
10 from soc.decoder.isa.caller import ISACaller, special_sprs
11 from soc.decoder.power_decoder import (create_pdecode)
12 from soc.decoder.power_decoder2 import (PowerDecode2)
13 from soc.decoder.power_enums import (XER_bits, Function, MicrOp, CryIn)
14 from soc.decoder.selectable_int import SelectableInt
15 from soc.simulator.program import Program
16 from soc.decoder.isa.all import ISA
17 from soc.config.endian import bigendian
18 from soc.consts import MSR
19
20 from soc.fu.test.common import (TestAccumulatorBase, TestCase, ALUHelpers)
21 from soc.fu.trap.pipeline import TrapBasePipe
22 from soc.fu.trap.pipe_data import TrapPipeSpec
23 import random
24
25
26 def get_cu_inputs(dec2, sim):
27 """naming (res) must conform to TrapFunctionUnit input regspec
28 """
29 res = {}
30
31 yield from ALUHelpers.get_sim_int_ra(res, sim, dec2) # RA
32 yield from ALUHelpers.get_sim_int_rb(res, sim, dec2) # RB
33 yield from ALUHelpers.get_sim_fast_spr1(res, sim, dec2) # SPR1
34 yield from ALUHelpers.get_sim_fast_spr2(res, sim, dec2) # SPR2
35 ALUHelpers.get_sim_cia(res, sim, dec2) # PC
36 ALUHelpers.get_sim_msr(res, sim, dec2) # MSR
37
38 print("alu get_cu_inputs", res)
39
40 return res
41
42
43 def set_alu_inputs(alu, dec2, sim):
44 # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43
45 # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok))
46 # and place it into data_i.b
47
48 inp = yield from get_cu_inputs(dec2, sim)
49 yield from ALUHelpers.set_int_ra(alu, dec2, inp)
50 yield from ALUHelpers.set_int_rb(alu, dec2, inp)
51 yield from ALUHelpers.set_fast_spr1(alu, dec2, inp) # SPR1
52 yield from ALUHelpers.set_fast_spr2(alu, dec2, inp) # SPR1
53
54 # yield from ALUHelpers.set_cia(alu, dec2, inp)
55 # yield from ALUHelpers.set_msr(alu, dec2, inp)
56 return inp
57
58 # This test bench is a bit different than is usual. Initially when I
59 # was writing it, I had all of the tests call a function to create a
60 # device under test and simulator, initialize the dut, run the
61 # simulation for ~2 cycles, and assert that the dut output what it
62 # should have. However, this was really slow, since it needed to
63 # create and tear down the dut and simulator for every test case.
64
65 # Now, instead of doing that, every test case in TrapTestCase puts some
66 # data into the test_data list below, describing the instructions to
67 # be tested and the initial state. Once all the tests have been run,
68 # test_data gets passed to TestRunner which then sets up the DUT and
69 # simulator once, runs all the data through it, and asserts that the
70 # results match the pseudocode sim at every cycle.
71
72 # By doing this, I've reduced the time it takes to run the test suite
73 # massively. Before, it took around 1 minute on my computer, now it
74 # takes around 3 seconds
75
76
77 class TrapTestCase(TestAccumulatorBase):
78
79 def case_0_hrfid(self):
80 lst = ["hrfid"]
81 initial_regs = [0] * 32
82 initial_regs[1] = 1
83 initial_sprs = {'HSRR0': 0x12345678, 'HSRR1': 0x5678}
84 self.add_case(Program(lst, bigendian),
85 initial_regs, initial_sprs)
86
87 def case_1_rfid(self):
88 lst = ["rfid"]
89 initial_regs = [0] * 32
90 initial_regs[1] = 1
91 initial_sprs = {'SRR0': 0x12345678, 'SRR1': 0x5678}
92 self.add_case(Program(lst, bigendian),
93 initial_regs, initial_sprs)
94
95 def case_0_trap_eq_imm(self):
96 insns = ["twi", "tdi"]
97 for i in range(2):
98 choice = random.choice(insns)
99 lst = [f"{choice} 4, 1, %d" % i] # TO=4: trap equal
100 initial_regs = [0] * 32
101 initial_regs[1] = 1
102 self.add_case(Program(lst, bigendian), initial_regs)
103
104 def case_0_trap_eq(self):
105 insns = ["tw", "td"]
106 for i in range(2):
107 choice = insns[i]
108 lst = [f"{choice} 4, 1, 2"] # TO=4: trap equal
109 initial_regs = [0] * 32
110 initial_regs[1] = 1
111 initial_regs[2] = 1
112 self.add_case(Program(lst, bigendian), initial_regs)
113
114 def case_3_mtmsr_0(self):
115 lst = ["mtmsr 1,0"]
116 initial_regs = [0] * 32
117 initial_regs[1] = 0xffffffffffffffff
118 self.add_case(Program(lst, bigendian), initial_regs)
119
120 def case_3_mtmsr_1(self):
121 lst = ["mtmsr 1,1"]
122 initial_regs = [0] * 32
123 initial_regs[1] = 0xffffffffffffffff
124 self.add_case(Program(lst, bigendian), initial_regs)
125
126 def case_4_mtmsrd_0(self):
127 lst = ["mtmsrd 1,0"]
128 initial_regs = [0] * 32
129 initial_regs[1] = 0xffffffffffffffff
130 self.add_case(Program(lst, bigendian), initial_regs)
131
132 def case_5_mtmsrd_1(self):
133 lst = ["mtmsrd 1,1"]
134 initial_regs = [0] * 32
135 initial_regs[1] = 0xffffffffffffffff
136 self.add_case(Program(lst, bigendian), initial_regs)
137
138 def case_6_mtmsr_priv_0(self):
139 lst = ["mtmsr 1,0"]
140 initial_regs = [0] * 32
141 initial_regs[1] = 0xffffffffffffffff
142 msr = 1 << MSR.PR # set in "problem state"
143 self.add_case(Program(lst, bigendian), initial_regs,
144 initial_msr=msr)
145
146 def case_7_rfid_priv_0(self):
147 lst = ["rfid"]
148 initial_regs = [0] * 32
149 initial_regs[1] = 1
150 initial_sprs = {'SRR0': 0x12345678, 'SRR1': 0x5678}
151 msr = 1 << MSR.PR # set in "problem state"
152 self.add_case(Program(lst, bigendian),
153 initial_regs, initial_sprs,
154 initial_msr=msr)
155
156 def case_8_mfmsr(self):
157 lst = ["mfmsr 1"]
158 initial_regs = [0] * 32
159 msr = (~(1 << MSR.PR)) & 0xffffffffffffffff
160 self.add_case(Program(lst, bigendian), initial_regs,
161 initial_msr=msr)
162
163 def case_9_mfmsr_priv(self):
164 lst = ["mfmsr 1"]
165 initial_regs = [0] * 32
166 msr = 1 << MSR.PR # set in "problem state"
167 self.add_case(Program(lst, bigendian), initial_regs,
168 initial_msr=msr)
169
170 def case_999_illegal(self):
171 # ok, um this is a bit of a cheat: use an instruction we know
172 # is not implemented by either ISACaller or the core
173 lst = ["tbegin.",
174 "mtmsr 1,1"] # should not get executed
175 initial_regs = [0] * 32
176 self.add_case(Program(lst, bigendian), initial_regs)
177
178 def case_ilang(self):
179 pspec = TrapPipeSpec(id_wid=2)
180 alu = TrapBasePipe(pspec)
181 vl = rtlil.convert(alu, ports=alu.ports())
182 with open("trap_pipeline.il", "w") as f:
183 f.write(vl)
184
185
186 class TestRunner(unittest.TestCase):
187 def __init__(self, test_data):
188 super().__init__("run_all")
189 self.test_data = test_data
190
191 def run_all(self):
192 m = Module()
193 comb = m.d.comb
194 instruction = Signal(32)
195
196 pdecode = create_pdecode()
197
198 m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode)
199
200 pspec = TrapPipeSpec(id_wid=2)
201 m.submodules.alu = alu = TrapBasePipe(pspec)
202
203 comb += alu.p.data_i.ctx.op.eq_from_execute1(pdecode2.do)
204 comb += alu.p.valid_i.eq(1)
205 comb += alu.n.ready_i.eq(1)
206 comb += pdecode2.dec.raw_opcode_in.eq(instruction)
207 sim = Simulator(m)
208
209 sim.add_clock(1e-6)
210
211 def process():
212 for test in self.test_data:
213 print(test.name)
214 program = test.program
215 self.subTest(test.name)
216 sim = ISA(pdecode2, test.regs, test.sprs, test.cr,
217 test.mem, test.msr,
218 bigendian=bigendian)
219 gen = program.generate_instructions()
220 instructions = list(zip(gen, program.assembly.splitlines()))
221
222 msr = sim.msr.value
223 pc = sim.pc.CIA.value
224 print("starting msr, pc %08x, %08x" % (msr, pc))
225 index = pc//4
226 while index < len(instructions):
227 ins, code = instructions[index]
228
229 print("pc %08x msr %08x instr: %08x" % (pc, msr, ins))
230 print(code)
231 if 'XER' in sim.spr:
232 so = 1 if sim.spr['XER'][XER_bits['SO']] else 0
233 ov = 1 if sim.spr['XER'][XER_bits['OV']] else 0
234 ov32 = 1 if sim.spr['XER'][XER_bits['OV32']] else 0
235 print("before: so/ov/32", so, ov, ov32)
236
237 # ask the decoder to decode this binary data (endian'd)
238 yield pdecode2.dec.bigendian.eq(bigendian) # little / big?
239 yield pdecode2.state.msr.eq(msr) # set MSR in pdecode2
240 yield pdecode2.state.pc.eq(pc) # set CIA in pdecode2
241 yield instruction.eq(ins) # raw binary instr.
242 yield Settle()
243 fn_unit = yield pdecode2.e.do.fn_unit
244 self.assertEqual(fn_unit, Function.TRAP.value)
245 alu_o = yield from set_alu_inputs(alu, pdecode2, sim)
246 yield
247 opname = code.split(' ')[0]
248 yield from sim.call(opname)
249 pc = sim.pc.CIA.value
250 index = pc//4
251 print("pc after %08x" % (pc))
252 msr = sim.msr.value
253 print("msr after %08x" % (msr))
254
255 vld = yield alu.n.valid_o
256 while not vld:
257 yield
258 vld = yield alu.n.valid_o
259 yield
260
261 yield from self.check_alu_outputs(alu, pdecode2, sim, code)
262
263 sim.add_sync_process(process)
264 with sim.write_vcd("alu_simulator.vcd", "simulator.gtkw",
265 traces=[]):
266 sim.run()
267
268 def check_alu_outputs(self, alu, dec2, sim, code):
269
270 rc = yield dec2.e.do.rc.data
271 cridx_ok = yield dec2.e.write_cr.ok
272 cridx = yield dec2.e.write_cr.data
273
274 print("check extra output", repr(code), cridx_ok, cridx)
275 if rc:
276 self.assertEqual(cridx, 0, code)
277
278 sim_o = {}
279 res = {}
280
281 yield from ALUHelpers.get_int_o(res, alu, dec2)
282 yield from ALUHelpers.get_fast_spr1(res, alu, dec2)
283 yield from ALUHelpers.get_fast_spr2(res, alu, dec2)
284 yield from ALUHelpers.get_nia(res, alu, dec2)
285 yield from ALUHelpers.get_msr(res, alu, dec2)
286
287 print("output", res)
288
289 yield from ALUHelpers.get_sim_int_o(sim_o, sim, dec2)
290 yield from ALUHelpers.get_wr_fast_spr1(sim_o, sim, dec2)
291 yield from ALUHelpers.get_wr_fast_spr2(sim_o, sim, dec2)
292 ALUHelpers.get_sim_nia(sim_o, sim, dec2)
293 ALUHelpers.get_sim_msr(sim_o, sim, dec2)
294
295 print("sim output", sim_o)
296
297 ALUHelpers.check_int_o(self, res, sim_o, code)
298 ALUHelpers.check_fast_spr1(self, res, sim_o, code)
299 ALUHelpers.check_fast_spr2(self, res, sim_o, code)
300 ALUHelpers.check_nia(self, res, sim_o, code)
301 ALUHelpers.check_msr(self, res, sim_o, code)
302
303
304 if __name__ == "__main__":
305 unittest.main(exit=False)
306 suite = unittest.TestSuite()
307 suite.addTest(TestRunner(TrapTestCase().test_data))
308
309 runner = unittest.TextTestRunner()
310 runner.run(suite)