diff options
-rw-r--r-- | hdl/core/alu.py | 97 | ||||
-rw-r--r-- | hdl/core/opcodes.py | 43 | ||||
-rw-r--r-- | hdl/utils.py | 2 |
3 files changed, 115 insertions, 27 deletions
diff --git a/hdl/core/alu.py b/hdl/core/alu.py index f8a1a25..8693ba7 100644 --- a/hdl/core/alu.py +++ b/hdl/core/alu.py @@ -1,9 +1,11 @@ +from cmath import exp from amaranth import * from amaranth.sim import Simulator, Settle, Delay from enum import Enum, unique from hdl.utils import * from hdl.lib.in_out_buff import InOutBuff +from hdl.config import NUM_RAND_TESTS @unique class AluOpCodes(Enum): @@ -18,10 +20,10 @@ class AluOpCodes(Enum): lleft = 8 lright = 9 aright = 10 - umult = 11 - smult = 12 - # udiv = 13 - # sdiv = 14 + multul = 11 # low 32 bits of unsigned multiplication + multuh = 12 # high 32 bits of unsigned multiplication + multsl = 13 # low 32 bits of signed multiplication + multsh = 14 # high 32 bits of signed multiplication @unique class ALUFlags(Enum): @@ -100,11 +102,17 @@ class ALU(Elaboratable): m.d.comb += tmp2.eq(Cat(0, self.in1).as_signed() >> self.in2[0:5]) m.d.comb += self.tmp.eq(Cat(tmp2[1:33], tmp2[0])) # move shifted bit to carry bit - with m.Case(AluOpCodes.umult.value): - m.d.comb += self.tmp.eq(Cat(self.in1[0:16] * self.in2[0:16], 0)) + with m.Case(AluOpCodes.multul.value): + m.d.comb += self.tmp.eq(Cat((self.in1 * self.in2)[:32], 0)) + + with m.Case(AluOpCodes.multuh.value): + m.d.comb += self.tmp.eq(Cat((self.in1 * self.in2)[32:], 0)) - with m.Case(AluOpCodes.smult.value): - m.d.comb += self.tmp.eq(Cat(self.in1[0:16].as_signed() * self.in2[0:16].as_signed(), 0)) + with m.Case(AluOpCodes.multsl.value): + m.d.comb += self.tmp.eq(Cat((self.in1.as_signed() * self.in2.as_signed())[:32], 0)) + + with m.Case(AluOpCodes.multsh.value): + m.d.comb += self.tmp.eq(Cat((self.in1.as_signed() * self.in2.as_signed())[32:], 0)) # bad juju, @@ -264,6 +272,79 @@ def test_alu_arith_shift_right(): assert 0 == out, f'ERROR: {out} != {0}' sim(dut, proc) +# test low unsigned multiply +def test_alu_mul_low_u(tests=NUM_RAND_TESTS): + dut = ALU(sim=True) + def proc(): + yield dut.op.eq(AluOpCodes.multul.value) + yield dut.c_in.eq(0) + + for _ in range(tests): + in1 = rand_bits_mix(32, sus='u') + in2 = rand_bits_mix(32, sus='u') + yield dut.in1.eq(in1) + yield dut.in2.eq(in2) + yield from eval() + expected = (in1 * in2) & 0xFFFFFFFF + assert (yield dut.out) == expected, f"mul_low_u failed: in1={hex(in1)}, in2={hex(in2)}, out={hex((yield dut.out))}, expected={hex(expected)}" + + sim(dut, proc) + +# test high unsigned multiply +def test_alu_mul_high_u(tests=NUM_RAND_TESTS): + dut = ALU(sim=True) + def proc(): + yield dut.op.eq(AluOpCodes.multuh.value) + yield dut.c_in.eq(0) + + for _ in range(tests): + in1 = rand_bits_mix(32, sus='u') + in2 = rand_bits_mix(32, sus='u') + yield dut.in1.eq(in1) + yield dut.in2.eq(in2) + yield from eval() + expected = ((in1 * in2) >> 32) & 0xFFFFFFFF + assert (yield dut.out) == expected, f"mul_high_u failed: in1={hex(in1)}, in2={hex(in2)}, out={hex((yield dut.out))}, expected={hex(expected)}" + + sim(dut, proc) + +# test low signed multiply +def test_alu_mul_low_s(tests=NUM_RAND_TESTS): + dut = ALU(sim=True) + def proc(): + yield dut.op.eq(AluOpCodes.multsl.value) + yield dut.c_in.eq(0) + + for _ in range(tests): + in1 = rand_bits_mix(32, sus='s') + in2 = rand_bits_mix(32, sus='s') + yield dut.in1.eq(in1) + yield dut.in2.eq(in2) + yield from eval() + expected = (in1 * in2) & 0xFFFFFFFF + assert (yield dut.out) == expected, f"mul_low_s failed: in1={hex(in1)}, in2={hex(in2)}, out={hex((yield dut.out))}, expected={hex(expected)}" + + sim(dut, proc) + +# test high signed multiply +def test_alu_mul_high_s(tests=NUM_RAND_TESTS): + dut = ALU(sim=True) + def proc(): + yield dut.op.eq(AluOpCodes.multsh.value) + yield dut.c_in.eq(0) + + for _ in range(tests): + in1 = rand_bits_mix(32, sus='s') + in2 = rand_bits_mix(32, sus='s') + yield dut.in1.eq(in1) + yield dut.in2.eq(in2) + yield from eval() + expected = ((in1 * in2) >> 32) & 0xFFFFFFFF + assert (yield dut.out) == expected, f"mul_high_s failed: in1={hex(in1)}, in2={hex(in2)}, out={hex((yield dut.out))}, expected={hex(expected)}" + + sim(dut, proc) + + # test unsigned overflow def test_alu_unsigned_overflow(): dut = ALU(sim=True) diff --git a/hdl/core/opcodes.py b/hdl/core/opcodes.py index 09c5d2c..cd1737b 100644 --- a/hdl/core/opcodes.py +++ b/hdl/core/opcodes.py @@ -1,25 +1,29 @@ -from ctypes.wintypes import INT from enum import unique, Enum -from http.client import MULTI_STATUS @unique class OpCodes(Enum): # R-type - NOP = 0x00 ADD = 0x01 - SUB = 0x02 - XOR = 0x03 - OR = 0x04 - AND = 0x05 - LSL = 0x06 - LSR = 0x07 - ASR = 0x08 - MUL = 0x09 - MULU = 0x0A - DIV = 0x0B # not implemented yet - DIVU = 0x0C # not implemented yet + ADDC = 0x02 + SUB = 0x03 + SUBC = 0x04 + XOR = 0x05 + OR = 0x06 + AND = 0x07 + LSL = 0x08 + LSR = 0x09 + ASR = 0x0A + MULL = 0x0B + MULH = 0x0C + MULLU = 0x0D + MULHU = 0x0E + DIV = 0x0F # not implemented yet + DIVU = 0x10 # not implemented yet + LDW = 0x11 + STW = 0x12 + # I-type ADDI = 0x40 @@ -30,16 +34,19 @@ class OpCodes(Enum): LSLI = 0x45 LSRI = 0x46 ASRI = 0x47 - MULI = 0x48 - MULUI = 0x49 - DIVI = 0x4A # not implemented yet - DIVUI = 0x4B # not implemented yet + MULIL = 0x48 + MULIH = 0x49 + MULIU = 0x4A + MULIUH = 0x4B + DIVI = 0x4C # not implemented yet + DIVUI = 0x4D # not implemented yet # J-type JMP = 0x80 JMPI = 0x81 # C-type (control), 2 MSB -> System mode only + NOP = 0x00 CALL = 0xA0 RET = 0xA1 SCALL = 0xA2 diff --git a/hdl/utils.py b/hdl/utils.py index a2f788e..792e8a7 100644 --- a/hdl/utils.py +++ b/hdl/utils.py @@ -133,7 +133,7 @@ def rand_bits_extremes(bits, sus=None): return random.choice(choices) -def rand_bits_mix(bits, low=None, high=None, sus=None, extrem_prob=0.25): +def rand_bits_mix(bits: int|Signal, low:int=None, high:int=None, sus:"None, 'u', 's'"=None, extrem_prob:float=0.25): ''' Take number of bits or a Signal sus determines if the number is signed or unsigned, or both ('s', 'u', or None) |