Testing
PeakRDL-etana includes a comprehensive test suite built with Cocotb, validating register block functionality across multiple CPU interfaces and configurations.
Test Framework Overview
The test suite validates:
Basic register operations (read, write, reset values)
All SystemRDL field types and properties
Hardware interface signal behavior
CPU interface error responses (NEW in v0.23)
External registers and memories
Counter fields, interrupts, and side effects
Multiple CPU interfaces and configurations
Test Modes
Tests can run in three different modes:
Etana Mode (Default)
Tests the PeakRDL-etana generated RTL using Icarus Verilog:
cd tests/test_simple
make clean etana sim COCOTB_REV=1.9.2
Regblock Reference Mode
Tests against PeakRDL-regblock reference implementation using Verilator:
make clean regblock sim COCOTB_REV=1.9.2 REGBLOCK=1
This validates that etana produces functionally equivalent RTL to the upstream project.
VHDL Mode
Tests VHDL generation (select tests only):
make clean regblock-vhdl sim COCOTB_REV=1.9.2 GHDL=1
Key Test Cases
test_simple
Basic register operations and field types.
Validates:
Register read/write operations
Reset value initialization
Basic field properties (sw, hw access)
test_cpuif_err_rsp
CPU interface error response validation (NEW).
Validates:
Error responses for unmapped addresses (
--err-if-bad-addr)Error responses for forbidden reads/writes (
--err-if-bad-rw)Read-only register write protection
Write-only register read protection
External register/memory error handling
Register Map:
0x00: r_rw - Read/Write register (internal)
0x04: r_r - Read-only register (internal)
0x08: r_w - Write-only register (internal)
0x0C: er_rw - External R/W register
0x10: er_r - External read-only register
0x14: er_w - External write-only register
0x18: <unmapped> - Generates error response
0x20: mem_rw - External R/W memory
0x28: mem_r - External read-only memory
0x30: mem_w - External write-only memory
Supported CPU Interfaces:
APB4 (validates
pslverrsignal)AXI4-Lite (validates
rresp/brespsignals)AHB (validates
hrespsignal)OBI (validates
errsignal)Wishbone (validates
wb_errsignal)Passthrough (validates
rd_err/wr_errsignals)
Usage:
cd tests/test_cpuif_err_rsp
make clean etana sim COCOTB_REV=1.9.2 CPUIF=apb4-flat
test_external
External register and memory validation.
Validates:
External register protocol (req, ack, data)
Read and write operations to external components
External memory block access
Hardware interface signal timing
test_counter_basics
Counter field type validation.
Validates:
Increment and decrement counters
Overflow/underflow behavior
Counter reset and enable
test_field_types
Comprehensive field type coverage.
Validates:
All standard SystemRDL field types
Field properties (onread, onwrite, etc.)
Field access combinations
Running Tests
Run All Tests
Execute the complete test suite:
cd tests
./test_all.sh
This runs all tests with default settings (Icarus Verilog, Cocotb 1.9.2).
Run Specific Test
Navigate to a test directory and run:
cd tests/test_cpuif_err_rsp
make clean etana sim COCOTB_REV=1.9.2
CPU Interface Selection
Test with different CPU interfaces:
# APB4 (default)
make sim CPUIF=apb4-flat
# AXI4-Lite
make sim CPUIF=axi4-lite-flat
# AHB
make sim CPUIF=ahb-flat
# OBI
make sim CPUIF=obi-flat
# Wishbone
make sim CPUIF=wishbone-flat
# Passthrough
make sim CPUIF=passthrough
Generate Waveforms
Enable waveform generation for debugging:
# Icarus (generates .fst file)
make sim WAVES=1
# View waveforms
gtkwave sim_build/*.fst
Test Infrastructure
Base Testbench
All tests use tb_base.py which provides:
Auto-detection of CPU interface type
Clock and reset management
Unified interface abstraction
Common utility functions
Bus Wrappers
Located in tests/interfaces/:
apb_wrapper.py- APB4 bus functional modelaxi_wrapper.py- AXI4-Lite bus functional modelahb_wrapper.py- AHB bus functional modelwishbone_wrapper.py- Wishbone B4 bus functional modelpassthrough.py- Passthrough protocol driver
All wrappers support the error_expected parameter for error response validation.
External Emulators
Located in tests/test_cpuif_err_rsp/external_emulators.py:
SimpleExtRegEmulator- Read/write external registerSimpleExtRegReadOnly- Read-only external registerSimpleExtRegWriteOnly- Write-only external registerSimpleExtMemEmulator- Read/write external memorySimpleExtMemReadOnly- Read-only external memorySimpleExtMemWriteOnly- Write-only external memory
Features:
Auto-detection of field naming (regblock vs etana)
Bit-enable mask support
Single-cycle response latency
Compatible with all CPU interfaces
Writing Tests
Basic Test Pattern
from cocotb import test
from tb_base import testbench
@test()
async def test_my_feature(dut):
"""Test description"""
tb = testbench(dut)
# Write to register
await tb.intf.write(0x00, 0x1234)
# Read back and verify
await tb.intf.read(0x00, 0x1234)
await tb.clk.end_test()
Error Response Testing
@test()
async def test_errors(dut):
"""Test error responses"""
tb = testbench(dut)
# Expect error on unmapped address
await tb.intf.read(0xFF, 0, error_expected=True)
# Expect error on write to read-only register
await tb.intf.write(0x04, 0x5678, error_expected=True)
await tb.clk.end_test()
External Register Testing
from cocotb import test, start_soon
from tb_base import testbench
from external_emulators import SimpleExtRegEmulator
@test()
async def test_external(dut):
"""Test external register"""
tb = testbench(dut)
# Create and start emulator
ext_reg = SimpleExtRegEmulator(dut, tb.clk.clk, "hwif_out_my_reg")
start_soon(ext_reg.run())
# Set value in emulator
ext_reg.value = 0xABCD
await tb.clk.wait_clkn(2)
# Read from CPU interface
await tb.intf.read(0x10, 0xABCD)
await tb.clk.end_test()
Test Directory Structure
Each test follows this structure:
tests/test_<name>/
├── Makefile # Includes ../tests.mak
├── regblock.rdl # Register definition (copied from upstream)
├── test_dut.py # Cocotb test implementation
└── external_emulators.py # (Optional) External component emulators
Continuous Integration
GitHub Actions workflows validate all tests across:
Python versions: 3.8, 3.9, 3.10, 3.11, 3.12, 3.13
Simulators: Icarus Verilog, Verilator
Cocotb version: 1.9.2
Test modes: Etana, Regblock reference
Workflows run on:
Every push to branches
Every pull request
Weekly schedule (Sunday 1:00 AM)
Test workflows skip on tag pushes to avoid redundant runs during releases.
Troubleshooting
Common Issues
ModuleNotFoundError: No module named ‘cocotb’
Activate the virtual environment:
source ../venv.2.0.0/bin/activate
Signal Name Mismatch
Regblock and etana have different field naming conventions:
Regblock: Includes field suffix (e.g.,
hwif_out_reg_wr_data_f)Etana: No field suffix (e.g.,
hwif_out_reg_wr_data)
The external emulators auto-detect this difference.
Cocotb 2.0.0 + AXI4-Lite Compatibility
Use Cocotb 1.9.2 for AXI4-Lite testing:
make sim COCOTB_REV=1.9.2
Further Documentation
For detailed test suite documentation, see tests/TEST_SUITE_README.md in the repository.
For test migration guidelines, see cursor_help/COCOTB_MIGRATION_GUIDE.md.