Tutorials

Learn More

An agent is a container that holds and connects the driver, monitor, and sequencer instances. The agent develops a structured hierarchy based on the protocol or interface requirement.

uvm_agent class declaration:

virtual class uvm_agent extends uvm_component

User-defined class declaration:

The user-defined agent has to be extended from the uvm_agent component class.

class <agent_name> extends uvm_agent;

uvm_agent class hierarchy

uvm_agent hierarchy

How to create a UVM agent?

  1. Create a user-defined agent class extended from uvm_agent and register it in the factory.
  2. In the build_phase, instantiate driver, monitor, and sequencer if it is an active agent. Instantiate monitor alone if it is a passive agent.
  3. In the connect_phase, connect driver and sequencer components.

Types of Agent

There are two types of agents

  1. Active agent
  2. Passive agent

Active Agent

An Active agent drives stimulus to the DUT. It instantiates all three components driver, monitor, and sequencer.

Active agent in UVM

Passive Agent

A passive agent does not drive stimulus to the DUT. It instantiates only a monitor component. It is used as a sample interface for coverage and checker purposes.

Passive agent in uvm

How to configure the agent as an active or passive agent?

An agent is usually instantiated at UVM environment class. So, it can be configured in the environment or any other component class where an agent is instantiated using int configuration parameter is_active as shown below

set_config_int("<path_to_agent>", "is_active", UVM_ACTIVE);
set_config_int("<path_to_agent>", "is_active", UVM_PASSIVE);

Note: By default, all agents are configured as UVM_ACTIVE.

Code snippet to configure agent type with set_config_int

// Env Code
class env extends uvm_agent;
  a_agent agt_a; // Active agent
  p_agent agt_p; // Passive agent
  `uvm_component_utils(env)
  
  function new(string name = "env", uvm_component parent = null);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    
    agt_a = a_agent::type_id::create("agt_a", this);
    agt_p = p_agent::type_id::create("agt_p", this);
    set_config_int("agt_p", "is_active", UVM_PASSIVE); // Configure p_agent as passive agent
  endfunction
endclass

Output:

UVM_WARNING /xcelium20.09/tools/methodology/UVM/CDNS-1.2/sv/src/base/uvm_component.svh(3061) @ 0: uvm_test_top.env_o [UVM/CFG/SET/DPR] get/set_config_* API has been deprecated. Use uvm_config_db instead.
UVM_INFO agent.sv(16) @ 0: uvm_test_top.env_o.agt_a [agt_a] This is Active agent
UVM_INFO agent.sv(40) @ 0: uvm_test_top.env_o.agt_p [agt_p] This is Passive agent
UVM_INFO /xcelium20.09/tools/methodology/UVM/CDNS-1.2/sv/src/base/uvm_root.svh(605) @ 0: reporter [UVMTOP] UVM testbench topology:
--------------------------------------------------------------
Name                       Type                    Size  Value
--------------------------------------------------------------
uvm_test_top               base_test               -     @1835
  env_o                    env                     -     @1902
    agt_a                  a_agent                 -     @1933
      drv                  driver                  -     @1996
        rsp_port           uvm_analysis_port       -     @2117
        seq_item_port      uvm_seq_item_pull_port  -     @2065
      mon_A                monitor_A               -     @2002
      seqr                 sequencer               -     @2150
        rsp_export         uvm_analysis_export     -     @2210
        seq_item_export    uvm_seq_item_pull_imp   -     @2770
        arbitration_queue  array                   0     -    
        lock_queue         array                   0     -    
        num_last_reqs      integral                32    'd1  
        num_last_rsps      integral                32    'd1  
    agt_p                  p_agent                 -     @1966
      mon_B                monitor_B               -     @2860
--------------------------------------------------------------

The set_config_int method is deprecated in uvm1.2. If you run code with uvm1.2, following UVM_WARNING is expected.

UVM_WARNING: uvm_test_top.env_o [UVM/CFG/SET/DPR] get/set_config_* API has been deprecated.
Use uvm_config_db instead.

Code snippet to configure agent type with uvm_config_db

// Env code
class env extends uvm_agent;
  a_agent agt_a; // Active agent
  p_agent agt_p; // Passive agent
  `uvm_component_utils(env)
  
  function new(string name = "env", uvm_component parent = null);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    
    agt_a = a_agent::type_id::create("agt_a", this);
    agt_p = p_agent::type_id::create("agt_p", this);
    uvm_config_db #(uvm_active_passive_enum)::set(this, "agt_p", "is_active", UVM_PASSIVE);
  endfunction
