summaryrefslogtreecommitdiff
path: root/hdl
diff options
context:
space:
mode:
Diffstat (limited to 'hdl')
-rw-r--r--hdl/core.py209
1 files changed, 135 insertions, 74 deletions
diff --git a/hdl/core.py b/hdl/core.py
index 17e2b33..655af68 100644
--- a/hdl/core.py
+++ b/hdl/core.py
@@ -1,6 +1,7 @@
from multiprocessing import dummy
from amaranth import *
from amaranth.sim import Simulator, Settle, Delay
+from enum import Enum, unique
from utils import cmd
@@ -78,23 +79,44 @@ from utils import cmd
# return m
+@unique
+class AluOpCodes(Enum):
+ add = 0
+ addc = 1
+ sub = 2
+ subc = 3
+ bit_and = 4
+ bit_or = 5
+ bit_xor = 6
+ bit_nor = 7
+ lleft = 8
+ lright = 9
+ aright = 10
+ set_bit = 11
+ clear_bit = 12
+ umult = 13
+ smult = 14
+ udiv = 15
+ sdiv = 16
+
class ALU(Elaboratable):
def __init__(self, sim=False):
self.in1 = Signal(32, reset_less=True)
self.in2 = Signal(32, reset_less=True)
+ self.c_in = Signal(1)
self.out = Signal(32, reset_less=True)
self.op = Signal(4, reset_less=True)
self.tmp = Signal(33, reset_less=True)
- self.signed_op = Signal(1, reset_less=True)
- self.carry = Signal(1, reset_less=True)
+ self.c_out = Signal(1, reset_less=True)
self.overflow = Signal(1, reset_less=True)
self.zero = Signal(1, reset_less=True)
- self.sign = Signal(1, reset_less=True)
+ self.neg = Signal(1, reset_less=True)
+ self.odd = Signal(1, reset_less=True)
self.sim = sim
- self.ports = [self.in1, self.in2, self.op, self.out, self.carry, self.overflow, self.zero, self.sign]
+ self.ports = [self.in1, self.in2, self.op, self.c_in, self.out, self.c_out, self.overflow, self.zero, self.neg]
def elaborate(self, platform=None):
m = Module()
@@ -105,38 +127,73 @@ class ALU(Elaboratable):
m.d.sync += dummy.eq(~dummy)
with m.Switch(self.op):
- with m.Case(0b0000):
+ with m.Case(AluOpCodes.add.value):
m.d.comb += self.tmp.eq(self.in1 + self.in2)
- with m.Case(0b0010):
- m.d.comb += self.tmp.eq(self.in1.as_signed() + self.in2.as_signed())
- m.d.comb += self.signed_op.eq(1)
- with m.Case(0b0001):
+
+ with m.Case(AluOpCodes.addc.value):
+ m.d.comb += self.tmp.eq(self.in1 + self.in2 + self.c_in)
+
+ with m.Case(AluOpCodes.sub.value):
m.d.comb += self.tmp.eq(self.in1 - self.in2)
- with m.Case(0b0011):
- m.d.comb += self.tmp.eq(self.in1.as_signed() - self.in2.as_signed())
- m.d.comb += self.signed_op.eq(1)
- with m.Case(4):
+
+ with m.Case(AluOpCodes.subc.value):
+ m.d.comb += self.tmp.eq(self.in1 + (~self.in2 + self.c_in))
+
+ with m.Case(AluOpCodes.bit_and.value):
m.d.comb += self.tmp.eq(Cat(self.in1 & self.in2, 0))
- with m.Case(5):
+
+ with m.Case(AluOpCodes.bit_or.value):
m.d.comb += self.tmp.eq(Cat(self.in1 | self.in2, 0))
- with m.Case(6):
+
+ with m.Case(AluOpCodes.bit_xor.value):
m.d.comb += self.tmp.eq(Cat(self.in1 ^ self.in2, 0))
- with m.Case(7):
- m.d.comb += self.tmp.eq(Cat(self.in1 << self.in2[0:5], 0))
- with m.Case(8):
- m.d.comb += self.tmp.eq(Cat(self.in1 >> self.in2[0:5], 0))
- with m.Case(9):
- m.d.comb += self.tmp.eq(Cat(self.in1.as_signed() >> self.in2[0:5], 0))
+
+ with m.Case(AluOpCodes.bit_nor.value):
+ m.d.comb += self.tmp.eq(Cat(~(self.in1 | self.in2), 0))
+
+ with m.Case(AluOpCodes.lleft.value):
+ m.d.comb += self.tmp.eq(Cat(self.in1, 0) << self.in2[0:5])
+
+ with m.Case(AluOpCodes.lright.value):
+ tmp2 = Signal(33)
+ m.d.comb += tmp2.eq(Cat(0, self.in1) >> 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.aright.value):
+ tmp2 = Signal(33)
+ 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.set_bit.value):
+ m.d.comb += self.tmp.eq(Cat(self.in1 | (1 << self.in2[0:5]), 0))
+
+ with m.Case(AluOpCodes.clear_bit.value):
+ m.d.comb += self.tmp.eq(Cat(self.in1 & ~(1 << self.in2[0:5]), 0))
+
+ 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.smult.value):
+ m.d.comb += self.tmp.eq(Cat(self.in1[0:16].as_signed() * self.in2[0:16].as_signed(), 0))
+
+
+ # bad juju,
+ # TODO: come back and check this will work
+ # with m.Case(AluOpCodes.udiv.value):
+ # m.d.comb += self.tmp.eq(Cat(self.in1 // self.in2, 0))
+
+ # with m.Case(AluOpCodes.sdiv.value):
+ # m.d.comb += self.tmp.eq(self.in1.as_signed() // self.in2.as_signed()) # for some reason I have not confirmed, signed div can yield a 33 bit number, acording to amaranth
+
with m.Case():
- m.d.comb += self.signed_op.eq(0)
m.d.comb += self.tmp.eq(0)
- m.d.comb += self.carry.eq(self.tmp[32])
+ m.d.comb += self.c_out.eq(self.tmp[32])
m.d.comb += self.overflow.eq(self.tmp[32] ^ self.tmp[31])
- m.d.comb += self.sign.eq(self.tmp.as_signed() < 0)
- m.d.comb += self.zero.eq(self.out == 0)
-
m.d.comb += self.out.eq(self.tmp[0:32])
+ m.d.comb += self.neg.eq(self.out.as_signed() < 0)
+ m.d.comb += self.zero.eq(self.out == 0)
+ m.d.comb += self.odd.eq(self.out[0])
return m
@@ -144,111 +201,115 @@ def test_alu(filename="alu.vcd"):
dut = ALU(sim=True)
def proc1():
- def sub_proc(val1, val2):
+ def sub_proc(val1, val2, c_in=0):
yield dut.in1.eq(val1)
yield dut.in2.eq(val2)
+ yield dut.c_in.eq(c_in)
yield
yield Settle()
- # test unsigned addition
- yield dut.op.eq(0b0000)
+ # test addition
+ yield dut.op.eq(AluOpCodes.add.value)
yield from sub_proc(27, 13)
out = yield dut.out
assert 27 + 13 == (out), f'ERROR: {out} != {27 + 13}'
- # test signed addition
- yield dut.op.eq(0b0010)
- yield from sub_proc(-11, 43)
+ # test addition with carry
+ yield dut.op.eq(AluOpCodes.addc.value)
+ yield from sub_proc(11, 43, 1)
out = yield dut.out.as_signed()
- assert -11 + 43 == out, f'ERROR: {out} != {-11 + 43}'
+ assert 11 + 43 + 1 == out, f'ERROR: {out} != {11 + 43 + 1}'
- # test unsigned subtraction
- yield dut.op.eq(0b0001)
+ # test subtraction
+ yield dut.op.eq(AluOpCodes.sub.value)
yield from sub_proc(25, 13)
out = yield dut.out
assert 25 - 13 == out, f'ERROR: {out} != {25 - 13}'
- # test signed subtraction
- yield dut.op.eq(0b0011)
- yield from sub_proc(25, -13)
+ # test subtraction with carry
+ yield dut.op.eq(AluOpCodes.subc.value)
+ yield from sub_proc(25, -13, 0)
+ out = yield dut.out.as_signed()
+ assert 25 + 13 -1 +0 == out, f'ERROR: {out} != {25 + 13 -1 +0}'
+
+ # test subtraction with carry
+ yield dut.op.eq(AluOpCodes.subc.value)
+ yield from sub_proc(25, -13, 1)
out = yield dut.out.as_signed()
- assert 25 + 13 == out, f'ERROR: {out} != {25 + 13}'
+ assert 25 + 13 -1 +1 == out, f'ERROR: {out} != {25 + 13 -1 +1}'
- # test unsigned logical and
- yield dut.op.eq(4)
+ # test binary and
+ yield dut.op.eq(AluOpCodes.bit_and.value)
yield from sub_proc(0b10101011, 0b01010101)
out = yield dut.out
assert 0b00000001 == out, f'ERROR: {out} != {0b00000001}'
- # test unsigned logical or
- yield dut.op.eq(5)
+ # test binary or
+ yield dut.op.eq(AluOpCodes.bit_or.value)
yield from sub_proc(0b10101011, 0b01000101)
out = yield dut.out
assert 0b11101111 == out, f'ERROR: {out} != {0b11101111}'
- # test logical xor
- yield dut.op.eq(6)
+ # test binary nor
+ yield dut.op.eq(AluOpCodes.bit_nor.value)
+ yield from sub_proc(0b10001011, 0b01000101)
+ out = yield dut.out
+ assert 0b11111111111111111111111100110000 == out, f'ERROR: {bin(out)} != {bin(0b11111111111111111111111100110000)}'
+
+ # test binary xor
+ yield dut.op.eq(AluOpCodes.bit_xor.value)
yield from sub_proc(0b10001011, 0b01000101)
out = yield dut.out
assert 0b11001110 == out, f'ERROR: {out} != {0b11001110}'
# test logical shift left
- yield dut.op.eq(7)
- yield from sub_proc(0b10001011, 5) # shift left by 5
+ yield dut.op.eq(AluOpCodes.lleft.value)
+ yield from sub_proc(0b10001011, 25) # shift left by 5
out = yield dut.out
- assert 0b1000101100000 == out, f'ERROR: {out} != {0b1000101100000}'
+ assert 0b00010110000000000000000000000000 == out, f'ERROR: {bin(out)} != {bin(0b00010110000000000000000000000000)}'
+ out = yield dut.c_out
+ assert 1 == out, f'ERROR: {out} != {1}'
# test logical shift right
- yield dut.op.eq(8)
- yield from sub_proc(0b10001011, 5) # shift right by 5
+ yield dut.op.eq(AluOpCodes.lright.value)
+ yield from sub_proc(0b10001011, 4) # shift right by 5
out = yield dut.out
- assert 0b100 == out, f'ERROR: {out} != {0b100}'
+ assert 0b1000 == out, f'ERROR: {bin(out)} != {bin(0b1000)}'
+ out = yield dut.c_out
+ assert 1 == out, f'ERROR: {out} != {1}'
# test aligned shift right
- yield dut.op.eq(9)
+ yield dut.op.eq(AluOpCodes.aright.value)
yield from sub_proc(0x80001234, 4) # shift right by 4
out = yield dut.out
assert 0xF8000123 == out, f'ERROR: {out} != {0xF8000123}'
+ out = yield dut.c_out
+ assert 0 == out, f'ERROR: {out} != {0}'
# test unsigned overflow
- yield dut.op.eq(0b0000)
+ yield dut.op.eq(AluOpCodes.add.value)
yield from sub_proc(0xFFFFFFFF, 1) # add 1 to 0xFFFFFFFF
out = yield dut.overflow
assert out == 1, f'ERROR: {out} != {1}'
- out = yield dut.carry
- assert out == 1, f'ERROR: {out} != {1}'
-
- # test signed overflow
- yield dut.op.eq(0b0010)
- yield from sub_proc(0x7FFFFFFF, 1) # add 1 to 0x7FFFFFFF
- out = yield dut.overflow
+ out = yield dut.c_out
assert out == 1, f'ERROR: {out} != {1}'
- out = yield dut.carry
- assert out == 0, f'ERROR: {out} != {0}'
# test unsigned underflow
- yield dut.op.eq(0b0001)
+ yield dut.op.eq(AluOpCodes.add.value)
yield from sub_proc(0, -1) # subtract 1 from 0
out = yield dut.overflow
assert out == 1, f'ERROR: {out} != {1}'
- out = yield dut.carry
- assert out == 1, f'ERROR: {out} != {1}'
-
- # test signed underflow
- yield dut.op.eq(0b0010)
- yield from sub_proc(0x80000000, -1) # sub 1 from 0x80000000 (most negative number in two's complement)
- assert out == 1, f'ERROR: {out} != {1}'
- out = yield dut.carry
- assert out == 1, f'ERROR: {out} != {1}'
+ out = yield dut.c_out
+ assert out == 0, f'ERROR: {out} != {0}'
# test zero
- yield dut.op.eq(0b0000)
+ yield dut.op.eq(AluOpCodes.add.value)
yield from sub_proc(0, 0) # add 0 to 0
out = yield dut.zero
assert out == 1, f'ERROR: {out} != {1}'
# test zero
- yield dut.op.eq(0b0000)
+ yield dut.op.eq(AluOpCodes.add.value)
yield from sub_proc(0, 1) # add 0 to 0
out = yield dut.zero
assert out == 0, f'ERROR: {out} != {0}'