| AUTO_BUILD_ARGS = [] | |
| #!/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 | |
| async def test_addb_reset(dut): | |
| """Test reset behavior and basic functionality.""" | |
| # Create clock | |
| 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 | |
| # 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" | |
| async def test_addb_scan_mode(dut): | |
| """Test that scan mode doesn't interfere with normal operation.""" | |
| # Create clock | |
| clock = Clock(dut.clk, 10, unit="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", | |
| ) | |
| 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='ADDB', | |
| build_args=AUTO_BUILD_ARGS, | |
| always=True, | |
| ) | |
| runner.test( | |
| hdl_toplevel='ADDB', | |
| test_module="tb", | |
| waves=False, | |
| ) | |
Xet Storage Details
- Size:
- 6.93 kB
- Xet hash:
- 4c5b700c5a32cca0e069aa1edddef348023cceb6162187b079a675d6a801de8c
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.