adding MSR.PR unit test intended to activate privileged trap
[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 (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
40 def set_alu_inputs(alu, dec2, sim):
41 # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43
42 # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok))
43 # and place it into data_i.b
44
45 inp = yield from get_cu_inputs(dec2, sim)
46 yield from ALUHelpers.set_int_ra(alu, dec2, inp)
47 yield from ALUHelpers.set_int_rb(alu, dec2, inp)
48 yield from ALUHelpers.set_fast_spr1(alu, dec2, inp) # SPR1
49 yield from ALUHelpers.set_fast_spr2(alu, dec2, inp) # SPR1
50
51 yield from ALUHelpers.set_cia(alu, dec2, inp)
52 yield from ALUHelpers.set_msr(alu, dec2, inp)
53
54
55 # This test bench is a bit different than is usual. Initially when I
56 # was writing it, I had all of the tests call a function to create a
57 # device under test and simulator, initialize the dut, run the
58 # simulation for ~2 cycles, and assert that the dut output what it
59 # should have. However, this was really slow, since it needed to
60 # create and tear down the dut and simulator for every test case.
61
62 # Now, instead of doing that, every test case in TrapTestCase puts some
63 # data into the test_data list below, describing the instructions to
64 # be tested and the initial state. Once all the tests have been run,
65 # test_data gets passed to TestRunner which then sets up the DUT and
66 # simulator once, runs all the data through it, and asserts that the
67 # results match the pseudocode sim at every cycle.
68
69 # By doing this, I've reduced the time it takes to run the test suite
70 # massively. Before, it took around 1 minute on my computer, now it
71 # takes around 3 seconds
72
73
74 class TrapTestCase(FHDLTestCase):
75 test_data = []
76
77 def __init__(self, name):
78 super().__init__(name)
79 self.test_name = name
80
81 def run_tst_program(self, prog, initial_regs=None, initial_sprs=None,
82 initial_msr=0):
83 tc = TestCase(prog, self.test_name, initial_regs, initial_sprs,
84 msr=initial_msr)
85 self.test_data.append(tc)
86
87 def test_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.run_tst_program(Program(lst, bigendian),
93 initial_regs, initial_sprs)
94
95 def test_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.run_tst_program(Program(lst, bigendian), initial_regs)
103
104 def test_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.run_tst_program(Program(lst, bigendian), initial_regs)
113
114
115 def test_3_mtmsr_0(self):
116 lst = ["mtmsr 1,0"]
117 initial_regs = [0] * 32
118 initial_regs[1] = 0xffffffffffffffff
119 self.run_tst_program(Program(lst, bigendian), initial_regs)
120
121 def test_3_mtmsr_1(self):
122 lst = ["mtmsr 1,1"]
123 initial_regs = [0] * 32
124 initial_regs[1] = 0xffffffffffffffff
125 self.run_tst_program(Program(lst, bigendian), initial_regs)
126
127 def test_4_mtmsrd_0(self):
128 lst = ["mtmsrd 1,0"]
129 initial_regs = [0] * 32
130 initial_regs[1] = 0xffffffffffffffff
131 self.run_tst_program(Program(lst, bigendian), initial_regs)
132
133 def test_5_mtmsrd_1(self):
134 lst = ["mtmsrd 1,1"]
135 initial_regs = [0] * 32
136 initial_regs[1] = 0xffffffffffffffff
137 self.run_tst_program(Program(lst, bigendian), initial_regs)
138
139 def test_6_mtmsr_priv_0(self):
140 lst = ["mtmsr 1,0"]
141 initial_regs = [0] * 32
142 initial_regs[1] = 0xffffffffffffffff
143 msr = 63-MSR.PR # set in "problem state"
144 self.run_tst_program(Program(lst, bigendian), initial_regs,
145 initial_msr=msr)
146 def test_999_illegal(self):
147 # ok, um this is a bit of a cheat: use an instruction we know
148 # is not implemented by either ISACaller or the core
149 lst = ["tbegin.",
150 "mtmsr 1,1"] # should not get executed
151 initial_regs = [0] * 32
152 self.run_tst_program(Program(lst, bigendian), initial_regs)
153
154 def test_ilang(self):
155 pspec = TrapPipeSpec(id_wid=2)
156 alu = TrapBasePipe(pspec)
157 vl = rtlil.convert(alu, ports=alu.ports())
158 with open("trap_pipeline.il", "w") as f:
159 f.write(vl)
160
161
162 class TestRunner(FHDLTestCase):
163 def __init__(self, test_data):
164 super().__init__("run_all")
165 self.test_data = test_data
166
167 def run_all(self):
168 m = Module()
169 comb = m.d.comb
170 instruction = Signal(32)
171
172 pdecode = create_pdecode()
173
174 m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode)
175
176 pspec = TrapPipeSpec(id_wid=2)
177 m.submodules.alu = alu = TrapBasePipe(pspec)
178
179 comb += alu.p.data_i.ctx.op.eq_from_execute1(pdecode2.e)
180 comb += alu.p.valid_i.eq(1)
181 comb += alu.n.ready_i.eq(1)
182 comb += pdecode2.dec.raw_opcode_in.eq(instruction)
183 sim = Simulator(m)
184
185 sim.add_clock(1e-6)
186 def process():
187 for test in self.test_data:
188 print(test.name)
189 program = test.program
190 self.subTest(test.name)
191 sim = ISA(pdecode2, test.regs, test.sprs, test.cr,
192 test.mem, test.msr,
193 bigendian=bigendian)
194 gen = program.generate_instructions()
195 instructions = list(zip(gen, program.assembly.splitlines()))
196
197 pc = sim.pc.CIA.value
198 index = pc//4
199 while index < len(instructions):
200 ins, code = instructions[index]
201
202 print("pc %08x instr: %08x" % (pc, ins & 0xffffffff))
203 print(code)
204 if 'XER' in sim.spr:
205 so = 1 if sim.spr['XER'][XER_bits['SO']] else 0
206 ov = 1 if sim.spr['XER'][XER_bits['OV']] else 0
207 ov32 = 1 if sim.spr['XER'][XER_bits['OV32']] else 0
208 print ("before: so/ov/32", so, ov, ov32)
209
210 # ask the decoder to decode this binary data (endian'd)
211 yield pdecode2.dec.bigendian.eq(bigendian) # little / big?
212 yield instruction.eq(ins) # raw binary instr.
213 yield Settle()
214 fn_unit = yield pdecode2.e.do.fn_unit
215 self.assertEqual(fn_unit, Function.TRAP.value)
216 yield from set_alu_inputs(alu, pdecode2, sim)
217 yield
218 opname = code.split(' ')[0]
219 yield from sim.call(opname)
220 pc = sim.pc.CIA.value
221 index = pc//4
222 print("pc after %08x" % (pc))
223
224 vld = yield alu.n.valid_o
225 while not vld:
226 yield
227 vld = yield alu.n.valid_o
228 yield
229
230 yield from self.check_alu_outputs(alu, pdecode2, sim, code)
231
232 sim.add_sync_process(process)
233 with sim.write_vcd("alu_simulator.vcd", "simulator.gtkw",
234 traces=[]):
235 sim.run()
236
237 def check_alu_outputs(self, alu, dec2, sim, code):
238
239 rc = yield dec2.e.do.rc.data
240 cridx_ok = yield dec2.e.write_cr.ok
241 cridx = yield dec2.e.write_cr.data
242
243 print ("check extra output", repr(code), cridx_ok, cridx)
244 if rc:
245 self.assertEqual(cridx, 0, code)
246
247 sim_o = {}
248 res = {}
249
250 yield from ALUHelpers.get_int_o(res, alu, dec2)
251 yield from ALUHelpers.get_fast_spr1(res, alu, dec2)
252 yield from ALUHelpers.get_fast_spr2(res, alu, dec2)
253 yield from ALUHelpers.get_nia(res, alu, dec2)
254 yield from ALUHelpers.get_msr(res, alu, dec2)
255
256 print ("output", res)
257
258 yield from ALUHelpers.get_sim_int_o(sim_o, sim, dec2)
259 yield from ALUHelpers.get_wr_fast_spr1(sim_o, sim, dec2)
260 yield from ALUHelpers.get_wr_fast_spr2(sim_o, sim, dec2)
261 ALUHelpers.get_sim_nia(sim_o, sim, dec2)
262 ALUHelpers.get_sim_msr(sim_o, sim, dec2)
263
264 print ("sim output", sim_o)
265
266 ALUHelpers.check_int_o(self, res, sim_o, code)
267 ALUHelpers.check_fast_spr1(self, res, sim_o, code)
268 ALUHelpers.check_fast_spr2(self, res, sim_o, code)
269 ALUHelpers.check_nia(self, res, sim_o, code)
270 ALUHelpers.check_msr(self, res, sim_o, code)
271
272
273 if __name__ == "__main__":
274 unittest.main(exit=False)
275 suite = unittest.TestSuite()
276 suite.addTest(TestRunner(TrapTestCase.test_data))
277
278 runner = unittest.TextTestRunner()
279 runner.run(suite)