summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjjsuperpower <jjs29356@gmail.com>2022-09-05 19:02:50 -0500
committerjjsuperpower <jjs29356@gmail.com>2022-09-05 19:02:50 -0500
commit762e8b8786d8c921726c8ddc92a2513f42dad683 (patch)
tree886a314bbf5ae6e03db78723f8e2f8b388fe50ee
parenta2bbe116cb725c92bca19aa25a3a74401c02107f (diff)
updated testbench format
-rw-r--r--hdl/core/alu.py195
-rw-r--r--hdl/lib/shift_reg.py39
-rw-r--r--hdl/utils.py57
3 files changed, 158 insertions, 133 deletions
diff --git a/hdl/core/alu.py b/hdl/core/alu.py
index 049c8af..d9858b1 100644
--- a/hdl/core/alu.py
+++ b/hdl/core/alu.py
@@ -2,7 +2,8 @@ from amaranth import *
from amaranth.sim import Simulator, Settle, Delay
from enum import Enum, unique
-from hdl.utils import cmd, DubbleBuff
+from hdl.utils import cmd, step, sim
+from hdl.lib.in_out_buff import InOutBuff
@unique
class AluOpCodes(Enum):
@@ -17,12 +18,10 @@ class AluOpCodes(Enum):
lleft = 8
lright = 9
aright = 10
- set_bit = 11
- clear_bit = 12
- umult = 13
- smult = 14
- udiv = 15
- sdiv = 16
+ umult = 11
+ smult = 12
+ # udiv = 13
+ # sdiv = 14
class ALU(Elaboratable):
def __init__(self, **kargs):
@@ -37,14 +36,13 @@ class ALU(Elaboratable):
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]
+ ports_out = [self.c_in, self.out, self.c_out, self.overflow, self.zero, self.neg]
self.ports = {'in': ports_in, 'out': ports_out}
def elaborate(self, platform=None):
@@ -66,7 +64,7 @@ class ALU(Elaboratable):
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))
+ 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))
@@ -93,12 +91,6 @@ 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.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))
@@ -122,148 +114,189 @@ class ALU(Elaboratable):
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()
+def sub_proc(dut, 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
+# test addition
+def test_alu_add():
+ dut = ALU(sim=True)
+ def proc():
yield dut.op.eq(AluOpCodes.add.value)
- yield from sub_proc(27, 13)
+ yield from sub_proc(dut, 27, 13)
out = yield dut.out
assert 27 + 13 == (out), f'ERROR: {out} != {27 + 13}'
+ sim(dut, proc)
- # test addition with carry
+# test addition with carry
+def test_alu_addc():
+ dut = ALU(sim=True)
+ def proc():
yield dut.op.eq(AluOpCodes.addc.value)
- yield from sub_proc(11, 43, 1)
+ yield from sub_proc(dut, 11, 43, 1)
out = yield dut.out.as_signed()
assert 11 + 43 + 1 == out, f'ERROR: {out} != {11 + 43 + 1}'
+ sim(dut, proc)
- # test subtraction
+# test subtraction
+def test_alu_sub():
+ dut = ALU(sim=True)
+ def proc():
yield dut.op.eq(AluOpCodes.sub.value)
- yield from sub_proc(25, 13)
+ yield from sub_proc(dut, 25, 13)
out = yield dut.out
assert 25 - 13 == out, f'ERROR: {out} != {25 - 13}'
+ sim(dut, proc)
- # test subtraction with carry
+# test subtraction with carry
+def test_alu_subc_0():
+ dut = ALU(sim=True)
+ def proc():
yield dut.op.eq(AluOpCodes.subc.value)
- yield from sub_proc(25, -13, 0)
+ yield from sub_proc(dut, 25, -13, 0)
out = yield dut.out.as_signed()
assert 25 + 13 -1 +0 == out, f'ERROR: {out} != {25 + 13 -1 +0}'
+ sim(dut, proc)
- # test subtraction with carry
+# test subtraction with carry
+def test_alu_subc_1():
+ dut = ALU(sim=True)
+ def proc():
yield dut.op.eq(AluOpCodes.subc.value)
- yield from sub_proc(25, -13, 1)
+ yield from sub_proc(dut, 25, -13, 1)
out = yield dut.out.as_signed()
assert 25 + 13 -1 +1 == out, f'ERROR: {out} != {25 + 13 -1 +1}'
+ sim(dut, proc)
- # test binary and
+# test binary and
+def test_alu_and():
+ dut = ALU(sim=True)
+ def proc():
yield dut.op.eq(AluOpCodes.bit_and.value)
- yield from sub_proc(0b10101011, 0b01010101)
+ yield from sub_proc(dut, 0b10101011, 0b01010101)
out = yield dut.out
assert 0b00000001 == out, f'ERROR: {out} != {0b00000001}'
+ sim(dut, proc)
- # test binary or
+# test binary or
+def test_alu_or():
+ dut = ALU(sim=True)
+ def proc():
yield dut.op.eq(AluOpCodes.bit_or.value)
- yield from sub_proc(0b10101011, 0b01000101)
+ yield from sub_proc(dut, 0b10101011, 0b01000101)
out = yield dut.out
assert 0b11101111 == out, f'ERROR: {out} != {0b11101111}'
+ sim(dut, proc)
- # test binary nor
+# test binary nor
+def test_alu_nor():
+ dut = ALU(sim=True)
+ def proc():
yield dut.op.eq(AluOpCodes.bit_nor.value)
- yield from sub_proc(0b10001011, 0b01000101)
+ yield from sub_proc(dut, 0b10001011, 0b01000101)
out = yield dut.out
assert 0b11111111111111111111111100110000 == out, f'ERROR: {bin(out)} != {bin(0b11111111111111111111111100110000)}'
+ sim(dut, proc)
- # test binary xor
+# test binary xor
+def test_alu_xor():
+ dut = ALU(sim=True)
+ def proc():
yield dut.op.eq(AluOpCodes.bit_xor.value)
- yield from sub_proc(0b10001011, 0b01000101)
+ yield from sub_proc(dut, 0b10001011, 0b01000101)
out = yield dut.out
assert 0b11001110 == out, f'ERROR: {out} != {0b11001110}'
+ sim(dut, proc)
- # test logical shift left
+# test logical shift left
+def test_alu_logic_shift_left():
+ dut = ALU(sim=True)
+ def proc():
yield dut.op.eq(AluOpCodes.lleft.value)
- yield from sub_proc(0b10001011, 25) # shift left by 5
+ yield from sub_proc(dut, 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}'
+ sim(dut, proc)
- # test logical shift right
+# test logical shift right
+def test_alu_logic_shift_right():
+ dut = ALU(sim=True)
+ def proc():
yield dut.op.eq(AluOpCodes.lright.value)
- yield from sub_proc(0b10001011, 4) # shift right by 5
+ yield from sub_proc(dut, 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}'
+ sim(dut, proc)
- # test aligned shift right
+# test arithmetic shift right
+def test_alu_arith_shift_right():
+ dut = ALU(sim=True)
+ def proc():
yield dut.op.eq(AluOpCodes.aright.value)
- yield from sub_proc(0x80001234, 4) # shift right by 4
+ yield from sub_proc(dut, 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}'
+ sim(dut, proc)
- # test unsigned overflow
+# test unsigned overflow
+def test_alu_unsigned_overflow():
+ dut = ALU(sim=True)
+ def proc():
yield dut.op.eq(AluOpCodes.add.value)
- yield from sub_proc(0xFFFFFFFF, 1) # add 1 to 0xFFFFFFFF
+ yield from sub_proc(dut, 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}'
+ sim(dut, proc)
- # test unsigned underflow
+# test unsigned underflow
+def test_alu_unsigned_underflow():
+ dut = ALU(sim=True)
+ def proc():
yield dut.op.eq(AluOpCodes.add.value)
- yield from sub_proc(0, -1) # subtract 1 from 0
+ yield from sub_proc(dut, 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}'
+ sim(dut, proc)
- # 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
+# test zero
+def test_alu_zero_0():
+ dut = ALU(sim=True)
+ def proc():
yield dut.op.eq(AluOpCodes.add.value)
- yield from sub_proc(0, 1) # add 0 to 0
+ yield from sub_proc(dut, 0, 1) # add 0 to 0
out = yield dut.zero
assert out == 0, f'ERROR: {out} != {0}'
+ sim(dut, proc)
- # 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
+# test zero
+def test_alu_zero_1():
+ dut = ALU(sim=True)
+ def proc():
yield dut.op.eq(AluOpCodes.add.value)
- yield from sub_proc(0, 0xAAAAAAAB) # add 0 to 0
- out = yield dut.odd
+ yield from sub_proc(dut, 0, 0) # add 0 to 0
+ out = yield dut.zero
assert out == 1, f'ERROR: {out} != {1}'
-
+ sim(dut, proc)
- 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)
+ hdl = InOutBuff(ALU())
+ cmd(hdl)
diff --git a/hdl/lib/shift_reg.py b/hdl/lib/shift_reg.py
index 3fb05c1..6966a77 100644
--- a/hdl/lib/shift_reg.py
+++ b/hdl/lib/shift_reg.py
@@ -1,7 +1,8 @@
from amaranth import *
from amaranth.sim import Simulator, Settle, Delay
-from hdl.utils import cmd
+from hdl.utils import cmd, sim, step
+from hdl.lib.in_out_buff import InOutBuff
class ShiftReg(Elaboratable):
def __init__(self, width):
@@ -31,52 +32,48 @@ class ShiftReg(Elaboratable):
return m
-def test_shift_reg(filename="out.vcd"):
+def test_shiftreg_right():
dut = ShiftReg(8)
-
- def proc1():
+ def proc():
val = 0xAB
yield dut.load_val.eq(val)
yield dut.en.eq(0)
yield dut.load.eq(1)
- yield
- yield Settle()
+ yield from step()
yield dut.load.eq(0)
yield dut.en.eq(1)
+ yield Settle()
for _ in range(9):
reg_val = yield dut.reg
assert reg_val == val, f"Incorrect shift ---EXPECTED: {hex(val)} ---GOT: {hex(reg_val)}"
val = val >> 1
- yield
- yield Settle()
+ yield from step()
+ sim(dut, proc)
+def test_shiftreg_left():
+ dut = ShiftReg(8)
+ def proc():
val = 0xBD
yield dut.load_val.eq(val)
+ yield dut.en.eq(0)
yield dut.load.eq(1)
yield dut.right_left.eq(1)
- yield
- yield Settle()
+ yield from step()
yield dut.load.eq(0)
+ yield dut.en.eq(1)
+ yield Settle()
for _ in range(9):
reg_val = yield dut.reg
assert reg_val == val, f"Incorrect shift ---EXPECTED: {hex(val)} ---GOT: {hex(reg_val)}"
val = (val << 1) & 0xff
- yield
- yield Settle()
-
-
+ yield from step()
+ sim(dut, proc)
- sim = Simulator(dut)
- sim.add_clock(1e-6)
- sim.add_sync_process(proc1)
-
- with sim.write_vcd(filename):
- sim.run()
if __name__ == '__main__':
shift_reg = ShiftReg(8)
- cmd(shift_reg, test_shift_reg) \ No newline at end of file
+ cmd(shift_reg) \ No newline at end of file
diff --git a/hdl/utils.py b/hdl/utils.py
index 249167a..80dc3ee 100644
--- a/hdl/utils.py
+++ b/hdl/utils.py
@@ -1,57 +1,52 @@
import sys
+from inspect import stack # get name of caller function
from typing import Callable
from amaranth import *
from amaranth import Elaboratable
from amaranth.back import verilog, cxxrtl
+from amaranth.sim import Settle, Delay, Simulator
-def cmd(hdl, tb:Callable):
+from hdl.config import *
+
+
+def cmd(hdl):
'''
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:
+ print('Usage: v|cc v = generate verilog, cc = generate cxxrtl')
exit()
if sys.argv[1] == "sim":
- tb(sys.argv[0].replace('.py', '.vcd'))
- exit()
+ # tb(sys.argv[0].replace('.py', '.vcd'))
+ # exit()
+ assert "sim option deprecated, use pytest command instead"
if sys.argv[1] == "v":
out = verilog.convert(hdl, ports=hdl.ports['in'] + hdl.ports['out'])
- with open(sys.argv[0].replace('.py', '.v'), 'w') as f:
+ with open(os.path.join(VERILOG_DIR, sys.argv[0].replace('.py', '.v')), 'w') as f:
f.write(out)
elif sys.argv[1] == "cc":
out = cxxrtl.convert(hdl, ports=hdl.ports['in'] + hdl.ports['out'])
- with open(sys.argv[0].replace('.py', '.cc'), 'w') as f:
+ with open(os.path.join(CXXRTL_DIR, sys.argv[0].replace('.py', '.cc')), 'w') as f:
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
+def sim(dut:Elaboratable, proc: Callable):
+ sim = Simulator(dut)
+ sim.add_clock(1e-6)
+ sim.add_sync_process(proc)
+
+ with sim.write_vcd(os.path.join(VCD_DIR, stack()[1].function + '.vcd')):
+ sim.run()
+
+def step(cycles=1):
+ for _ in range(cycles):
+ yield Settle() # settle comb logic before clock
+ yield # clock edge
+ yield Settle() # settle comb logic after clock
+ yield Delay(5e-7) # used for debugging, change values on neg edge of clock \ No newline at end of file