X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fsoc%2Ffu%2Fdiv%2Ftest%2Ftest_pipe_caller.py;h=a6ee55057e9d663df0dc42424f315290b6398bad;hb=78096b62db0345846cca70ab2f75f9c3519006c4;hp=3b58490deb247e0e4f852887897aad44aa2e4e08;hpb=736b7c87a60181ba6c761ddcf1b70487bcb80e41;p=soc.git diff --git a/src/soc/fu/div/test/test_pipe_caller.py b/src/soc/fu/div/test/test_pipe_caller.py index 3b58490d..a6ee5505 100644 --- a/src/soc/fu/div/test/test_pipe_caller.py +++ b/src/soc/fu/div/test/test_pipe_caller.py @@ -1,27 +1,37 @@ +import random +import unittest from nmigen import Module, Signal -from nmigen.back.pysim import Simulator, Delay, Settle -from nmutil.formaltest import FHDLTestCase +from nmigen.back.pysim import Simulator, Delay from nmigen.cli import rtlil -import unittest -from soc.decoder.isa.caller import ISACaller, special_sprs 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.selectable_int import SelectableInt +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 (TestCase, ALUHelpers) from soc.fu.div.pipeline import DivBasePipe -from soc.fu.div.pipe_data import DivPipeSpec -import random +from soc.fu.div.pipe_data import DivPipeSpec, DivPipeKind + + +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 -class TestCase: - def __init__(self, program, regs, sprs, name): - self.program = program - self.regs = regs - self.sprs = sprs - self.name = name + print("alu get_cu_inputs", res) + + return res def set_alu_inputs(alu, dec2, sim): @@ -29,40 +39,11 @@ def set_alu_inputs(alu, dec2, sim): # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok)) # and place it into data_i.b - reg3_ok = yield dec2.e.read_reg3.ok - reg1_ok = yield dec2.e.read_reg1.ok - assert reg3_ok != reg1_ok - if reg3_ok: - data1 = yield dec2.e.read_reg3.data - data1 = sim.gpr(data1).value - elif reg1_ok: - data1 = yield dec2.e.read_reg1.data - data1 = sim.gpr(data1).value - else: - data1 = 0 - - yield alu.p.data_i.a.eq(data1) - - # If there's an immediate, set the B operand to that - reg2_ok = yield dec2.e.read_reg2.ok - imm_ok = yield dec2.e.imm_data.imm_ok - if imm_ok: - data2 = yield dec2.e.imm_data.imm - elif reg2_ok: - data2 = yield dec2.e.read_reg2.data - data2 = sim.gpr(data2).value - else: - data2 = 0 - yield alu.p.data_i.b.eq(data2) - - -def set_extra_alu_inputs(alu, dec2, sim): - carry = 1 if sim.spr['XER'][XER_bits['CA']] else 0 - carry32 = 1 if sim.spr['XER'][XER_bits['CA32']] else 0 - yield alu.p.data_i.xer_ca[0].eq(carry) - yield alu.p.data_i.xer_ca[1].eq(carry32) - so = 1 if sim.spr['XER'][XER_bits['SO']] else 0 - yield alu.p.data_i.xer_so.eq(so) + 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) # This test bench is a bit different than is usual. Initially when I @@ -72,7 +53,7 @@ def set_extra_alu_inputs(alu, dec2, sim): # 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 ALUTestCase puts some +# 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 @@ -83,106 +64,193 @@ def set_extra_alu_inputs(alu, dec2, sim): # massively. Before, it took around 1 minute on my computer, now it # takes around 3 seconds -test_data = [] +class DivTestCases: + def __init__(self): + self.test_data = [] + for n, v in self.__class__.__dict__.items(): + if n.startswith("test") and callable(v): + self._current_test_name = n + v(self) -class DivTestCase(FHDLTestCase): - def __init__(self, name): - super().__init__(name) - self.test_name = name + def run_test_program(self, prog, initial_regs=None, initial_sprs=None): + tc = TestCase(prog, self._current_test_name, + initial_regs, initial_sprs) + self.test_data.append(tc) - def run_tst_program(self, prog, initial_regs=[0] * 32, initial_sprs={}): - tc = TestCase(prog, initial_regs, initial_sprs, self.test_name) - test_data.append(tc) - - def test_rand(self): - insns = ["and", "or", "xor"] + def tst_0_regression(self): for i in range(40): - choice = random.choice(insns) - lst = [f"{choice} 3, 1, 2"] + lst = ["divwo 3, 1, 2"] initial_regs = [0] * 32 - initial_regs[1] = random.randint(0, (1 << 64)-1) - initial_regs[2] = random.randint(0, (1 << 64)-1) - self.run_tst_program(Program(lst), initial_regs) + initial_regs[1] = 0xbc716835f32ac00c + initial_regs[2] = 0xcdf69a7f7042db66 + self.run_test_program(Program(lst, bigendian), initial_regs) - def test_rand_imm_logical(self): - insns = ["andi.", "andis.", "ori", "oris", "xori", "xoris"] - for i in range(10): - choice = random.choice(insns) - imm = random.randint(0, (1 << 16)-1) - lst = [f"{choice} 3, 1, {imm}"] - print(lst) - initial_regs = [0] * 32 - initial_regs[1] = random.randint(0, (1 << 64)-1) - self.run_tst_program(Program(lst), initial_regs) + def tst_1_regression(self): + lst = ["divwo 3, 1, 2"] + initial_regs = [0] * 32 + initial_regs[1] = 0x10000000000000000-4 + initial_regs[2] = 0x10000000000000000-2 + self.run_test_program(Program(lst, bigendian), initial_regs) - def test_cntz(self): - insns = ["cntlzd", "cnttzd", "cntlzw", "cnttzw"] - for i in range(100): - choice = random.choice(insns) - lst = [f"{choice} 3, 1"] - print(lst) - initial_regs = [0] * 32 - initial_regs[1] = random.randint(0, (1 << 64)-1) - self.run_tst_program(Program(lst), initial_regs) + def tst_2_regression(self): + lst = ["divwo 3, 1, 2"] + initial_regs = [0] * 32 + initial_regs[1] = 0xffffffffffff9321 + initial_regs[2] = 0xffffffffffff7012 + self.run_test_program(Program(lst, bigendian), initial_regs) - def test_parity(self): - insns = ["prtyw", "prtyd"] - for i in range(10): - choice = random.choice(insns) - lst = [f"{choice} 3, 1"] - print(lst) - initial_regs = [0] * 32 - initial_regs[1] = random.randint(0, (1 << 64)-1) - self.run_tst_program(Program(lst), initial_regs) + def tst_3_regression(self): + lst = ["divwo. 3, 1, 2"] + initial_regs = [0] * 32 + initial_regs[1] = 0x1b8e32f2458746af + initial_regs[2] = 0x6b8aee2ccf7d62e9 + self.run_test_program(Program(lst, bigendian), initial_regs) - def test_popcnt(self): - insns = ["popcntb", "popcntw", "popcntd"] - for i in range(10): - choice = random.choice(insns) - lst = [f"{choice} 3, 1"] - print(lst) - initial_regs = [0] * 32 - initial_regs[1] = random.randint(0, (1 << 64)-1) - self.run_tst_program(Program(lst), initial_regs) + def tst_4_regression(self): + lst = ["divw 3, 1, 2"] + initial_regs = [0] * 32 + initial_regs[1] = 0x1c4e6c2f3aa4a05c + initial_regs[2] = 0xe730c2eed6cc8dd7 + self.run_test_program(Program(lst, bigendian), initial_regs) - def test_popcnt_edge(self): - insns = ["popcntb", "popcntw", "popcntd"] - for choice in insns: - lst = [f"{choice} 3, 1"] - initial_regs = [0] * 32 - initial_regs[1] = -1 - self.run_tst_program(Program(lst), initial_regs) + def tst_5_regression(self): + lst = ["divw 3, 1, 2", + "divwo. 6, 4, 5"] + initial_regs = [0] * 32 + initial_regs[1] = 0x1c4e6c2f3aa4a05c + initial_regs[2] = 0xe730c2eed6cc8dd7 + initial_regs[4] = 0x1b8e32f2458746af + initial_regs[5] = 0x6b8aee2ccf7d62e9 + self.run_test_program(Program(lst, bigendian), initial_regs) + + def tst_6_regression(self): + # CR0 not getting set properly for this one + # turns out that overflow is not set correctly in + # fu/div/output_stage.py calc_overflow + # https://bugs.libre-soc.org/show_bug.cgi?id=425 + lst = ["divw. 3, 1, 2"] + initial_regs = [0] * 32 + initial_regs[1] = 0x61c1cc3b80f2a6af + initial_regs[2] = 0x9dc66a7622c32bc0 + self.run_test_program(Program(lst, bigendian), initial_regs) + + def tst_7_regression(self): + # https://bugs.libre-soc.org/show_bug.cgi?id=425 + lst = ["divw. 3, 1, 2"] + initial_regs = [0] * 32 + initial_regs[1] = 0xf1791627e05e8096 + initial_regs[2] = 0xffc868bf4573da0b + self.run_test_program(Program(lst, bigendian), initial_regs) + + def tst_divw_by_zero_1(self): + lst = ["divw. 3, 1, 2"] + initial_regs = [0] * 32 + initial_regs[1] = 0x1 + initial_regs[2] = 0x0 + self.run_test_program(Program(lst, bigendian), initial_regs) - def test_cmpb(self): - lst = ["cmpb 3, 1, 2"] + def tst_divw_overflow2(self): + lst = ["divw. 3, 1, 2"] initial_regs = [0] * 32 - initial_regs[1] = 0xdeadbeefcafec0de - initial_regs[2] = 0xd0adb0000afec1de - self.run_tst_program(Program(lst), initial_regs) + initial_regs[1] = 0x80000000 + initial_regs[2] = 0xffffffffffffffff # top bits don't seem to matter + self.run_test_program(Program(lst, bigendian), initial_regs) - def test_bpermd(self): - lst = ["bpermd 3, 1, 2"] - for i in range(20): + def tst_divw_overflow3(self): + lst = ["divw. 3, 1, 2"] + initial_regs = [0] * 32 + initial_regs[1] = 0x80000000 + initial_regs[2] = 0xffffffff + self.run_test_program(Program(lst, bigendian), initial_regs) + + def tst_divwuo_regression_1(self): + lst = ["divwuo. 3, 1, 2"] + initial_regs = [0] * 32 + initial_regs[1] = 0x7591a398c4e32b68 + initial_regs[2] = 0x48674ab432867d69 + self.run_test_program(Program(lst, bigendian), initial_regs) + + def tst_divwuo_1(self): + lst = ["divwuo. 3, 1, 2"] + initial_regs = [0] * 32 + initial_regs[1] = 0x50 + initial_regs[2] = 0x2 + self.run_test_program(Program(lst, bigendian), initial_regs) + + def test_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 + prog = Program(l, bigendian) + self.run_test_program(prog, initial_regs) + + def tst_rand_divwu(self): + insns = ["divwu", "divwu.", "divwuo", "divwuo."] + for i in range(40): + choice = random.choice(insns) + lst = [f"{choice} 3, 1, 2"] initial_regs = [0] * 32 - initial_regs[1] = 1<