Skip to content
RTL Design Sherpa CocoTB Framework · Verification Infrastructure for RTL Testing
GitHub · Documentation Index · MIT License

gaxi_factories.py

Updated GAXI factories with fixed parameter handling to match TB instantiation patterns. This module provides simplified factory functions for creating GAXI components with proper defaults and consistent parameter handling across all factory methods.

Overview

The gaxi_factories.py module provides factory functions for creating GAXI components (Master, Slave, Monitor, Scoreboard) with simplified configuration and proper parameter defaults. All existing APIs are preserved and parameters are passed through exactly as before, with enhanced defaults for signal prefixes and naming.

Key Features

  • Simplified component creation with sensible defaults
  • Consistent parameter handling across all factories
  • Backward compatibility - all existing parameters preserved
  • Enhanced defaults for signal prefixes (empty strings work for most cases)
  • Memory model integration using base MemoryModel directly
  • Complete system creation with factory methods for full environments

Field Configuration

get_default_field_config(data_width=32)

Get standard field configuration for GAXI protocol.

Parameters: - data_width: Data width in bits (default: 32)

Returns: FieldConfig object for standard data field

# Get default 32-bit data configuration
config = get_default_field_config()

# Get 64-bit data configuration
config_64 = get_default_field_config(data_width=64)

Component Factories

create_gaxi_master()

Create a GAXI Master component with simplified configuration.

