From: Luke Kenneth Casson Leighton Date: Sun, 31 May 2020 18:27:56 +0000 (+0100) Subject: split out common code from test_alu_compunit.py X-Git-Tag: div_pipeline~709 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=7e2999fdb4a418f044d768c1e94e8451760572bc;p=soc.git split out common code from test_alu_compunit.py --- diff --git a/src/soc/fu/compunits/test/test_alu_compunit.py b/src/soc/fu/compunits/test/test_alu_compunit.py index 00fe101b..2d001a0e 100644 --- a/src/soc/fu/compunits/test/test_alu_compunit.py +++ b/src/soc/fu/compunits/test/test_alu_compunit.py @@ -13,6 +13,7 @@ from soc.decoder.isa.all import ISA from soc.fu.alu.test.test_pipe_caller import TestCase, ALUTestCase, test_data from soc.fu.compunits.compunits import ALUFunctionUnit +from soc.fu.compunits.test.test_compunit import TestRunner from soc.experiment.compalu_multi import find_ok # hack import random @@ -63,177 +64,50 @@ def get_cu_output(cu, idx, code): return result -def get_cu_rd_mask(dec2): - mask = 0b1100 # XER CA/SO - - reg3_ok = yield dec2.e.read_reg3.ok - reg1_ok = yield dec2.e.read_reg1.ok - - if reg3_ok or reg1_ok: - mask |= 0b1 - - # If there's an immediate, set the B operand to that - reg2_ok = yield dec2.e.read_reg2.ok - if reg2_ok: - mask |= 0b10 - - return mask - - -def set_cu_inputs(cu, 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 - - 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 - - if reg3_ok or reg1_ok: - yield from set_cu_input(cu, 0, data1) - - # If there's an immediate, set the B operand to that - reg2_ok = yield dec2.e.read_reg2.ok - if reg2_ok: - data2 = yield dec2.e.read_reg2.data - data2 = sim.gpr(data2).value - else: - data2 = 0 - - if reg2_ok: - yield from set_cu_input(cu, 1, data2) - - -def set_operand(cu, dec2, sim): - yield from cu.oper_i.eq_from_execute1(dec2.e) - yield cu.issue_i.eq(1) - yield - yield cu.issue_i.eq(0) - yield - - -def set_extra_cu_inputs(cu, 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 from set_cu_input(cu, 3, carry | (carry32<<1)) - so = 1 if sim.spr['XER'][XER_bits['SO']] else 0 - yield from set_cu_input(cu, 2, so) - - -def get_cu_outputs(cu, code): - res = {} - for i in range(cu.n_dst): - wr_rel_o = yield cu.wr.rel[i] - if wr_rel_o: - result = yield from get_cu_output(cu, i, code) - wrop = cu.get_out_name(i) - print ("output", i, wrop, hex(result)) - res[wrop] = result - return res - - -class TestRunner(FHDLTestCase): +class ALUTestRunner(TestRunner): def __init__(self, test_data): - super().__init__("run_all") - self.test_data = test_data - - def run_all(self): - m = Module() - comb = m.d.comb - instruction = Signal(32) - - pdecode = create_pdecode() - - m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode) - m.submodules.cu = cu = ALUFunctionUnit() - - comb += pdecode2.dec.raw_opcode_in.eq(instruction) - sim = Simulator(m) - - sim.add_clock(1e-6) - - def process(): - yield cu.issue_i.eq(0) - yield - - for test in self.test_data: - print(test.name) - program = test.program - self.subTest(test.name) - sim = ISA(pdecode2, test.regs, test.sprs, 0) - gen = program.generate_instructions() - instructions = list(zip(gen, program.assembly.splitlines())) - - index = sim.pc.CIA.value//4 - while index < len(instructions): - ins, code = instructions[index] - - print("0x{:X}".format(ins & 0xffffffff)) - print(code) - - # ask the decoder to decode this binary data (endian'd) - yield pdecode2.dec.bigendian.eq(0) # little / big? - yield instruction.eq(ins) # raw binary instr. - yield Settle() - fn_unit = yield pdecode2.e.fn_unit - self.assertEqual(fn_unit, Function.ALU.value) - # reset read-operand mask - rdmask = yield from get_cu_rd_mask(pdecode2) - yield cu.rdmaskn.eq(~rdmask) - # reset write-operand mask - for idx in range(cu.n_dst): - wrok = cu.get_out(idx) - fname = find_ok(wrok.fields) - yield getattr(wrok, fname).eq(0) - - # set operand and inputs - yield from set_operand(cu, pdecode2, sim) - rd_rel_o = yield cu.rd.rel - wr_rel_o = yield cu.wr.rel - print ("before inputs, rd_rel, wr_rel: ", - bin(rd_rel_o), bin(wr_rel_o)) - yield from set_cu_inputs(cu, pdecode2, sim) - yield from set_extra_cu_inputs(cu, pdecode2, sim) - yield - rd_rel_o = yield cu.rd.rel - wr_rel_o = yield cu.wr.rel - wrmask = yield cu.wrmask - print ("after inputs, rd_rel, wr_rel, wrmask: ", - bin(rd_rel_o), bin(wr_rel_o), bin(wrmask)) - - # call simulated operation - opname = code.split(' ')[0] - yield from sim.call(opname) - index = sim.pc.CIA.value//4 - - # get all outputs (one by one, just "because") - res = yield from get_cu_outputs(cu, code) - - out_reg_valid = yield pdecode2.e.write_reg.ok - if out_reg_valid: - write_reg_idx = yield pdecode2.e.write_reg.data - expected = sim.gpr(write_reg_idx).value - cu_out = res['o'] - print(f"expected {expected:x}, actual: {cu_out:x}") - self.assertEqual(expected, cu_out, code) - yield from self.check_extra_cu_outputs(res, pdecode2, - sim, code) - - sim.add_sync_process(process) - with sim.write_vcd("simulator.vcd", "simulator.gtkw", - traces=[]): - sim.run() + super().__init__(test_data, ALUFunctionUnit, self) + + def get_cu_inputs(self, 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 + res = {} + + 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 + res[0] = sim.gpr(data1).value + elif reg1_ok: + data1 = yield dec2.e.read_reg1.data + res[0] = sim.gpr(data1).value + + # If there's an immediate, set the B operand to that + reg2_ok = yield dec2.e.read_reg2.ok + if reg2_ok: + data2 = yield dec2.e.read_reg2.data + res[1] = sim.gpr(data2).value + + carry = 1 if sim.spr['XER'][XER_bits['CA']] else 0 + carry32 = 1 if sim.spr['XER'][XER_bits['CA32']] else 0 + res[3] = carry | (carry32<<1) + so = 1 if sim.spr['XER'][XER_bits['SO']] else 0 + res[2] = so + + return res + + def check_cu_outputs(self, res, dec2, sim, code): + out_reg_valid = yield dec2.e.write_reg.ok + if out_reg_valid: + write_reg_idx = yield dec2.e.write_reg.data + expected = sim.gpr(write_reg_idx).value + cu_out = res['o'] + print(f"expected {expected:x}, actual: {cu_out:x}") + self.assertEqual(expected, cu_out, code) - def check_extra_cu_outputs(self, res, dec2, sim, code): rc = yield dec2.e.rc.data op = yield dec2.e.insn_type cridx_ok = yield dec2.e.write_cr.ok @@ -271,7 +145,7 @@ class TestRunner(FHDLTestCase): if __name__ == "__main__": unittest.main(exit=False) suite = unittest.TestSuite() - suite.addTest(TestRunner(test_data)) + suite.addTest(ALUTestRunner(test_data)) runner = unittest.TextTestRunner() runner.run(suite) diff --git a/src/soc/fu/compunits/test/test_compunit.py b/src/soc/fu/compunits/test/test_compunit.py new file mode 100644 index 00000000..93df11e5 --- /dev/null +++ b/src/soc/fu/compunits/test/test_compunit.py @@ -0,0 +1,188 @@ +from nmigen import Module, Signal +from nmigen.back.pysim import Simulator, Delay, Settle +from nmigen.test.utils import FHDLTestCase +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, InternalOp) +from soc.decoder.selectable_int import SelectableInt +from soc.simulator.program import Program +from soc.decoder.isa.all import ISA + +from soc.fu.alu.test.test_pipe_caller import TestCase, ALUTestCase, test_data +from soc.experiment.compalu_multi import find_ok # hack +import random + +def set_cu_input(cu, idx, data): + rdop = cu.get_in_name(idx) + yield cu.src_i[idx].eq(data) + while True: + rd_rel_o = yield cu.rd.rel[idx] + print ("rd_rel %d wait HI" % idx, rd_rel_o, rdop, hex(data)) + if rd_rel_o: + break + yield + yield cu.rd.go[idx].eq(1) + while True: + yield + rd_rel_o = yield cu.rd.rel[idx] + if rd_rel_o: + break + print ("rd_rel %d wait HI" % idx, rd_rel_o) + yield + yield cu.rd.go[idx].eq(0) + + +def get_cu_output(cu, idx, code): + wrmask = yield cu.wrmask + wrop = cu.get_out_name(idx) + wrok = cu.get_out(idx) + fname = find_ok(wrok.fields) + wrok = yield getattr(wrok, fname) + print ("wr_rel mask", repr(code), idx, wrop, bin(wrmask), fname, wrok) + assert wrmask & (1<