add mtmsrd instruction and unit test
[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
15 from soc.fu.test.common import (TestCase, ALUHelpers)
16 from soc.fu.trap.pipeline import TrapBasePipe
17 from soc.fu.trap.pipe_data import TrapPipeSpec
18 import random
19
20
21 def get_cu_inputs(dec2, sim):
22 """naming (res) must conform to TrapFunctionUnit input regspec
23 """
24 res = {}
25
26 yield from ALUHelpers.get_sim_int_ra(res, sim, dec2) # RA
27 yield from ALUHelpers.get_sim_int_rb(res, sim, dec2) # RB
28 yield from ALUHelpers.get_sim_fast_spr1(res, sim, dec2) # SPR1
29 yield from ALUHelpers.get_sim_fast_spr2(res, sim, dec2) # SPR2
30 ALUHelpers.get_sim_cia(res, sim, dec2) # PC
31 ALUHelpers.get_sim_msr(res, sim, dec2) # MSR
32
33 print ("alu get_cu_inputs", res)
34
35 return res
36
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
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(FHDLTestCase):
74 test_data = []
75
76 def __init__(self, name):
77 super().__init__(name)
78 self.test_name = name
79
80 def run_tst_program(self, prog, initial_regs=None, initial_sprs=None):
81 tc = TestCase(prog, self.test_name, initial_regs, initial_sprs)
82 self.test_data.append(tc)
83
84 def test_1_rfid(self):
85 lst = ["rfid"]
86 initial_regs = [0] * 32
87 initial_regs[1] = 1
88 initial_sprs = {'SRR0': 0x12345678, 'SRR1': 0x5678}
89 self.run_tst_program(Program(lst, bigendian),
90 initial_regs, initial_sprs)
91
92 def test_0_trap_eq_imm(self):
93 insns = ["twi", "tdi"]
94 for i in range(2):
95 choice = random.choice(insns)
96 lst = [f"{choice} 4, 1, %d" % i] # TO=4: trap equal
97 initial_regs = [0] * 32
98 initial_regs[1] = 1
99 self.run_tst_program(Program(lst, bigendian), initial_regs)
100
101 def test_0_trap_eq(self):
102 insns = ["tw", "td"]
103 for i in range(2):
104 choice = insns[i]
105 lst = [f"{choice} 4, 1, 2"] # TO=4: trap equal
106 initial_regs = [0] * 32
107 initial_regs[1] = 1
108 initial_regs[2] = 1
109 self.run_tst_program(Program(lst, bigendian), initial_regs)
110
111 def test_3_mtmsr_0(self):
112 lst = ["mtmsr 1,0"]
113 initial_regs = [0] * 32
114 initial_regs[1] = 0xffffffffffffffff
115 self.run_tst_program(Program(lst, bigendian), initial_regs)
116
117 def test_3_mtmsr_1(self):
118 lst = ["mtmsr 1,1"]
119 initial_regs = [0] * 32
120 initial_regs[1] = 0xffffffffffffffff
121 self.run_tst_program(Program(lst, bigendian), initial_regs)
122
123 def test_4_mtmsrd_0(self):
124 lst = ["mtmsrd 1,0"]
125 initial_regs = [0] * 32
126 initial_regs[1] = 0xffffffffffffffff
127 self.run_tst_program(Program(lst, bigendian), initial_regs)
128
129 def test_5_mtmsrd_1(self):
130 lst = ["mtmsrd 1,1"]
131 initial_regs = [0] * 32
132 initial_regs[1] = 0xffffffffffffffff
133 self.run_tst_program(Program(lst, bigendian), initial_regs)
134
135 def test_999_illegal(self):
136 # ok, um this is a bit of a cheat: use an instruction we know
137 # is not implemented by either ISACaller or the core
138 lst = ["tbegin.",
139 "mtmsr 1,1"] # should not get executed
140 initial_regs = [0] * 32
141 self.run_tst_program(Program(lst, bigendian), initial_regs)
142
143 def test_ilang(self):
144 pspec = TrapPipeSpec(id_wid=2)
145 alu = TrapBasePipe(pspec)
146 vl = rtlil.convert(alu, ports=alu.ports())
147 with open("trap_pipeline.il", "w") as f:
148 f.write(vl)
149
150
151 class TestRunner(FHDLTestCase):
152 def __init__(self, test_data):
153 super().__init__("run_all")
154 self.test_data = test_data
155
156 def run_all(self):
157 m = Module()
158 comb = m.d.comb
159 instruction = Signal(32)
160
161 pdecode = create_pdecode()
162
163 m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode)
164
165 pspec = TrapPipeSpec(id_wid=2)
166 m.submodules.alu = alu = TrapBasePipe(pspec)
167
168 comb += alu.p.data_i.ctx.op.eq_from_execute1(pdecode2.e)
169 comb += alu.p.valid_i.eq(1)
170 comb += alu.n.ready_i.eq(1)
171 comb += pdecode2.dec.raw_opcode_in.eq(instruction)
172 sim = Simulator(m)
173
174 sim.add_clock(1e-6)
175 def process():
176 for test in self.test_data:
177 print(test.name)
178 program = test.program
179 self.subTest(test.name)
180 sim = ISA(pdecode2, test.regs, test.sprs, test.cr,
181 test.mem, test.msr,
182 bigendian=bigendian)
183 gen = program.generate_instructions()
184 instructions = list(zip(gen, program.assembly.splitlines()))
185
186 pc = sim.pc.CIA.value
187 index = pc//4
188 while index < len(instructions):
189 ins, code = instructions[index]
190
191 print("pc %08x instr: %08x" % (pc, ins & 0xffffffff))
192 print(code)
193 if 'XER' in sim.spr:
194 so = 1 if sim.spr['XER'][XER_bits['SO']] else 0
195 ov = 1 if sim.spr['XER'][XER_bits['OV']] else 0
196 ov32 = 1 if sim.spr['XER'][XER_bits['OV32']] else 0
197 print ("before: so/ov/32", so, ov, ov32)
198
199 # ask the decoder to decode this binary data (endian'd)
200 yield pdecode2.dec.bigendian.eq(bigendian) # little / big?
201 yield instruction.eq(ins) # raw binary instr.
202 yield Settle()
203 fn_unit = yield pdecode2.e.do.fn_unit
204 self.assertEqual(fn_unit, Function.TRAP.value)
205 yield from set_alu_inputs(alu, pdecode2, sim)
206 yield
207 opname = code.split(' ')[0]
208 yield from sim.call(opname)
209 pc = sim.pc.CIA.value
210 index = pc//4
211 print("pc after %08x" % (pc))
212
213 vld = yield alu.n.valid_o
214 while not vld:
215 yield
216 vld = yield alu.n.valid_o
217 yield
218
219 yield from self.check_alu_outputs(alu, pdecode2, sim, code)
220
221 sim.add_sync_process(process)
222 with sim.write_vcd("alu_simulator.vcd", "simulator.gtkw",
223 traces=[]):
224 sim.run()
225
226 def check_alu_outputs(self, alu, dec2, sim, code):
227
228 rc = yield dec2.e.do.rc.data
229 cridx_ok = yield dec2.e.write_cr.ok
230 cridx = yield dec2.e.write_cr.data
231
232 print ("check extra output", repr(code), cridx_ok, cridx)
233 if rc:
234 self.assertEqual(cridx, 0, code)
235
236 sim_o = {}
237 res = {}
238
239 yield from ALUHelpers.get_int_o(res, alu, dec2)
240 yield from ALUHelpers.get_fast_spr1(res, alu, dec2)
241 yield from ALUHelpers.get_fast_spr2(res, alu, dec2)
242 yield from ALUHelpers.get_nia(res, alu, dec2)
243 yield from ALUHelpers.get_msr(res, alu, dec2)
244
245 print ("output", res)
246
247 yield from ALUHelpers.get_sim_int_o(sim_o, sim, dec2)
248 yield from ALUHelpers.get_wr_fast_spr1(sim_o, sim, dec2)
249 yield from ALUHelpers.get_wr_fast_spr2(sim_o, sim, dec2)
250 ALUHelpers.get_sim_nia(sim_o, sim, dec2)
251 ALUHelpers.get_sim_msr(sim_o, sim, dec2)
252
253 print ("sim output", sim_o)
254
255 ALUHelpers.check_int_o(self, res, sim_o, code)
256 ALUHelpers.check_fast_spr1(self, res, sim_o, code)
257 ALUHelpers.check_fast_spr2(self, res, sim_o, code)
258 ALUHelpers.check_nia(self, res, sim_o, code)
259 ALUHelpers.check_msr(self, res, sim_o, code)
260
261
262 if __name__ == "__main__":
263 unittest.main(exit=False)
264 suite = unittest.TestSuite()
265 suite.addTest(TestRunner(TrapTestCase.test_data))
266
267 runner = unittest.TextTestRunner()
268 runner.run(suite)