Allow the formal engine to perform a same-cycle result in the ALU
[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.power_decoder import (create_pdecode)
10 from openpower.decoder.power_decoder2 import (PowerDecode2)
11 from openpower.decoder.power_enums import Function
12 from openpower.simulator.program import Program
13 from openpower.decoder.isa.all import ISA
14 from soc.regfile.regfiles import FastRegs
15 from openpower.endian import bigendian
16
17 from openpower.test.common import ALUHelpers
18 from soc.fu.branch.pipeline import BranchBasePipe
19 from soc.fu.branch.pipe_data import BranchPipeSpec
20 import random
21
22 from openpower.test.branch.branch_cases import BranchTestCase
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 BranchAllCases(BranchTestCase):
51
52 def case_ilang(self):
53 pspec = BranchPipeSpec(id_wid=2, parent_pspec=None)
54 alu = BranchBasePipe(pspec)
55 vl = rtlil.convert(alu, ports=alu.ports())
56 with open("branch_pipeline.il", "w") as f:
57 f.write(vl)
58
59
60 class TestRunner(unittest.TestCase):
61 def test_it(self):
62 test_data = BranchTestCase().test_data
63 print ("test data", test_data)
64 m = Module()
65 comb = m.d.comb
66 instruction = Signal(32)
67
68 fn_name = "BRANCH"
69 opkls = BranchPipeSpec.opsubsetkls
70
71 m.submodules.pdecode2 = pdecode2 = PowerDecode2(None, opkls, fn_name)
72 pdecode = pdecode2.dec
73
74 pspec = BranchPipeSpec(id_wid=2, parent_pspec=None)
75 m.submodules.branch = branch = BranchBasePipe(pspec)
76
77 comb += branch.p.i_data.ctx.op.eq_from_execute1(pdecode2.do)
78 comb += branch.p.i_valid.eq(1)
79 comb += branch.n.i_ready.eq(1)
80 comb += pdecode2.dec.raw_opcode_in.eq(instruction)
81 sim = Simulator(m)
82
83 sim.add_clock(1e-6)
84
85 def process():
86 for test in test_data:
87 print(test.name)
88 program = test.program
89 with self.subTest(test.name):
90 simulator = ISA(pdecode2, test.regs, test.sprs, test.cr,
91 test.mem, test.msr,
92 bigendian=bigendian)
93 initial_cia = 0x2000
94 simulator.set_pc(initial_cia)
95 gen = program.generate_instructions()
96 instructions = list(
97 zip(gen, program.assembly.splitlines()))
98
99 pc = simulator.pc.CIA.value
100 msr = simulator.msr.value
101 index = (pc - initial_cia)//4
102 while index < len(instructions) and index >= 0:
103 print(index)
104 ins, code = instructions[index]
105
106 print("insn 0x{:X}".format(ins & 0xffffffff))
107 print(code)
108
109 # ask the decoder to decode this binary data (endian'd)
110 # little / big?
111 yield pdecode2.dec.bigendian.eq(bigendian)
112 yield pdecode2.state.msr.eq(msr) # set MSR in pdecode2
113 yield pdecode2.state.pc.eq(pc) # set PC in pdecode2
114 yield instruction.eq(ins) # raw binary instr.
115 # note, here, the op will need further decoding in order
116 # to set the correct SPRs on SPR1/2/3. op_bc* require
117 # spr1 to be set to CTR, op_bctar require spr2 to be
118 # set to TAR, op_bclr* require spr2 to be set to LR.
119 # if op_sc*, op_rf* and op_hrfid are to be added here
120 # then additional op-decoding is required, accordingly
121 yield Settle()
122 lk = yield pdecode2.e.do.lk
123 print("lk:", lk)
124 yield from self.set_inputs(branch, pdecode2, simulator)
125 fn_unit = yield pdecode2.e.do.fn_unit
126 self.assertEqual(fn_unit, Function.BRANCH.value, code)
127 yield
128 yield
129 opname = code.split(' ')[0]
130 prev_nia = simulator.pc.NIA.value
131 yield from simulator.call(opname)
132 pc = simulator.pc.CIA.value
133 msr = simulator.msr.value
134 index = (pc - initial_cia)//4
135
136 yield from self.assert_outputs(branch, pdecode2,
137 simulator, prev_nia,
138 code)
139
140 sim.add_sync_process(process)
141 with sim.write_vcd("branch_simulator.vcd"):
142 sim.run()
143
144 def assert_outputs(self, branch, dec2, sim, prev_nia, code):
145 branch_taken = yield branch.n.o_data.nia.ok
146 sim_branch_taken = prev_nia != sim.pc.CIA
147 self.assertEqual(branch_taken, sim_branch_taken, code)
148 if branch_taken:
149 branch_addr = yield branch.n.o_data.nia.data
150 print(f"real: {branch_addr:x}, sim: {sim.pc.CIA.value:x}")
151 self.assertEqual(branch_addr, sim.pc.CIA.value, code)
152
153 # TODO: check write_fast1 as well (should contain CTR)
154
155 # TODO: this should be checking write_fast2
156 lk = yield dec2.e.do.lk
157 branch_lk = yield branch.n.o_data.lr.ok
158 self.assertEqual(lk, branch_lk, code)
159 if lk:
160 branch_lr = yield branch.n.o_data.lr.data
161 self.assertEqual(sim.spr['LR'], branch_lr, code)
162
163 def set_inputs(self, branch, dec2, sim):
164 print(f"cr0: {sim.crl[0].get_range()}")
165
166 inp = yield from get_cu_inputs(dec2, sim)
167
168 yield from ALUHelpers.set_fast_spr1(branch, dec2, inp)
169 yield from ALUHelpers.set_fast_spr2(branch, dec2, inp)
170 yield from ALUHelpers.set_cr_a(branch, dec2, inp)
171
172
173 if __name__ == "__main__":
174 unittest.main()