hrfid unit test sets up HSRR0 and HSRR1
[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_0_hrfid(self):
76 lst = ["hrfid"]
77 initial_regs = [0] * 32
78 initial_regs[1] = 1
79 initial_sprs = {'HSRR0': 0x12345678, 'HSRR1': 0x5678}
80 self.add_case(Program(lst, bigendian),
81 initial_regs, initial_sprs)
82
83 def case_1_rfid(self):
84 lst = ["rfid"]
85 initial_regs = [0] * 32
86 initial_regs[1] = 1
87 initial_sprs = {'SRR0': 0x12345678, 'SRR1': 0x5678}
88 self.add_case(Program(lst, bigendian),
89 initial_regs, initial_sprs)
90
91 def case_0_trap_eq_imm(self):
92 insns = ["twi", "tdi"]
93 for i in range(2):
94 choice = random.choice(insns)
95 lst = [f"{choice} 4, 1, %d" % i] # TO=4: trap equal
96 initial_regs = [0] * 32
97 initial_regs[1] = 1
98 self.add_case(Program(lst, bigendian), initial_regs)
99
100 def case_0_trap_eq(self):
101 insns = ["tw", "td"]
102 for i in range(2):
103 choice = insns[i]
104 lst = [f"{choice} 4, 1, 2"] # TO=4: trap equal
105 initial_regs = [0] * 32
106 initial_regs[1] = 1
107 initial_regs[2] = 1
108 self.add_case(Program(lst, bigendian), initial_regs)
109
110 def case_3_mtmsr_0(self):
111 lst = ["mtmsr 1,0"]
112 initial_regs = [0] * 32
113 initial_regs[1] = 0xffffffffffffffff
114 self.add_case(Program(lst, bigendian), initial_regs)
115
116 def case_3_mtmsr_1(self):
117 lst = ["mtmsr 1,1"]
118 initial_regs = [0] * 32
119 initial_regs[1] = 0xffffffffffffffff
120 self.add_case(Program(lst, bigendian), initial_regs)
121
122 def case_4_mtmsrd_0(self):
123 lst = ["mtmsrd 1,0"]
124 initial_regs = [0] * 32
125 initial_regs[1] = 0xffffffffffffffff
126 self.add_case(Program(lst, bigendian), initial_regs)
127
128 def case_5_mtmsrd_1(self):
129 lst = ["mtmsrd 1,1"]
130 initial_regs = [0] * 32
131 initial_regs[1] = 0xffffffffffffffff
132 self.add_case(Program(lst, bigendian), initial_regs)
133
134 def case_6_mtmsr_priv_0(self):
135 lst = ["mtmsr 1,0"]
136 initial_regs = [0] * 32
137 initial_regs[1] = 0xffffffffffffffff
138 msr = 1 << MSR.PR # set in "problem state"
139 self.add_case(Program(lst, bigendian), initial_regs,
140 initial_msr=msr)
141
142 def case_7_rfid_priv_0(self):
143 lst = ["rfid"]
144 initial_regs = [0] * 32
145 initial_regs[1] = 1
146 initial_sprs = {'SRR0': 0x12345678, 'SRR1': 0x5678}
147 msr = 1 << MSR.PR # set in "problem state"
148 self.add_case(Program(lst, bigendian),
149 initial_regs, initial_sprs,
150 initial_msr=msr)
151
152 def case_8_mfmsr(self):
153 lst = ["mfmsr 1"]
154 initial_regs = [0] * 32
155 msr = (~(1 << MSR.PR)) & 0xffffffffffffffff
156 self.add_case(Program(lst, bigendian), initial_regs,
157 initial_msr=msr)
158
159 def case_9_mfmsr_priv(self):
160 lst = ["mfmsr 1"]
161 initial_regs = [0] * 32
162 msr = 1 << MSR.PR # set in "problem state"
163 self.add_case(Program(lst, bigendian), initial_regs,
164 initial_msr=msr)
165
166 def case_999_illegal(self):
167 # ok, um this is a bit of a cheat: use an instruction we know
168 # is not implemented by either ISACaller or the core
169 lst = ["tbegin.",
170 "mtmsr 1,1"] # should not get executed
171 initial_regs = [0] * 32
172 self.add_case(Program(lst, bigendian), initial_regs)
173
174 def case_ilang(self):
175 pspec = TrapPipeSpec(id_wid=2)
176 alu = TrapBasePipe(pspec)
177 vl = rtlil.convert(alu, ports=alu.ports())
178 with open("trap_pipeline.il", "w") as f:
179 f.write(vl)
180
181
182 class TestRunner(unittest.TestCase):
183 def __init__(self, test_data):
184 super().__init__("run_all")
185 self.test_data = test_data
186
187 def run_all(self):
188 m = Module()
189 comb = m.d.comb
190 instruction = Signal(32)
191
192 pdecode = create_pdecode()
193
194 m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode)
195
196 pspec = TrapPipeSpec(id_wid=2)
197 m.submodules.alu = alu = TrapBasePipe(pspec)
198
199 comb += alu.p.data_i.ctx.op.eq_from_execute1(pdecode2.e)
200 comb += alu.p.valid_i.eq(1)
201 comb += alu.n.ready_i.eq(1)
202 comb += pdecode2.dec.raw_opcode_in.eq(instruction)
203 sim = Simulator(m)
204
205 sim.add_clock(1e-6)
206
207 def process():
208 for test in self.test_data:
209 print(test.name)
210 program = test.program
211 self.subTest(test.name)
212 sim = ISA(pdecode2, test.regs, test.sprs, test.cr,
213 test.mem, test.msr,
214 bigendian=bigendian)
215 gen = program.generate_instructions()
216 instructions = list(zip(gen, program.assembly.splitlines()))
217
218 msr = sim.msr.value
219 pc = sim.pc.CIA.value
220 print("starting msr, pc %08x, %08x" % (msr, pc))
221 index = pc//4
222 while index < len(instructions):
223 ins, code = instructions[index]
224
225 print("pc %08x msr %08x instr: %08x" % (pc, msr, ins))
226 print(code)
227 if 'XER' in sim.spr:
228 so = 1 if sim.spr['XER'][XER_bits['SO']] else 0
229 ov = 1 if sim.spr['XER'][XER_bits['OV']] else 0
230 ov32 = 1 if sim.spr['XER'][XER_bits['OV32']] else 0
231 print("before: so/ov/32", so, ov, ov32)
232
233 # ask the decoder to decode this binary data (endian'd)
234 yield pdecode2.dec.bigendian.eq(bigendian) # little / big?
235 yield pdecode2.state.msr.eq(msr) # set MSR in pdecode2
236 yield pdecode2.state.pc.eq(pc) # set CIA in pdecode2
237 yield instruction.eq(ins) # raw binary instr.
238 yield Settle()
239 fn_unit = yield pdecode2.e.do.fn_unit
240 self.assertEqual(fn_unit, Function.TRAP.value)
241 alu_o = yield from set_alu_inputs(alu, pdecode2, sim)
242 yield
243 opname = code.split(' ')[0]
244 yield from sim.call(opname)
245 pc = sim.pc.CIA.value
246 index = pc//4
247 print("pc after %08x" % (pc))
248 msr = sim.msr.value
249 print("msr after %08x" % (msr))
250
251 vld = yield alu.n.valid_o
252 while not vld:
253 yield
254 vld = yield alu.n.valid_o
255 yield
256
257 yield from self.check_alu_outputs(alu, pdecode2, sim, code)
258
259 sim.add_sync_process(process)
260 with sim.write_vcd("alu_simulator.vcd", "simulator.gtkw",
261 traces=[]):
262 sim.run()
263
264 def check_alu_outputs(self, alu, dec2, sim, code):
265
266 rc = yield dec2.e.do.rc.data
267 cridx_ok = yield dec2.e.write_cr.ok
268 cridx = yield dec2.e.write_cr.data
269
270 print("check extra output", repr(code), cridx_ok, cridx)
271 if rc:
272 self.assertEqual(cridx, 0, code)
273
274 sim_o = {}
275 res = {}
276
277 yield from ALUHelpers.get_int_o(res, alu, dec2)
278 yield from ALUHelpers.get_fast_spr1(res, alu, dec2)
279 yield from ALUHelpers.get_fast_spr2(res, alu, dec2)
280 yield from ALUHelpers.get_nia(res, alu, dec2)
281 yield from ALUHelpers.get_msr(res, alu, dec2)
282
283 print("output", res)
284
285 yield from ALUHelpers.get_sim_int_o(sim_o, sim, dec2)
286 yield from ALUHelpers.get_wr_fast_spr1(sim_o, sim, dec2)
287 yield from ALUHelpers.get_wr_fast_spr2(sim_o, sim, dec2)
288 ALUHelpers.get_sim_nia(sim_o, sim, dec2)
289 ALUHelpers.get_sim_msr(sim_o, sim, dec2)
290
291 print("sim output", sim_o)
292
293 ALUHelpers.check_int_o(self, res, sim_o, code)
294 ALUHelpers.check_fast_spr1(self, res, sim_o, code)
295 ALUHelpers.check_fast_spr2(self, res, sim_o, code)
296 ALUHelpers.check_nia(self, res, sim_o, code)
297 ALUHelpers.check_msr(self, res, sim_o, code)
298
299
300 if __name__ == "__main__":
301 unittest.main(exit=False)
302 suite = unittest.TestSuite()
303 suite.addTest(TestRunner(TrapTestCase().test_data))
304
305 runner = unittest.TextTestRunner()
306 runner.run(suite)