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