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 soc
.decoder
.power_decoder
import (create_pdecode
)
11 from soc
.decoder
.power_decoder2
import (PowerDecode2
)
12 from soc
.decoder
.power_enums
import XER_bits
, Function
13 from soc
.decoder
.isa
.all
import ISA
14 from soc
.config
.endian
import bigendian
16 from soc
.fu
.test
.common
import ALUHelpers
17 from soc
.fu
.div
.pipeline
import DivBasePipe
18 from soc
.fu
.div
.pipe_data
import DivPipeSpec
21 def log_rand(n
, min_val
=1):
22 logrange
= random
.randint(1, n
)
23 return random
.randint(min_val
, (1 << logrange
)-1)
26 def get_cu_inputs(dec2
, sim
):
27 """naming (res) must conform to DivFunctionUnit input regspec
31 yield from ALUHelpers
.get_sim_int_ra(res
, sim
, dec2
) # RA
32 yield from ALUHelpers
.get_sim_int_rb(res
, sim
, dec2
) # RB
33 yield from ALUHelpers
.get_sim_xer_so(res
, sim
, dec2
) # XER.so
35 print("alu get_cu_inputs", res
)
40 def pia_res_to_output(pia_res
):
42 if pia_res
.rt
is not None:
43 retval
["o"] = pia_res
.rt
44 if pia_res
.cr0
is not None:
56 if pia_res
.overflow
is not None:
57 overflow
= pia_res
.overflow
64 retval
["xer_so"] = overflow
.so
71 def set_alu_inputs(alu
, dec2
, sim
):
72 # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43
73 # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok))
74 # and place it into data_i.b
76 inp
= yield from get_cu_inputs(dec2
, sim
)
77 yield from ALUHelpers
.set_int_ra(alu
, dec2
, inp
)
78 yield from ALUHelpers
.set_int_rb(alu
, dec2
, inp
)
80 yield from ALUHelpers
.set_xer_so(alu
, dec2
, inp
)
85 overflow
= pia
.OverflowFlags(so
=bool(so
),
88 return pia
.InstructionInput(ra
=inp
["ra"], rb
=inp
["rb"], overflow
=overflow
)
91 class DivTestHelper(unittest
.TestCase
):
92 def execute(self
, alu
, instruction
, pdecode2
, test
, div_pipe_kind
, sim
):
94 isa_sim
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
,
97 gen
= prog
.generate_instructions()
98 instructions
= list(zip(gen
, prog
.assembly
.splitlines()))
101 index
= isa_sim
.pc
.CIA
.value
//4
102 while index
< len(instructions
):
103 ins
, code
= instructions
[index
]
105 print("instruction: 0x{:X}".format(ins
& 0xffffffff))
109 so
= 1 if spr
['XER'][XER_bits
['SO']] else 0
110 ov
= 1 if spr
['XER'][XER_bits
['OV']] else 0
111 ov32
= 1 if spr
['XER'][XER_bits
['OV32']] else 0
112 print("before: so/ov/32", so
, ov
, ov32
)
114 # ask the decoder to decode this binary data (endian'd)
116 yield pdecode2
.dec
.bigendian
.eq(bigendian
)
117 yield instruction
.eq(ins
) # raw binary instr.
119 fn_unit
= yield pdecode2
.e
.do
.fn_unit
120 self
.assertEqual(fn_unit
, Function
.DIV
.value
)
121 pia_inputs
= yield from set_alu_inputs(alu
, pdecode2
,
124 # set valid for one cycle, propagate through pipeline..
125 # note that it is critically important to do this
126 # for DIV otherwise it starts trying to produce
128 yield alu
.p
.valid_i
.eq(1)
130 yield alu
.p
.valid_i
.eq(0)
132 opname
= code
.split(' ')[0]
133 fnname
= opname
.replace(".", "_")
134 print(f
"{fnname}({pia_inputs})")
136 pia
, opname
.replace(".", "_"))(pia_inputs
)
137 print(f
"-> {pia_res}")
139 yield from isa_sim
.call(opname
)
140 index
= isa_sim
.pc
.CIA
.value
//4
142 vld
= yield alu
.n
.valid_o
146 # XXX sim._engine is an internal variable
147 # Waiting on https://github.com/nmigen/nmigen/issues/443
149 print(f
"time: {sim._engine.now * 1e6}us")
150 except AttributeError:
152 vld
= yield alu
.n
.valid_o
153 # bug #425 investigation
154 do
= alu
.pipe_end
.div_out
156 is_32bit
= yield ctx_op
.is_32bit
157 is_signed
= yield ctx_op
.is_signed
158 quotient_root
= yield do
.i
.core
.quotient_root
159 quotient_65
= yield do
.quotient_65
160 dive_abs_ov32
= yield do
.i
.dive_abs_ov32
161 div_by_zero
= yield do
.i
.div_by_zero
162 quotient_neg
= yield do
.quotient_neg
163 print("32bit", hex(is_32bit
))
164 print("signed", hex(is_signed
))
165 print("quotient_root", hex(quotient_root
))
166 print("quotient_65", hex(quotient_65
))
167 print("div_by_zero", hex(div_by_zero
))
168 print("dive_abs_ov32", hex(dive_abs_ov32
))
169 print("quotient_neg", hex(quotient_neg
))
174 # XXX sim._engine is an internal variable
175 # Waiting on https://github.com/nmigen/nmigen/issues/443
177 print(f
"check time: {sim._engine.now * 1e6}us")
178 except AttributeError:
180 msg
= "%s: %s" % (div_pipe_kind
.name
, code
)
181 msg
+= f
" {prog.assembly!r} {list(map(hex, test.regs))!r}"
182 yield from self
.check_alu_outputs(alu
, pdecode2
,
187 def run_all(self
, test_data
, div_pipe_kind
, file_name_prefix
):
190 instruction
= Signal(32)
192 pdecode
= create_pdecode()
194 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
196 pspec
= DivPipeSpec(id_wid
=2, div_pipe_kind
=div_pipe_kind
)
197 m
.submodules
.alu
= alu
= DivBasePipe(pspec
)
199 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
200 comb
+= alu
.n
.ready_i
.eq(1)
201 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
207 for test
in test_data
:
209 with self
.subTest(test
.name
):
210 yield from self
.execute(alu
, instruction
, pdecode2
,
211 test
, div_pipe_kind
, sim
)
213 sim
.add_sync_process(process
)
214 with sim
.write_vcd(f
"{file_name_prefix}_{div_pipe_kind.name}.vcd"):
217 def check_alu_outputs(self
, alu
, dec2
, sim
, code
, pia_res
):
219 rc
= yield dec2
.e
.do
.rc
.data
220 cridx_ok
= yield dec2
.e
.write_cr
.ok
221 cridx
= yield dec2
.e
.write_cr
.data
223 print("check extra output", repr(code
), cridx_ok
, cridx
)
225 self
.assertEqual(cridx
, 0, code
)
230 yield from ALUHelpers
.get_cr_a(res
, alu
, dec2
)
231 yield from ALUHelpers
.get_xer_ov(res
, alu
, dec2
)
232 yield from ALUHelpers
.get_int_o(res
, alu
, dec2
)
233 yield from ALUHelpers
.get_xer_so(res
, alu
, dec2
)
235 print("res output", res
)
237 yield from ALUHelpers
.get_sim_int_o(sim_o
, sim
, dec2
)
238 yield from ALUHelpers
.get_wr_sim_cr_a(sim_o
, sim
, dec2
)
239 yield from ALUHelpers
.get_sim_xer_ov(sim_o
, sim
, dec2
)
240 yield from ALUHelpers
.get_sim_xer_so(sim_o
, sim
, dec2
)
242 print("sim output", sim_o
)
244 print("power-instruction-analyzer result:")
246 if pia_res
is not None:
247 with self
.subTest(check
="pia", sim_o
=sim_o
, pia_res
=str(pia_res
)):
248 pia_o
= pia_res_to_output(pia_res
)
249 ALUHelpers
.check_int_o(self
, res
, pia_o
, code
)
250 ALUHelpers
.check_cr_a(self
, res
, pia_o
, code
)
251 ALUHelpers
.check_xer_ov(self
, res
, pia_o
, code
)
252 ALUHelpers
.check_xer_so(self
, res
, pia_o
, code
)
254 with self
.subTest(check
="sim", sim_o
=sim_o
, pia_res
=str(pia_res
)):
255 ALUHelpers
.check_int_o(self
, res
, sim_o
, code
)
256 ALUHelpers
.check_cr_a(self
, res
, sim_o
, code
)
257 ALUHelpers
.check_xer_ov(self
, res
, sim_o
, code
)
258 ALUHelpers
.check_xer_so(self
, res
, sim_o
, code
)
260 oe
= yield dec2
.e
.do
.oe
.oe
261 oe_ok
= yield dec2
.e
.do
.oe
.ok
262 print("oe, oe_ok", oe
, oe_ok
)
263 if not oe
or not oe_ok
:
264 # if OE not enabled, XER SO and OV must not be activated
265 so_ok
= yield alu
.n
.data_o
.xer_so
.ok
266 ov_ok
= yield alu
.n
.data_o
.xer_ov
.ok
267 print("so, ov", so_ok
, ov_ok
)
268 self
.assertEqual(ov_ok
, False, code
)
269 self
.assertEqual(so_ok
, False, code
)