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