3 import power_instruction_analyzer
as pia
4 from nmigen
import Module
, Signal
5 from nmigen
.back
.pysim
import Simulator
, Delay
6 from soc
.decoder
.power_decoder
import (create_pdecode
)
7 from soc
.decoder
.power_decoder2
import (PowerDecode2
)
8 from soc
.decoder
.power_enums
import XER_bits
, Function
9 from soc
.decoder
.isa
.all
import ISA
10 from soc
.config
.endian
import bigendian
12 from soc
.fu
.test
.common
import ALUHelpers
13 from soc
.fu
.div
.pipeline
import DivBasePipe
14 from soc
.fu
.div
.pipe_data
import DivPipeSpec
17 def log_rand(n
, min_val
=1):
18 logrange
= random
.randint(1, n
)
19 return random
.randint(min_val
, (1 << logrange
)-1)
22 def get_cu_inputs(dec2
, sim
):
23 """naming (res) must conform to DivFunctionUnit input regspec
27 yield from ALUHelpers
.get_sim_int_ra(res
, sim
, dec2
) # RA
28 yield from ALUHelpers
.get_sim_int_rb(res
, sim
, dec2
) # RB
29 yield from ALUHelpers
.get_sim_xer_so(res
, sim
, dec2
) # XER.so
31 print("alu get_cu_inputs", res
)
36 def pia_res_to_output(pia_res
):
38 if pia_res
.rt
is not None:
39 retval
["o"] = pia_res
.rt
40 if pia_res
.cr0
is not None:
52 if pia_res
.overflow
is not None:
53 overflow
= pia_res
.overflow
60 retval
["xer_so"] = overflow
.so
67 def set_alu_inputs(alu
, dec2
, sim
):
68 # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43
69 # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok))
70 # and place it into data_i.b
72 inp
= yield from get_cu_inputs(dec2
, sim
)
73 yield from ALUHelpers
.set_int_ra(alu
, dec2
, inp
)
74 yield from ALUHelpers
.set_int_rb(alu
, dec2
, inp
)
76 yield from ALUHelpers
.set_xer_so(alu
, dec2
, inp
)
81 overflow
= pia
.OverflowFlags(so
=bool(so
),
84 return pia
.InstructionInput(ra
=inp
["ra"], rb
=inp
["rb"], overflow
=overflow
)
87 class DivTestHelper(unittest
.TestCase
):
88 def execute(self
, alu
, instruction
, pdecode2
, test
, div_pipe_kind
, sim
):
90 isa_sim
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
,
93 gen
= prog
.generate_instructions()
94 instructions
= list(zip(gen
, prog
.assembly
.splitlines()))
97 index
= isa_sim
.pc
.CIA
.value
//4
98 while index
< len(instructions
):
99 ins
, code
= instructions
[index
]
101 print("instruction: 0x{:X}".format(ins
& 0xffffffff))
105 so
= 1 if spr
['XER'][XER_bits
['SO']] else 0
106 ov
= 1 if spr
['XER'][XER_bits
['OV']] else 0
107 ov32
= 1 if spr
['XER'][XER_bits
['OV32']] else 0
108 print("before: so/ov/32", so
, ov
, ov32
)
110 # ask the decoder to decode this binary data (endian'd)
112 yield pdecode2
.dec
.bigendian
.eq(bigendian
)
113 yield instruction
.eq(ins
) # raw binary instr.
115 fn_unit
= yield pdecode2
.e
.do
.fn_unit
116 self
.assertEqual(fn_unit
, Function
.DIV
.value
)
117 pia_inputs
= yield from set_alu_inputs(alu
, pdecode2
,
120 # set valid for one cycle, propagate through pipeline..
121 # note that it is critically important to do this
122 # for DIV otherwise it starts trying to produce
124 yield alu
.p
.valid_i
.eq(1)
126 yield alu
.p
.valid_i
.eq(0)
128 opname
= code
.split(' ')[0]
129 fnname
= opname
.replace(".", "_")
130 print(f
"{fnname}({pia_inputs})")
132 pia
, opname
.replace(".", "_"))(pia_inputs
)
133 print(f
"-> {pia_res}")
135 yield from isa_sim
.call(opname
)
136 index
= isa_sim
.pc
.CIA
.value
//4
138 vld
= yield alu
.n
.valid_o
142 # XXX sim._engine is an internal variable
143 # Waiting on https://github.com/nmigen/nmigen/issues/443
145 print(f
"time: {sim._engine.now * 1e6}us")
146 except AttributeError:
148 vld
= yield alu
.n
.valid_o
149 # bug #425 investigation
150 do
= alu
.pipe_end
.div_out
152 is_32bit
= yield ctx_op
.is_32bit
153 is_signed
= yield ctx_op
.is_signed
154 quotient_root
= yield do
.i
.core
.quotient_root
155 quotient_65
= yield do
.quotient_65
156 dive_abs_ov32
= yield do
.i
.dive_abs_ov32
157 div_by_zero
= yield do
.i
.div_by_zero
158 quotient_neg
= yield do
.quotient_neg
159 print("32bit", hex(is_32bit
))
160 print("signed", hex(is_signed
))
161 print("quotient_root", hex(quotient_root
))
162 print("quotient_65", hex(quotient_65
))
163 print("div_by_zero", hex(div_by_zero
))
164 print("dive_abs_ov32", hex(dive_abs_ov32
))
165 print("quotient_neg", hex(quotient_neg
))
170 # XXX sim._engine is an internal variable
171 # Waiting on https://github.com/nmigen/nmigen/issues/443
173 print(f
"check time: {sim._engine.now * 1e6}us")
174 except AttributeError:
176 msg
= "%s: %s" % (div_pipe_kind
.name
, code
)
177 msg
+= " %s" % (repr(prog
.assembly
))
178 msg
+= " %s" % (repr(test
.regs
))
179 yield from self
.check_alu_outputs(alu
, pdecode2
,
184 def run_all(self
, test_data
, div_pipe_kind
, file_name_prefix
):
187 instruction
= Signal(32)
189 pdecode
= create_pdecode()
191 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
193 pspec
= DivPipeSpec(id_wid
=2, div_pipe_kind
=div_pipe_kind
)
194 m
.submodules
.alu
= alu
= DivBasePipe(pspec
)
196 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
197 comb
+= alu
.n
.ready_i
.eq(1)
198 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
204 for test
in test_data
:
206 with self
.subTest(test
.name
):
207 yield from self
.execute(alu
, instruction
, pdecode2
,
208 test
, div_pipe_kind
, sim
)
210 sim
.add_sync_process(process
)
211 with sim
.write_vcd(f
"{file_name_prefix}_{div_pipe_kind.name}.vcd"):
214 def check_alu_outputs(self
, alu
, dec2
, sim
, code
, pia_res
):
216 rc
= yield dec2
.e
.do
.rc
.data
217 cridx_ok
= yield dec2
.e
.write_cr
.ok
218 cridx
= yield dec2
.e
.write_cr
.data
220 print("check extra output", repr(code
), cridx_ok
, cridx
)
222 self
.assertEqual(cridx
, 0, code
)
227 yield from ALUHelpers
.get_cr_a(res
, alu
, dec2
)
228 yield from ALUHelpers
.get_xer_ov(res
, alu
, dec2
)
229 yield from ALUHelpers
.get_int_o(res
, alu
, dec2
)
230 yield from ALUHelpers
.get_xer_so(res
, alu
, dec2
)
232 print("res output", res
)
234 yield from ALUHelpers
.get_sim_int_o(sim_o
, sim
, dec2
)
235 yield from ALUHelpers
.get_wr_sim_cr_a(sim_o
, sim
, dec2
)
236 yield from ALUHelpers
.get_sim_xer_ov(sim_o
, sim
, dec2
)
237 yield from ALUHelpers
.get_sim_xer_so(sim_o
, sim
, dec2
)
239 print("sim output", sim_o
)
241 print("power-instruction-analyzer result:")
243 if pia_res
is not None:
244 with self
.subTest(check
="pia", sim_o
=sim_o
, pia_res
=str(pia_res
)):
245 pia_o
= pia_res_to_output(pia_res
)
246 ALUHelpers
.check_int_o(self
, res
, pia_o
, code
)
247 ALUHelpers
.check_cr_a(self
, res
, pia_o
, code
)
248 ALUHelpers
.check_xer_ov(self
, res
, pia_o
, code
)
249 ALUHelpers
.check_xer_so(self
, res
, pia_o
, code
)
251 with self
.subTest(check
="sim", sim_o
=sim_o
, pia_res
=str(pia_res
)):
252 ALUHelpers
.check_int_o(self
, res
, sim_o
, code
)
253 ALUHelpers
.check_cr_a(self
, res
, sim_o
, code
)
254 ALUHelpers
.check_xer_ov(self
, res
, sim_o
, code
)
255 ALUHelpers
.check_xer_so(self
, res
, sim_o
, code
)
257 oe
= yield dec2
.e
.do
.oe
.oe
258 oe_ok
= yield dec2
.e
.do
.oe
.ok
259 print("oe, oe_ok", oe
, oe_ok
)
260 if not oe
or not oe_ok
:
261 # if OE not enabled, XER SO and OV must not be activated
262 so_ok
= yield alu
.n
.data_o
.xer_so
.ok
263 ov_ok
= yield alu
.n
.data_o
.xer_ov
.ok
264 print("so, ov", so_ok
, ov_ok
)
265 self
.assertEqual(ov_ok
, False, code
)
266 self
.assertEqual(so_ok
, False, code
)