convert branch pipeline to use msr/cia as immediates
[soc.git] / src / soc / fu / spr / 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
17 from soc.fu.test.common import (TestCase, ALUHelpers)
18 from soc.fu.spr.pipeline import SPRBasePipe
19 from soc.fu.spr.pipe_data import SPRPipeSpec
20 import random
21
22
23 def get_cu_inputs(dec2, sim):
24 """naming (res) must conform to SPRFunctionUnit input regspec
25 """
26 res = {}
27
28 yield from ALUHelpers.get_sim_int_ra(res, sim, dec2) # RA
29 yield from ALUHelpers.get_sim_int_rb(res, sim, dec2) # RB
30 yield from ALUHelpers.get_sim_slow_spr1(res, sim, dec2) # FAST1
31 yield from ALUHelpers.get_sim_fast_spr1(res, sim, dec2) # FAST1
32 yield from ALUHelpers.get_rd_sim_xer_ca(res, sim, dec2) # XER.ca
33 yield from ALUHelpers.get_sim_xer_ov(res, sim, dec2) # XER.ov
34 yield from ALUHelpers.get_sim_xer_so(res, sim, dec2) # XER.so
35
36 print ("spr get_cu_inputs", res)
37
38 return res
39
40
41
42 def set_alu_inputs(alu, dec2, sim):
43 # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43
44 # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok))
45 # and place it into data_i.b
46
47 inp = yield from get_cu_inputs(dec2, sim)
48 yield from ALUHelpers.set_int_ra(alu, dec2, inp)
49 yield from ALUHelpers.set_xer_ca(alu, dec2, inp)
50 yield from ALUHelpers.set_xer_ov(alu, dec2, inp)
51 yield from ALUHelpers.set_xer_so(alu, dec2, inp)
52
53 yield from ALUHelpers.set_fast_spr1(alu, dec2, inp)
54 yield from ALUHelpers.set_slow_spr1(alu, dec2, inp)
55 return inp
56
57
58 # This test bench is a bit different than is usual. Initially when I
59 # was writing it, I had all of the tests call a function to create a
60 # device under test and simulator, initialize the dut, run the
61 # simulation for ~2 cycles, and assert that the dut output what it
62 # should have. However, this was really slow, since it needed to
63 # create and tear down the dut and simulator for every test case.
64
65 # Now, instead of doing that, every test case in SPRTestCase puts some
66 # data into the test_data list below, describing the instructions to
67 # be tested and the initial state. Once all the tests have been run,
68 # test_data gets passed to TestRunner which then sets up the DUT and
69 # simulator once, runs all the data through it, and asserts that the
70 # results match the pseudocode sim at every cycle.
71
72 # By doing this, I've reduced the time it takes to run the test suite
73 # massively. Before, it took around 1 minute on my computer, now it
74 # takes around 3 seconds
75
76
77 class SPRTestCase(FHDLTestCase):
78 test_data = []
79
80 def __init__(self, name):
81 super().__init__(name)
82 self.test_name = name
83
84 def run_tst_program(self, prog, initial_regs=None, initial_sprs=None,
85 initial_msr=0):
86 tc = TestCase(prog, self.test_name, initial_regs, initial_sprs,
87 msr=initial_msr)
88 self.test_data.append(tc)
89
90 def test_1_mfspr(self):
91 lst = ["mfspr 1, 26", # SRR0
92 "mfspr 2, 27", # SRR1
93 "mfspr 3, 8", # LR
94 "mfspr 4, 1",] # XER
95 initial_regs = [0] * 32
96 initial_sprs = {'SRR0': 0x12345678, 'SRR1': 0x5678, 'LR': 0x1234,
97 'XER': 0xe00c0000}
98 self.run_tst_program(Program(lst, bigendian), initial_regs, initial_sprs)
99
100 def test_1_mtspr(self):
101 lst = ["mtspr 26, 1", # SRR0
102 "mtspr 27, 2", # SRR1
103 "mtspr 1, 3", # XER
104 "mtspr 9, 4",] # CTR
105 initial_regs = [0] * 32
106 initial_regs[1] = 0x129518230011feed
107 initial_regs[2] = 0x123518230011feed
108 initial_regs[3] = 0xe00c0000
109 initial_regs[4] = 0x1010101010101010
110 initial_sprs = {'SRR0': 0x12345678, 'SRR1': 0x5678, 'LR': 0x1234,
111 'XER': 0x0}
112 self.run_tst_program(Program(lst, bigendian),
113 initial_regs, initial_sprs)
114
115 def test_2_mtspr_mfspr(self):
116 lst = ["mtspr 26, 1", # SRR0
117 "mtspr 27, 2", # SRR1
118 "mtspr 1, 3", # XER
119 "mtspr 9, 4", # CTR
120 "mfspr 2, 26", # SRR0
121 "mfspr 3, 27", # and into reg 2
122 "mfspr 4, 1", # XER
123 "mfspr 5, 9",] # CTR
124 initial_regs = [0] * 32
125 initial_regs[1] = 0x129518230011feed
126 initial_regs[2] = 0x123518230011feed
127 initial_regs[3] = 0xe00c0000
128 initial_regs[4] = 0x1010101010101010
129 initial_sprs = {'SRR0': 0x12345678, 'SRR1': 0x5678, 'LR': 0x1234,
130 'XER': 0x0}
131 self.run_tst_program(Program(lst, bigendian),
132 initial_regs, initial_sprs)
133
134 @unittest.skip("spr does not have TRAP in it. has to be done another way")
135 def test_3_mtspr_priv(self):
136 lst = ["mtspr 26, 1", # SRR0
137 "mtspr 27, 2", # SRR1
138 "mtspr 1, 3", # XER
139 "mtspr 9, 4",] # CTR
140 initial_regs = [0] * 32
141 initial_regs[1] = 0x129518230011feed
142 initial_regs[2] = 0x123518230011feed
143 initial_regs[3] = 0xe00c0000
144 initial_regs[4] = 0x1010101010101010
145 initial_sprs = {'SRR0': 0x12345678, 'SRR1': 0x5678, 'LR': 0x1234,
146 'XER': 0x0}
147 msr = 1<<MSR.PR
148 self.run_tst_program(Program(lst, bigendian),
149 initial_regs, initial_sprs, initial_msr=msr)
150
151 def test_ilang(self):
152 pspec = SPRPipeSpec(id_wid=2)
153 alu = SPRBasePipe(pspec)
154 vl = rtlil.convert(alu, ports=alu.ports())
155 with open("trap_pipeline.il", "w") as f:
156 f.write(vl)
157
158
159 class TestRunner(FHDLTestCase):
160 def __init__(self, test_data):
161 super().__init__("run_all")
162 self.test_data = test_data
163
164 def run_all(self):
165 m = Module()
166 comb = m.d.comb
167 instruction = Signal(32)
168
169 pdecode = create_pdecode()
170
171 m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode)
172
173 pspec = SPRPipeSpec(id_wid=2)
174 m.submodules.alu = alu = SPRBasePipe(pspec)
175
176 comb += alu.p.data_i.ctx.op.eq_from_execute1(pdecode2.e)
177 comb += alu.p.valid_i.eq(1)
178 comb += alu.n.ready_i.eq(1)
179 comb += pdecode2.dec.raw_opcode_in.eq(instruction)
180 sim = Simulator(m)
181
182 sim.add_clock(1e-6)
183 def process():
184 for test in self.test_data:
185 print("test", test.name)
186 print ("sprs", test.sprs)
187 program = test.program
188 self.subTest(test.name)
189 sim = ISA(pdecode2, test.regs, test.sprs, test.cr,
190 test.mem, test.msr,
191 bigendian=bigendian)
192 gen = program.generate_instructions()
193 instructions = list(zip(gen, program.assembly.splitlines()))
194
195 pc = sim.pc.CIA.value
196 msr = sim.msr.value
197 index = pc//4
198 while index < len(instructions):
199 ins, code = instructions[index]
200
201 print("pc %08x instr: %08x" % (pc, ins & 0xffffffff))
202 print(code)
203
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 pdecode2.msr.eq(msr) # set MSR in pdecode2
213 yield pdecode2.cia.eq(pc) # set PC in pdecode2
214 yield instruction.eq(ins) # raw binary instr.
215 yield Settle()
216
217 fast_in = yield pdecode2.e.read_fast1.data
218 spr_in = yield pdecode2.e.read_spr1.data
219 print ("dec2 spr/fast in", fast_in, spr_in)
220
221 fast_out = yield pdecode2.e.write_fast1.data
222 spr_out = yield pdecode2.e.write_spr.data
223 print ("dec2 spr/fast in", fast_out, spr_out)
224
225 fn_unit = yield pdecode2.e.do.fn_unit
226 self.assertEqual(fn_unit, Function.SPR.value)
227 alu_o = yield from set_alu_inputs(alu, pdecode2, sim)
228 yield
229 opname = code.split(' ')[0]
230 yield from sim.call(opname)
231 pc = sim.pc.CIA.value
232 msr = sim.msr.value
233 index = pc//4
234 print("pc after %08x" % (pc))
235
236 vld = yield alu.n.valid_o
237 while not vld:
238 yield
239 vld = yield alu.n.valid_o
240 yield
241
242 yield from self.check_alu_outputs(alu, pdecode2, sim, code)
243
244 sim.add_sync_process(process)
245 with sim.write_vcd("alu_simulator.vcd", "simulator.gtkw",
246 traces=[]):
247 sim.run()
248
249 def check_alu_outputs(self, alu, dec2, sim, code):
250
251 rc = yield dec2.e.do.rc.data
252 cridx_ok = yield dec2.e.write_cr.ok
253 cridx = yield dec2.e.write_cr.data
254
255 print ("check extra output", repr(code), cridx_ok, cridx)
256 if rc:
257 self.assertEqual(cridx, 0, code)
258
259 sim_o = {}
260 res = {}
261
262 yield from ALUHelpers.get_int_o(res, alu, dec2)
263 yield from ALUHelpers.get_fast_spr1(res, alu, dec2)
264 yield from ALUHelpers.get_slow_spr1(res, alu, dec2)
265 yield from ALUHelpers.get_xer_ov(res, alu, dec2)
266 yield from ALUHelpers.get_xer_ca(res, alu, dec2)
267 yield from ALUHelpers.get_xer_so(res, alu, dec2)
268
269 print ("output", res)
270
271 yield from ALUHelpers.get_sim_int_o(sim_o, sim, dec2)
272 yield from ALUHelpers.get_wr_sim_xer_so(sim_o, sim, alu, dec2)
273 yield from ALUHelpers.get_wr_sim_xer_ov(sim_o, sim, alu, dec2)
274 yield from ALUHelpers.get_wr_sim_xer_ca(sim_o, sim, dec2)
275 yield from ALUHelpers.get_wr_fast_spr1(sim_o, sim, dec2)
276 yield from ALUHelpers.get_wr_slow_spr1(sim_o, sim, dec2)
277
278 print ("sim output", sim_o)
279
280 ALUHelpers.check_xer_ov(self, res, sim_o, code)
281 ALUHelpers.check_xer_ca(self, res, sim_o, code)
282 ALUHelpers.check_xer_so(self, res, sim_o, code)
283 ALUHelpers.check_int_o(self, res, sim_o, code)
284 ALUHelpers.check_fast_spr1(self, res, sim_o, code)
285 ALUHelpers.check_slow_spr1(self, res, sim_o, code)
286
287
288 if __name__ == "__main__":
289 unittest.main(exit=False)
290 suite = unittest.TestSuite()
291 suite.addTest(TestRunner(SPRTestCase.test_data))
292
293 runner = unittest.TextTestRunner()
294 runner.run(suite)