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