create_gaxi_master(dut, title, prefix, clock, field_config=None, packet_class=None,
                   randomizer=None, memory_model=None, memory_fields=None, log=None,
                   signal_map=None, optional_signal_map=None, field_mode=False,
                   multi_sig=False, mode='skid', bus_name='', pkt_prefix='',

Parameters: - dut: Device under test - title: Component title - prefix: Signal prefix - clock: Clock signal - field_config: Field configuration (default: standard data field) - packet_class: Packet class to use - randomizer: Timing randomizer (default: standard master constraints) - memory_model: Memory model for transactions (optional) - memory_fields: Field mapping for memory operations (unused - kept for compatibility) - log: Logger instance (default: dut's logger) - signal_map: Signal mapping (unused - kept for compatibility) - optional_signal_map: Optional signal mapping (unused - kept for compatibility) - field_mode: Field mode (unused - kept for compatibility) - multi_sig: Whether using multi-signal mode - mode: Operating mode ('skid', 'fifo_mux', 'fifo_flop') - bus_name: Bus/channel name - pkt_prefix: Packet field prefix - **kwargs: Additional arguments

Returns: GAXIMaster instance

# Basic master creation
master = create_gaxi_master(
    dut=dut,
    title="TestMaster",
    prefix="master_",
    clock=dut.clk
)

# Advanced master with custom configuration
master = create_gaxi_master(
    dut=dut,
    title="AdvancedMaster",
    prefix="",
    clock=dut.clk,
    field_config=custom_field_config,
    memory_model=shared_memory,
    multi_sig=True,
    mode='fifo_flop',
    log=custom_logger
)

create_gaxi_slave()

Create a GAXI Slave component with simplified configuration.

create_gaxi_slave(dut, title, prefix, clock, field_config=None, field_mode=False,
                  packet_class=None, randomizer=None, memory_model=None,
                  memory_fields=None, log=None, mode='skid', signal_map=None,
                  optional_signal_map=None, multi_sig=False, bus_name='',

Parameters: Same as create_gaxi_master() with slave-specific defaults

Returns: GAXISlave instance

# Basic slave creation
slave = create_gaxi_slave(
    dut=dut,
    title="TestSlave",
    prefix="slave_",
    clock=dut.clk
)

# Slave with shared memory model
slave = create_gaxi_slave(
    dut=dut,
    title="MemorySlave",
    prefix="",
    clock=dut.clk,
    memory_model=shared_memory,
    mode='skid'
)

create_gaxi_monitor()

Create a GAXI Monitor component with simplified configuration.

create_gaxi_monitor(dut, title, prefix, clock, field_config=None, is_slave=False,
                    log=None, mode='skid', multi_sig=False, bus_name='',

Parameters: - dut: Device under test - title: Component title - prefix: Signal prefix - clock: Clock signal - field_config: Field configuration (default: standard data field) - is_slave: If True, monitor slave side; if False, monitor master side - log: Logger instance (default: dut's logger) - mode: Operating mode ('skid', 'fifo_mux', 'fifo_flop') - multi_sig: Whether using multi-signal mode - bus_name: Bus/channel name - pkt_prefix: Packet field prefix - **kwargs: Additional arguments

Returns: GAXIMonitor instance

# Master-side monitor
master_monitor = create_gaxi_monitor(
    dut=dut,
    title="MasterMonitor",
    prefix="",
    clock=dut.clk,
    is_slave=False
)

# Slave-side monitor
slave_monitor = create_gaxi_monitor(
    dut=dut,
    title="SlaveMonitor",
    prefix="",
    clock=dut.clk,
    is_slave=True,
    mode='fifo_flop'
)

create_gaxi_scoreboard()

Create a GAXI Scoreboard with simplified configuration.

create_gaxi_scoreboard(name, field_config=None, log=None)

Parameters: - name: Scoreboard name - field_config: Field configuration (default: standard data field) - log: Logger instance

Returns: GAXIScoreboard instance

# Basic scoreboard
scoreboard = create_gaxi_scoreboard("TestScoreboard")

# Scoreboard with custom configuration
scoreboard = create_gaxi_scoreboard(
    name="CustomScoreboard",
    field_config=custom_field_config,
    log=custom_logger
)

System Creation Factories

create_gaxi_components()

Create a complete set of GAXI components (master, slave, monitors, scoreboard).

create_gaxi_components(dut, clock, title_prefix="", field_config=None,
                       field_mode=False, packet_class=None, memory_model=None,
                       log=None, mode='skid', signal_map=None, optional_signal_map=None,
                       multi_sig=False, bus_name='', pkt_prefix='',

Parameters: - dut: Device under test - clock: Clock signal - title_prefix: Prefix for component titles - field_config: Field configuration (default: standard data field) - field_mode: Field mode (unused - kept for compatibility) - packet_class: Packet class to use - memory_model: Memory model for components (auto-created if None) - log: Logger instance - mode: Operating mode for slave/monitor - signal_map: Signal mapping (unused - kept for compatibility) - optional_signal_map: Optional signal mapping (unused - kept for compatibility) - multi_sig: Whether using multi-signal mode - bus_name: Bus/channel name - pkt_prefix: Packet field prefix - **kwargs: Additional configuration passed to all components

Returns: Dictionary containing all created components

# Create complete GAXI system
components = create_gaxi_components(
    dut=dut,
    clock=dut.clk,
    title_prefix="GAXI_"
)

# Access components
master = components['master']
slave = components['slave']
master_monitor = components['master_monitor']
slave_monitor = components['slave_monitor']
scoreboard = components['scoreboard']
memory_model = components['memory_model']

create_gaxi_system()

Create a complete GAXI system with all components - alias for create_gaxi_components().

create_gaxi_system(dut, clock, title_prefix="", field_config=None,
                   memory_model=None, log=None, bus_name='', pkt_prefix='',

Parameters: Simplified version of create_gaxi_components() parameters

Returns: Dictionary containing all created components and shared resources

# Create GAXI system with clean API
system = create_gaxi_system(
    dut=dut,
    clock=dut.clk,
    title_prefix="System_",
    field_config=custom_config
)

create_gaxi_test_environment()

Create a complete GAXI test environment ready for immediate use.

create_gaxi_test_environment(dut, clock, bus_name='', pkt_prefix='',

Parameters: - dut: Device under test - clock: Clock signal - bus_name: Bus/channel name - pkt_prefix: Packet field prefix - **kwargs: Configuration overrides including: - title_prefix: Component title prefix (default: 'GAXI_') - field_config: Field configuration - data_width: Data width (default: 32) - memory_size: Memory size in lines (default: 1024) - log: Logger instance

Returns: Dictionary with complete test environment including convenience functions

# Create ready-to-use test environment
env = create_gaxi_test_environment(
    dut=dut,
    clock=dut.clk,
    data_width=64,
    memory_size=2048
)

# Use convenience functions
await env['send_data'](0xDEADBEEF)
data = env['read_memory'](0x1000)
env['write_memory'](0x1000, 0x12345678)
all_stats = env['get_all_stats']()

Usage Patterns

Basic Component Creation

@cocotb.test()
async def test_basic_gaxi(dut):
    """Basic GAXI test with factory-created components"""

    # Create individual components
    master = create_gaxi_master(
        dut=dut,
        title="TestMaster",
        prefix="",
        clock=dut.clk
    )

    slave = create_gaxi_slave(
        dut=dut,
        title="TestSlave", 
        prefix="",
        clock=dut.clk
    )

    # Test basic functionality
    await master.reset_bus()
    await slave.reset_bus()

    # Send test transaction
    packet = master.create_packet(data=0xDEADBEEF)
    await master.send(packet)

    # Verify reception
    await Timer(100, units='ns')
    received = slave.get_observed_packets()
    assert len(received) > 0

Complete System Creation

@cocotb.test()
async def test_complete_system(dut):
    """Test with complete GAXI system"""

    # Create complete system
    system = create_gaxi_system(
        dut=dut,
        clock=dut.clk,
        title_prefix="Test_",
        data_width=32,
        memory_size=1024
    )

    # Extract components
    master = system['master']
    slave = system['slave']
    master_monitor = system['master_monitor']
    slave_monitor = system['slave_monitor']
    scoreboard = system['scoreboard']
    memory = system['memory_model']

    # Connect monitors to scoreboard
    master_monitor.add_callback(scoreboard.master_transaction)
    slave_monitor.add_callback(scoreboard.slave_transaction)

    # Run test sequence
    await run_test_sequence(master, slave)

    # Check results
    stats = {
        'master': master.get_stats(),
        'slave': slave.get_stats(),
        'master_monitor': master_monitor.get_stats(),
        'slave_monitor': slave_monitor.get_stats(),
        'memory': memory.get_stats()
    }

    log.info(f"Test completed: {stats}")

Test Environment Creation

@cocotb.test()
async def test_with_environment(dut):
    """Test using complete test environment"""

    # Create test environment with convenience functions
    env = create_gaxi_test_environment(
        dut=dut,
        clock=dut.clk,
        title_prefix="ENV_",
        data_width=64,
        memory_size=2048
    )

    # Use convenience functions for testing
    test_data = [0xDEADBEEF, 0xCAFEBABE, 0x12345678, 0x87654321]

    for i, data in enumerate(test_data):
        # Send data using convenience function
        await env['send_data'](data)

        # Write to memory using convenience function
        env['write_memory'](0x1000 + i*4, data)

    # Read back and verify
    for i, expected_data in enumerate(test_data):
        addr = 0x1000 + i*4
        read_data = env['read_memory'](addr)

        # Convert bytearray to integer for comparison
        if isinstance(read_data, bytearray):
            read_value = int.from_bytes(read_data, byteorder='little')
        else:
            read_value = read_data

        assert read_value == expected_data, f"Memory mismatch at 0x{addr:X}"

    # Get comprehensive statistics
    all_stats = env['get_all_stats']()
    log.info(f"Environment test completed: {all_stats}")

Advanced Configuration

async def create_advanced_gaxi_system(dut, clock):
    """Create advanced GAXI system with custom configuration"""

    # Create custom field configuration
    field_config = FieldConfig()
    field_config.add_field(FieldDefinition("addr", 32, format="hex"))
    field_config.add_field(FieldDefinition("data", 64, format="hex"))
    field_config.add_field(FieldDefinition("cmd", 4, format="hex", encoding={
        0x0: "NOP", 0x1: "READ", 0x2: "WRITE", 0x3: "BURST"
    }))

    # Create shared memory model
    memory = MemoryModel(
        num_lines=4096,
        bytes_per_line=8,  # 64-bit data
        log=dut._log
    )

    # Create components with advanced configuration
    master = create_gaxi_master(
        dut=dut,
        title="AdvancedMaster",
        prefix="m_",
        clock=clock,
        field_config=field_config,
        memory_model=memory,
        multi_sig=True,
        mode='fifo_flop',
    )

    slave = create_gaxi_slave(
        dut=dut,
        title="AdvancedSlave",
        prefix="s_",
        clock=clock,
        field_config=field_config,
        memory_model=memory,
        multi_sig=True,
        mode='fifo_flop',
    )

    # Create monitors for both sides
    master_monitor = create_gaxi_monitor(
        dut=dut,
        title="MasterSideMonitor",
        prefix="m_",
        clock=clock,
        field_config=field_config,
        is_slave=False,
        multi_sig=True
    )

    slave_monitor = create_gaxi_monitor(
        dut=dut,
        title="SlaveSideMonitor",
        prefix="s_",
        clock=clock,
        field_config=field_config,
        is_slave=True,
        multi_sig=True,
        mode='fifo_flop'
    )

    # Create scoreboard
    scoreboard = create_gaxi_scoreboard(
        name="AdvancedScoreboard",
        field_config=field_config,
        log=dut._log
    )

    return {
        'master': master,
        'slave': slave,
        'master_monitor': master_monitor,
        'slave_monitor': slave_monitor,
        'scoreboard': scoreboard,
        'memory_model': memory,
        'field_config': field_config
    }

Multi-Instance Systems

async def create_multi_master_system(dut, clock):
    """Create system with multiple masters and one slave"""

    # Shared resources
    shared_memory = MemoryModel(num_lines=2048, bytes_per_line=4)
    shared_config = get_default_field_config(data_width=32)

    # Create multiple masters
    masters = {}
    for i in range(4):
        masters[f'master_{i}'] = create_gaxi_master(
            dut=dut,
            title=f"Master{i}",
            prefix=f"m{i}_",
            clock=clock,
            field_config=shared_config,
            memory_model=shared_memory
        )

    # Create single slave
    slave = create_gaxi_slave(
        dut=dut,
        title="SharedSlave",
        prefix="s_",
        clock=clock,
        field_config=shared_config,
        memory_model=shared_memory
    )

    # Create monitors for each master
    monitors = {}
    for i in range(4):
        monitors[f'master_{i}_monitor'] = create_gaxi_monitor(
            dut=dut,
            title=f"Master{i}Monitor",
            prefix=f"m{i}_",
            clock=clock,
            field_config=shared_config,
            is_slave=False
        )

    # Slave monitor
    monitors['slave_monitor'] = create_gaxi_monitor(
        dut=dut,
        title="SlaveMonitor",
        prefix="s_",
        clock=clock,
        field_config=shared_config,
        is_slave=True
    )

    # Scoreboard for transaction checking
    scoreboard = create_gaxi_scoreboard(
        name="MultiMasterScoreboard",
        field_config=shared_config
    )

    return {
        'masters': masters,
        'slave': slave,
        'monitors': monitors,
        'scoreboard': scoreboard,
        'shared_memory': shared_memory
    }

Factory Pattern Integration

class GAXITestFactory:
    """Factory class for creating GAXI test environments"""

    def __init__(self, dut, clock):
        self.dut = dut
        self.clock = clock
        self.default_config = get_default_field_config()

    def create_basic_system(self, prefix=""):
        """Create basic GAXI system"""
        return create_gaxi_system(
            dut=self.dut,
            clock=self.clock,
            title_prefix=prefix
        )

    def create_performance_test_system(self, data_width=32, memory_size=4096):
        """Create system optimized for performance testing"""
        return create_gaxi_test_environment(
            dut=self.dut,
            clock=self.clock,
            title_prefix="PERF_",
            data_width=data_width,
            memory_size=memory_size
        )

    def create_protocol_test_system(self, multi_sig=True, mode='skid'):
        """Create system for protocol compliance testing"""
        field_config = FieldConfig()
        field_config.add_field(FieldDefinition("addr", 32))
        field_config.add_field(FieldDefinition("data", 32))
        field_config.add_field(FieldDefinition("prot", 3))
        field_config.add_field(FieldDefinition("user", 4))

        return create_gaxi_components(
            dut=self.dut,
            clock=self.clock,
            title_prefix="PROT_",
            field_config=field_config,
            multi_sig=multi_sig,
            mode=mode
        )

    def create_stress_test_system(self):
        """Create system for stress testing"""
        return create_gaxi_test_environment(
            dut=self.dut,
            clock=self.clock,
            title_prefix="STRESS_",
            data_width=64,
            memory_size=8192
        )

# Usage
@cocotb.test()
async def test_with_factory(dut):
    factory = GAXITestFactory(dut, dut.clk)

    # Create different systems for different test phases
    basic_system = factory.create_basic_system("BASIC_")
    perf_system = factory.create_performance_test_system(64, 2048)
    stress_system = factory.create_stress_test_system()

    # Run tests with different systems...

Error Handling and Validation

Parameter Validation

# Factories automatically handle parameter validation
try:
    master = create_gaxi_master(
        dut=dut,
        title="TestMaster",
        prefix="",
        clock=dut.clk,
        field_config=invalid_config  # Will be validated and corrected
    )
except Exception as e:
    log.error(f"Factory creation failed: {e}")

Default Fallbacks

# Factories provide sensible defaults for all parameters
master = create_gaxi_master(dut, "Master", "", dut.clk)
# Uses: default field config, dut's logger, empty prefixes, etc.

Memory Model Auto-Creation

# Memory model is automatically created if not provided
system = create_gaxi_components(dut, dut.clk)
# Automatically creates MemoryModel(1024, 4) with proper configuration

Best Practices

1. Use Empty String Prefixes for Most Cases

# Empty prefixes work for most DUT configurations

2. Create Complete Systems for Full Testing

# Use create_gaxi_test_environment for comprehensive testing
env = create_gaxi_test_environment(dut, dut.clk)
# Includes all components plus convenience functions

3. Share Memory Models Across Components

# Share memory for consistent state
memory = MemoryModel(1024, 4, log=log)
master = create_gaxi_master(dut, "Master", "", dut.clk, memory_model=memory)
slave = create_gaxi_slave(dut, "Slave", "", dut.clk, memory_model=memory)

4. Use Multi-Signal Mode for Complex Protocols

# Enable multi-signal mode for protocols with many fields
components = create_gaxi_components(dut, dut.clk, multi_sig=True)

5. Leverage Factory Patterns for Complex Tests

# Create factory class for standardized test setups
factory = GAXITestFactory(dut, dut.clk)
system = factory.create_protocol_test_system()

Backward Compatibility

All factory functions maintain complete backward compatibility:

  • All existing parameters are preserved and passed through exactly as before
  • Parameter order is maintained for positional arguments
  • Default values are enhanced but don't break existing code
  • New parameters have sensible defaults that work with existing configurations
  • Legacy parameter names are supported (e.g., field_mode, signal_map) even when unused
# Legacy code continues to work unchanged
components = create_gaxi_components(
    dut, clock, title_prefix="Legacy_", field_mode=True,
    signal_map=old_signal_map, optional_signal_map=old_optional_map
)

The GAXI factories provide a robust, simplified interface for creating GAXI components while maintaining full backward compatibility and supporting advanced configuration scenarios.