Files
PeakRDL-BusDecoder/tests/cocotb/testbenches/test_integration.py
Copilot 4dc61d24ca Add cocotb testbench for validating generated bus decoder RTL across APB3, APB4, and AXI4-Lite interfaces (#9)
* Initial plan

* Add cocotb test infrastructure and testbenches for APB3, APB4, and AXI4-Lite

Co-authored-by: arnavsacheti <36746504+arnavsacheti@users.noreply.github.com>

* Add integration tests, examples, and documentation for cocotb testbenches

Co-authored-by: arnavsacheti <36746504+arnavsacheti@users.noreply.github.com>

* Address code review feedback: use relative imports and update installation docs

Co-authored-by: arnavsacheti <36746504+arnavsacheti@users.noreply.github.com>

* Add implementation summary document

Co-authored-by: arnavsacheti <36746504+arnavsacheti@users.noreply.github.com>

* Merge cocotb dependencies into test group

Co-authored-by: arnavsacheti <36746504+arnavsacheti@users.noreply.github.com>

* Add optional cocotb simulation workflow with Icarus Verilog

Co-authored-by: arnavsacheti <36746504+arnavsacheti@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: arnavsacheti <36746504+arnavsacheti@users.noreply.github.com>
2025-10-23 23:46:51 -07:00

217 lines
7.2 KiB
Python

"""
Integration tests for cocotb testbench infrastructure.
These tests validate that the code generation and testbench setup works correctly
without requiring an actual HDL simulator. They check:
- RDL compilation and SystemVerilog generation
- Generated code contains expected elements
- Testbench utilities work correctly
"""
import tempfile
from pathlib import Path
import pytest
from peakrdl_busdecoder.cpuif.apb3 import APB3Cpuif
from peakrdl_busdecoder.cpuif.apb4 import APB4Cpuif
from peakrdl_busdecoder.cpuif.axi4lite import AXI4LiteCpuif
from ..common.utils import compile_rdl_and_export, get_verilog_sources
class TestCodeGeneration:
"""Test code generation for different CPU interfaces."""
def test_apb4_simple_register(self):
"""Test APB4 code generation for simple register."""
rdl_source = """
addrmap simple_test {
reg {
field { sw=rw; hw=r; } data[31:0];
} test_reg @ 0x0;
};
"""
with tempfile.TemporaryDirectory() as tmpdir:
module_path, package_path = compile_rdl_and_export(
rdl_source, "simple_test", tmpdir, APB4Cpuif
)
# Verify files exist
assert module_path.exists()
assert package_path.exists()
# Verify module content
module_content = module_path.read_text()
assert "module simple_test" in module_content
assert "apb4_intf.slave s_apb" in module_content
assert "test_reg" in module_content
# Verify package content
package_content = package_path.read_text()
assert "package simple_test_pkg" in package_content
def test_apb3_multiple_registers(self):
"""Test APB3 code generation for multiple registers."""
rdl_source = """
addrmap multi_reg {
reg { field { sw=rw; hw=r; } data[31:0]; } reg1 @ 0x0;
reg { field { sw=r; hw=w; } status[15:0]; } reg2 @ 0x4;
reg { field { sw=rw; hw=r; } control[7:0]; } reg3 @ 0x8;
};
"""
with tempfile.TemporaryDirectory() as tmpdir:
module_path, package_path = compile_rdl_and_export(
rdl_source, "multi_reg", tmpdir, APB3Cpuif
)
assert module_path.exists()
assert package_path.exists()
module_content = module_path.read_text()
assert "module multi_reg" in module_content
assert "apb3_intf.slave s_apb" in module_content
assert "reg1" in module_content
assert "reg2" in module_content
assert "reg3" in module_content
def test_axi4lite_nested_addrmap(self):
"""Test AXI4-Lite code generation for nested address map."""
rdl_source = """
addrmap inner_block {
reg { field { sw=rw; hw=r; } data[31:0]; } inner_reg @ 0x0;
};
addrmap outer_block {
inner_block inner @ 0x0;
reg { field { sw=rw; hw=r; } outer_data[31:0]; } outer_reg @ 0x100;
};
"""
with tempfile.TemporaryDirectory() as tmpdir:
module_path, package_path = compile_rdl_and_export(
rdl_source, "outer_block", tmpdir, AXI4LiteCpuif
)
assert module_path.exists()
assert package_path.exists()
module_content = module_path.read_text()
assert "module outer_block" in module_content
assert "axi4lite_intf.slave s_axi" in module_content
assert "inner" in module_content
assert "outer_reg" in module_content
def test_register_array(self):
"""Test code generation with register arrays."""
rdl_source = """
addrmap array_test {
reg { field { sw=rw; hw=r; } data[31:0]; } regs[4] @ 0x0 += 0x4;
};
"""
with tempfile.TemporaryDirectory() as tmpdir:
module_path, package_path = compile_rdl_and_export(
rdl_source, "array_test", tmpdir, APB4Cpuif
)
assert module_path.exists()
assert package_path.exists()
module_content = module_path.read_text()
assert "module array_test" in module_content
assert "regs" in module_content
class TestUtilityFunctions:
"""Test utility functions for testbench setup."""
def test_get_verilog_sources(self):
"""Test that get_verilog_sources returns correct file list."""
hdl_src_dir = Path(__file__).parent.parent.parent.parent / "hdl-src"
module_path = Path("/tmp/test_module.sv")
package_path = Path("/tmp/test_pkg.sv")
intf_files = [
hdl_src_dir / "apb4_intf.sv",
hdl_src_dir / "apb3_intf.sv",
]
sources = get_verilog_sources(module_path, package_path, intf_files)
# Verify order: interfaces first, then package, then module
assert len(sources) == 4
assert str(intf_files[0]) in sources[0]
assert str(intf_files[1]) in sources[1]
assert str(package_path) in sources[2]
assert str(module_path) in sources[3]
def test_compile_rdl_and_export_with_custom_names(self):
"""Test code generation with custom module and package names."""
rdl_source = """
addrmap test_map {
reg { field { sw=rw; hw=r; } data[31:0]; } test_reg @ 0x0;
};
"""
with tempfile.TemporaryDirectory() as tmpdir:
module_path, package_path = compile_rdl_and_export(
rdl_source,
"test_map",
tmpdir,
APB4Cpuif,
module_name="custom_module",
package_name="custom_pkg",
)
# Verify custom names
assert module_path.name == "custom_module.sv"
assert package_path.name == "custom_pkg.sv"
# Verify content uses custom names
module_content = module_path.read_text()
assert "module custom_module" in module_content
package_content = package_path.read_text()
assert "package custom_pkg" in package_content
class TestMultipleCpuInterfaces:
"""Test that all CPU interfaces generate valid code."""
@pytest.mark.parametrize(
"cpuif_cls,intf_name",
[
(APB3Cpuif, "apb3_intf"),
(APB4Cpuif, "apb4_intf"),
(AXI4LiteCpuif, "axi4lite_intf"),
],
)
def test_cpuif_generation(self, cpuif_cls, intf_name):
"""Test code generation for each CPU interface type."""
rdl_source = """
addrmap test_block {
reg {
field { sw=rw; hw=r; } data[31:0];
} test_reg @ 0x0;
};
"""
with tempfile.TemporaryDirectory() as tmpdir:
module_path, package_path = compile_rdl_and_export(
rdl_source, "test_block", tmpdir, cpuif_cls
)
assert module_path.exists()
assert package_path.exists()
module_content = module_path.read_text()
assert "module test_block" in module_content
assert intf_name in module_content
if __name__ == "__main__":
pytest.main([__file__, "-v"])