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
152 pspec
= MulPipeSpec(id_wid
=2, parent_pspec
=pps
)
153 m
.submodules
.alu
= alu
= MulBasePipe(pspec
)
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
)
163 for test
in test_data
:
165 with self
.subTest(test
.name
):
166 yield from self
.execute(pdecode2
, test
, instruction
, alu
,
167 has_third_input
, sim
)
169 sim
.add_sync_process(process
)
170 with sim
.write_vcd(f
"{file_name_prefix}.vcd"):
173 def check_alu_outputs(self
, alu
, dec2
, sim
, code
, pia_res
):
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
179 print("check extra output", repr(code
), cridx_ok
, cridx
)
181 self
.assertEqual(cridx
, 0, code
)
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
)
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
)
200 print("res output", res
)
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
)
207 print("sim output", sim_o
)
209 print("power-instruction-analyzer result:")
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
)
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
))