|
CocoTB Framework · Verification Infrastructure for RTL Testing GitHub · Documentation Index · MIT License |
axi4_scoreboard.py¶
AXI4 protocol scoreboard implementation for verifying AXI4 transactions with ID-based tracking, channel separation, and protocol compliance checking. This module provides comprehensive verification for complex AXI4 systems with multiple outstanding transactions.
Overview¶
The AXI4 scoreboard system provides: - ID-based Transaction Tracking: Separate transaction queues per AXI4 ID - Channel Separation: Independent handling of read and write channels - Master/Slave Monitoring: Dual-side transaction verification - Protocol Compliance: Built-in AXI4 protocol violation detection - Performance Analysis: Transaction timing and throughput metrics
Classes¶
AXI4Scoreboard¶
Advanced AXI4 transaction verification with full protocol support.
class AXI4Scoreboard(BaseScoreboard):
def __init__(self, name, id_width=8, addr_width=32, data_width=32, user_width=1, log=None)
Parameters:
- name: Scoreboard name for identification
- id_width: Width of ID fields in bits (default: 8)
- addr_width: Width of address fields in bits (default: 32)
- data_width: Width of data fields in bits (default: 32)
- user_width: Width of user fields in bits (default: 1)
- log: Logger instance for detailed reporting
Key Attributes:
- write_count: Number of write transactions processed
- read_count: Number of read transactions processed
- protocol_error_count: Number of protocol violations detected
- master_writes: Dictionary mapping IDs to master-side write transactions
- slave_writes: Dictionary mapping IDs to slave-side write transactions
- master_reads: Dictionary mapping IDs to master-side read transactions
- slave_reads: Dictionary mapping IDs to slave-side read transactions
Monitor Integration¶
Master Monitor Connection¶
add_master_monitor(monitor)¶
Connect master-side AXI4 monitor to scoreboard.
Parameters:
- monitor: AXI4 monitor instance observing master interface
Behavior:
- Registers write callback: _handle_master_write
- Registers read callback: _handle_master_read
- Enables automatic transaction capture from master side
# Connect master monitor
axi4_scoreboard.add_master_monitor(master_monitor)
# Monitor automatically feeds transactions to scoreboard
Slave Monitor Connection¶
add_slave_monitor(monitor)¶
Connect slave-side AXI4 monitor to scoreboard.
Parameters:
- monitor: AXI4 monitor instance observing slave interface
Behavior:
- Registers write callback: _handle_slave_write
- Registers read callback: _handle_slave_read
- Enables automatic transaction capture from slave side
# Connect slave monitor
axi4_scoreboard.add_slave_monitor(slave_monitor)
# Complete master-slave verification setup
Transaction Processing¶
Write Transaction Handling¶
_handle_master_write(id_value, transaction)¶
Process completed write transaction from master side.
Parameters:
- id_value: AXI4 ID of the transaction
- transaction: Completed write transaction
Behavior:
- Stores transaction in master_writes[id_value]
- Checks for matching slave-side transaction
- Triggers comparison if both sides available
- Updates write transaction counters
_handle_slave_write(id_value, transaction)¶
Process completed write transaction from slave side.
Parameters:
- id_value: AXI4 ID of the transaction
- transaction: Completed write transaction
Behavior:
- Stores transaction in slave_writes[id_value]
- Checks for matching master-side transaction
- Triggers comparison if both sides available
- Validates write response compliance
Read Transaction Handling¶
_handle_master_read(id_value, transaction)¶
Process completed read transaction from master side.
Parameters:
- id_value: AXI4 ID of the transaction
- transaction: Completed read transaction
Behavior:
- Stores transaction in master_reads[id_value]
- Checks for matching slave-side transaction
- Triggers comparison if both sides available
- Updates read transaction counters
_handle_slave_read(id_value, transaction)¶
Process completed read transaction from slave side.
Parameters:
- id_value: AXI4 ID of the transaction
- transaction: Completed read transaction
Behavior:
- Stores transaction in slave_reads[id_value]
- Checks for matching master-side transaction
- Triggers comparison if both sides available
- Validates read data and response codes
Transaction Verification¶
Write Transaction Matching¶
_check_write_match(id_value, master_transaction, slave_transaction)¶
Compare master and slave write transactions for specific ID.
Parameters:
- id_value: Transaction ID
- master_transaction: Master-side write transaction
- slave_transaction: Slave-side write transaction
Verification Checks: - Address field consistency - Data payload matching - Write strobe validation - Burst parameters compliance - Response code verification
# Example write verification
# Master: AWADDR=0x1000, WDATA=[0xDEADBEEF, 0x12345678], WSTRB=[0xF, 0xF]
# Slave: AWADDR=0x1000, WDATA=[0xDEADBEEF, 0x12345678], BRESP=OKAY
# Result: MATCH - addresses align, data matches, response is OKAY
Read Transaction Matching¶
_check_read_match(id_value, master_transaction, slave_transaction)¶
Compare master and slave read transactions for specific ID.
Parameters:
- id_value: Transaction ID
- master_transaction: Master-side read transaction
- slave_transaction: Slave-side read transaction
Verification Checks: - Address field consistency - Burst length matching - Read data validation - Response code checking - Timing constraint compliance
# Example read verification
# Master: ARADDR=0x2000, ARLEN=3, ARID=5
# Slave: ARADDR=0x2000, RDATA=[0x11, 0x22, 0x33, 0x44], RID=5, RRESP=OKAY
# Result: MATCH - address correct, data length matches, ID preserved
Protocol Compliance Checking¶
Built-in Validation¶
The AXI4 scoreboard automatically checks for: - ID Consistency: Transaction IDs match between request and response - Burst Alignment: Address alignment matches burst size requirements - Response Codes: Valid RESP field values (OKAY, EXOKAY, SLVERR, DECERR) - Outstanding Limits: Configurable limits on outstanding transactions per ID - Ordering Requirements: AXI4 ordering model compliance
Protocol Error Detection¶
# Protocol errors automatically logged:
# - Mismatched transaction IDs
# - Invalid burst parameters
# - Out-of-order responses
# - Response timeout violations
# - Invalid response codes
if axi4_scoreboard.protocol_error_count > 0:
print(f"Protocol violations detected: {axi4_scoreboard.protocol_error_count}")
Performance Analysis¶
Transaction Statistics¶
The scoreboard automatically tracks: - Transaction Counts: Read and write transaction totals - ID Utilization: Distribution of transactions across ID space - Channel Efficiency: Bandwidth utilization analysis - Latency Metrics: Average response times per transaction type
Performance Reporting¶
# Access performance statistics
stats = {
'total_transactions': axi4_scoreboard.transaction_count,
'write_transactions': axi4_scoreboard.write_count,
'read_transactions': axi4_scoreboard.read_count,
'protocol_errors': axi4_scoreboard.protocol_error_count,
'id_utilization': len(axi4_scoreboard.master_writes) + len(axi4_scoreboard.master_reads)
}
print(f"AXI4 Performance: {stats['total_transactions']} transactions")
print(f"Read/Write Ratio: {stats['read_transactions']}/{stats['write_transactions']}")
print(f"Protocol Compliance: {stats['protocol_errors']} violations")
Usage Examples¶
Basic AXI4 Verification Setup¶
from CocoTBFramework.scoreboards.axi4_scoreboard import AXI4Scoreboard
from CocoTBFramework.components.axi4.axi4_monitor import AXI4Monitor
# Create scoreboard for 64-bit AXI4 with 4-bit IDs
scoreboard = AXI4Scoreboard(
name="AXI4_Memory",
id_width=4,
addr_width=64,
data_width=64,
user_width=4,
log=logger
)
# Create and connect monitors
master_monitor = AXI4Monitor(dut.master_axi, "Master", clock)
slave_monitor = AXI4Monitor(dut.slave_axi, "Slave", clock)
scoreboard.add_master_monitor(master_monitor)
scoreboard.add_slave_monitor(slave_monitor)
# Scoreboard automatically captures and verifies transactions
await Timer(1000, units='ns') # Run test
# Generate verification report
error_count = scoreboard.report()
success_rate = scoreboard.result()
print(f"AXI4 Verification: {'PASS' if error_count == 0 else 'FAIL'} ({success_rate:.2%})")
Advanced Multi-ID Verification¶
# Test with multiple outstanding transactions
async def test_multi_id_axi4():
# Configure for high-performance testing
scoreboard = AXI4Scoreboard(
name="HighPerf_AXI4",
id_width=8, # 256 possible IDs
addr_width=32,
data_width=128, # Wide data bus
log=logger
)
# Connect monitors
scoreboard.add_master_monitor(master_monitor)
scoreboard.add_slave_monitor(slave_monitor)
# Generate transactions with different IDs
master = AXI4Master(dut.master_axi, clock)
# Launch multiple concurrent transactions
for i in range(16):
write_transaction = master.create_write_transaction(
addr=0x10000 + (i * 0x1000),
data=[0xDEADBEEF + i],
id=i,
burst_len=4
)
await master.send_write(write_transaction)
# Wait for completion and verify
await Timer(5000, units='ns')
# Analyze results by ID
print(f"Write transactions: {scoreboard.write_count}")
print(f"Active IDs: {len(scoreboard.master_writes)}")
print(f"Protocol errors: {scoreboard.protocol_error_count}")
Memory System Verification¶
# Verify AXI4 memory controller
async def test_memory_controller():
scoreboard = AXI4Scoreboard("MemCtrl", log=logger)
# Connect to memory controller interfaces
cpu_monitor = AXI4Monitor(dut.cpu_axi, "CPU", clock)
ddr_monitor = AXI4Monitor(dut.ddr_axi, "DDR", clock)
scoreboard.add_master_monitor(cpu_monitor)
scoreboard.add_slave_monitor(ddr_monitor)
# Generate realistic memory access patterns
cpu_master = AXI4Master(dut.cpu_axi, clock)
# Test different access patterns
patterns = [
# Sequential reads
[(0x0000 + i*8, 'READ') for i in range(64)],
# Random writes
[(random.randint(0x1000, 0x2000) & ~7, 'WRITE') for _ in range(32)],
# Burst transfers
[(0x3000 + i*64, 'BURST_READ', 8) for i in range(8)]
]
for pattern in patterns:
for access in pattern:
if access[1] == 'READ':
await cpu_master.read(access[0], id=random.randint(0, 15))
elif access[1] == 'WRITE':
await cpu_master.write(access[0], random.randint(0, 0xFFFFFFFF), id=random.randint(0, 15))
elif access[1] == 'BURST_READ':
await cpu_master.burst_read(access[0], access[2], id=random.randint(0, 15))
# Check intermediate results
if scoreboard.protocol_error_count > 0:
print(f"Protocol errors after pattern: {scoreboard.protocol_error_count}")
break
# Final verification
final_errors = scoreboard.report()
print(f"Memory controller verification: {final_errors} errors")
Cross-Clock Domain Verification¶
# Verify AXI4 clock domain crossing
async def test_clock_domain_crossing():
# Separate scoreboards for each clock domain
fast_scoreboard = AXI4Scoreboard("FastDomain", log=logger)
slow_scoreboard = AXI4Scoreboard("SlowDomain", log=logger)
# Connect monitors on both sides of CDC
fast_monitor = AXI4Monitor(dut.fast_axi, "Fast", fast_clock)
slow_monitor = AXI4Monitor(dut.slow_axi, "Slow", slow_clock)
fast_scoreboard.add_master_monitor(fast_monitor)
slow_scoreboard.add_slave_monitor(slow_monitor)
# Create cross-domain transaction tracker
class CDCTracker:
def __init__(self):
self.fast_transactions = {}
self.slow_transactions = {}
def on_fast_transaction(self, id_val, transaction):
self.fast_transactions[id_val] = transaction
self.check_matching()
def on_slow_transaction(self, id_val, transaction):
self.slow_transactions[id_val] = transaction
self.check_matching()
def check_matching(self):
# Verify transactions cross domains correctly
for id_val in self.fast_transactions:
if id_val in self.slow_transactions:
fast_tx = self.fast_transactions[id_val]
slow_tx = self.slow_transactions[id_val]
# Compare transactions accounting for CDC latency
if not self.compare_cdc_transactions(fast_tx, slow_tx):
print(f"CDC mismatch for ID {id_val}")
tracker = CDCTracker()
# Connect tracker to monitors
fast_monitor.add_callback(tracker.on_fast_transaction)
slow_monitor.add_callback(tracker.on_slow_transaction)
# Run test with clock domain crossing
await Timer(10000, units='ns')
Best Practices¶
Monitor Configuration¶
- Connect both master and slave monitors for complete verification
- Use appropriate ID width for system requirements
- Configure timeout values for protocol compliance checking
Performance Optimization¶
- Clear completed transactions periodically in long tests
- Monitor memory usage with high transaction volumes
- Use ID-based filtering for targeted verification
Error Analysis¶
- Enable detailed logging for protocol violation analysis
- Use transaction timestamps for timing analysis
- Preserve failed transaction pairs for debugging
Integration Guidelines¶
- Connect monitors before starting transaction generation
- Use scoreboard statistics for test coverage analysis
- Implement custom callbacks for specialized verification
Integration Points¶
Test Environment Integration¶
# Integration with test sequence
class AXI4TestEnvironment:
def __init__(self, dut, clock):
self.scoreboard = AXI4Scoreboard("TestEnv", log=logger)
self.master_monitor = AXI4Monitor(dut.master, "Master", clock)
self.slave_monitor = AXI4Monitor(dut.slave, "Slave", clock)
self.scoreboard.add_master_monitor(self.master_monitor)
self.scoreboard.add_slave_monitor(self.slave_monitor)
def run_verification(self):
return self.scoreboard.report()
Coverage Integration¶
# Functional coverage with scoreboard
def calculate_id_coverage():
used_ids = set(scoreboard.master_writes.keys()) | set(scoreboard.master_reads.keys())
total_ids = 2 ** scoreboard.id_width
coverage = len(used_ids) / total_ids * 100
print(f"ID Coverage: {coverage:.1f}% ({len(used_ids)}/{total_ids})")
The AXI4 scoreboard provides comprehensive verification for complex AXI4 systems with robust protocol compliance checking, performance analysis, and multi-ID transaction tracking capabilities.