From e55587a73a3975ac3eb886ba1eceded65bc11871 Mon Sep 17 00:00:00 2001 From: AndyOja Date: Mon, 19 Jan 2026 17:02:19 +0000 Subject: [PATCH 1/9] using cocotblib --- tests/adapters/umi2apb/__init__.py | 6 + tests/adapters/umi2apb/env.py | 101 ++++++++++++++++ tests/adapters/umi2apb/run.py | 27 +++++ tests/adapters/umi2apb/test_backpressure.py | 79 ++++++++++++ tests/adapters/umi2apb/test_basic_WR.py | 101 ++++++++++++++++ .../adapters/umi2apb/test_full_throughput.py | 91 ++++++++++++++ tests/adapters/umi2apb/test_posted_write.py | 66 ++++++++++ .../adapters/umi2apb/test_random_stimulus.py | 114 ++++++++++++++++++ 8 files changed, 585 insertions(+) create mode 100644 tests/adapters/umi2apb/__init__.py create mode 100644 tests/adapters/umi2apb/env.py create mode 100644 tests/adapters/umi2apb/run.py create mode 100644 tests/adapters/umi2apb/test_backpressure.py create mode 100644 tests/adapters/umi2apb/test_basic_WR.py create mode 100644 tests/adapters/umi2apb/test_full_throughput.py create mode 100644 tests/adapters/umi2apb/test_posted_write.py create mode 100644 tests/adapters/umi2apb/test_random_stimulus.py diff --git a/tests/adapters/umi2apb/__init__.py b/tests/adapters/umi2apb/__init__.py new file mode 100644 index 00000000..158a731e --- /dev/null +++ b/tests/adapters/umi2apb/__init__.py @@ -0,0 +1,6 @@ +# Import tests so cocotb can discover them +from adapters.umi2apb.test_basic_WR import * +from adapters.umi2apb.test_full_throughput import * +from adapters.umi2apb.test_random_stimulus import * +from adapters.umi2apb.test_posted_write import * +from adapters.umi2apb.test_backpressure import * diff --git a/tests/adapters/umi2apb/env.py b/tests/adapters/umi2apb/env.py new file mode 100644 index 00000000..5be666e9 --- /dev/null +++ b/tests/adapters/umi2apb/env.py @@ -0,0 +1,101 @@ +# Owns the driver, monitor, and scoreboard for UMI to APB adapter tests, +# and provides common functionality for the tests. + +import math +from cocotb.clock import Clock +from cocotb.triggers import ClockCycles + +from cocotb_bus.scoreboard import Scoreboard +from cocotbext.apb import ApbBus, ApbSlave, MemoryRegion + +from cocotblib.umi.drivers.sumi_driver import SumiDriver +from cocotblib.umi.monitors.sumi_monitor import SumiMonitor +from cocotblib.umi.sumi import SumiTransaction, SumiCmdType, SumiCmd +from cocotblib.common import drive_reset + + +# Creates the umi2apb test environment +class UMI2APBEnv: + def __init__(self, dut, clk_period_ns=10, mem_size=2**16): + self.dut = dut + self.clk_period_ns = clk_period_ns + self.mem_size = mem_size + + self.data_width = int(dut.RW.value) # default of 64 + self.addr_width = int(dut.AW.value) # default of 64 + self.data_size = self.data_width // 8 + + self.expected_responses = [] + + self.clk = dut.apb_pclk + self.nreset = dut.apb_nreset + + self._build() + + def _build(self): + dut = self.dut + + # Instantiates UMI driver + self.sumi_driver = SumiDriver( + entity=dut, + name="udev_req", + clock=self.clk, + bus_separator="_" + ) + + # Instantiates APB slave and memory region + apb_bus = ApbBus.from_prefix(dut, "apb") + self.apb_slave = ApbSlave(apb_bus, self.clk, self.nreset) + self.region = MemoryRegion(self.mem_size) + self.apb_slave.target = self.region + + # Creates UMI monitor (for responses) + self.sumi_monitor = SumiMonitor( + entity=dut, + name="udev_resp", + clock=self.clk, + bus_separator="_" + ) + + # Creates scoreboard + self.scoreboard = Scoreboard(dut, fail_immediately=True) + self.scoreboard.add_interface(monitor=self.sumi_monitor,expected_output=self.expected_responses) + + # Prerequisites for starting tests + async def start(self): + Clock(self.clk, self.clk_period_ns, unit="ns").start() + await drive_reset(self.nreset, self.clk_period_ns) + self.dut.udev_resp_ready.value = 1 + + # Waits for umi responses + async def wait_for_responses(self, max_cycles): + cycles = 0 + while self.expected_responses: + await ClockCycles(self.clk, 1) + cycles += 1 + if cycles > max_cycles: + raise TimeoutError( + f"Timeout waiting for responses " + f"({len(self.expected_responses)} remaining)" + ) + + +# Creates an ideal umi write response +def create_expected_write_response(write_txn, data_size, addr_width=64): + req_da = int(write_txn.da.value) if hasattr(write_txn.da, "value") else int(write_txn.da) + req_sa = int(write_txn.sa.value) if hasattr(write_txn.sa, "value") else int(write_txn.sa) + + req_size = int(write_txn.cmd.size) + req_len = int(write_txn.cmd.len) + + return SumiTransaction( + cmd=SumiCmd.from_fields( + cmd_type=int(SumiCmdType.UMI_RESP_WRITE), + size=req_size, + len=req_len + ), + da=req_sa, + sa=req_da, + data=bytearray(data_size), # Expect no data in write response + addr_width=addr_width + ) \ No newline at end of file diff --git a/tests/adapters/umi2apb/run.py b/tests/adapters/umi2apb/run.py new file mode 100644 index 00000000..89615cb9 --- /dev/null +++ b/tests/adapters/umi2apb/run.py @@ -0,0 +1,27 @@ +# tests/adapters/umi2apb/run.py + +import pytest +from siliconcompiler import Sim + +from umi.adapters import UMI2APB +from cocotblib.common import run_cocotb +def run_umi2apb(simulator="verilator", waves=True): + project = Sim(UMI2APB()) + project.add_fileset("rtl") + + tests_failed = run_cocotb( + project=project, + test_module_name="adapters.umi2apb", + simulator_name=simulator, + timescale=("1ns", "1ps"), + build_args=["--report-unoptflat"] if simulator == "verilator" else [], + output_dir_name=f"umi2apb_{simulator}", + waves=waves, + ) + + assert tests_failed == 0 + +@pytest.mark.sim +@pytest.mark.parametrize("simulator", ["verilator"]) +def test_umi2apb(simulator): + run_umi2apb(simulator) diff --git a/tests/adapters/umi2apb/test_backpressure.py b/tests/adapters/umi2apb/test_backpressure.py new file mode 100644 index 00000000..ddf1b11c --- /dev/null +++ b/tests/adapters/umi2apb/test_backpressure.py @@ -0,0 +1,79 @@ +import math +import cocotb + +from cocotb.handle import SimHandleBase +from cocotb.triggers import ClockCycles, RisingEdge + +from cocotblib.umi.sumi import SumiTransaction, SumiCmdType, SumiCmd +from adapters.umi2apb.env import UMI2APBEnv, create_expected_write_response + + +@cocotb.test(timeout_time=50, timeout_unit="ms") +async def test_backpressure(dut: SimHandleBase): + """ + Test response backpressure handling: + 1. Disable response ready + 2. Send transactions + 3. Verify responses are held and not lost + 4. Enable ready and verify all responses arrive correctly + """ + + env = UMI2APBEnv(dut) + await env.start() + + umi_size = int(math.log2(env.data_size)) + + print("=== Backpressure Test ===") + + # Disable response ready + dut.udev_resp_ready.value = 0 + + # Send a write transaction + test_addr = 0x100 + test_data = 0xDEADBEEF + + write_txn = SumiTransaction( + cmd=SumiCmd.from_fields( + cmd_type=int(SumiCmdType.UMI_REQ_WRITE), + size=umi_size, + len=0, + ), + da=test_addr, + sa=0x0, + data=test_data.to_bytes(env.data_size, byteorder="little"), + ) + + env.expected_responses.append( + create_expected_write_response( + write_txn, + data_size=env.data_size, + addr_width=env.addr_width, + ) + ) + + env.sumi_driver.append(write_txn) + print(f"Sent write: addr=0x{test_addr:x}, data=0x{test_data:08x}") + + await ClockCycles(env.clk, 20) + + # Verify response is being held + assert dut.udev_resp_valid.value == 1, "Response should be valid" + assert len(env.expected_responses) == 1, "Response should not have been consumed yet" + print("Response held with backpressure") + + # enable response ready + dut.udev_resp_ready.value = 1 + print("Re-enabled udev_resp_ready") + + await env.wait_for_responses(max_cycles=10) + + # Verify mem was written correctly + mem_data = await env.region.read(test_addr, env.data_size) + actual_data = int.from_bytes(mem_data, byteorder="little") + assert actual_data == test_data, ( + f"Write data mismatch: expected 0x{test_data:x}, got 0x{actual_data:x}" + ) + print(f"Memory verified: 0x{actual_data:08x}") + + print("\n=== Backpressure Test PASSED ===") + raise env.scoreboard.result diff --git a/tests/adapters/umi2apb/test_basic_WR.py b/tests/adapters/umi2apb/test_basic_WR.py new file mode 100644 index 00000000..56a054bd --- /dev/null +++ b/tests/adapters/umi2apb/test_basic_WR.py @@ -0,0 +1,101 @@ +import math +import cocotb + +from cocotb.handle import SimHandleBase +from cocotb.triggers import ClockCycles + +from cocotblib.umi.sumi import SumiTransaction, SumiCmdType, SumiCmd +from adapters.umi2apb.env import UMI2APBEnv, create_expected_write_response + + +@cocotb.test(timeout_time=50, timeout_unit="ms") +async def test_basic_WR(dut: SimHandleBase): + """ + Basic sanity test: + 1. Single aligned UMI write + 2. Verify APB memory contents + 3. Single UMI read + 4. Verify response payload + """ + + # Grab shared test environment + env = UMI2APBEnv(dut) + await env.start() + + umi_size = int(math.log2(env.data_size)) + test_addr = 0x100 + test_data = 0xDEADBEEF + + print("=== Basic Write Test ===") + + # WRITE transaction + write_txn = SumiTransaction( + cmd=SumiCmd.from_fields( + cmd_type=int(SumiCmdType.UMI_REQ_WRITE), + size=umi_size, + len=0, + ), + da=test_addr, + sa=0x0, + data=test_data.to_bytes(env.data_size, byteorder="little"), + ) + + env.expected_responses.append( + create_expected_write_response( + write_txn, + data_size=env.data_size, + addr_width=env.addr_width, + ) + ) + + env.sumi_driver.append(write_txn) + + # Wait for write response + await env.wait_for_responses(max_cycles=100) + + # Verify APB memory contents + mem_data = await env.region.read(test_addr, env.data_size) + assert int.from_bytes(mem_data, byteorder="little") == test_data, ( + f"Write failed: expected 0x{test_data:x}, " + f"got 0x{int.from_bytes(mem_data, 'little'):x}" + ) + + print(f" Data written to memory: 0x{test_data:08x}") + print(f" UMI write response verified by scoreboard") + + print("\n=== Basic Read Test ===") + + # READ transaction + read_txn = SumiTransaction( + cmd=SumiCmd.from_fields( + cmd_type=int(SumiCmdType.UMI_REQ_READ), + size=umi_size, + len=0, + ), + da=test_addr, + sa=0x0, + data=bytearray(env.data_size), + ) + + expected_read_resp = SumiTransaction( + cmd=SumiCmd.from_fields( + cmd_type=int(SumiCmdType.UMI_RESP_READ), + size=umi_size, + len=0, + ), + da=0x0, + sa=test_addr, + data=test_data.to_bytes(env.data_size, byteorder="little"), + addr_width=env.addr_width, + ) + + env.expected_responses.append(expected_read_resp) + env.sumi_driver.append(read_txn) + + # Wait for read response + await env.wait_for_responses(max_cycles=100) + + print(f" Read response verified by scoreboard") + + # Check scoreboard results + raise env.scoreboard.result diff --git a/tests/adapters/umi2apb/test_full_throughput.py b/tests/adapters/umi2apb/test_full_throughput.py new file mode 100644 index 00000000..ba99e8c3 --- /dev/null +++ b/tests/adapters/umi2apb/test_full_throughput.py @@ -0,0 +1,91 @@ +import math +import cocotb +from cocotb.triggers import ClockCycles + +from adapters.umi2apb.env import UMI2APBEnv +from cocotblib.umi.sumi import SumiTransaction, SumiCmdType, SumiCmd + + +@cocotb.test(timeout_time=50, timeout_unit="ms") +async def test_full_throughput(dut): + """ + Back-to-back full-throughput tests alternating read/write transactions. + + - New request arrives in same cycle response becomes valid + """ + + env = UMI2APBEnv(dut) + await env.start() + + data_size = env.data_size + addr_width = env.addr_width + umi_size = int(math.log2(data_size)) + + num_transactions = 100 + + print("=== Back-to-Back Full Throughput Test ===") + + for i in range(num_transactions): + txn_size = i % (umi_size + 1) + txn_bytes = 1 << txn_size + addr = i * data_size + + is_read = (i % 2) == 0 + + if is_read: + txn = SumiTransaction( + cmd=SumiCmd.from_fields( + cmd_type=int(SumiCmdType.UMI_REQ_READ), + size=txn_size, + len=0, + ), + da=addr, + sa=0x0, + data=bytearray(txn_bytes), + ) + + expected_resp = SumiTransaction( + cmd=SumiCmd.from_fields( + cmd_type=int(SumiCmdType.UMI_RESP_READ), + size=txn_size, + len=0, + ), + da=0x0, + sa=addr, + data=bytearray(txn_bytes), + addr_width=addr_width, + ) + + else: + data = bytes([i & 0xFF] * txn_bytes) + txn = SumiTransaction( + cmd=SumiCmd.from_fields( + cmd_type=int(SumiCmdType.UMI_REQ_WRITE), + size=txn_size, + len=0, + ), + da=addr, + sa=0x0, + data=data, + ) + + expected_resp = SumiTransaction( + cmd=SumiCmd.from_fields( + cmd_type=int(SumiCmdType.UMI_RESP_WRITE), + size=txn_size, + len=0, + ), + da=0x0, + sa=addr, + data=bytearray(txn_bytes), + addr_width=addr_width, + ) + + env.expected_responses.append(expected_resp) + env.sumi_driver.append(txn) + + # Wait for all responses + await env.wait_for_responses(max_cycles=num_transactions * 50) + + print(f" All {num_transactions} back-to-back transactions completed successfully!") + raise env.scoreboard.result diff --git a/tests/adapters/umi2apb/test_posted_write.py b/tests/adapters/umi2apb/test_posted_write.py new file mode 100644 index 00000000..031e4003 --- /dev/null +++ b/tests/adapters/umi2apb/test_posted_write.py @@ -0,0 +1,66 @@ +import math +import cocotb + +from cocotb.handle import SimHandleBase +from cocotb.triggers import ClockCycles + +from cocotblib.umi.sumi import SumiTransaction, SumiCmdType, SumiCmd +from adapters.umi2apb.env import UMI2APBEnv + + +@cocotb.test(timeout_time=50, timeout_unit="ms") +async def test_posted_write(dut: SimHandleBase): + """ + Test posted writes (no UMI response expected): + 1. Send multiple writes to different addresses + 2. Verify APB memory contents + """ + + env = UMI2APBEnv(dut) + await env.start() + + umi_size = int(math.log2(env.data_size)) + + print("=== Posted Write Test ===") + + # Test data: address -> value + test_data = { + 0x100: 0xDEADBEEF, + 0x200: 0xCAFEBABE, + 0x300: 0x12345678, + 0x400: 0xABCD1234, + } + + # Send writes + for addr, data in test_data.items(): + posted_txn = SumiTransaction( + cmd=SumiCmd.from_fields( + cmd_type=int(SumiCmdType.UMI_REQ_POSTED), + size=umi_size, + len=0, + ), + da=addr, + sa=0x0, + data=data.to_bytes(env.data_size, byteorder="little"), + ) + env.sumi_driver.append(posted_txn) + print(f" Sent posted write: addr=0x{addr:x}, data=0x{data:08x}") + + # Wait for transactions to complete + await ClockCycles(env.clk, 50) + + # Verify APB memory contents directly + print("\n=== Verifying Memory Contents ===") + for addr, expected_data in test_data.items(): + mem_data = await env.region.read(addr, env.data_size) + actual_data = int.from_bytes(mem_data, byteorder="little") + assert actual_data == expected_data, ( + f"Posted write failed at 0x{addr:x}: " + f"expected 0x{expected_data:x}, got 0x{actual_data:x}" + ) + print(f" Verified addr=0x{addr:x}: 0x{actual_data:08x}") + + # Note: If any unexpected responses arrive, the scoreboard will + # raise error + + print("\n=== Posted Write Test PASSED ===") diff --git a/tests/adapters/umi2apb/test_random_stimulus.py b/tests/adapters/umi2apb/test_random_stimulus.py new file mode 100644 index 00000000..180c7d42 --- /dev/null +++ b/tests/adapters/umi2apb/test_random_stimulus.py @@ -0,0 +1,114 @@ +import math +import cocotb +from random import randint, randbytes +from cocotb.triggers import ClockCycles + +from adapters.umi2apb.env import UMI2APBEnv, create_expected_write_response +from cocotblib.umi.sumi import SumiTransaction, SumiCmdType, SumiCmd + + +@cocotb.test(timeout_time=50, timeout_unit="ms") +async def test_random_stimulus(dut): + """ + Randomized read/write stimulus. + + - Aligned addresses + - Full-width accesses + - Memory model checked at the end + """ + # Grab shared test environment + env = UMI2APBEnv(dut) + await env.start() + + data_size = env.data_size + addr_width = env.addr_width + umi_size = int(math.log2(data_size)) + + mem_size = 2**16 + num_random_transactions = 512 + read_probability = 0.5 + + print(f"=== Randomized Test: {num_random_transactions} transactions ===") + + # Ideal memory model for writes/reads + memory_model = {} + + for i in range(num_random_transactions): + txn_bytes = env.data_size + max_addr = (mem_size - txn_bytes) // txn_bytes + + # Randomized address and command type + addr = randint(0, max_addr) * txn_bytes + is_read = randint(0, 99) < (read_probability * 100) + + if is_read: + txn = SumiTransaction( + cmd=SumiCmd.from_fields( + cmd_type=int(SumiCmdType.UMI_REQ_READ), + size=umi_size, + len=0, + ), + da=addr, + sa=0x0, + data=bytearray(txn_bytes), + ) + + expected_data = memory_model.get(addr, bytearray(txn_bytes)) + expected_resp = SumiTransaction( + cmd=SumiCmd.from_fields( + cmd_type=int(SumiCmdType.UMI_RESP_READ), + size=umi_size, + len=0, + ), + da=0x0, + sa=addr, + data=expected_data, + addr_width=addr_width, + ) + + env.expected_responses.append(expected_resp) + + else: + data = randbytes(txn_bytes) + memory_model[addr] = data + + txn = SumiTransaction( + cmd=SumiCmd.from_fields( + cmd_type=int(SumiCmdType.UMI_REQ_WRITE), + size=umi_size, + len=0, + ), + da=addr, + sa=0x0, + data=data, + ) + + env.expected_responses.append( + create_expected_write_response(txn, txn_bytes, addr_width) + ) + + await env.sumi_driver.send(txn) + + if (i + 1) % 100 == 0: + print(f" Sent {i+1}/{num_random_transactions} transactions...") + await ClockCycles(env.clk, 1) + + await env.wait_for_responses(max_cycles=num_random_transactions * 50) + + # Memory verification + num_verified = 0 + for addr, expected_data in memory_model.items(): + mem_data = await env.region.read(addr, data_size) + assert mem_data == expected_data, ( + f"Memory mismatch at 0x{addr:x}: " + f"expected {expected_data.hex()}, got {mem_data.hex()}" + ) + num_verified += 1 + + print(f"\n=== Test Statistics ===") + print(f" Total transactions: {num_random_transactions}") + print(f" Unique addresses written: {len(memory_model)}") + print(f" Memory locations verified: {num_verified}") + print(f" All transactions completed") + + raise env.scoreboard.result From c13bff9e0fb83b54f0ceb974fee31de9b60b2426 Mon Sep 17 00:00:00 2001 From: AndyOja Date: Mon, 19 Jan 2026 18:21:12 +0000 Subject: [PATCH 2/9] renamed for CI --- tests/adapters/umi2apb/{run.py => test_run.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/adapters/umi2apb/{run.py => test_run.py} (100%) diff --git a/tests/adapters/umi2apb/run.py b/tests/adapters/umi2apb/test_run.py similarity index 100% rename from tests/adapters/umi2apb/run.py rename to tests/adapters/umi2apb/test_run.py From 79c1c5baf8a5d5478cca9f2b48567ceea73a21d3 Mon Sep 17 00:00:00 2001 From: AndyOja Date: Mon, 19 Jan 2026 18:34:15 +0000 Subject: [PATCH 3/9] lint issues --- tests/adapters/umi2apb/__init__.py | 12 +++++++----- tests/adapters/umi2apb/test_basic_WR.py | 6 +++--- tests/adapters/umi2apb/test_full_throughput.py | 4 ++-- tests/adapters/umi2apb/test_posted_write.py | 4 ++-- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/tests/adapters/umi2apb/__init__.py b/tests/adapters/umi2apb/__init__.py index 158a731e..69ee0ffe 100644 --- a/tests/adapters/umi2apb/__init__.py +++ b/tests/adapters/umi2apb/__init__.py @@ -1,6 +1,8 @@ # Import tests so cocotb can discover them -from adapters.umi2apb.test_basic_WR import * -from adapters.umi2apb.test_full_throughput import * -from adapters.umi2apb.test_random_stimulus import * -from adapters.umi2apb.test_posted_write import * -from adapters.umi2apb.test_backpressure import * +from adapters.umi2apb.test_basic_WR import test_basic_WR +from adapters.umi2apb.test_full_throughput import test_full_throughput +from adapters.umi2apb.test_random_stimulus import test_random_stimulus +from adapters.umi2apb.test_posted_write import test_posted_write +from adapters.umi2apb.test_backpressure import test_backpressure + + diff --git a/tests/adapters/umi2apb/test_basic_WR.py b/tests/adapters/umi2apb/test_basic_WR.py index 56a054bd..42db176b 100644 --- a/tests/adapters/umi2apb/test_basic_WR.py +++ b/tests/adapters/umi2apb/test_basic_WR.py @@ -60,8 +60,8 @@ async def test_basic_WR(dut: SimHandleBase): f"got 0x{int.from_bytes(mem_data, 'little'):x}" ) - print(f" Data written to memory: 0x{test_data:08x}") - print(f" UMI write response verified by scoreboard") + print(f" Data written to memory: 0x{test_data:08x}") + print(" UMI write response verified by scoreboard") print("\n=== Basic Read Test ===") @@ -95,7 +95,7 @@ async def test_basic_WR(dut: SimHandleBase): # Wait for read response await env.wait_for_responses(max_cycles=100) - print(f" Read response verified by scoreboard") + print("Read response verified by scoreboard") # Check scoreboard results raise env.scoreboard.result diff --git a/tests/adapters/umi2apb/test_full_throughput.py b/tests/adapters/umi2apb/test_full_throughput.py index ba99e8c3..b8c04953 100644 --- a/tests/adapters/umi2apb/test_full_throughput.py +++ b/tests/adapters/umi2apb/test_full_throughput.py @@ -82,10 +82,10 @@ async def test_full_throughput(dut): ) env.expected_responses.append(expected_resp) - env.sumi_driver.append(txn) + env.sumi_driver.append(txn) # Wait for all responses await env.wait_for_responses(max_cycles=num_transactions * 50) - print(f" All {num_transactions} back-to-back transactions completed successfully!") + print(f" All {num_transactions} back-to-back transactions completed successfully!") raise env.scoreboard.result diff --git a/tests/adapters/umi2apb/test_posted_write.py b/tests/adapters/umi2apb/test_posted_write.py index 031e4003..1cc3b1af 100644 --- a/tests/adapters/umi2apb/test_posted_write.py +++ b/tests/adapters/umi2apb/test_posted_write.py @@ -46,7 +46,7 @@ async def test_posted_write(dut: SimHandleBase): env.sumi_driver.append(posted_txn) print(f" Sent posted write: addr=0x{addr:x}, data=0x{data:08x}") - # Wait for transactions to complete + # Wait for transactions to complete await ClockCycles(env.clk, 50) # Verify APB memory contents directly @@ -60,7 +60,7 @@ async def test_posted_write(dut: SimHandleBase): ) print(f" Verified addr=0x{addr:x}: 0x{actual_data:08x}") - # Note: If any unexpected responses arrive, the scoreboard will + # Note: If any unexpected responses arrive, the scoreboard will # raise error print("\n=== Posted Write Test PASSED ===") From 112acb9bf253f7be330bc184c7b0a383e1bc9723 Mon Sep 17 00:00:00 2001 From: AndyOja Date: Mon, 19 Jan 2026 18:42:39 +0000 Subject: [PATCH 4/9] added cocotb dep --- pyproject.toml | 3 +++ tests/adapters/umi2apb/__init__.py | 2 -- tests/adapters/umi2apb/env.py | 6 +++--- tests/adapters/umi2apb/test_random_stimulus.py | 4 ++-- tests/adapters/umi2apb/test_run.py | 2 ++ 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 5cf90d03..509766a5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,6 +32,9 @@ test = [ "pytest-xdist == 3.8.0", "pytest-timeout == 2.4.0", "flake8 == 7.3.0", + "cocotb==2.0.1", + "cocotb-bus==0.3.0", + "cocotbext-apb==0.7.4", "switchboard-hw == 0.3.0" ] diff --git a/tests/adapters/umi2apb/__init__.py b/tests/adapters/umi2apb/__init__.py index 69ee0ffe..ef998997 100644 --- a/tests/adapters/umi2apb/__init__.py +++ b/tests/adapters/umi2apb/__init__.py @@ -4,5 +4,3 @@ from adapters.umi2apb.test_random_stimulus import test_random_stimulus from adapters.umi2apb.test_posted_write import test_posted_write from adapters.umi2apb.test_backpressure import test_backpressure - - diff --git a/tests/adapters/umi2apb/env.py b/tests/adapters/umi2apb/env.py index 5be666e9..14e943ba 100644 --- a/tests/adapters/umi2apb/env.py +++ b/tests/adapters/umi2apb/env.py @@ -59,7 +59,7 @@ def _build(self): # Creates scoreboard self.scoreboard = Scoreboard(dut, fail_immediately=True) - self.scoreboard.add_interface(monitor=self.sumi_monitor,expected_output=self.expected_responses) + self.scoreboard.add_interface(monitor=self.sumi_monitor, expected_output=self.expected_responses) # Prerequisites for starting tests async def start(self): @@ -96,6 +96,6 @@ def create_expected_write_response(write_txn, data_size, addr_width=64): ), da=req_sa, sa=req_da, - data=bytearray(data_size), # Expect no data in write response + data=bytearray(data_size), # Expect no data in write response addr_width=addr_width - ) \ No newline at end of file + ) diff --git a/tests/adapters/umi2apb/test_random_stimulus.py b/tests/adapters/umi2apb/test_random_stimulus.py index 180c7d42..1ca13b03 100644 --- a/tests/adapters/umi2apb/test_random_stimulus.py +++ b/tests/adapters/umi2apb/test_random_stimulus.py @@ -105,10 +105,10 @@ async def test_random_stimulus(dut): ) num_verified += 1 - print(f"\n=== Test Statistics ===") + print("\n=== Test Statistics ===") print(f" Total transactions: {num_random_transactions}") print(f" Unique addresses written: {len(memory_model)}") print(f" Memory locations verified: {num_verified}") - print(f" All transactions completed") + print(" All transactions completed") raise env.scoreboard.result diff --git a/tests/adapters/umi2apb/test_run.py b/tests/adapters/umi2apb/test_run.py index 89615cb9..957b2683 100644 --- a/tests/adapters/umi2apb/test_run.py +++ b/tests/adapters/umi2apb/test_run.py @@ -5,6 +5,8 @@ from umi.adapters import UMI2APB from cocotblib.common import run_cocotb + + def run_umi2apb(simulator="verilator", waves=True): project = Sim(UMI2APB()) project.add_fileset("rtl") From e8060018d75b9034428234f0c661f3ca40308f0a Mon Sep 17 00:00:00 2001 From: AndyOja Date: Mon, 19 Jan 2026 18:46:28 +0000 Subject: [PATCH 5/9] lint contd. --- tests/adapters/umi2apb/__init__.py | 10 +++++----- tests/adapters/umi2apb/env.py | 1 - tests/adapters/umi2apb/test_backpressure.py | 4 +++- tests/adapters/umi2apb/test_basic_WR.py | 2 +- tests/adapters/umi2apb/test_full_throughput.py | 2 +- tests/adapters/umi2apb/test_run.py | 1 + 6 files changed, 11 insertions(+), 9 deletions(-) diff --git a/tests/adapters/umi2apb/__init__.py b/tests/adapters/umi2apb/__init__.py index ef998997..95d79faa 100644 --- a/tests/adapters/umi2apb/__init__.py +++ b/tests/adapters/umi2apb/__init__.py @@ -1,6 +1,6 @@ # Import tests so cocotb can discover them -from adapters.umi2apb.test_basic_WR import test_basic_WR -from adapters.umi2apb.test_full_throughput import test_full_throughput -from adapters.umi2apb.test_random_stimulus import test_random_stimulus -from adapters.umi2apb.test_posted_write import test_posted_write -from adapters.umi2apb.test_backpressure import test_backpressure +from adapters.umi2apb.test_basic_WR import test_basic_WR # noqa: F401 +from adapters.umi2apb.test_full_throughput import test_full_throughput # noqa: F401 +from adapters.umi2apb.test_random_stimulus import test_random_stimulus # noqa: F401 +from adapters.umi2apb.test_posted_write import test_posted_write # noqa: F401 +from adapters.umi2apb.test_backpressure import test_backpressure # noqa: F401 diff --git a/tests/adapters/umi2apb/env.py b/tests/adapters/umi2apb/env.py index 14e943ba..687b40a9 100644 --- a/tests/adapters/umi2apb/env.py +++ b/tests/adapters/umi2apb/env.py @@ -1,7 +1,6 @@ # Owns the driver, monitor, and scoreboard for UMI to APB adapter tests, # and provides common functionality for the tests. -import math from cocotb.clock import Clock from cocotb.triggers import ClockCycles diff --git a/tests/adapters/umi2apb/test_backpressure.py b/tests/adapters/umi2apb/test_backpressure.py index ddf1b11c..dcf4ace2 100644 --- a/tests/adapters/umi2apb/test_backpressure.py +++ b/tests/adapters/umi2apb/test_backpressure.py @@ -2,7 +2,7 @@ import cocotb from cocotb.handle import SimHandleBase -from cocotb.triggers import ClockCycles, RisingEdge +from cocotb.triggers import ClockCycles from cocotblib.umi.sumi import SumiTransaction, SumiCmdType, SumiCmd from adapters.umi2apb.env import UMI2APBEnv, create_expected_write_response @@ -77,3 +77,5 @@ async def test_backpressure(dut: SimHandleBase): print("\n=== Backpressure Test PASSED ===") raise env.scoreboard.result + + diff --git a/tests/adapters/umi2apb/test_basic_WR.py b/tests/adapters/umi2apb/test_basic_WR.py index 42db176b..8f22e5ae 100644 --- a/tests/adapters/umi2apb/test_basic_WR.py +++ b/tests/adapters/umi2apb/test_basic_WR.py @@ -2,7 +2,6 @@ import cocotb from cocotb.handle import SimHandleBase -from cocotb.triggers import ClockCycles from cocotblib.umi.sumi import SumiTransaction, SumiCmdType, SumiCmd from adapters.umi2apb.env import UMI2APBEnv, create_expected_write_response @@ -99,3 +98,4 @@ async def test_basic_WR(dut: SimHandleBase): # Check scoreboard results raise env.scoreboard.result + diff --git a/tests/adapters/umi2apb/test_full_throughput.py b/tests/adapters/umi2apb/test_full_throughput.py index b8c04953..11bb254d 100644 --- a/tests/adapters/umi2apb/test_full_throughput.py +++ b/tests/adapters/umi2apb/test_full_throughput.py @@ -1,6 +1,5 @@ import math import cocotb -from cocotb.triggers import ClockCycles from adapters.umi2apb.env import UMI2APBEnv from cocotblib.umi.sumi import SumiTransaction, SumiCmdType, SumiCmd @@ -89,3 +88,4 @@ async def test_full_throughput(dut): print(f" All {num_transactions} back-to-back transactions completed successfully!") raise env.scoreboard.result + diff --git a/tests/adapters/umi2apb/test_run.py b/tests/adapters/umi2apb/test_run.py index 957b2683..15bbbc1c 100644 --- a/tests/adapters/umi2apb/test_run.py +++ b/tests/adapters/umi2apb/test_run.py @@ -23,6 +23,7 @@ def run_umi2apb(simulator="verilator", waves=True): assert tests_failed == 0 + @pytest.mark.sim @pytest.mark.parametrize("simulator", ["verilator"]) def test_umi2apb(simulator): From 1ef2c98bd333e9f735383da2db31af3225761770 Mon Sep 17 00:00:00 2001 From: AndyOja Date: Mon, 19 Jan 2026 18:55:07 +0000 Subject: [PATCH 6/9] lint again --- tests/adapters/umi2apb/test_backpressure.py | 2 -- tests/adapters/umi2apb/test_basic_WR.py | 1 - tests/adapters/umi2apb/test_full_throughput.py | 1 - 3 files changed, 4 deletions(-) diff --git a/tests/adapters/umi2apb/test_backpressure.py b/tests/adapters/umi2apb/test_backpressure.py index dcf4ace2..972c23f2 100644 --- a/tests/adapters/umi2apb/test_backpressure.py +++ b/tests/adapters/umi2apb/test_backpressure.py @@ -77,5 +77,3 @@ async def test_backpressure(dut: SimHandleBase): print("\n=== Backpressure Test PASSED ===") raise env.scoreboard.result - - diff --git a/tests/adapters/umi2apb/test_basic_WR.py b/tests/adapters/umi2apb/test_basic_WR.py index 8f22e5ae..72d947e8 100644 --- a/tests/adapters/umi2apb/test_basic_WR.py +++ b/tests/adapters/umi2apb/test_basic_WR.py @@ -98,4 +98,3 @@ async def test_basic_WR(dut: SimHandleBase): # Check scoreboard results raise env.scoreboard.result - diff --git a/tests/adapters/umi2apb/test_full_throughput.py b/tests/adapters/umi2apb/test_full_throughput.py index 11bb254d..c0f11d92 100644 --- a/tests/adapters/umi2apb/test_full_throughput.py +++ b/tests/adapters/umi2apb/test_full_throughput.py @@ -88,4 +88,3 @@ async def test_full_throughput(dut): print(f" All {num_transactions} back-to-back transactions completed successfully!") raise env.scoreboard.result - From e3a46429668e86a45212402f8a22df2bd57fc9f0 Mon Sep 17 00:00:00 2001 From: AndyOja Date: Mon, 19 Jan 2026 19:25:15 +0000 Subject: [PATCH 7/9] cocotblib dep --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 509766a5..7fde638e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,6 +35,7 @@ test = [ "cocotb==2.0.1", "cocotb-bus==0.3.0", "cocotbext-apb==0.7.4", + "za-cocotblib >= 0.0.1, < 0.1.0", "switchboard-hw == 0.3.0" ] From 2760da192af6d509fc23a990ee56b516e768fc74 Mon Sep 17 00:00:00 2001 From: AndyOja Date: Mon, 19 Jan 2026 19:27:32 +0000 Subject: [PATCH 8/9] fix cocotblib toml q --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 7fde638e..96ad27cd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,7 @@ [build-system] requires = [ "setuptools >= 61.2", + "za-cocotblib >= 0.0.1, < 0.1.0", "setuptools_scm[toml] >= 6.2" ] build-backend = "setuptools.build_meta" @@ -35,7 +36,6 @@ test = [ "cocotb==2.0.1", "cocotb-bus==0.3.0", "cocotbext-apb==0.7.4", - "za-cocotblib >= 0.0.1, < 0.1.0", "switchboard-hw == 0.3.0" ] From 7500cd39c556a08906c3eb0142c763bd2db02744 Mon Sep 17 00:00:00 2001 From: AndyOja Date: Mon, 19 Jan 2026 20:02:56 +0000 Subject: [PATCH 9/9] deps --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 96ad27cd..7fde638e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,6 @@ [build-system] requires = [ "setuptools >= 61.2", - "za-cocotblib >= 0.0.1, < 0.1.0", "setuptools_scm[toml] >= 6.2" ] build-backend = "setuptools.build_meta" @@ -36,6 +35,7 @@ test = [ "cocotb==2.0.1", "cocotb-bus==0.3.0", "cocotbext-apb==0.7.4", + "za-cocotblib >= 0.0.1, < 0.1.0", "switchboard-hw == 0.3.0" ]