Scalable Architecture & Parameterization

How to build reusable UVM environments using parameters and configuration objects, enabling VIP reuse across blocks and SoCs.

Horizontal vs. Vertical Reuse

A truly advanced UVM architecture is designed with Vertical Reuse in mind. This means the code you write for a small Block-level testbench should be instantly reusable when that block is integrated into a larger Subsystem or a full SoC.

Key Architectures:

  • Horizontal Reuse: Using the same VIP across different projects (e.g., a standard AXI Agent).
  • Vertical Reuse: Moving a block-level Env into a system-level Env without modifying its source code.

Layered Agents (Protocol Translation)

In complex systems, you often need to drive high-level transactions (like "Read Memory") over a low-level physical bus (like AXI). Layered Agents allow you to stack sequencers.

The Translation Pattern:

You create a "Transformation Sequence" that runs on the low-level sequencer but pulls items from the high-level sequencer. This keeps your test stimulus clean and decoupled from the physical implementation.

Architecture: Layered Squencer

class ahb_to_axi_translator extends uvm_sequence;
    axi_sequencer axi_sqr; // Physical layer
    task body();
        forever begin
            p_sequencer.ahb_fifo.get(ahb_item); // Get high-level
            // Translate to multiple AXI bursts
            `uvm_do_on_with(axi_txn, axi_sqr, { ... }) 
        end
    endtask
endclass
                            

Advanced Configuration Strategies

As environments grow, uvm_config_db becomes a bottleneck. The solution is a Hierarchical Configuration Object.

  • One-Set Principle: The Test sets a single large config object at the top level.
  • Sub-configs: The Env extracts its relevant pieces and passes specific "Sub-configs" to child agents.
  • Dynamic Updates: Since objects are passed by reference, the Test can modify a knob mid-simulation and the Agent sees it instantly.

VIP Best Practices

The "Interface in Config" Rule

Never put a virtual interface directly in an Agent or Driver. Always store it inside the Configuration Object. This makes your components port-agnostic and easier to override using the UVM Factory.