From: Luke Kenneth Casson Leighton Date: Thu, 28 May 2020 10:41:24 +0000 (+0100) Subject: start on a compunit ALU test X-Git-Tag: div_pipeline~772 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=02bb03089f59a8e131e4632c44da991808eb3067;p=soc.git start on a compunit ALU test --- diff --git a/src/soc/fu/compunits/test/test_alu_compunit.py b/src/soc/fu/compunits/test/test_alu_compunit.py new file mode 100644 index 00000000..0d83e4c5 --- /dev/null +++ b/src/soc/fu/compunits/test/test_alu_compunit.py @@ -0,0 +1,165 @@ +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.fu.compunits import ALUFunctionUnit +import random + + +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 + + 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) + + + +class TestRunner(FHDLTestCase): + 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 += cu.oper_i.eq_from_execute1(pdecode2.e) + comb += alu.p.valid_i.eq(1) + 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) + program = test.program + self.subTest(test.name) + simulator = ISA(pdecode2, test.regs, test.sprs, 0) + gen = program.generate_instructions() + instructions = list(zip(gen, program.assembly.splitlines())) + + index = simulator.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) + yield from set_alu_inputs(alu, pdecode2, simulator) + yield from set_extra_alu_inputs(alu, pdecode2, simulator) + yield + opname = code.split(' ')[0] + yield from simulator.call(opname) + index = simulator.pc.CIA.value//4 + + vld = yield alu.n.valid_o + while not vld: + yield + vld = yield alu.n.valid_o + yield + alu_out = yield alu.n.data_o.o.data + out_reg_valid = yield pdecode2.e.write_reg.ok + if out_reg_valid: + write_reg_idx = yield pdecode2.e.write_reg.data + expected = simulator.gpr(write_reg_idx).value + print(f"expected {expected:x}, actual: {alu_out:x}") + self.assertEqual(expected, alu_out, code) + yield from self.check_extra_alu_outputs(alu, pdecode2, + simulator, code) + + sim.add_sync_process(process) + with sim.write_vcd("simulator.vcd", "simulator.gtkw", + traces=[]): + sim.run() + + def check_extra_alu_outputs(self, alu, dec2, sim, code): + rc = yield dec2.e.rc.data + if rc: + cr_expected = sim.crl[0].get_range().value + cr_actual = yield alu.n.data_o.cr0.data + self.assertEqual(cr_expected, cr_actual, code) + + op = yield dec2.e.insn_type + if op == InternalOp.OP_CMP.value or \ + op == InternalOp.OP_CMPEQB.value: + bf = yield dec2.dec.BF + cr_actual = yield alu.n.data_o.cr0.data + cr_expected = sim.crl[bf].get_range().value + self.assertEqual(cr_expected, cr_actual, code) + + cry_out = yield dec2.e.output_carry + if cry_out: + expected_carry = 1 if sim.spr['XER'][XER_bits['CA']] else 0 + real_carry = yield alu.n.data_o.xer_ca.data[0] # XXX CO not CO32 + self.assertEqual(expected_carry, real_carry, code) + expected_carry32 = 1 if sim.spr['XER'][XER_bits['CA32']] else 0 + real_carry32 = yield alu.n.data_o.xer_ca.data[1] # XXX CO32 + self.assertEqual(expected_carry32, real_carry32, code) + + + +if __name__ == "__main__": + unittest.main(exit=False) + suite = unittest.TestSuite() + suite.addTest(TestRunner(test_data)) + + runner = unittest.TextTestRunner() + runner.run(suite)