UVM Agent

The container component that encapsulates the verification logic for a specific interface.

The Container Architecture

What is an Agent?

The Simple Version: An Agent is a container that groups related components together. It typically contains a Driver, Monitor, and Sequencer that all work with the same interface.

Think of it like: A department in a company. Just like HR has recruiters, trainers, and managers working together, an Agent has Driver, Monitor, and Sequencer working together.

A UVM Agent is a hierarchical container that encapsulates all verification components required for a specific interface. Instead of scattering drivers and monitors throughout your environment, you group them into an Agent to ensure Reusability and Portability.

Components of an Agent:

  • Sequencer: Controls the flow of stimulus from sequences.
  • Driver: Converts high-level transactions into pin-level activity.
  • Monitor: Observes pin-level activity and converts it back to transactions.

Dynamic Mode: Active vs. Passive

Professional Agents are smart. They have a switch called is_active.

If you set it to ACTIVE, the Agent builds everything (Driver, Sequencer, Monitor) so it can drive signals.
If you set it to PASSIVE, it only builds the Monitor. We do this when the Agent is just listening (Spy Mode) and not driving anything.

Real World Analogy:
  • Active Agent: A player on the field (playing the game).
  • Passive Agent: A commentator in the booth (watching and reporting, but not playing).

The Build Logic:

  • UVM_ACTIVE (Default): Build Driver + Sequencer + Monitor.
  • UVM_PASSIVE: Build ONLY the Monitor. This is critical for system-level tests where the bus is driven by a design-under-test (DUT) sub-module.
Implementation: Config-Driven Build

class ahb_agent extends uvm_agent;
    `uvm_component_utils(ahb_agent)
    ahb_driver    drv;
    ahb_sequencer sqr;
    ahb_monitor   mon;
    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        // 1. Monitor is ALWAYS built
        mon = ahb_monitor::type_id::create("mon", this);
        // 2. Logic to build Driver/Sequencer
        if(get_is_active() == UVM_ACTIVE) begin
            drv = ahb_driver::type_id::create("drv", this);
            sqr = ahb_sequencer::type_id::create("sqr", this);
        end
    endfunction
endclass
                            

Hierarchical Connectivity

The connect_phase in the Agent is where the internal wiring happens. Specifically, the Driver's seq_item_port must be connected to the Sequencer's seq_item_export.


function void connect_phase(uvm_phase phase);
    // Only connect if the agent is driving
    if(get_is_active() == UVM_ACTIVE) begin
        drv.seq_item_port.connect(sqr.seq_item_export);
    end
endfunction
                            

Architectural Best Practice

Never connect the Monitor to the Driver. The Monitor should be independent, sampling the bus interface directly. This ensures that the Monitor validates what actually happened on the wires, not what the Driver intended to happen.