3 import power_instruction_analyzer
as pia
4 from nmigen
import Module
, Signal
6 # NOTE: to use cxxsim, export NMIGEN_SIM_MODE=cxxsim from the shell
7 # Also, check out the cxxsim nmigen branch, and latest yosys from git
8 from nmutil
.sim_tmp_alternative
import Simulator
, Delay
10 from openpower
.decoder
.power_decoder
import (create_pdecode
)
11 from openpower
.decoder
.power_decoder2
import (PowerDecode2
)
12 from openpower
.decoder
.power_enums
import XER_bits
, Function
13 from openpower
.decoder
.isa
.all
import ISA
14 from soc
.config
.endian
import bigendian
16 from soc
.fu
.test
.common
import ALUHelpers
17 from soc
.fu
.test
.pia
import pia_res_to_output
18 from soc
.fu
.div
.pipeline
import DivBasePipe
19 from soc
.fu
.div
.pipe_data
import DivPipeSpec
22 def log_rand(n
, min_val
=1):
23 logrange
= random
.randint(1, n
)
24 return random
.randint(min_val
, (1 << logrange
)-1)
27 def get_cu_inputs(dec2
, sim
):
28 """naming (res) must conform to DivFunctionUnit 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_xer_so(res
, sim
, dec2
) # XER.so
36 print("alu get_cu_inputs", res
)
41 def set_alu_inputs(alu
, dec2
, sim
):
42 # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43
43 # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok))
44 # and place it into data_i.b
46 inp
= yield from get_cu_inputs(dec2
, sim
)
47 yield from ALUHelpers
.set_int_ra(alu
, dec2
, inp
)
48 yield from ALUHelpers
.set_int_rb(alu
, dec2
, inp
)
50 yield from ALUHelpers
.set_xer_so(alu
, dec2
, inp
)
55 overflow
= pia
.OverflowFlags(so
=bool(so
),
58 return pia
.InstructionInput(ra
=inp
["ra"], rb
=inp
["rb"], overflow
=overflow
)
61 class DivTestHelper(unittest
.TestCase
):
62 def execute(self
, alu
, instruction
, pdecode2
, test
, div_pipe_kind
, sim
):
64 isa_sim
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
,
67 gen
= prog
.generate_instructions()
68 instructions
= list(zip(gen
, prog
.assembly
.splitlines()))
71 index
= isa_sim
.pc
.CIA
.value
//4
72 while index
< len(instructions
):
73 ins
, code
= instructions
[index
]
75 print("instruction: 0x{:X}".format(ins
& 0xffffffff))
79 so
= 1 if spr
['XER'][XER_bits
['SO']] else 0
80 ov
= 1 if spr
['XER'][XER_bits
['OV']] else 0
81 ov32
= 1 if spr
['XER'][XER_bits
['OV32']] else 0
82 print("before: so/ov/32", so
, ov
, ov32
)
84 # ask the decoder to decode this binary data (endian'd)
86 yield pdecode2
.dec
.bigendian
.eq(bigendian
)
87 yield instruction
.eq(ins
) # raw binary instr.
89 fn_unit
= yield pdecode2
.e
.do
.fn_unit
90 self
.assertEqual(fn_unit
, Function
.DIV
.value
)
91 pia_inputs
= yield from set_alu_inputs(alu
, pdecode2
,
94 # set valid for one cycle, propagate through pipeline..
95 # note that it is critically important to do this
96 # for DIV otherwise it starts trying to produce
98 yield alu
.p
.valid_i
.eq(1)
100 yield alu
.p
.valid_i
.eq(0)
102 opname
= code
.split(' ')[0]
103 fnname
= opname
.replace(".", "_")
104 print(f
"{fnname}({pia_inputs})")
106 pia
, opname
.replace(".", "_"))(pia_inputs
)
107 print(f
"-> {pia_res}")
109 yield from isa_sim
.call(opname
)
110 index
= isa_sim
.pc
.CIA
.value
//4
112 vld
= yield alu
.n
.valid_o
116 # XXX sim._engine is an internal variable
117 # Waiting on https://github.com/nmigen/nmigen/issues/443
119 print(f
"time: {sim._engine.now * 1e6}us")
120 except AttributeError:
122 vld
= yield alu
.n
.valid_o
123 # bug #425 investigation
124 do
= alu
.pipe_end
.div_out
126 is_32bit
= yield ctx_op
.is_32bit
127 is_signed
= yield ctx_op
.is_signed
128 quotient_root
= yield do
.i
.core
.quotient_root
129 quotient_65
= yield do
.quotient_65
130 dive_abs_ov32
= yield do
.i
.dive_abs_ov32
131 div_by_zero
= yield do
.i
.div_by_zero
132 quotient_neg
= yield do
.quotient_neg
133 print("32bit", hex(is_32bit
))
134 print("signed", hex(is_signed
))
135 print("quotient_root", hex(quotient_root
))
136 print("quotient_65", hex(quotient_65
))
137 print("div_by_zero", hex(div_by_zero
))
138 print("dive_abs_ov32", hex(dive_abs_ov32
))
139 print("quotient_neg", hex(quotient_neg
))
144 # XXX sim._engine is an internal variable
145 # Waiting on https://github.com/nmigen/nmigen/issues/443
147 print(f
"check time: {sim._engine.now * 1e6}us")
148 except AttributeError:
150 msg
= "%s: %s" % (div_pipe_kind
.name
, code
)
151 msg
+= f
" {prog.assembly!r} {list(map(hex, test.regs))!r}"
152 yield from self
.check_alu_outputs(alu
, pdecode2
,
157 def run_all(self
, test_data
, div_pipe_kind
, file_name_prefix
):
160 instruction
= Signal(32)
162 pdecode
= create_pdecode()
164 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
166 pspec
= DivPipeSpec(id_wid
=2, div_pipe_kind
=div_pipe_kind
)
167 m
.submodules
.alu
= alu
= DivBasePipe(pspec
)
169 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.do
)
170 comb
+= alu
.n
.ready_i
.eq(1)
171 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
177 for test
in test_data
:
179 with self
.subTest(test
.name
):
180 yield from self
.execute(alu
, instruction
, pdecode2
,
181 test
, div_pipe_kind
, sim
)
183 sim
.add_sync_process(process
)
184 with sim
.write_vcd(f
"{file_name_prefix}_{div_pipe_kind.name}.vcd"):
187 def check_alu_outputs(self
, alu
, dec2
, sim
, code
, pia_res
):
189 rc
= yield dec2
.e
.do
.rc
.data
190 cridx_ok
= yield dec2
.e
.write_cr
.ok
191 cridx
= yield dec2
.e
.write_cr
.data
193 print("check extra output", repr(code
), cridx_ok
, cridx
)
195 self
.assertEqual(cridx
, 0, code
)
200 yield from ALUHelpers
.get_cr_a(res
, alu
, dec2
)
201 yield from ALUHelpers
.get_xer_ov(res
, alu
, dec2
)
202 yield from ALUHelpers
.get_int_o(res
, alu
, dec2
)
203 yield from ALUHelpers
.get_xer_so(res
, alu
, dec2
)
205 print("res output", res
)
207 yield from ALUHelpers
.get_sim_int_o(sim_o
, sim
, dec2
)
208 yield from ALUHelpers
.get_wr_sim_cr_a(sim_o
, sim
, dec2
)
209 yield from ALUHelpers
.get_sim_xer_ov(sim_o
, sim
, dec2
)
210 yield from ALUHelpers
.get_sim_xer_so(sim_o
, sim
, dec2
)
212 print("sim output", sim_o
)
214 print("power-instruction-analyzer result:")
216 if pia_res
is not None:
217 with self
.subTest(check
="pia", sim_o
=sim_o
, pia_res
=str(pia_res
)):
218 pia_o
= pia_res_to_output(pia_res
)
219 ALUHelpers
.check_int_o(self
, res
, pia_o
, code
)
220 ALUHelpers
.check_cr_a(self
, res
, pia_o
, code
)
221 ALUHelpers
.check_xer_ov(self
, res
, pia_o
, code
)
222 ALUHelpers
.check_xer_so(self
, res
, pia_o
, code
)
224 with self
.subTest(check
="sim", sim_o
=sim_o
, pia_res
=str(pia_res
)):
225 ALUHelpers
.check_int_o(self
, res
, sim_o
, code
)
226 ALUHelpers
.check_cr_a(self
, res
, sim_o
, code
)
227 ALUHelpers
.check_xer_ov(self
, res
, sim_o
, code
)
228 ALUHelpers
.check_xer_so(self
, res
, sim_o
, code
)
230 oe
= yield dec2
.e
.do
.oe
.oe
231 oe_ok
= yield dec2
.e
.do
.oe
.ok
232 print("oe, oe_ok", oe
, oe_ok
)
233 if not oe
or not oe_ok
:
234 # if OE not enabled, XER SO and OV must not be activated
235 so_ok
= yield alu
.n
.data_o
.xer_so
.ok
236 ov_ok
= yield alu
.n
.data_o
.xer_ov
.ok
237 print("so, ov", so_ok
, ov_ok
)
238 self
.assertEqual(ov_ok
, False, code
)
239 self
.assertEqual(so_ok
, False, code
)