summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--README9
-rw-r--r--hdl/__init__.py0
-rw-r--r--hdl/core/__init__.py0
-rw-r--r--hdl/core/alu.py269
-rw-r--r--hdl/core/core.py36
-rw-r--r--hdl/core/reg.py (renamed from hdl/core.py)313
-rw-r--r--hdl/lib/shift_reg.py (renamed from hdl/shift_reg.py)6
-rw-r--r--hdl/utils.py41
9 files changed, 366 insertions, 310 deletions
diff --git a/Makefile b/Makefile
index ae34634..4586ff3 100644
--- a/Makefile
+++ b/Makefile
@@ -18,4 +18,4 @@ test-w:
py.test -v $(HDL)
clean:
- $(RM) -rf $(HDL_FOLDER)/*.cc $(HDL_FOLDER)/*.v $(HDL_FOLDER)/*.vcd $(HDL_FOLDER)/*.pyc $(HDL_FOLDER)/*.out \ No newline at end of file
+ $(RM) -rf $(HDL_FOLDER)/*.cc $(HDL_FOLDER)/*.v $(HDL_FOLDER)/*.vcd $(HDL_FOLDER)/*.pyc $(HDL_FOLDER)/*.out $(HDL_FOLDER)/*.bak \ No newline at end of file
diff --git a/README b/README
new file mode 100644
index 0000000..8e457e8
--- /dev/null
+++ b/README
@@ -0,0 +1,9 @@
+# ASAP32 ISA & SoC - A KISS inspired architecture
+## As Simple As Possible
+
+add stuff -> problem for later me
+
+
+
+### Development Getting Started
+Run `export PYTHONPATH=$(pwd):$PYTHONPATH` to add the current directory to the Python path.
diff --git a/hdl/__init__.py b/hdl/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/hdl/__init__.py
diff --git a/hdl/core/__init__.py b/hdl/core/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/hdl/core/__init__.py
diff --git a/hdl/core/alu.py b/hdl/core/alu.py
new file mode 100644
index 0000000..049c8af
--- /dev/null
+++ b/hdl/core/alu.py
@@ -0,0 +1,269 @@
+from amaranth import *
+from amaranth.sim import Simulator, Settle, Delay
+from enum import Enum, unique
+
+from hdl.utils import cmd, DubbleBuff
+
+@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, **kargs):
+ self.in1 = Signal(32, reset_less=True)
+ self.in2 = Signal(32, reset_less=True)
+ self.c_in = Signal(1)
+ self.op = Signal(4, reset_less=True)
+
+ self.tmp = Signal(33, 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.neg = Signal(1, reset_less=True)
+ self.odd = Signal(1, reset_less=True)
+
+ self.out = Signal(32, reset_less=True)
+
+ self.sim = kargs["sim"] if "sim" in kargs else None
+
+ ports_in = [self.in1, self.in2, self.op, self.c_in]
+ ports_out = [self.c_in, self.out, self.c_out, self.overflow, self.zero, self.neg, self.odd]
+ self.ports = {'in': ports_in, 'out': ports_out}
+
+ def elaborate(self, platform=None):
+ m = Module()
+
+ # dummy sync for simulation only
+ if self.sim == True:
+ dummy = Signal()
+ m.d.sync += dummy.eq(~dummy)
+
+ with m.Switch(self.op):
+ with m.Case(AluOpCodes.add.value):
+ m.d.comb += self.tmp.eq(self.in1 + self.in2)
+
+ 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(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(AluOpCodes.bit_or.value):
+ m.d.comb += self.tmp.eq(Cat(self.in1 | self.in2, 0))
+
+ with m.Case(AluOpCodes.bit_xor.value):
+ m.d.comb += self.tmp.eq(Cat(self.in1 ^ self.in2, 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.tmp.eq(0)
+
+ 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.out.eq(self.tmp[0:32])
+ m.d.comb += self.neg.eq(self.out[31])
+ m.d.comb += self.zero.eq(self.out == 0)
+ m.d.comb += self.odd.eq(self.out.xor()) # 1 if odd number of bits, 0 if even
+
+ return m
+
+def test_alu(filename="alu.vcd"):
+ dut = ALU(sim=True)
+
+ def proc1():
+ 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 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 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 + 1 == out, f'ERROR: {out} != {11 + 43 + 1}'
+
+ # 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 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 -1 +1 == out, f'ERROR: {out} != {25 + 13 -1 +1}'
+
+ # 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 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 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(AluOpCodes.lleft.value)
+ yield from sub_proc(0b10001011, 25) # shift left by 5
+ out = yield dut.out
+ 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(AluOpCodes.lright.value)
+ yield from sub_proc(0b10001011, 4) # shift right by 5
+ out = yield dut.out
+ 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(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(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.c_out
+ assert out == 1, f'ERROR: {out} != {1}'
+
+ # test unsigned underflow
+ 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.c_out
+ assert out == 0, f'ERROR: {out} != {0}'
+
+ # test zero
+ 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(AluOpCodes.add.value)
+ yield from sub_proc(0, 1) # add 0 to 0
+ out = yield dut.zero
+ assert out == 0, f'ERROR: {out} != {0}'
+
+ # test odd
+ yield dut.op.eq(AluOpCodes.add.value)
+ yield from sub_proc(0, 0xAAAAAAAA) # add 0 to 0
+ out = yield dut.odd
+ assert out == 0, f'ERROR: {out} != {0}'
+
+ # test odd
+ yield dut.op.eq(AluOpCodes.add.value)
+ yield from sub_proc(0, 0xAAAAAAAB) # add 0 to 0
+ out = yield dut.odd
+ assert out == 1, f'ERROR: {out} != {1}'
+
+
+ sim = Simulator(dut)
+ sim.add_clock(1e-6)
+ sim.add_sync_process(proc1)
+
+ with sim.write_vcd(filename):
+ sim.run()
+
+
+if __name__ == '__main__':
+ hdl = DubbleBuff(ALU())
+ cmd(hdl, test_alu)
diff --git a/hdl/core/core.py b/hdl/core/core.py
new file mode 100644
index 0000000..a00eab3
--- /dev/null
+++ b/hdl/core/core.py
@@ -0,0 +1,36 @@
+from amaranth import *
+from amaranth.sim import Simulator, Settle, Delay
+from enum import Enum, unique
+
+from hdl.utils import cmd
+
+
+
+
+# class ASAP32Core(Elaboratable):
+# def __init__(self):
+# self.interupt_msk = Signal(32)
+# self.interupt_addr = Signal(32)
+# self.interupt_en = Signal(1)
+# self.interupt_sig = Signal(1)
+
+# self.jump = Signal(1)
+# self.instruction_addr = Signal(32)
+
+# self.ports = []
+
+# def elaborate(self, platform=None):
+# m = Module()
+
+# m.submodules.reg = reg = Reg()
+
+# # interupt setup
+# m.d.comb += self.interupt_en.eq(reg.cr[0])
+
+# # get instruction address, account for jumps and interupts
+# m.d.sync += self.instruction_addr.eq(Mux(self.interupt_en & self.interupt_sig, self.interupt_addr, Mux(self.jump, reg.ja, reg.ip)))
+
+# # update program counter
+# m.d.sync += reg.ip.eq(self.instruction_addr + 1)
+
+# return m \ No newline at end of file
diff --git a/hdl/core.py b/hdl/core/reg.py
index 2b7a977..3859dc5 100644
--- a/hdl/core.py
+++ b/hdl/core/reg.py
@@ -1,16 +1,10 @@
-from ast import Del
-from curses.ascii import SI
-from multiprocessing import dummy
-from tkinter import S, Y
from amaranth import *
from amaranth.sim import Simulator, Settle, Delay
-from enum import Enum, unique
-
-from utils import cmd
+from hdl.utils import cmd
class Reg(Elaboratable):
- def __init__(self, sim=False): # sim is only for modularity, does nothing for this
+ def __init__(self, **kargs): # sim is only for modularity, does nothing for this
# enable write
self.wr_en = Signal(1)
@@ -87,7 +81,11 @@ class Reg(Elaboratable):
setattr(reg, 'idx', idx) # set idx attribute to each register
self.reg_arr = Array(reg_list)
- self.ports = [self.wr_en, self.alu_flgs, self.jump, self.int_sig, self.int_en, self.iret, self.stack_instr, self.stack_down_up, self.rd_addr, self.rs1_addr, self.rs2_addr, self.rd, self.rs1, self.rs2, self.ip]
+
+ ports_in = [self.wr_en, self.alu_flgs, self.jump, self.int_sig, self.iret, self.stack_instr, self.stack_down_up, self.rd_addr, self.rd, self.rs1_addr, self.rs2_addr]
+ ports_out = [self.int_en, self.rs1, self.rs2, self.ip ]
+ self.ports = {'in': ports_in, 'out': ports_out}
+
def elaborate(self, platform=None):
m = Module()
@@ -279,294 +277,6 @@ def test_reg(filename="reg.vcd"):
yield from step()
assert (yield dut.flg) == (yield dut.alu_flgs), f'ERROR: alu is not writing to flg register'
-
-
-
- sim = Simulator(dut)
- sim.add_clock(1e-6)
- sim.add_sync_process(proc1)
-
- with sim.write_vcd(filename):
- sim.run()
-
-
-
-# class ASAP32Core(Elaboratable):
-# def __init__(self):
-# self.interupt_msk = Signal(32)
-# self.interupt_addr = Signal(32)
-# self.interupt_en = Signal(1)
-# self.interupt_sig = Signal(1)
-
-# self.jump = Signal(1)
-# self.instruction_addr = Signal(32)
-
-# self.ports = []
-
-# def elaborate(self, platform=None):
-# m = Module()
-
-# m.submodules.reg = reg = Reg()
-
-# # interupt setup
-# m.d.comb += self.interupt_en.eq(reg.cr[0])
-
-# # get instruction address, account for jumps and interupts
-# m.d.sync += self.instruction_addr.eq(Mux(self.interupt_en & self.interupt_sig, self.interupt_addr, Mux(self.jump, reg.ja, reg.ip)))
-
-# # update program counter
-# m.d.sync += reg.ip.eq(self.instruction_addr + 1)
-
-# 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.c_out = Signal(1, reset_less=True)
- self.overflow = Signal(1, reset_less=True)
- self.zero = 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.c_in, self.out, self.c_out, self.overflow, self.zero, self.neg]
-
- def elaborate(self, platform=None):
- m = Module()
-
- # dummy sync for simulation only
- if self.sim == True:
- dummy = Signal()
- m.d.sync += dummy.eq(~dummy)
-
- with m.Switch(self.op):
- with m.Case(AluOpCodes.add.value):
- m.d.comb += self.tmp.eq(self.in1 + self.in2)
-
- 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(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(AluOpCodes.bit_or.value):
- m.d.comb += self.tmp.eq(Cat(self.in1 | self.in2, 0))
-
- with m.Case(AluOpCodes.bit_xor.value):
- m.d.comb += self.tmp.eq(Cat(self.in1 ^ self.in2, 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.tmp.eq(0)
-
- 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.out.eq(self.tmp[0:32])
- m.d.comb += self.neg.eq(self.out[31])
- m.d.comb += self.zero.eq(self.out == 0)
- m.d.comb += self.odd.eq(self.out.xor()) # 1 if odd number of bits, 0 if even
-
- return m
-
-def test_alu(filename="alu.vcd"):
- dut = ALU(sim=True)
-
- def proc1():
- 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 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 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 + 1 == out, f'ERROR: {out} != {11 + 43 + 1}'
-
- # 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 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 -1 +1 == out, f'ERROR: {out} != {25 + 13 -1 +1}'
-
- # 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 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 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(AluOpCodes.lleft.value)
- yield from sub_proc(0b10001011, 25) # shift left by 5
- out = yield dut.out
- 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(AluOpCodes.lright.value)
- yield from sub_proc(0b10001011, 4) # shift right by 5
- out = yield dut.out
- 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(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(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.c_out
- assert out == 1, f'ERROR: {out} != {1}'
-
- # test unsigned underflow
- 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.c_out
- assert out == 0, f'ERROR: {out} != {0}'
-
- # test zero
- 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(AluOpCodes.add.value)
- yield from sub_proc(0, 1) # add 0 to 0
- out = yield dut.zero
- assert out == 0, f'ERROR: {out} != {0}'
-
- # test odd
- yield dut.op.eq(AluOpCodes.add.value)
- yield from sub_proc(0, 0xAAAAAAAA) # add 0 to 0
- out = yield dut.odd
- assert out == 0, f'ERROR: {out} != {0}'
-
- # test odd
- yield dut.op.eq(AluOpCodes.add.value)
- yield from sub_proc(0, 0xAAAAAAAB) # add 0 to 0
- out = yield dut.odd
- assert out == 1, f'ERROR: {out} != {1}'
-
-
sim = Simulator(dut)
sim.add_clock(1e-6)
sim.add_sync_process(proc1)
@@ -574,11 +284,6 @@ def test_alu(filename="alu.vcd"):
with sim.write_vcd(filename):
sim.run()
-
-
if __name__ == '__main__':
- # reg = Reg()
- # cmd(reg, test_reg)
-
- hdl = ALU()
- cmd(hdl, test_alu)
+ reg = Reg()
+ cmd(reg, test_reg) \ No newline at end of file
diff --git a/hdl/shift_reg.py b/hdl/lib/shift_reg.py
index 40af39b..3fb05c1 100644
--- a/hdl/shift_reg.py
+++ b/hdl/lib/shift_reg.py
@@ -1,7 +1,7 @@
from amaranth import *
from amaranth.sim import Simulator, Settle, Delay
-from utils import cmd
+from hdl.utils import cmd
class ShiftReg(Elaboratable):
def __init__(self, width):
@@ -13,7 +13,9 @@ class ShiftReg(Elaboratable):
self.en = Signal()
self.right_left = Signal()
- self.ports = [self.load_val, self.en, self.right_left, self.reg]
+ ports_in = [self.load_val, self.en, self.load, self.right_left]
+ ports_out = [self.reg]
+ self.ports = {'in': ports_in, 'out': ports_out}
def elaborate(self, platform):
m = Module()
diff --git a/hdl/utils.py b/hdl/utils.py
index 6aad95f..249167a 100644
--- a/hdl/utils.py
+++ b/hdl/utils.py
@@ -1,9 +1,17 @@
import sys
from typing import Callable
+from amaranth import *
from amaranth import Elaboratable
from amaranth.back import verilog, cxxrtl
def cmd(hdl, tb:Callable):
+ '''
+ Very simple command line interface
+ Accepts a Elaboratable class and a testbench function
+ The elaboratable class must have a ports attribute that is a dict of in and out ports {'in': [Signals()], 'out': [Signals()]}
+ The testbench function should only expect one argument: path to save .vcd file
+ '''
+
if len(sys.argv) <= 1:
exit()
@@ -12,11 +20,38 @@ def cmd(hdl, tb:Callable):
exit()
if sys.argv[1] == "v":
- out = verilog.convert(hdl, ports=hdl.ports)
+ out = verilog.convert(hdl, ports=hdl.ports['in'] + hdl.ports['out'])
with open(sys.argv[0].replace('.py', '.v'), 'w') as f:
f.write(out)
elif sys.argv[1] == "cc":
- out = cxxrtl.convert(hdl, ports=hdl.ports)
+ out = cxxrtl.convert(hdl, ports=hdl.ports['in'] + hdl.ports['out'])
with open(sys.argv[0].replace('.py', '.cc'), 'w') as f:
- f.write(out) \ No newline at end of file
+ f.write(out)
+
+class DubbleBuff(Elaboratable):
+ '''
+ This module wraps another modules input and output with a buffer
+ This is usefull for doing timeing analysis on combinational logic
+
+ An instance of a module should be passed, not the module itself
+ '''
+ def __init__(self, sub_module: Elaboratable):
+ assert sub_module.ports is not None, 'sub_module must have ports'
+
+ self.sub_module = sub_module
+ ports_in = [Signal(port.width, name=port.name + '_inbuf') for port in sub_module.ports['in']]
+ ports_out = [Signal(port.width, name=port.name + '_outbuf') for port in sub_module.ports['out']]
+ self.ports = {'in': ports_in, 'out': ports_out}
+
+ def elaborate(self, platform):
+ m = Module()
+ m.submodules.sub = self.sub_module
+
+ for i in range(len(self.ports['in'])):
+ m.d.sync += self.sub_module.ports['in'][i].eq(self.ports['in'][i])
+
+ for i in range(len(self.ports['out'])):
+ m.d.sync += self.ports['out'][i].eq(self.sub_module.ports['out'][i])
+
+ return m \ No newline at end of file