* 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>
222 lines
6.3 KiB
Python
222 lines
6.3 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Example script showing how to generate and test bus decoders.
|
|
|
|
This script demonstrates:
|
|
1. Compiling RDL specifications
|
|
2. Generating SystemVerilog decoders for different CPU interfaces
|
|
3. Validating the generated code (syntax check only, no simulation)
|
|
|
|
To run actual cocotb simulations, you need:
|
|
- Icarus Verilog, Verilator, or other HDL simulator
|
|
- cocotb and cocotb-bus Python packages
|
|
"""
|
|
|
|
import sys
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
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
|
|
|
|
|
|
def example_apb4_simple_register():
|
|
"""Generate APB4 decoder for a simple register."""
|
|
print("\n" + "=" * 70)
|
|
print("Example 1: APB4 Decoder with Simple Register")
|
|
print("=" * 70)
|
|
|
|
rdl_source = """
|
|
addrmap simple_test {
|
|
name = "Simple Register Test";
|
|
desc = "A simple register for testing";
|
|
|
|
reg {
|
|
name = "Test Register";
|
|
desc = "32-bit test register";
|
|
|
|
field {
|
|
sw=rw;
|
|
hw=r;
|
|
desc = "Data field";
|
|
} data[31:0];
|
|
} test_reg @ 0x0;
|
|
};
|
|
"""
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
print(f"\nGenerating SystemVerilog in: {tmpdir}")
|
|
module_path, package_path = compile_rdl_and_export(
|
|
rdl_source, "simple_test", tmpdir, APB4Cpuif
|
|
)
|
|
|
|
print(f"✓ Generated module: {module_path.name}")
|
|
print(f"✓ Generated package: {package_path.name}")
|
|
|
|
# Show snippet of generated code
|
|
with open(module_path) as f:
|
|
lines = f.readlines()[:20]
|
|
print("\n--- Generated Module (first 20 lines) ---")
|
|
for line in lines:
|
|
print(line, end="")
|
|
|
|
|
|
def example_apb3_multiple_registers():
|
|
"""Generate APB3 decoder for multiple registers."""
|
|
print("\n" + "=" * 70)
|
|
print("Example 2: APB3 Decoder with Multiple Registers")
|
|
print("=" * 70)
|
|
|
|
rdl_source = """
|
|
addrmap multi_reg {
|
|
name = "Multiple Register Block";
|
|
|
|
reg {
|
|
name = "Control Register";
|
|
field { sw=rw; hw=r; } data[31:0];
|
|
} ctrl @ 0x0;
|
|
|
|
reg {
|
|
name = "Status Register";
|
|
field { sw=r; hw=w; } status[15:0];
|
|
} status @ 0x4;
|
|
|
|
reg {
|
|
name = "Data Register";
|
|
field { sw=rw; hw=r; } data[31:0];
|
|
} data @ 0x8;
|
|
};
|
|
"""
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
print(f"\nGenerating SystemVerilog in: {tmpdir}")
|
|
module_path, package_path = compile_rdl_and_export(
|
|
rdl_source, "multi_reg", tmpdir, APB3Cpuif
|
|
)
|
|
|
|
print(f"✓ Generated module: {module_path.name}")
|
|
print(f"✓ Generated package: {package_path.name}")
|
|
|
|
# Count registers in generated code
|
|
with open(module_path) as f:
|
|
content = f.read()
|
|
print(f"\n✓ Found 'ctrl' in generated code: {'ctrl' in content}")
|
|
print(f"✓ Found 'status' in generated code: {'status' in content}")
|
|
print(f"✓ Found 'data' in generated code: {'data' in content}")
|
|
|
|
|
|
def example_axi4lite_nested_addrmap():
|
|
"""Generate AXI4-Lite decoder for nested address map."""
|
|
print("\n" + "=" * 70)
|
|
print("Example 3: AXI4-Lite Decoder with Nested Address Map")
|
|
print("=" * 70)
|
|
|
|
rdl_source = """
|
|
addrmap inner_block {
|
|
name = "Inner Block";
|
|
reg {
|
|
field { sw=rw; hw=r; } data[31:0];
|
|
} inner_reg @ 0x0;
|
|
};
|
|
|
|
addrmap outer_block {
|
|
name = "Outer Block";
|
|
inner_block inner @ 0x0;
|
|
|
|
reg {
|
|
field { sw=rw; hw=r; } outer_data[31:0];
|
|
} outer_reg @ 0x100;
|
|
};
|
|
"""
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
print(f"\nGenerating SystemVerilog in: {tmpdir}")
|
|
module_path, package_path = compile_rdl_and_export(
|
|
rdl_source, "outer_block", tmpdir, AXI4LiteCpuif
|
|
)
|
|
|
|
print(f"✓ Generated module: {module_path.name}")
|
|
print(f"✓ Generated package: {package_path.name}")
|
|
|
|
# Check for nested structure
|
|
with open(module_path) as f:
|
|
content = f.read()
|
|
print(f"\n✓ Found 'inner' in generated code: {'inner' in content}")
|
|
print(f"✓ Found 'outer_reg' in generated code: {'outer_reg' in content}")
|
|
|
|
|
|
def example_register_array():
|
|
"""Generate decoder with register arrays."""
|
|
print("\n" + "=" * 70)
|
|
print("Example 4: Decoder with Register Arrays")
|
|
print("=" * 70)
|
|
|
|
rdl_source = """
|
|
addrmap array_test {
|
|
name = "Register Array Test";
|
|
|
|
reg {
|
|
field { sw=rw; hw=r; } data[31:0];
|
|
} regs[8] @ 0x0 += 0x4;
|
|
};
|
|
"""
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
print(f"\nGenerating SystemVerilog in: {tmpdir}")
|
|
module_path, package_path = compile_rdl_and_export(
|
|
rdl_source, "array_test", tmpdir, APB4Cpuif
|
|
)
|
|
|
|
print(f"✓ Generated module: {module_path.name}")
|
|
print(f"✓ Generated package: {package_path.name}")
|
|
|
|
with open(module_path) as f:
|
|
content = f.read()
|
|
print(f"\n✓ Found 'regs' in generated code: {'regs' in content}")
|
|
|
|
|
|
def main():
|
|
"""Run all examples."""
|
|
print("\n")
|
|
print("*" * 70)
|
|
print("*" + " " * 68 + "*")
|
|
print("*" + " PeakRDL-BusDecoder: Code Generation Examples".center(68) + "*")
|
|
print("*" + " " * 68 + "*")
|
|
print("*" * 70)
|
|
|
|
try:
|
|
example_apb4_simple_register()
|
|
example_apb3_multiple_registers()
|
|
example_axi4lite_nested_addrmap()
|
|
example_register_array()
|
|
|
|
print("\n" + "=" * 70)
|
|
print("All examples completed successfully!")
|
|
print("=" * 70)
|
|
print(
|
|
"""
|
|
To run actual simulations with cocotb:
|
|
1. Install simulator: apt-get install iverilog (or verilator)
|
|
2. Install cocotb: pip install cocotb cocotb-bus
|
|
3. Run tests: pytest tests/cocotb/testbenches/
|
|
|
|
For more information, see: tests/cocotb/README.md
|
|
"""
|
|
)
|
|
|
|
except Exception as e:
|
|
print(f"\n✗ Error: {e}")
|
|
import traceback
|
|
|
|
traceback.print_exc()
|
|
return 1
|
|
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|