minor reorg on how Bus and Config classes are set up
[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 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, InternalOp)
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.regfile.regfiles import FastRegs
14
15 from soc.fu.test.common import 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(FHDLTestCase):
68 test_data = []
69 def __init__(self, name):
70 super().__init__(name)
71 self.test_name = name
72
73 def run_tst_program(self, prog, initial_regs=None,
74 initial_sprs=None, initial_cr=0):
75 tc = TestCase(prog, self.test_name,
76 initial_regs, initial_sprs, initial_cr)
77 self.test_data.append(tc)
78
79 def test_unconditional(self):
80 choices = ["b", "ba", "bl", "bla"]
81 for i in range(20):
82 choice = random.choice(choices)
83 imm = random.randrange(-1<<23, (1<<23)-1) * 4
84 lst = [f"{choice} {imm}"]
85 initial_regs = [0] * 32
86 self.run_tst_program(Program(lst), initial_regs)
87
88 def test_bc_cr(self):
89 for i in range(20):
90 bc = random.randrange(-1<<13, (1<<13)-1) * 4
91 bo = random.choice([0b01100, 0b00100, 0b10100])
92 bi = random.randrange(0, 31)
93 cr = random.randrange(0, (1<<32)-1)
94 lst = [f"bc {bo}, {bi}, {bc}"]
95 initial_regs = [0] * 32
96 self.run_tst_program(Program(lst), initial_cr=cr)
97
98 def test_bc_ctr(self):
99 for i in range(20):
100 bc = random.randrange(-1<<13, (1<<13)-1) * 4
101 bo = random.choice([0, 2, 8, 10, 16, 18])
102 bi = random.randrange(0, 31)
103 cr = random.randrange(0, (1<<32)-1)
104 ctr = random.randint(0, (1<<32)-1)
105 lst = [f"bc {bo}, {bi}, {bc}"]
106 initial_sprs={9: SelectableInt(ctr, 64)}
107 self.run_tst_program(Program(lst),
108 initial_sprs=initial_sprs,
109 initial_cr=cr)
110
111 def test_bc_reg(self):
112 # XXX: bcctr and bcctrl time out (irony: they're counters)
113 choices = ["bclr", "bclrl", "bcctr", "bcctrl", "bctar", "bctarl"]
114 for insn in choices:
115 for i in range(20):
116 bh = random.randrange(0, 3)
117 bo = random.choice([4, 12])
118 bi = random.randrange(0, 31)
119 cr = random.randrange(0, (1<<32)-1)
120 ctr = random.randint(0, (1<<32)-1)
121 lr = random.randint(0, (1<<64)-1) & ~3
122 tar = random.randint(0, (1<<64)-1) & ~3
123 lst = [f"{insn} {bo}, {bi}, {bh}"]
124 initial_sprs={9: SelectableInt(ctr, 64),
125 8: SelectableInt(lr, 64),
126 815: SelectableInt(tar, 64)}
127 self.run_tst_program(Program(lst),
128 initial_sprs=initial_sprs,
129 initial_cr=cr)
130
131 def test_ilang(self):
132 pspec = BranchPipeSpec(id_wid=2)
133 alu = BranchBasePipe(pspec)
134 vl = rtlil.convert(alu, ports=alu.ports())
135 with open("branch_pipeline.il", "w") as f:
136 f.write(vl)
137
138
139 class TestRunner(FHDLTestCase):
140 def __init__(self, test_data):
141 super().__init__("run_all")
142 self.test_data = test_data
143
144 def run_all(self):
145 m = Module()
146 comb = m.d.comb
147 instruction = Signal(32)
148
149 pdecode = create_pdecode()
150
151 m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode)
152
153 pspec = BranchPipeSpec(id_wid=2)
154 m.submodules.branch = branch = BranchBasePipe(pspec)
155
156 comb += branch.p.data_i.ctx.op.eq_from_execute1(pdecode2.e)
157 comb += branch.p.valid_i.eq(1)
158 comb += branch.n.ready_i.eq(1)
159 comb += pdecode2.dec.raw_opcode_in.eq(instruction)
160 sim = Simulator(m)
161
162 sim.add_clock(1e-6)
163 def process():
164 for test in self.test_data:
165 print(test.name)
166 program = test.program
167 self.subTest(test.name)
168 simulator = ISA(pdecode2, test.regs, test.sprs, test.cr,
169 test.mem, test.msr)
170 initial_cia = 0x2000
171 simulator.set_pc(initial_cia)
172 gen = program.generate_instructions()
173 instructions = list(zip(gen, program.assembly.splitlines()))
174
175 index = (simulator.pc.CIA.value - initial_cia)//4
176 while index < len(instructions) and index >= 0:
177 print(index)
178 ins, code = instructions[index]
179
180 print("0x{:X}".format(ins & 0xffffffff))
181 print(code)
182
183 # ask the decoder to decode this binary data (endian'd)
184 yield pdecode2.dec.bigendian.eq(0) # little / big?
185 yield instruction.eq(ins) # raw binary instr.
186 # note, here, the op will need further decoding in order
187 # to set the correct SPRs on SPR1/2/3. op_bc* require
188 # spr1 to be set to CTR, op_bctar require spr2 to be
189 # set to TAR, op_bclr* require spr2 to be set to LR.
190 # if op_sc*, op_rf* and op_hrfid are to be added here
191 # then additional op-decoding is required, accordingly
192 yield Settle()
193 yield from self.set_inputs(branch, pdecode2, simulator)
194 fn_unit = yield pdecode2.e.fn_unit
195 self.assertEqual(fn_unit, Function.BRANCH.value, code)
196 yield
197 yield
198 opname = code.split(' ')[0]
199 prev_nia = simulator.pc.NIA.value
200 yield from simulator.call(opname)
201 index = (simulator.pc.CIA.value - initial_cia)//4
202
203 yield from self.assert_outputs(branch, pdecode2,
204 simulator, prev_nia, code)
205
206 sim.add_sync_process(process)
207 with sim.write_vcd("simulator.vcd", "simulator.gtkw",
208 traces=[]):
209 sim.run()
210
211 def assert_outputs(self, branch, dec2, sim, prev_nia, code):
212 branch_taken = yield branch.n.data_o.nia.ok
213 sim_branch_taken = prev_nia != sim.pc.CIA
214 self.assertEqual(branch_taken, sim_branch_taken, code)
215 if branch_taken:
216 branch_addr = yield branch.n.data_o.nia.data
217 print(f"real: {branch_addr:x}, sim: {sim.pc.CIA.value:x}")
218 self.assertEqual(branch_addr, sim.pc.CIA.value, code)
219
220 # TODO: check write_fast1 as well (should contain CTR)
221
222 # TODO: this should be checking write_fast2
223 lk = yield dec2.e.lk
224 branch_lk = yield branch.n.data_o.lr.ok
225 self.assertEqual(lk, branch_lk, code)
226 if lk:
227 branch_lr = yield branch.n.data_o.lr.data
228 self.assertEqual(sim.spr['LR'], branch_lr, code)
229
230 def set_inputs(self, branch, dec2, sim):
231 print(f"cr0: {sim.crl[0].get_range()}")
232
233 inp = yield from get_cu_inputs(dec2, sim)
234
235 yield from ALUHelpers.set_fast_cia(branch, dec2, inp)
236 yield from ALUHelpers.set_fast_spr1(branch, dec2, inp)
237 yield from ALUHelpers.set_fast_spr2(branch, dec2, inp)
238 yield from ALUHelpers.set_cr_a(branch, dec2, inp)
239
240
241 if __name__ == "__main__":
242 unittest.main(exit=False)
243 suite = unittest.TestSuite()
244 suite.addTest(TestRunner(BranchTestCase.test_data))
245
246 runner = unittest.TextTestRunner()
247 runner.run(suite)