From: Jacob Lifshay Date: Tue, 28 Jul 2020 23:49:10 +0000 (-0700) Subject: clean up div pipe tests to allow them to be run in parallel X-Git-Tag: semi_working_ecp5~505 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=96845f04045c47f7e1768d7d033b60860f51bce6;p=soc.git clean up div pipe tests to allow them to be run in parallel --- diff --git a/src/soc/fu/div/test/helper.py b/src/soc/fu/div/test/helper.py new file mode 100644 index 00000000..38a41c91 --- /dev/null +++ b/src/soc/fu/div/test/helper.py @@ -0,0 +1,258 @@ +import random +import unittest +import power_instruction_analyzer as pia +from nmigen import Module, Signal +from nmigen.back.pysim import Simulator, Delay +from soc.decoder.power_decoder import (create_pdecode) +from soc.decoder.power_decoder2 import (PowerDecode2) +from soc.decoder.power_enums import XER_bits, Function +from soc.decoder.isa.all import ISA +from soc.config.endian import bigendian + +from soc.fu.test.common import ALUHelpers +from soc.fu.div.pipeline import DivBasePipe +from soc.fu.div.pipe_data import DivPipeSpec + + +def log_rand(n, min_val=1): + logrange = random.randint(1, n) + return random.randint(min_val, (1 << logrange)-1) + + +def get_cu_inputs(dec2, sim): + """naming (res) must conform to DivFunctionUnit input regspec + """ + res = {} + + yield from ALUHelpers.get_sim_int_ra(res, sim, dec2) # RA + yield from ALUHelpers.get_sim_int_rb(res, sim, dec2) # RB + yield from ALUHelpers.get_sim_xer_so(res, sim, dec2) # XER.so + + print("alu get_cu_inputs", res) + + return res + + +def pia_res_to_output(pia_res): + retval = {} + if pia_res.rt is not None: + retval["o"] = pia_res.rt + if pia_res.cr0 is not None: + cr0 = pia_res.cr0 + v = 0 + if cr0.lt: + v |= 8 + if cr0.gt: + v |= 4 + if cr0.eq: + v |= 2 + if cr0.so: + v |= 1 + retval["cr_a"] = v + if pia_res.overflow is not None: + overflow = pia_res.overflow + v = 0 + if overflow.ov: + v |= 1 + if overflow.ov32: + v |= 2 + retval["xer_ov"] = v + retval["xer_so"] = overflow.so + else: + retval["xer_ov"] = 0 + retval["xer_so"] = 0 + return retval + + +def set_alu_inputs(alu, dec2, sim): + # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43 + # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok)) + # and place it into data_i.b + + inp = yield from get_cu_inputs(dec2, sim) + yield from ALUHelpers.set_int_ra(alu, dec2, inp) + yield from ALUHelpers.set_int_rb(alu, dec2, inp) + + yield from ALUHelpers.set_xer_so(alu, dec2, inp) + return pia.InstructionInput(ra=inp["ra"], rb=inp["rb"], rc=0) + + +class DivTestHelper(unittest.TestCase): + def execute(self, alu, instruction, pdecode2, test, div_pipe_kind): + prog = test.program + isa_sim = ISA(pdecode2, test.regs, test.sprs, test.cr, + test.mem, test.msr, + bigendian=bigendian) + gen = prog.generate_instructions() + instructions = list(zip(gen, prog.assembly.splitlines())) + yield Delay(0.1e-6) + + index = isa_sim.pc.CIA.value//4 + while index < len(instructions): + ins, code = instructions[index] + + print("instruction: 0x{:X}".format(ins & 0xffffffff)) + print(code) + spr = isa_sim.spr + if 'XER' in spr: + so = 1 if spr['XER'][XER_bits['SO']] else 0 + ov = 1 if spr['XER'][XER_bits['OV']] else 0 + ov32 = 1 if spr['XER'][XER_bits['OV32']] else 0 + xer_zero = not (so or ov or ov32) + print("before: so/ov/32", so, ov, ov32) + else: + xer_zero = True + + # ask the decoder to decode this binary data (endian'd) + # little / big? + yield pdecode2.dec.bigendian.eq(bigendian) + yield instruction.eq(ins) # raw binary instr. + yield Delay(0.1e-6) + fn_unit = yield pdecode2.e.do.fn_unit + self.assertEqual(fn_unit, Function.DIV.value) + pia_inputs = yield from set_alu_inputs(alu, pdecode2, + isa_sim) + + # set valid for one cycle, propagate through pipeline.. + # note that it is critically important to do this + # for DIV otherwise it starts trying to produce + # multiple results. + yield alu.p.valid_i.eq(1) + yield + yield alu.p.valid_i.eq(0) + + opname = code.split(' ')[0] + if xer_zero: + fnname = opname.replace(".", "_") + print(f"{fnname}({pia_inputs})") + pia_res = getattr( + pia, opname.replace(".", "_"))(pia_inputs) + print(f"-> {pia_res}") + else: + pia_res = None + + yield from isa_sim.call(opname) + index = isa_sim.pc.CIA.value//4 + + vld = yield alu.n.valid_o + while not vld: + yield + yield Delay(0.1e-6) + vld = yield alu.n.valid_o + # bug #425 investigation + do = alu.pipe_end.div_out + ctx_op = do.i.ctx.op + is_32bit = yield ctx_op.is_32bit + is_signed = yield ctx_op.is_signed + quotient_root = yield do.i.core.quotient_root + quotient_65 = yield do.quotient_65 + dive_abs_ov32 = yield do.i.dive_abs_ov32 + div_by_zero = yield do.i.div_by_zero + quotient_neg = yield do.quotient_neg + print("32bit", hex(is_32bit)) + print("signed", hex(is_signed)) + print("quotient_root", hex(quotient_root)) + print("quotient_65", hex(quotient_65)) + print("div_by_zero", hex(div_by_zero)) + print("dive_abs_ov32", hex(dive_abs_ov32)) + print("quotient_neg", hex(quotient_neg)) + print("") + yield + + yield Delay(0.1e-6) + # XXX sim._state is an internal variable + # and timeline does not exist + # AttributeError: '_SimulatorState' object + # has no attribute 'timeline' + # TODO: raise bugreport with whitequark + # requesting a public API to access this "officially" + # XXX print("time:", sim._state.timeline.now) + msg = "%s: %s" % (div_pipe_kind.name, code) + msg += " %s" % (repr(prog.assembly)) + msg += " %s" % (repr(test.regs)) + yield from self.check_alu_outputs(alu, pdecode2, + isa_sim, msg, + pia_res) + + def run_all(self, test_data, div_pipe_kind, file_name_prefix): + m = Module() + comb = m.d.comb + instruction = Signal(32) + + pdecode = create_pdecode() + + m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode) + + pspec = DivPipeSpec(id_wid=2, div_pipe_kind=div_pipe_kind) + m.submodules.alu = alu = DivBasePipe(pspec) + + comb += alu.p.data_i.ctx.op.eq_from_execute1(pdecode2.e) + comb += alu.n.ready_i.eq(1) + comb += pdecode2.dec.raw_opcode_in.eq(instruction) + sim = Simulator(m) + + sim.add_clock(1e-6) + + def process(): + for test in test_data: + print(test.name) + with self.subTest(test.name): + yield from self.execute(alu, instruction, pdecode2, test, div_pipe_kind) + + sim.add_sync_process(process) + with sim.write_vcd(f"{file_name_prefix}_{div_pipe_kind.name}.vcd"): + sim.run() + + def check_alu_outputs(self, alu, dec2, sim, code, pia_res): + + rc = yield dec2.e.do.rc.data + cridx_ok = yield dec2.e.write_cr.ok + cridx = yield dec2.e.write_cr.data + + print("check extra output", repr(code), cridx_ok, cridx) + if rc: + self.assertEqual(cridx, 0, code) + + sim_o = {} + res = {} + + yield from ALUHelpers.get_cr_a(res, alu, dec2) + yield from ALUHelpers.get_xer_ov(res, alu, dec2) + yield from ALUHelpers.get_int_o(res, alu, dec2) + yield from ALUHelpers.get_xer_so(res, alu, dec2) + + print("res output", res) + + yield from ALUHelpers.get_sim_int_o(sim_o, sim, dec2) + yield from ALUHelpers.get_wr_sim_cr_a(sim_o, sim, dec2) + yield from ALUHelpers.get_sim_xer_ov(sim_o, sim, dec2) + yield from ALUHelpers.get_sim_xer_so(sim_o, sim, dec2) + + print("sim output", sim_o) + + print("power-instruction-analyzer result:") + print(pia_res) + if pia_res is not None: + with self.subTest(check="pia", sim_o=sim_o, pia_res=str(pia_res)): + pia_o = pia_res_to_output(pia_res) + ALUHelpers.check_int_o(self, res, pia_o, code) + ALUHelpers.check_cr_a(self, res, pia_o, code) + ALUHelpers.check_xer_ov(self, res, pia_o, code) + ALUHelpers.check_xer_so(self, res, pia_o, code) + + with self.subTest(check="sim", sim_o=sim_o, pia_res=str(pia_res)): + ALUHelpers.check_int_o(self, res, sim_o, code) + ALUHelpers.check_cr_a(self, res, sim_o, code) + ALUHelpers.check_xer_ov(self, res, sim_o, code) + ALUHelpers.check_xer_so(self, res, sim_o, code) + + oe = yield dec2.e.do.oe.oe + oe_ok = yield dec2.e.do.oe.ok + print("oe, oe_ok", oe, oe_ok) + if not oe or not oe_ok: + # if OE not enabled, XER SO and OV must not be activated + so_ok = yield alu.n.data_o.xer_so.ok + ov_ok = yield alu.n.data_o.xer_ov.ok + print("so, ov", so_ok, ov_ok) + self.assertEqual(ov_ok, False, code) + self.assertEqual(so_ok, False, code) diff --git a/src/soc/fu/div/test/runner.py b/src/soc/fu/div/test/runner.py deleted file mode 100644 index ff2a1385..00000000 --- a/src/soc/fu/div/test/runner.py +++ /dev/null @@ -1,294 +0,0 @@ -import random -import unittest -from nmigen import Module, Signal -from nmigen.back.pysim import Simulator, Delay -from nmigen.cli import rtlil -from soc.decoder.power_decoder import (create_pdecode) -from soc.decoder.power_decoder2 import (PowerDecode2) -from soc.decoder.power_enums import XER_bits, Function -from soc.simulator.program import Program -from soc.decoder.isa.all import ISA -from soc.config.endian import bigendian - -from soc.fu.test.common import ALUHelpers -from soc.fu.div.pipeline import DivBasePipe -from soc.fu.div.pipe_data import DivPipeSpec, DivPipeKind - -import power_instruction_analyzer as pia - - -def log_rand(n, min_val=1): - logrange = random.randint(1, n) - return random.randint(min_val, (1 << logrange)-1) - - -def get_cu_inputs(dec2, sim): - """naming (res) must conform to DivFunctionUnit input regspec - """ - res = {} - - yield from ALUHelpers.get_sim_int_ra(res, sim, dec2) # RA - yield from ALUHelpers.get_sim_int_rb(res, sim, dec2) # RB - yield from ALUHelpers.get_sim_xer_so(res, sim, dec2) # XER.so - - print("alu get_cu_inputs", res) - - return res - - -def pia_res_to_output(pia_res): - retval = {} - if pia_res.rt is not None: - retval["o"] = pia_res.rt - if pia_res.cr0 is not None: - cr0 = pia_res.cr0 - v = 0 - if cr0.lt: - v |= 8 - if cr0.gt: - v |= 4 - if cr0.eq: - v |= 2 - if cr0.so: - v |= 1 - retval["cr_a"] = v - if pia_res.overflow is not None: - overflow = pia_res.overflow - v = 0 - if overflow.ov: - v |= 1 - if overflow.ov32: - v |= 2 - retval["xer_ov"] = v - retval["xer_so"] = overflow.so - else: - retval["xer_ov"] = 0 - retval["xer_so"] = 0 - return retval - - -def set_alu_inputs(alu, dec2, sim): - # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43 - # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok)) - # and place it into data_i.b - - inp = yield from get_cu_inputs(dec2, sim) - yield from ALUHelpers.set_int_ra(alu, dec2, inp) - yield from ALUHelpers.set_int_rb(alu, dec2, inp) - - yield from ALUHelpers.set_xer_so(alu, dec2, inp) - return pia.InstructionInput(ra=inp["ra"], rb=inp["rb"], rc=0) - - -# This test bench is a bit different than is usual. Initially when I -# was writing it, I had all of the tests call a function to create a -# device under test and simulator, initialize the dut, run the -# simulation for ~2 cycles, and assert that the dut output what it -# should have. However, this was really slow, since it needed to -# create and tear down the dut and simulator for every test case. - -# Now, instead of doing that, every test case in DivTestCase puts some -# data into the test_data list below, describing the instructions to -# be tested and the initial state. Once all the tests have been run, -# test_data gets passed to TestRunner which then sets up the DUT and -# simulator once, runs all the data through it, and asserts that the -# results match the pseudocode sim at every cycle. - -# By doing this, I've reduced the time it takes to run the test suite -# massively. Before, it took around 1 minute on my computer, now it -# takes around 3 seconds - - -class DivRunner(unittest.TestCase): - def __init__(self, test_data, div_pipe_kind=None): - print("DivRunner", test_data, div_pipe_kind) - super().__init__("run_all") - self.test_data = test_data - self.div_pipe_kind = div_pipe_kind - - def execute(self, alu, instruction, pdecode2, test): - prog = test.program - isa_sim = ISA(pdecode2, test.regs, test.sprs, test.cr, - test.mem, test.msr, - bigendian=bigendian) - gen = prog.generate_instructions() - instructions = list(zip(gen, prog.assembly.splitlines())) - yield Delay(0.1e-6) - - index = isa_sim.pc.CIA.value//4 - while index < len(instructions): - ins, code = instructions[index] - - print("instruction: 0x{:X}".format(ins & 0xffffffff)) - print(code) - spr = isa_sim.spr - if 'XER' in spr: - so = 1 if spr['XER'][XER_bits['SO']] else 0 - ov = 1 if spr['XER'][XER_bits['OV']] else 0 - ov32 = 1 if spr['XER'][XER_bits['OV32']] else 0 - xer_zero = not (so or ov or ov32) - print("before: so/ov/32", so, ov, ov32) - else: - xer_zero = True - - # ask the decoder to decode this binary data (endian'd) - # little / big? - yield pdecode2.dec.bigendian.eq(bigendian) - yield instruction.eq(ins) # raw binary instr. - yield Delay(0.1e-6) - fn_unit = yield pdecode2.e.do.fn_unit - self.assertEqual(fn_unit, Function.DIV.value) - pia_inputs = yield from set_alu_inputs(alu, pdecode2, - isa_sim) - - # set valid for one cycle, propagate through pipeline.. - # note that it is critically important to do this - # for DIV otherwise it starts trying to produce - # multiple results. - yield alu.p.valid_i.eq(1) - yield - yield alu.p.valid_i.eq(0) - - opname = code.split(' ')[0] - if xer_zero: - fnname = opname.replace(".", "_") - print(f"{fnname}({pia_inputs})") - pia_res = getattr( - pia, opname.replace(".", "_"))(pia_inputs) - print(f"-> {pia_res}") - else: - pia_res = None - - yield from isa_sim.call(opname) - index = isa_sim.pc.CIA.value//4 - - vld = yield alu.n.valid_o - while not vld: - yield - yield Delay(0.1e-6) - vld = yield alu.n.valid_o - # bug #425 investigation - do = alu.pipe_end.div_out - ctx_op = do.i.ctx.op - is_32bit = yield ctx_op.is_32bit - is_signed = yield ctx_op.is_signed - quotient_root = yield do.i.core.quotient_root - quotient_65 = yield do.quotient_65 - dive_abs_ov32 = yield do.i.dive_abs_ov32 - div_by_zero = yield do.i.div_by_zero - quotient_neg = yield do.quotient_neg - print("32bit", hex(is_32bit)) - print("signed", hex(is_signed)) - print("quotient_root", hex(quotient_root)) - print("quotient_65", hex(quotient_65)) - print("div_by_zero", hex(div_by_zero)) - print("dive_abs_ov32", hex(dive_abs_ov32)) - print("quotient_neg", hex(quotient_neg)) - print("") - yield - - yield Delay(0.1e-6) - # XXX sim._state is an internal variable - # and timeline does not exist - # AttributeError: '_SimulatorState' object - # has no attribute 'timeline' - # TODO: raise bugreport with whitequark - # requesting a public API to access this "officially" - # XXX print("time:", sim._state.timeline.now) - msg = "%s: %s" % (self.div_pipe_kind.name, code) - msg += " %s" % (repr(prog.assembly)) - msg += " %s" % (repr(test.regs)) - yield from self.check_alu_outputs(alu, pdecode2, - isa_sim, msg, - pia_res) - - def run_all(self): - # *sigh* this is a mess. unit test gets added by code-walking - # (unittest module) and picked up with a test name. - # we don't want that: we want it explicitly called - # (see div test_pipe_caller.py) - don't know what to do, - # so "fix" it by adding default param and returning here - if self.div_pipe_kind is None: - return - - m = Module() - comb = m.d.comb - instruction = Signal(32) - - pdecode = create_pdecode() - - m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode) - - pspec = DivPipeSpec(id_wid=2, div_pipe_kind=self.div_pipe_kind) - m.submodules.alu = alu = DivBasePipe(pspec) - - comb += alu.p.data_i.ctx.op.eq_from_execute1(pdecode2.e) - comb += alu.n.ready_i.eq(1) - comb += pdecode2.dec.raw_opcode_in.eq(instruction) - sim = Simulator(m) - - sim.add_clock(1e-6) - - def process(): - for test in self.test_data: - print(test.name) - with self.subTest(test.name): - yield from self.execute(alu, instruction, pdecode2, test) - - sim.add_sync_process(process) - with sim.write_vcd(f"div_simulator_{self.div_pipe_kind.name}.vcd"): - sim.run() - - def check_alu_outputs(self, alu, dec2, sim, code, pia_res): - - rc = yield dec2.e.do.rc.data - cridx_ok = yield dec2.e.write_cr.ok - cridx = yield dec2.e.write_cr.data - - print("check extra output", repr(code), cridx_ok, cridx) - if rc: - self.assertEqual(cridx, 0, code) - - sim_o = {} - res = {} - - yield from ALUHelpers.get_cr_a(res, alu, dec2) - yield from ALUHelpers.get_xer_ov(res, alu, dec2) - yield from ALUHelpers.get_int_o(res, alu, dec2) - yield from ALUHelpers.get_xer_so(res, alu, dec2) - - print("res output", res) - - yield from ALUHelpers.get_sim_int_o(sim_o, sim, dec2) - yield from ALUHelpers.get_wr_sim_cr_a(sim_o, sim, dec2) - yield from ALUHelpers.get_sim_xer_ov(sim_o, sim, dec2) - yield from ALUHelpers.get_sim_xer_so(sim_o, sim, dec2) - - print("sim output", sim_o) - - print("power-instruction-analyzer result:") - print(pia_res) - if pia_res is not None: - with self.subTest(check="pia", sim_o=sim_o, pia_res=str(pia_res)): - pia_o = pia_res_to_output(pia_res) - ALUHelpers.check_int_o(self, res, pia_o, code) - ALUHelpers.check_cr_a(self, res, pia_o, code) - ALUHelpers.check_xer_ov(self, res, pia_o, code) - ALUHelpers.check_xer_so(self, res, pia_o, code) - - with self.subTest(check="sim", sim_o=sim_o, pia_res=str(pia_res)): - ALUHelpers.check_int_o(self, res, sim_o, code) - ALUHelpers.check_cr_a(self, res, sim_o, code) - ALUHelpers.check_xer_ov(self, res, sim_o, code) - ALUHelpers.check_xer_so(self, res, sim_o, code) - - oe = yield dec2.e.do.oe.oe - oe_ok = yield dec2.e.do.oe.ok - print("oe, oe_ok", oe, oe_ok) - if not oe or not oe_ok: - # if OE not enabled, XER SO and OV must not be activated - so_ok = yield alu.n.data_o.xer_so.ok - ov_ok = yield alu.n.data_o.xer_ov.ok - print("so, ov", so_ok, ov_ok) - self.assertEqual(ov_ok, False, code) - self.assertEqual(so_ok, False, code) diff --git a/src/soc/fu/div/test/test_all_pipe_caller.py b/src/soc/fu/div/test/test_all_pipe_caller.py deleted file mode 100644 index bf62cd5f..00000000 --- a/src/soc/fu/div/test/test_all_pipe_caller.py +++ /dev/null @@ -1,57 +0,0 @@ -import random -import inspect -import unittest -from soc.simulator.program import Program -from soc.config.endian import bigendian - -from soc.fu.test.common import TestCase, TestAccumulatorBase -from soc.fu.div.test.runner import DivRunner -from soc.fu.div.pipe_data import DivPipeKind - - -class DivTestLong(TestAccumulatorBase): - - def case_all(self): - instrs = [] - for width in ("w", "d"): - for sign in ("", "u"): - for ov in ("", "o"): - for cnd in ("", "."): - instrs += ["div" + width + sign + ov + cnd, - "div" + width + "e" + sign + ov + cnd] - for sign in ("s", "u"): - instrs += ["mod" + sign + width] - test_values = [ - 0x0, - 0x1, - 0x2, - 0xFFFF_FFFF_FFFF_FFFF, - 0xFFFF_FFFF_FFFF_FFFE, - 0x7FFF_FFFF_FFFF_FFFF, - 0x8000_0000_0000_0000, - 0x1234_5678_0000_0000, - 0x1234_5678_8000_0000, - 0x1234_5678_FFFF_FFFF, - 0x1234_5678_7FFF_FFFF, - ] - for instr in instrs: - l = [f"{instr} 3, 1, 2"] - for ra in test_values: - for rb in test_values: - initial_regs = [0] * 32 - initial_regs[1] = ra - initial_regs[2] = rb - # use "with" so as to close the files used - with Program(l, bigendian) as prog: - self.add_case(prog, initial_regs) - - -if __name__ == "__main__": - unittest.main(exit=False) - suite = unittest.TestSuite() - suite.addTest(DivRunner(DivTestLong().test_data, DivPipeKind.DivPipeCore)) - suite.addTest(DivRunner(DivTestLong().test_data, DivPipeKind.FSMDivCore)) - suite.addTest(DivRunner(DivTestLong().test_data, DivPipeKind.SimOnly)) - - runner = unittest.TextTestRunner() - runner.run(suite) diff --git a/src/soc/fu/div/test/test_pipe_caller.py b/src/soc/fu/div/test/test_pipe_caller.py index 88e72155..55180261 100644 --- a/src/soc/fu/div/test/test_pipe_caller.py +++ b/src/soc/fu/div/test/test_pipe_caller.py @@ -6,8 +6,8 @@ from soc.config.endian import bigendian from soc.fu.test.common import (TestCase, TestAccumulatorBase) from soc.fu.div.pipe_data import DivPipeKind -from soc.fu.div.test.runner import (log_rand, get_cu_inputs, - set_alu_inputs, DivRunner) +from soc.fu.div.test.helper import (log_rand, get_cu_inputs, + set_alu_inputs, DivTestHelper) class DivTestCases(TestAccumulatorBase): @@ -164,12 +164,19 @@ class DivTestCases(TestAccumulatorBase): self.add_case(prog, initial_regs) +class TestPipe(DivTestHelper): + def test_div_pipe_core(self): + self.run_all(DivTestCases().test_data, + DivPipeKind.DivPipeCore, "div_pipe_caller") + + def test_fsm_div_core(self): + self.run_all(DivTestCases().test_data, + DivPipeKind.FSMDivCore, "div_pipe_caller") + + def test_sim_only(self): + self.run_all(DivTestCases().test_data, + DivPipeKind.SimOnly, "div_pipe_caller") + + if __name__ == "__main__": - unittest.main(exit=False) - suite = unittest.TestSuite() - suite.addTest(DivRunner(DivTestCases().test_data, DivPipeKind.DivPipeCore)) - suite.addTest(DivRunner(DivTestCases().test_data, DivPipeKind.FSMDivCore)) - suite.addTest(DivRunner(DivTestCases().test_data, DivPipeKind.SimOnly)) - - runner = unittest.TextTestRunner() - runner.run(suite) + unittest.main() diff --git a/src/soc/fu/div/test/test_pipe_caller_long.py b/src/soc/fu/div/test/test_pipe_caller_long.py new file mode 100644 index 00000000..5a8d205f --- /dev/null +++ b/src/soc/fu/div/test/test_pipe_caller_long.py @@ -0,0 +1,61 @@ +import unittest +from soc.simulator.program import Program +from soc.config.endian import bigendian + +from soc.fu.test.common import TestAccumulatorBase +from soc.fu.div.test.helper import DivTestHelper +from soc.fu.div.pipe_data import DivPipeKind + + +class DivTestLong(TestAccumulatorBase): + def case_all(self): + instrs = [] + for width in ("w", "d"): + for sign in ("", "u"): + for ov in ("", "o"): + for cnd in ("", "."): + instrs += ["div" + width + sign + ov + cnd, + "div" + width + "e" + sign + ov + cnd] + for sign in ("s", "u"): + instrs += ["mod" + sign + width] + test_values = [ + 0x0, + 0x1, + 0x2, + 0xFFFF_FFFF_FFFF_FFFF, + 0xFFFF_FFFF_FFFF_FFFE, + 0x7FFF_FFFF_FFFF_FFFF, + 0x8000_0000_0000_0000, + 0x1234_5678_0000_0000, + 0x1234_5678_8000_0000, + 0x1234_5678_FFFF_FFFF, + 0x1234_5678_7FFF_FFFF, + ] + for instr in instrs: + l = [f"{instr} 3, 1, 2"] + for ra in test_values: + for rb in test_values: + initial_regs = [0] * 32 + initial_regs[1] = ra + initial_regs[2] = rb + # use "with" so as to close the files used + with Program(l, bigendian) as prog: + self.add_case(prog, initial_regs) + + +class TestPipeLong(DivTestHelper): + def test_div_pipe_core(self): + self.run_all(DivTestLong().test_data, + DivPipeKind.DivPipeCore, "div_pipe_caller_long") + + def test_fsm_div_core(self): + self.run_all(DivTestLong().test_data, + DivPipeKind.FSMDivCore, "div_pipe_caller_long") + + def test_sim_only(self): + self.run_all(DivTestLong().test_data, + DivPipeKind.SimOnly, "div_pipe_caller_long") + + +if __name__ == "__main__": + unittest.main()