2e4d7a8928559b6a167f0cd3e9ffbb552dd7ab2e
[soc.git] / src / soc / fu / branch / test / test_pipe_caller.py
1 from nmigen import Module, Signal
2
3 # NOTE: to use cxxsim, export NMIGEN_SIM_MODE=cxxsim from the shell
4 # Also, check out the cxxsim nmigen branch, and latest yosys from git
5 from nmutil.sim_tmp_alternative import Simulator, Settle
6
7 from nmigen.cli import rtlil
8 import unittest
9 from soc.decoder.isa.caller import ISACaller, special_sprs
10 from soc.decoder.power_decoder import (create_pdecode)
11 from soc.decoder.power_decoder2 import (PowerDecode2)
12 from soc.decoder.power_enums import (XER_bits, Function, MicrOp)
13 from soc.decoder.selectable_int import SelectableInt
14 from soc.simulator.program import Program
15 from soc.decoder.isa.all import ISA
16 from soc.regfile.regfiles import FastRegs
17 from soc.config.endian import bigendian
18
19 from soc.fu.test.common import TestAccumulatorBase, TestCase, ALUHelpers
20 from soc.fu.branch.pipeline import BranchBasePipe
21 from soc.fu.branch.pipe_data import BranchPipeSpec
22 import random
23
24 from soc.regfile.util import fast_reg_to_spr # HACK!
25
26
27 def get_rec_width(rec):
28 recwidth = 0
29 # Setup random inputs for dut.op
30 for p in rec.ports():
31 width = p.width
32 recwidth += width
33 return recwidth
34
35
36 def get_cu_inputs(dec2, sim):
37 """naming (res) must conform to BranchFunctionUnit input regspec
38 """
39 res = {}
40
41 # CIA (PC)
42 #res['cia'] = sim.pc.CIA.value
43
44 yield from ALUHelpers.get_sim_fast_spr1(res, sim, dec2)
45 yield from ALUHelpers.get_sim_fast_spr2(res, sim, dec2)
46 yield from ALUHelpers.get_sim_cr_a(res, sim, dec2)
47
48 print("get inputs", res)
49 return res
50
51
52 class BranchTestCase(TestAccumulatorBase):
53
54 def case_0_regression_unconditional(self):
55 for i in range(2):
56 imm = random.randrange(-1 << 23, (1 << 23)-1) * 4
57 lst = [f"bl {imm}"]
58 initial_regs = [0] * 32
59 self.add_case(Program(lst, bigendian), initial_regs)
60
61 def case_unconditional(self):
62 choices = ["b", "ba", "bl", "bla"]
63 for i in range(20):
64 choice = random.choice(choices)
65 imm = random.randrange(-1 << 23, (1 << 23)-1) * 4
66 lst = [f"{choice} {imm}"]
67 initial_regs = [0] * 32
68 self.add_case(Program(lst, bigendian), initial_regs)
69
70 def case_bc_cr(self):
71 for i in range(20):
72 bc = random.randrange(-1 << 13, (1 << 13)-1) * 4
73 bo = random.choice([0b01100, 0b00100, 0b10100])
74 bi = random.randrange(0, 31)
75 cr = random.randrange(0, (1 << 32)-1)
76 lst = [f"bc {bo}, {bi}, {bc}"]
77 initial_regs = [0] * 32
78 self.add_case(Program(lst, bigendian), initial_cr=cr)
79
80 def case_bc_ctr(self):
81 for i in range(20):
82 bc = random.randrange(-1 << 13, (1 << 13)-1) * 4
83 bo = random.choice([0, 2, 8, 10, 16, 18])
84 bi = random.randrange(0, 31)
85 cr = random.randrange(0, (1 << 32)-1)
86 ctr = random.randint(0, (1 << 32)-1)
87 lst = [f"bc {bo}, {bi}, {bc}"]
88 initial_sprs = {9: SelectableInt(ctr, 64)}
89 self.add_case(Program(lst, bigendian),
90 initial_sprs=initial_sprs,
91 initial_cr=cr)
92
93 def case_bc_reg(self):
94 # XXX: bcctr and bcctrl time out (irony: they're counters)
95 choices = ["bclr", "bclrl", "bcctr", "bcctrl", "bctar", "bctarl"]
96 for insn in choices:
97 for i in range(20):
98 bh = random.randrange(0, 3)
99 bo = random.choice([4, 12])
100 bi = random.randrange(0, 31)
101 cr = random.randrange(0, (1 << 32)-1)
102 ctr = random.randint(0, (1 << 32)-1)
103 lr = random.randint(0, (1 << 64)-1) & ~3
104 tar = random.randint(0, (1 << 64)-1) & ~3
105 lst = [f"{insn} {bo}, {bi}, {bh}"]
106 initial_sprs = {9: SelectableInt(ctr, 64),
107 8: SelectableInt(lr, 64),
108 815: SelectableInt(tar, 64)}
109 self.add_case(Program(lst, bigendian),
110 initial_sprs=initial_sprs,
111 initial_cr=cr)
112
113 def case_bc_microwatt_1_regression(self):
114 """bc found to be testing ctr rather than (ctr-1)
115 11fb4: 08 00 49 40 bc 2,4*cr2+gt,0x11fbc
116 cr_file.vhdl:83:13:@136835ns:(report note): Reading CR 33209703
117 """
118 lst = ["bc 2, 9, 8"]
119 initial_regs = [0] * 32
120 cr = 0x33209703
121 self.add_case(Program(lst, bigendian), initial_regs,
122 initial_cr=cr)
123
124 def case_bc_microwatt_2_regression(self):
125 """modified version, set CTR=1 so that it hits zero in BC
126 """
127 lst = ["bc 2, 9, 8"]
128 initial_regs = [0] * 32
129 cr = 0x33209703
130 ctr = 1
131 initial_sprs = {9: SelectableInt(ctr, 64),
132 }
133 self.add_case(Program(lst, bigendian), initial_regs,
134 initial_sprs=initial_sprs,
135 initial_cr=cr)
136
137 def case_ilang(self):
138 pspec = BranchPipeSpec(id_wid=2)
139 alu = BranchBasePipe(pspec)
140 vl = rtlil.convert(alu, ports=alu.ports())
141 with open("branch_pipeline.il", "w") as f:
142 f.write(vl)
143
144
145 class TestRunner(unittest.TestCase):
146 def test_it(self):
147 test_data = BranchTestCase().test_data
148 m = Module()
149 comb = m.d.comb
150 instruction = Signal(32)
151
152 fn_name = "BRANCH"
153 opkls = BranchPipeSpec.opsubsetkls
154
155 m.submodules.pdecode2 = pdecode2 = PowerDecode2(None, opkls, fn_name)
156 pdecode = pdecode2.dec
157
158 pspec = BranchPipeSpec(id_wid=2)
159 m.submodules.branch = branch = BranchBasePipe(pspec)
160
161 comb += branch.p.data_i.ctx.op.eq_from_execute1(pdecode2.e)
162 comb += branch.p.valid_i.eq(1)
163 comb += branch.n.ready_i.eq(1)
164 comb += pdecode2.dec.raw_opcode_in.eq(instruction)
165 sim = Simulator(m)
166
167 sim.add_clock(1e-6)
168
169 def process():
170 for test in test_data:
171 print(test.name)
172 program = test.program
173 with self.subTest(test.name):
174 simulator = ISA(pdecode2, test.regs, test.sprs, test.cr,
175 test.mem, test.msr,
176 bigendian=bigendian)
177 initial_cia = 0x2000
178 simulator.set_pc(initial_cia)
179 gen = program.generate_instructions()
180 instructions = list(
181 zip(gen, program.assembly.splitlines()))
182
183 pc = simulator.pc.CIA.value
184 msr = simulator.msr.value
185 index = (pc - initial_cia)//4
186 while index < len(instructions) and index >= 0:
187 print(index)
188 ins, code = instructions[index]
189
190 print("0x{:X}".format(ins & 0xffffffff))
191 print(code)
192
193 # ask the decoder to decode this binary data (endian'd)
194 # little / big?
195 yield pdecode2.dec.bigendian.eq(bigendian)
196 yield pdecode2.state.msr.eq(msr) # set MSR in pdecode2
197 yield pdecode2.state.pc.eq(pc) # set PC in pdecode2
198 yield instruction.eq(ins) # raw binary instr.
199 # note, here, the op will need further decoding in order
200 # to set the correct SPRs on SPR1/2/3. op_bc* require
201 # spr1 to be set to CTR, op_bctar require spr2 to be
202 # set to TAR, op_bclr* require spr2 to be set to LR.
203 # if op_sc*, op_rf* and op_hrfid are to be added here
204 # then additional op-decoding is required, accordingly
205 yield Settle()
206 lk = yield pdecode2.e.do.lk
207 print("lk:", lk)
208 yield from self.set_inputs(branch, pdecode2, simulator)
209 fn_unit = yield pdecode2.e.do.fn_unit
210 self.assertEqual(fn_unit, Function.BRANCH.value, code)
211 yield
212 yield
213 opname = code.split(' ')[0]
214 prev_nia = simulator.pc.NIA.value
215 yield from simulator.call(opname)
216 pc = simulator.pc.CIA.value
217 msr = simulator.msr.value
218 index = (pc - initial_cia)//4
219
220 yield from self.assert_outputs(branch, pdecode2,
221 simulator, prev_nia,
222 code)
223
224 sim.add_sync_process(process)
225 with sim.write_vcd("branch_simulator.vcd"):
226 sim.run()
227
228 def assert_outputs(self, branch, dec2, sim, prev_nia, code):
229 branch_taken = yield branch.n.data_o.nia.ok
230 sim_branch_taken = prev_nia != sim.pc.CIA
231 self.assertEqual(branch_taken, sim_branch_taken, code)
232 if branch_taken:
233 branch_addr = yield branch.n.data_o.nia.data
234 print(f"real: {branch_addr:x}, sim: {sim.pc.CIA.value:x}")
235 self.assertEqual(branch_addr, sim.pc.CIA.value, code)
236
237 # TODO: check write_fast1 as well (should contain CTR)
238
239 # TODO: this should be checking write_fast2
240 lk = yield dec2.e.do.lk
241 branch_lk = yield branch.n.data_o.lr.ok
242 self.assertEqual(lk, branch_lk, code)
243 if lk:
244 branch_lr = yield branch.n.data_o.lr.data
245 self.assertEqual(sim.spr['LR'], branch_lr, code)
246
247 def set_inputs(self, branch, dec2, sim):
248 print(f"cr0: {sim.crl[0].get_range()}")
249
250 inp = yield from get_cu_inputs(dec2, sim)
251
252 yield from ALUHelpers.set_fast_spr1(branch, dec2, inp)
253 yield from ALUHelpers.set_fast_spr2(branch, dec2, inp)
254 yield from ALUHelpers.set_cr_a(branch, dec2, inp)
255
256
257 if __name__ == "__main__":
258 unittest.main()