endclass

Output:

UVM_INFO agent.sv(16) @ 0: uvm_test_top.env_o.agt_a [agt_a] This is Active agent
UVM_INFO agent.sv(40) @ 0: uvm_test_top.env_o.agt_p [agt_p] This is Passive agent
UVM_INFO /xcelium20.09/tools/methodology/UVM/CDNS-1.2/sv/src/base/uvm_root.svh(605) @ 0: reporter [UVMTOP] UVM testbench topology:
--------------------------------------------------------------
Name                       Type                    Size  Value
--------------------------------------------------------------
uvm_test_top               base_test               -     @1838
  env_o                    env                     -     @1905
    agt_a                  a_agent                 -     @1936
      drv                  driver                  -     @1999
        rsp_port           uvm_analysis_port       -     @2117
        seq_item_port      uvm_seq_item_pull_port  -     @2065
      mon_A                monitor_A               -     @1873
      seqr                 sequencer               -     @2150
        rsp_export         uvm_analysis_export     -     @2210
        seq_item_export    uvm_seq_item_pull_imp   -     @2770
        arbitration_queue  array                   0     -    
        lock_queue         array                   0     -    
        num_last_reqs      integral                32    'd1  
        num_last_rsps      integral                32    'd1  
    agt_p                  p_agent                 -     @1969
      mon_B                monitor_B               -     @2859
--------------------------------------------------------------

How does the user-defined agent know whether it is an active or passive agent?

The get_is_active() function is used to find out the type of agent. The driver, sequencer instances are created if it is an active agent and monitor instance can be created by default irrespective of agent type.

The get_is_active() function returns an enum as UVM_ACTIVE or UVM_PASSIVE of type uvm_active_passive_enum.

Active Agent example

class a_agent extends uvm_agent;
  driver drv;
  sequencer seqr;
  monitor_A mon_A;
  `uvm_component_utils(a_agent)
  
  function new(string name = "a_agent", uvm_component parent = null);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    if(get_is_active() == UVM_ACTIVE) begin
      drv = driver::type_id::create("drv", this);
      seqr = sequencer::type_id::create("seqr", this);
      `uvm_info(get_name(), "This is Active agent", UVM_LOW);
    end
    mon_A = monitor_A::type_id::create("mon_A", this);
  endfunction
  
  function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    if(get_is_active() == UVM_ACTIVE)
      drv.seq_item_port.connect(seqr.seq_item_export);
  endfunction
endclass

Passive Agent example

class p_agent extends uvm_agent;
  monitor_B mon_B;
  `uvm_component_utils(p_agent)
  
  function new(string name = "p_agent", uvm_component parent = null);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    if(get_is_active() == UVM_PASSIVE) begin
      mon_B = monitor_B::type_id::create("mon_B", this);
      `uvm_info(get_name(), "This is Passive agent", UVM_LOW);
    end
  endfunction
endclass

How an agent build a structural hierarchy with various protocols?

Based on the protocol interface, the stimulus has to be driven to the DUT. So, the agent provides flexibility to build a structural hierarchy by having different agents for different protocol interfaces.

For example:

In the below diagram,

  1. agent_ahb is specific to the AHB interface and involves driver, sequence, and sequencers to drive the interface.
  2. agent_axi is specific to the AXI interface and involves driver, sequence, and sequencers to drive the interface.
  3. agent_apb is specific to the APB interface and involves driver, sequence, and sequencers to drive the interface.
multiple agents for varous protocols