set parent pspec to class with XLEN = 64
[soc.git] / src / soc / fu / mul / test / helper.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, Delay, Settle
6
7 import power_instruction_analyzer as pia
8
9 from nmigen.cli import rtlil
10 import unittest
11 from openpower.decoder.isa.caller import ISACaller, special_sprs
12 from openpower.decoder.power_decoder import (create_pdecode)
13 from openpower.decoder.power_decoder2 import (PowerDecode2)
14 from openpower.decoder.power_enums import (XER_bits, Function, MicrOp, CryIn)
15 from openpower.decoder.selectable_int import SelectableInt
16 from openpower.simulator.program import Program
17 from openpower.decoder.isa.all import ISA
18 from openpower.endian import bigendian
19
20 from openpower.test.common import (TestAccumulatorBase, TestCase, ALUHelpers)
21 from soc.fu.test.pia import pia_res_to_output
22 from soc.fu.mul.pipeline import MulBasePipe
23 from soc.fu.mul.pipe_data import MulPipeSpec
24 import random
25
26
27 def get_cu_inputs(dec2, sim):
28 """naming (res) must conform to MulFunctionUnit input regspec
29 """
30 res = {}
31
32 yield from ALUHelpers.get_sim_int_ra(res, sim, dec2) # RA
33 yield from ALUHelpers.get_sim_int_rb(res, sim, dec2) # RB
34 yield from ALUHelpers.get_sim_int_rc(res, sim, dec2) # RC
35 yield from ALUHelpers.get_sim_xer_so(res, sim, dec2) # XER.so
36
37 print("alu get_cu_inputs", res)
38
39 return res
40
41
42 def set_alu_inputs(alu, dec2, sim, has_third_input):
43 # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43
44 # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok))
45 # and place it into i_data.b
46
47 inp = yield from get_cu_inputs(dec2, sim)
48 print("set alu inputs", inp)
49 yield from ALUHelpers.set_int_ra(alu, dec2, inp)
50 yield from ALUHelpers.set_int_rb(alu, dec2, inp)
51 if has_third_input:
52 yield from ALUHelpers.set_int_rc(alu, dec2, inp)
53
54 yield from ALUHelpers.set_xer_so(alu, dec2, inp)
55
56 overflow = None
57 if 'xer_so' in inp:
58 so = inp['xer_so']
59 overflow = pia.OverflowFlags(so=bool(so),
60 ov=False,
61 ov32=False)
62 immediate_ok = yield dec2.e.do.imm_data.ok
63 if immediate_ok:
64 immediate = yield dec2.e.do.imm_data.data
65 else:
66 immediate = None
67 rc = inp["rc"] if has_third_input else None
68 return pia.InstructionInput(ra=inp.get("ra"), rb=inp.get("rb"),
69 immediate=immediate,
70 rc=rc, overflow=overflow)
71
72
73 class MulTestHelper(unittest.TestCase):
74 def execute(self, pdecode2, test, instruction, alu, has_third_input, sim):
75 program = test.program
76 isa_sim = ISA(pdecode2, test.regs, test.sprs, test.cr,
77 test.mem, test.msr,
78 bigendian=bigendian)
79 gen = program.generate_instructions()
80 instructions = list(zip(gen, program.assembly.splitlines()))
81 yield Settle()
82
83 index = isa_sim.pc.CIA.value//4
84 while index < len(instructions):
85 ins, code = instructions[index]
86
87 print("instruction: 0x{:X}".format(ins & 0xffffffff))
88 print(code)
89 if 'XER' in isa_sim.spr:
90 so = 1 if isa_sim.spr['XER'][XER_bits['SO']] else 0
91 ov = 1 if isa_sim.spr['XER'][XER_bits['OV']] else 0
92 ov32 = 1 if isa_sim.spr['XER'][XER_bits['OV32']] else 0
93 print("before: so/ov/32", so, ov, ov32)
94
95 # ask the decoder to decode this binary data (endian'd)
96 yield pdecode2.dec.bigendian.eq(bigendian) # little / big?
97 yield instruction.eq(ins) # raw binary instr.
98 yield Delay(0.1e-6)
99 fn_unit = yield pdecode2.e.do.fn_unit
100 self.assertEqual(fn_unit, Function.MUL.value)
101 pia_inputs = yield from set_alu_inputs(alu, pdecode2, isa_sim,
102 has_third_input)
103
104 # set valid for one cycle, propagate through pipeline...
105 yield alu.p.i_valid.eq(1)
106 yield
107 yield alu.p.i_valid.eq(0)
108
109 opname = code.split(' ')[0]
110 fnname = opname.replace(".", "_")
111 print(f"{fnname}({pia_inputs})")
112 pia_res = getattr(pia, fnname)(pia_inputs)
113 print(f"-> {pia_res}")
114
115 yield from isa_sim.call(opname)
116 index = isa_sim.pc.CIA.value//4
117
118 # ...wait for valid to pop out the end
119 vld = yield alu.n.o_valid
120 while not vld:
121 yield
122 yield Delay(0.1e-6)
123 vld = yield alu.n.o_valid
124 yield Delay(0.1e-6)
125
126 # XXX sim._engine is an internal variable
127 # Waiting on https://github.com/nmigen/nmigen/issues/443
128 try:
129 print(f"check time: {sim._engine.now * 1e6}us")
130 except AttributeError:
131 pass
132 msg = (f"{code!r} {program.assembly!r} "
133 f"{list(map(hex, test.regs))!r}")
134 yield from self.check_alu_outputs(alu, pdecode2, isa_sim, msg,
135 pia_res)
136 yield
137
138 def run_all(self, test_data, file_name_prefix, has_third_input):
139 m = Module()
140 comb = m.d.comb
141 instruction = Signal(32)
142
143 fn_name = "MUL"
144 opkls = MulPipeSpec.opsubsetkls
145
146 m.submodules.pdecode2 = pdecode2 = PowerDecode2(None, opkls, fn_name)
147 pdecode = pdecode2.dec
148
149 class PPspec:
150 XLEN = 64
151 pps = PPspec()
152 pspec = MulPipeSpec(id_wid=2, parent_pspec=pps)
153 m.submodules.alu = alu = MulBasePipe(pspec)
154
155 comb += alu.p.i_data.ctx.op.eq_from_execute1(pdecode2.do)
156 comb += alu.n.i_ready.eq(1)
157 comb += pdecode2.dec.raw_opcode_in.eq(instruction)
158 sim = Simulator(m)
159
160 sim.add_clock(1e-6)
161
162 def process():
163 for test in test_data:
164 print(test.name)
165 with self.subTest(test.name):
166 yield from self.execute(pdecode2, test, instruction, alu,
167 has_third_input, sim)
168
169 sim.add_sync_process(process)
170 with sim.write_vcd(f"{file_name_prefix}.vcd"):
171 sim.run()
172
173 def check_alu_outputs(self, alu, dec2, sim, code, pia_res):
174
175 rc = yield dec2.e.do.rc.rc
176 cridx_ok = yield dec2.e.write_cr.ok
177 cridx = yield dec2.e.write_cr.data
178
179 print("check extra output", repr(code), cridx_ok, cridx)
180 if rc:
181 self.assertEqual(cridx, 0, code)
182
183 oe = yield dec2.e.do.oe.oe
184 oe_ok = yield dec2.e.do.oe.ok
185 if not oe or not oe_ok:
186 # if OE not enabled, XER SO and OV must correspondingly be false
187 so_ok = yield alu.n.o_data.xer_so.ok
188 ov_ok = yield alu.n.o_data.xer_ov.ok
189 self.assertEqual(so_ok, False, code)
190 self.assertEqual(ov_ok, False, code)
191
192 sim_o = {}
193 res = {}
194
195 yield from ALUHelpers.get_cr_a(res, alu, dec2)
196 yield from ALUHelpers.get_xer_ov(res, alu, dec2)
197 yield from ALUHelpers.get_int_o(res, alu, dec2)
198 yield from ALUHelpers.get_xer_so(res, alu, dec2)
199
200 print("res output", res)
201
202 yield from ALUHelpers.get_sim_int_o(sim_o, sim, dec2)
203 yield from ALUHelpers.get_wr_sim_cr_a(sim_o, sim, dec2)
204 yield from ALUHelpers.get_sim_xer_ov(sim_o, sim, dec2)
205 yield from ALUHelpers.get_sim_xer_so(sim_o, sim, dec2)
206
207 print("sim output", sim_o)
208
209 print("power-instruction-analyzer result:")
210 print(pia_res)
211 if pia_res is not None:
212 with self.subTest(check="pia", sim_o=sim_o, pia_res=str(pia_res)):
213 pia_o = pia_res_to_output(pia_res)
214 ALUHelpers.check_int_o(self, res, pia_o, code)
215 ALUHelpers.check_cr_a(self, res, pia_o, code)
216 ALUHelpers.check_xer_ov(self, res, pia_o, code)
217 ALUHelpers.check_xer_so(self, res, pia_o, code)
218
219 with self.subTest(check="sim", sim_o=sim_o, pia_res=str(pia_res)):
220 ALUHelpers.check_int_o(self, res, sim_o, code)
221 ALUHelpers.check_xer_ov(self, res, sim_o, code)
222 ALUHelpers.check_xer_so(self, res, sim_o, code)
223 ALUHelpers.check_cr_a(self, res, sim_o, "CR%d %s" % (cridx, code))