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