rename InternalOp to MicrOp
[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_999_illegal(self):
124 # ok, um this is a bit of a cheat: use an instruction we know
125 # is not implemented by either ISACaller or the core
126 lst = ["tbegin."]
127 initial_regs = [0] * 32
128 self.run_tst_program(Program(lst, bigendian), initial_regs)
129
130 def test_ilang(self):
131 pspec = TrapPipeSpec(id_wid=2)
132 alu = TrapBasePipe(pspec)
133 vl = rtlil.convert(alu, ports=alu.ports())
134 with open("trap_pipeline.il", "w") as f:
135 f.write(vl)
136
137
138 class TestRunner(FHDLTestCase):
139 def __init__(self, test_data):
140 super().__init__("run_all")
141 self.test_data = test_data
142
143 def run_all(self):
144 m = Module()
145 comb = m.d.comb
146 instruction = Signal(32)
147
148 pdecode = create_pdecode()
149
150 m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode)
151
152 pspec = TrapPipeSpec(id_wid=2)
153 m.submodules.alu = alu = TrapBasePipe(pspec)
154
155 comb += alu.p.data_i.ctx.op.eq_from_execute1(pdecode2.e)
156 comb += alu.p.valid_i.eq(1)
157 comb += alu.n.ready_i.eq(1)
158 comb += pdecode2.dec.raw_opcode_in.eq(instruction)
159 sim = Simulator(m)
160
161 sim.add_clock(1e-6)
162 def process():
163 for test in self.test_data:
164 print(test.name)
165 program = test.program
166 self.subTest(test.name)
167 sim = ISA(pdecode2, test.regs, test.sprs, test.cr,
168 test.mem, test.msr,
169 bigendian=bigendian)
170 gen = program.generate_instructions()
171 instructions = list(zip(gen, program.assembly.splitlines()))
172
173 pc = sim.pc.CIA.value
174 index = pc//4
175 while index < len(instructions):
176 ins, code = instructions[index]
177
178 print("pc %08x instr: %08x" % (pc, ins & 0xffffffff))
179 print(code)
180 if 'XER' in sim.spr:
181 so = 1 if sim.spr['XER'][XER_bits['SO']] else 0
182 ov = 1 if sim.spr['XER'][XER_bits['OV']] else 0
183 ov32 = 1 if sim.spr['XER'][XER_bits['OV32']] else 0
184 print ("before: so/ov/32", so, ov, ov32)
185
186 # ask the decoder to decode this binary data (endian'd)
187 yield pdecode2.dec.bigendian.eq(bigendian) # little / big?
188 yield instruction.eq(ins) # raw binary instr.
189 yield Settle()
190 fn_unit = yield pdecode2.e.do.fn_unit
191 self.assertEqual(fn_unit, Function.TRAP.value)
192 yield from set_alu_inputs(alu, pdecode2, sim)
193 yield
194 opname = code.split(' ')[0]
195 yield from sim.call(opname)
196 pc = sim.pc.CIA.value
197 index = pc//4
198 print("pc after %08x" % (pc))
199
200 vld = yield alu.n.valid_o
201 while not vld:
202 yield
203 vld = yield alu.n.valid_o
204 yield
205
206 yield from self.check_alu_outputs(alu, pdecode2, sim, code)
207
208 sim.add_sync_process(process)
209 with sim.write_vcd("alu_simulator.vcd", "simulator.gtkw",
210 traces=[]):
211 sim.run()
212
213 def check_alu_outputs(self, alu, dec2, sim, code):
214
215 rc = yield dec2.e.do.rc.data
216 cridx_ok = yield dec2.e.write_cr.ok
217 cridx = yield dec2.e.write_cr.data
218
219 print ("check extra output", repr(code), cridx_ok, cridx)
220 if rc:
221 self.assertEqual(cridx, 0, code)
222
223 sim_o = {}
224 res = {}
225
226 yield from ALUHelpers.get_int_o(res, alu, dec2)
227 yield from ALUHelpers.get_fast_spr1(res, alu, dec2)
228 yield from ALUHelpers.get_fast_spr2(res, alu, dec2)
229 yield from ALUHelpers.get_nia(res, alu, dec2)
230 yield from ALUHelpers.get_msr(res, alu, dec2)
231
232 print ("output", res)
233
234 yield from ALUHelpers.get_sim_int_o(sim_o, sim, dec2)
235 yield from ALUHelpers.get_wr_fast_spr1(sim_o, sim, dec2)
236 yield from ALUHelpers.get_wr_fast_spr2(sim_o, sim, dec2)
237 ALUHelpers.get_sim_nia(sim_o, sim, dec2)
238 ALUHelpers.get_sim_msr(sim_o, sim, dec2)
239
240 print ("sim output", sim_o)
241
242 ALUHelpers.check_int_o(self, res, sim_o, code)
243 ALUHelpers.check_fast_spr1(self, res, sim_o, code)
244 ALUHelpers.check_fast_spr2(self, res, sim_o, code)
245 ALUHelpers.check_nia(self, res, sim_o, code)
246 ALUHelpers.check_msr(self, res, sim_o, code)
247
248
249 if __name__ == "__main__":
250 unittest.main(exit=False)
251 suite = unittest.TestSuite()
252 suite.addTest(TestRunner(TrapTestCase.test_data))
253
254 runner = unittest.TextTestRunner()
255 runner.run(suite)