download
raw
5.73 kB
AUTO_BUILD_ARGS = []
#!/usr/bin/env python3
"""
cocotb testbench for ADDC module.
Tests the adder with carry functionality including sign conversion and zero detection.
"""
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge, FallingEdge, Timer
from pathlib import Path
import sys
import os
# Add parent directory to path for runner import
sys.path.insert(0, str(Path(__file__).resolve().parent))
from cocotb_tools.runner import get_runner
@cocotb.test()
async def test_reset_behavior(dut):
"""Test that outputs are stable after reset."""
clock = Clock(dut.clk, 10, unit="ns")
cocotb.start_soon(clock.start())
# Apply reset
dut.reset.value = 1
dut.scan_enable.value = 0
dut.test_mode.value = 0
# Give some inputs
dut.DQ.value = 0
dut.SEZ.value = 0
await RisingEdge(dut.clk)
await RisingEdge(dut.clk)
# Release reset
dut.reset.value = 0
await RisingEdge(dut.clk)
# Check outputs are defined (not X or Z)
assert dut.PK0.value.is_resolvable, "PK0 should be resolvable after reset"
assert dut.SIGPK.value.is_resolvable, "SIGPK should be resolvable after reset"
@cocotb.test()
async def test_positive_addition(dut):
"""Test addition of two positive numbers."""
clock = Clock(dut.clk, 10, unit="ns")
cocotb.start_soon(clock.start())
# Initialize
dut.reset.value = 0
dut.scan_enable.value = 0
dut.test_mode.value = 0
await RisingEdge(dut.clk)
# Test case 1: DQ = 100 (positive), SEZ = 50 (positive)
# DQ[15] = 0, SEZ[14] = 0
dut.DQ.value = 100 # 0x0064
dut.SEZ.value = 50 # 0x0032
await RisingEdge(dut.clk)
# DQI = DQ = 100, SEZI = SEZ = 50
# DQSEZ = 100 + 50 = 150
# PK0 = DQSEZ[15] = 0 (positive)
# SIGPK = (DQSEZ == 0) = 0 (not zero)
assert dut.PK0.value == 0, f"PK0 should be 0 for positive sum, got {dut.PK0.value}"
assert dut.SIGPK.value == 0, f"SIGPK should be 0 for non-zero sum, got {dut.SIGPK.value}"
@cocotb.test()
async def test_negative_addition(dut):
"""Test addition resulting in negative number."""
clock = Clock(dut.clk, 10, unit="ns")
cocotb.start_soon(clock.start())
# Initialize
dut.reset.value = 0
dut.scan_enable.value = 0
dut.test_mode.value = 0
await RisingEdge(dut.clk)
# Test case: DQ = -100, SEZ = 50
# DQ in sign-magnitude: sign=1, magnitude=100
# DQ = 0x8000 | 100 = 0x8064
dut.DQ.value = 0x8064 # Sign bit set, magnitude 100
dut.SEZ.value = 50 # Positive
await RisingEdge(dut.clk)
# DQS = 1 (negative)
# DQI = 65536 - (DQ & 32767) = 65536 - 100 = 65436 (0xFF9C)
# SEZI = SEZ = 50
# DQSEZ = 65436 + 50 = 65486 (0xFFCE) = -50 in 16-bit 2's complement
# PK0 = DQSEZ[15] = 1 (negative)
# SIGPK = 0 (not zero)
assert dut.PK0.value == 1, f"PK0 should be 1 for negative sum, got {dut.PK0.value}"
assert dut.SIGPK.value == 0, f"SIGPK should be 0 for non-zero sum, got {dut.SIGPK.value}"
@cocotb.test()
async def test_zero_result(dut):
"""Test addition resulting in zero."""
clock = Clock(dut.clk, 10, unit="ns")
cocotb.start_soon(clock.start())
# Initialize
dut.reset.value = 0
dut.scan_enable.value = 0
dut.test_mode.value = 0
await RisingEdge(dut.clk)
# Test case: DQ = 100, SEZ = -100
# DQ = 100 (positive)
# SEZ in 15-bit 2's complement: -100 = 32768 - 100 = 32668 (0x7F9C)
dut.DQ.value = 100
dut.SEZ.value = 32668 # -100 in 15-bit 2's complement
await RisingEdge(dut.clk)
# DQI = 100
# SEZS = 1 (negative since SEZ[14] = 1)
# SEZI = 32768 + SEZ = 32768 + 32668 = 65436 (0xFF9C) = -100 in 16-bit 2's complement
# DQSEZ = 100 + (-100) = 0
# PK0 = 0 (MSB of 0 is 0)
# SIGPK = 1 (zero result)
assert dut.SIGPK.value == 1, f"SIGPK should be 1 for zero sum, got {dut.SIGPK.value}"
# Note: PK0 for zero result is 0 since DQSEZ[15] = 0
@cocotb.test()
async def test_scan_mode_disabled(dut):
"""Test that scan outputs are driven when scan is disabled."""
clock = Clock(dut.clk, 10, unit="ns")
cocotb.start_soon(clock.start())
# Initialize with scan disabled
dut.reset.value = 0
dut.scan_enable.value = 0
dut.test_mode.value = 0
# Set some scan inputs
dut.scan_in0.value = 1
dut.scan_in1.value = 1
dut.scan_in2.value = 1
dut.scan_in3.value = 1
dut.scan_in4.value = 1
await RisingEdge(dut.clk)
# With scan disabled, scan outputs should still be driven (not high-Z)
# Check they are resolvable (not X or Z)
if hasattr(dut, "scan_out0"):
assert dut.scan_out0.value.is_resolvable, "scan_out0 should be driven"
if hasattr(dut, "scan_out1"):
assert dut.scan_out1.value.is_resolvable, "scan_out1 should be driven"
if hasattr(dut, "scan_out2"):
assert dut.scan_out2.value.is_resolvable, "scan_out2 should be driven"
if hasattr(dut, "scan_out3"):
assert dut.scan_out3.value.is_resolvable, "scan_out3 should be driven"
if hasattr(dut, "scan_out4"):
assert dut.scan_out4.value.is_resolvable, "scan_out4 should be driven"
if __name__ == "__main__":
from pathlib import Path
from cocotb_tools.runner import get_runner
project_root = Path(__file__).resolve().parents[1]
sources = [
project_root / "reference" / "top.v"
]
runner = get_runner("icarus")
runner.build(
sources=[str(path) for path in sources],
hdl_toplevel='ADDC',
build_args=AUTO_BUILD_ARGS,
always=True,
)
runner.test(
hdl_toplevel='ADDC',
test_module="tb",
waves=False,
)

Xet Storage Details

Size:
5.73 kB
·
Xet hash:
106373ed84b69cb552d3d193f71c4ae67879184c961090d216f72e13513c6088

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.