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
)
79 if 'xer_so' not in inp
:
83 # XXX doesn't work because it's not being properly kept up-to-date
84 # and we're 2 days before a code-freeze.
85 # https://bugs.libre-soc.org/show_bug.cgi?id=497
88 overflow
= pia
.OverflowFlags(so
=bool(so
),
91 return pia
.InstructionInput(ra
=inp
["ra"], rb
=inp
["rb"], rc
=0,
95 class DivTestHelper(unittest
.TestCase
):
96 def execute(self
, alu
, instruction
, pdecode2
, test
, div_pipe_kind
, sim
):
98 isa_sim
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
,
101 gen
= prog
.generate_instructions()
102 instructions
= list(zip(gen
, prog
.assembly
.splitlines()))
105 index
= isa_sim
.pc
.CIA
.value
//4
106 while index
< len(instructions
):
107 ins
, code
= instructions
[index
]
109 print("instruction: 0x{:X}".format(ins
& 0xffffffff))
113 so
= 1 if spr
['XER'][XER_bits
['SO']] else 0
114 ov
= 1 if spr
['XER'][XER_bits
['OV']] else 0
115 ov32
= 1 if spr
['XER'][XER_bits
['OV32']] else 0
116 print("before: so/ov/32", so
, ov
, ov32
)
118 # ask the decoder to decode this binary data (endian'd)
120 yield pdecode2
.dec
.bigendian
.eq(bigendian
)
121 yield instruction
.eq(ins
) # raw binary instr.
123 fn_unit
= yield pdecode2
.e
.do
.fn_unit
124 self
.assertEqual(fn_unit
, Function
.DIV
.value
)
125 pia_inputs
= yield from set_alu_inputs(alu
, pdecode2
,
128 # set valid for one cycle, propagate through pipeline..
129 # note that it is critically important to do this
130 # for DIV otherwise it starts trying to produce
132 yield alu
.p
.valid_i
.eq(1)
134 yield alu
.p
.valid_i
.eq(0)
136 opname
= code
.split(' ')[0]
137 fnname
= opname
.replace(".", "_")
140 print(f
"{fnname}({pia_inputs})")
142 pia
, opname
.replace(".", "_"))(pia_inputs
)
143 print(f
"-> {pia_res}")
145 yield from isa_sim
.call(opname
)
146 index
= isa_sim
.pc
.CIA
.value
//4
148 vld
= yield alu
.n
.valid_o
152 # XXX sim._engine is an internal variable
153 # Waiting on https://github.com/nmigen/nmigen/issues/443
155 print(f
"time: {sim._engine.now * 1e6}us")
156 except AttributeError:
158 vld
= yield alu
.n
.valid_o
159 # bug #425 investigation
160 do
= alu
.pipe_end
.div_out
162 is_32bit
= yield ctx_op
.is_32bit
163 is_signed
= yield ctx_op
.is_signed
164 quotient_root
= yield do
.i
.core
.quotient_root
165 quotient_65
= yield do
.quotient_65
166 dive_abs_ov32
= yield do
.i
.dive_abs_ov32
167 div_by_zero
= yield do
.i
.div_by_zero
168 quotient_neg
= yield do
.quotient_neg
169 print("32bit", hex(is_32bit
))
170 print("signed", hex(is_signed
))
171 print("quotient_root", hex(quotient_root
))
172 print("quotient_65", hex(quotient_65
))
173 print("div_by_zero", hex(div_by_zero
))
174 print("dive_abs_ov32", hex(dive_abs_ov32
))
175 print("quotient_neg", hex(quotient_neg
))
180 # XXX sim._engine is an internal variable
181 # Waiting on https://github.com/nmigen/nmigen/issues/443
183 print(f
"check time: {sim._engine.now * 1e6}us")
184 except AttributeError:
186 msg
= "%s: %s" % (div_pipe_kind
.name
, code
)
187 msg
+= " %s" % (repr(prog
.assembly
))
188 msg
+= " %s" % (repr(test
.regs
))
189 yield from self
.check_alu_outputs(alu
, pdecode2
,
194 def run_all(self
, test_data
, div_pipe_kind
, file_name_prefix
):
197 instruction
= Signal(32)
199 pdecode
= create_pdecode()
201 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
203 pspec
= DivPipeSpec(id_wid
=2, div_pipe_kind
=div_pipe_kind
)
204 m
.submodules
.alu
= alu
= DivBasePipe(pspec
)
206 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
207 comb
+= alu
.n
.ready_i
.eq(1)
208 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
214 for test
in test_data
:
216 with self
.subTest(test
.name
):
217 yield from self
.execute(alu
, instruction
, pdecode2
,
218 test
, div_pipe_kind
, sim
)
220 sim
.add_sync_process(process
)
221 with sim
.write_vcd(f
"{file_name_prefix}_{div_pipe_kind.name}.vcd"):
224 def check_alu_outputs(self
, alu
, dec2
, sim
, code
, pia_res
):
226 rc
= yield dec2
.e
.do
.rc
.data
227 cridx_ok
= yield dec2
.e
.write_cr
.ok
228 cridx
= yield dec2
.e
.write_cr
.data
230 print("check extra output", repr(code
), cridx_ok
, cridx
)
232 self
.assertEqual(cridx
, 0, code
)
237 yield from ALUHelpers
.get_cr_a(res
, alu
, dec2
)
238 yield from ALUHelpers
.get_xer_ov(res
, alu
, dec2
)
239 yield from ALUHelpers
.get_int_o(res
, alu
, dec2
)
240 yield from ALUHelpers
.get_xer_so(res
, alu
, dec2
)
242 print("res output", res
)
244 yield from ALUHelpers
.get_sim_int_o(sim_o
, sim
, dec2
)
245 yield from ALUHelpers
.get_wr_sim_cr_a(sim_o
, sim
, dec2
)
246 yield from ALUHelpers
.get_sim_xer_ov(sim_o
, sim
, dec2
)
247 yield from ALUHelpers
.get_sim_xer_so(sim_o
, sim
, dec2
)
249 print("sim output", sim_o
)
251 print("power-instruction-analyzer result:")
253 if pia_res
is not None:
254 with self
.subTest(check
="pia", sim_o
=sim_o
, pia_res
=str(pia_res
)):
255 pia_o
= pia_res_to_output(pia_res
)
256 ALUHelpers
.check_int_o(self
, res
, pia_o
, code
)
257 ALUHelpers
.check_cr_a(self
, res
, pia_o
, code
)
258 ALUHelpers
.check_xer_ov(self
, res
, pia_o
, code
)
259 ALUHelpers
.check_xer_so(self
, res
, pia_o
, code
)
261 with self
.subTest(check
="sim", sim_o
=sim_o
, pia_res
=str(pia_res
)):
262 ALUHelpers
.check_int_o(self
, res
, sim_o
, code
)
263 ALUHelpers
.check_cr_a(self
, res
, sim_o
, code
)
264 ALUHelpers
.check_xer_ov(self
, res
, sim_o
, code
)
265 ALUHelpers
.check_xer_so(self
, res
, sim_o
, code
)
267 oe
= yield dec2
.e
.do
.oe
.oe
268 oe_ok
= yield dec2
.e
.do
.oe
.ok
269 print("oe, oe_ok", oe
, oe_ok
)
270 if not oe
or not oe_ok
:
271 # if OE not enabled, XER SO and OV must not be activated
272 so_ok
= yield alu
.n
.data_o
.xer_so
.ok
273 ov_ok
= yield alu
.n
.data_o
.xer_ov
.ok
274 print("so, ov", so_ok
, ov_ok
)
275 self
.assertEqual(ov_ok
, False, code
)
276 self
.assertEqual(so_ok
, False, code
)