summaryrefslogtreecommitdiff
path: root/hdl
diff options
context:
space:
mode:
Diffstat (limited to 'hdl')
-rw-r--r--hdl/core/alu.py97
-rw-r--r--hdl/core/opcodes.py43
-rw-r--r--hdl/utils.py2
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)