observerw's picture
download
raw
6.44 kB
```python
#!/usr/bin/env python3
"""
cocotb testbench for ADDB module.
Tests basic arithmetic functionality and reset behavior.
"""
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.append(str(Path(__file__).parent))
from cocotb_tools.runner import get_runner
@cocotb.test()
async def test_addb_reset(dut):
"""Test reset behavior and basic functionality."""
# Create clock
clock = Clock(dut.clk, 10, units="ns")
cocotb.start_soon(clock.start())
# Apply reset
dut.reset.value = 1
dut.scan_enable.value = 0
dut.test_mode.value = 0
# Set some default values for scan inputs
if hasattr(dut, "scan_in0"):
dut.scan_in0.value = 0
if hasattr(dut, "scan_in1"):
dut.scan_in1.value = 0
if hasattr(dut, "scan_in2"):
dut.scan_in2.value = 0
if hasattr(dut, "scan_in3"):
dut.scan_in3.value = 0
if hasattr(dut, "scan_in4"):
dut.scan_in4.value = 0
# Wait for a few clock cycles with reset active
for _ in range(3):
await RisingEdge(dut.clk)
# Release reset
dut.reset.value = 0
await RisingEdge(dut.clk)
# Test 1: Positive DQ, Positive SE
dut.DQ.value = 0x1234 # Positive number (MSB = 0)
dut.SE.value = 0x567 # Positive number (MSB = 0)
await RisingEdge(dut.clk)
# DQI = DQ (since DQS=0), SEI = SE (since SES=0)
# SR = 0x1234 + 0x0567 = 0x179B
expected = (0x1234 + 0x0567) & 0xFFFF
assert dut.SR.value == expected, f"Test 1 failed: got {dut.SR.value.integer}, expected {expected}"
# Test 2: Negative DQ (sign magnitude), Positive SE
dut.DQ.value = 0x8234 # Negative: MSB=1, magnitude=0x0234
dut.SE.value = 0x567 # Positive: MSB=0
await RisingEdge(dut.clk)
# DQS=1, so DQI = 65536 - 0x0234 = 0xFDCB (in 16-bit 2's complement: -0x0234)
# SEI = 0x0567
# SR = 0xFDCB + 0x0567 = 0x0332 (with 16-bit wrap-around)
# Actually: 0xFDCB + 0x0567 = 0x10332, lower 16 bits = 0x0332
dq_magnitude = 0x0234
dqi = (65536 - dq_magnitude) & 0xFFFF # 0xFDCB
sei = 0x0567
expected = (dqi + sei) & 0xFFFF # 0x0332
assert dut.SR.value == expected, f"Test 2 failed: got {dut.SR.value.integer}, expected {expected}"
# Test 3: Positive DQ, Negative SE (15-bit 2's complement)
dut.DQ.value = 0x1234 # Positive
dut.SE.value = 0xC567 # Negative: MSB=1 (15-bit), value = 0x4567 with sign
await RisingEdge(dut.clk)
# SES=1, so SEI = 32768 + 0x4567 = 0x8567 (16-bit 2's complement: -0x7A99)
# Actually: 32768 + 0x4567 = 0x8567
# DQI = 0x1234
# SR = 0x1234 + 0x8567 = 0x979B (with wrap-around)
sei = (32768 + 0x4567) & 0xFFFF # 0x8567
expected = (0x1234 + sei) & 0xFFFF # 0x979B
assert dut.SR.value == expected, f"Test 3 failed: got {dut.SR.value.integer}, expected {expected}"
# Test 4: Both negative
dut.DQ.value = 0x8234 # Negative DQ
dut.SE.value = 0xC567 # Negative SE
await RisingEdge(dut.clk)
# DQI = 65536 - 0x0234 = 0xFDCB
# SEI = 32768 + 0x4567 = 0x8567
# SR = 0xFDCB + 0x8567 = 0x8332 (with wrap-around, carry out)
dqi = (65536 - 0x0234) & 0xFFFF # 0xFDCB
sei = (32768 + 0x4567) & 0xFFFF # 0x8567
expected = (dqi + sei) & 0xFFFF # 0x8332
assert dut.SR.value == expected, f"Test 4 failed: got {dut.SR.value.integer}, expected {expected}"
# Test 5: Zero inputs
dut.DQ.value = 0
dut.SE.value = 0
await RisingEdge(dut.clk)
assert dut.SR.value == 0, f"Zero test failed: got {dut.SR.value.integer}, expected 0"
@cocotb.test()
async def test_addb_scan_mode(dut):
"""Test that scan mode doesn't interfere with normal operation."""
# Create clock
clock = Clock(dut.clk, 10, units="ns")
cocotb.start_soon(clock.start())
# Reset
dut.reset.value = 1
dut.scan_enable.value = 0
dut.test_mode.value = 0
await RisingEdge(dut.clk)
await RisingEdge(dut.clk)
dut.reset.value = 0
await RisingEdge(dut.clk)
# Test normal operation first
dut.DQ.value = 0x1111
dut.SE.value = 0x222
await RisingEdge(dut.clk)
expected = (0x1111 + 0x0222) & 0xFFFF # 0x1333
assert dut.SR.value == expected, f"Normal op failed: got {dut.SR.value.integer}, expected {expected}"
# Enable test mode (should not affect arithmetic)
dut.test_mode.value = 1
dut.scan_enable.value = 1
# Set some scan values if ports exist
if hasattr(dut, "scan_in0"):
dut.scan_in0.value = 1
if hasattr(dut, "scan_in1"):
dut.scan_in1.value = 0
if hasattr(dut, "scan_in2"):
dut.scan_in2.value = 1
if hasattr(dut, "scan_in3"):
dut.scan_in3.value = 0
if hasattr(dut, "scan_in4"):
dut.scan_in4.value = 1
# Test another arithmetic operation
dut.DQ.value = 0x3333
dut.SE.value = 0x444
await RisingEdge(dut.clk)
expected = (0x3333 + 0x0444) & 0xFFFF # 0x3777
assert dut.SR.value == expected, f"Test mode op failed: got {dut.SR.value.integer}, expected {expected}"
# Check scan outputs exist (but don't verify values since scan chain not implemented)
if hasattr(dut, "scan_out0"):
_ = dut.scan_out0.value # Just access to ensure it exists
if hasattr(dut, "scan_out1"):
_ = dut.scan_out1.value
if hasattr(dut, "scan_out2"):
_ = dut.scan_out2.value
if hasattr(dut, "scan_out3"):
_ = dut.scan_out3.value
if hasattr(dut, "scan_out4"):
_ = dut.scan_out4.value
def run_simulation():
"""Run the simulation using cocotb runner."""
# Get project root (parent of testbench directory)
project_root = Path(__file__).resolve().parents[1]
# Path to the main Verilog file
verilog_sources = [project_root / "reference" / "top.v"]
# Parameters for the runner
hdl_toplevel = "ADDB"
build_args = []
sim_args = []
# Create and run the simulator
runner = get_runner("icarus")
runner.build(
verilog_sources=verilog_sources,
hdl_toplevel=hdl_toplevel,
build_args=build_args,
always=True,
)
runner.test(
hdl_toplevel=hdl_toplevel,
test_module="tb",
test_args=sim_args,
)
if __name

Xet Storage Details

Size:
6.44 kB
·
Xet hash:
d69a507ba43a175fa95e47b210a17f79c4d68cba4d8a5e99d02cc4a5e259eee3

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