1 from nmigen
import Module
, Signal
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
7 import power_instruction_analyzer
as pia
9 from nmigen
.cli
import rtlil
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
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
27 def get_cu_inputs(dec2
, sim
):
28 """naming (res) must conform to MulFunctionUnit input regspec
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
37 print("alu get_cu_inputs", res
)
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
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
)
52 yield from ALUHelpers
.set_int_rc(alu
, dec2
, inp
)
54 yield from ALUHelpers
.set_xer_so(alu
, dec2
, inp
)
59 overflow
= pia
.OverflowFlags(so
=bool(so
),
62 immediate_ok
= yield dec2
.e
.do
.imm_data
.ok
64 immediate
= yield dec2
.e
.do
.imm_data
.data
67 rc
= inp
["rc"] if has_third_input
else None
68 return pia
.InstructionInput(ra
=inp
.get("ra"), rb
=inp
.get("rb"),
70 rc
=rc
, overflow
=overflow
)
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
,
79 gen
= program
.generate_instructions()
80 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
83 index
= isa_sim
.pc
.CIA
.value
//4
84 while index
< len(instructions
):
85 ins
, code
= instructions
[index
]
87 print("instruction: 0x{:X}".format(ins
& 0xffffffff))
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
)
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.
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
,
104 # set valid for one cycle, propagate through pipeline...
105 yield alu
.p
.i_valid
.eq(1)
107 yield alu
.p
.i_valid
.eq(0)
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}")
115 yield from isa_sim
.call(opname
)
116 index
= isa_sim
.pc
.CIA
.value
//4
118 # ...wait for valid to pop out the end
119 vld
= yield alu
.n
.o_valid
123 vld
= yield alu
.n
.o_valid
126 # XXX sim._engine is an internal variable
127 # Waiting on https://github.com/nmigen/nmigen/issues/443
129 print(f
"check time: {sim._engine.now * 1e6}us")
130 except AttributeError:
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
,
138 def run_all(self
, test_data
, file_name_prefix
, has_third_input
):
141 instruction
= Signal(32)
144 opkls
= MulPipeSpec
.opsubsetkls
146 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(None, opkls
, fn_name
)
147 pdecode
= pdecode2
.dec
149 pspec
= MulPipeSpec(id_wid
=2, parent_pspec
=None)
150 m
.submodules
.alu
= alu
= MulBasePipe(pspec
)
152 comb
+= alu
.p
.i_data
.ctx
.op
.eq_from_execute1(pdecode2
.do
)
153 comb
+= alu
.n
.i_ready
.eq(1)
154 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
160 for test
in test_data
:
162 with self
.subTest(test
.name
):
163 yield from self
.execute(pdecode2
, test
, instruction
, alu
,
164 has_third_input
, sim
)
166 sim
.add_sync_process(process
)
167 with sim
.write_vcd(f
"{file_name_prefix}.vcd"):
170 def check_alu_outputs(self
, alu
, dec2
, sim
, code
, pia_res
):
172 rc
= yield dec2
.e
.do
.rc
.rc
173 cridx_ok
= yield dec2
.e
.write_cr
.ok
174 cridx
= yield dec2
.e
.write_cr
.data
176 print("check extra output", repr(code
), cridx_ok
, cridx
)
178 self
.assertEqual(cridx
, 0, code
)
180 oe
= yield dec2
.e
.do
.oe
.oe
181 oe_ok
= yield dec2
.e
.do
.oe
.ok
182 if not oe
or not oe_ok
:
183 # if OE not enabled, XER SO and OV must correspondingly be false
184 so_ok
= yield alu
.n
.o_data
.xer_so
.ok
185 ov_ok
= yield alu
.n
.o_data
.xer_ov
.ok
186 self
.assertEqual(so_ok
, False, code
)
187 self
.assertEqual(ov_ok
, False, code
)
192 yield from ALUHelpers
.get_cr_a(res
, alu
, dec2
)
193 yield from ALUHelpers
.get_xer_ov(res
, alu
, dec2
)
194 yield from ALUHelpers
.get_int_o(res
, alu
, dec2
)
195 yield from ALUHelpers
.get_xer_so(res
, alu
, dec2
)
197 print("res output", res
)
199 yield from ALUHelpers
.get_sim_int_o(sim_o
, sim
, dec2
)
200 yield from ALUHelpers
.get_wr_sim_cr_a(sim_o
, sim
, dec2
)
201 yield from ALUHelpers
.get_sim_xer_ov(sim_o
, sim
, dec2
)
202 yield from ALUHelpers
.get_sim_xer_so(sim_o
, sim
, dec2
)
204 print("sim output", sim_o
)
206 print("power-instruction-analyzer result:")
208 if pia_res
is not None:
209 with self
.subTest(check
="pia", sim_o
=sim_o
, pia_res
=str(pia_res
)):
210 pia_o
= pia_res_to_output(pia_res
)
211 ALUHelpers
.check_int_o(self
, res
, pia_o
, code
)
212 ALUHelpers
.check_cr_a(self
, res
, pia_o
, code
)
213 ALUHelpers
.check_xer_ov(self
, res
, pia_o
, code
)
214 ALUHelpers
.check_xer_so(self
, res
, pia_o
, code
)
216 with self
.subTest(check
="sim", sim_o
=sim_o
, pia_res
=str(pia_res
)):
217 ALUHelpers
.check_int_o(self
, res
, sim_o
, code
)
218 ALUHelpers
.check_xer_ov(self
, res
, sim_o
, code
)
219 ALUHelpers
.check_xer_so(self
, res
, sim_o
, code
)
220 ALUHelpers
.check_cr_a(self
, res
, sim_o
, "CR%d %s" % (cridx
, code
))