Tutorials
Learn More
UVM Agent
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
How to create a UVM agent?
- Create a user-defined agent class extended from uvm_agent and register it in the factory.
- In the build_phase, instantiate driver, monitor, and sequencer if it is an active agent. Instantiate monitor alone if it is a passive agent.
- In the connect_phase, connect driver and sequencer components.
Types of Agent
There are two types of agents
- Active agent
- Passive agent
Active Agent
An Active agent drives stimulus to the DUT. It instantiates all three components driver, monitor, and sequencer.
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.
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,
- agent_ahb is specific to the AHB interface and involves driver, sequence, and sequencers to drive the interface.
- agent_axi is specific to the AXI interface and involves driver, sequence, and sequencers to drive the interface.
- agent_apb is specific to the APB interface and involves driver, sequence, and sequencers to drive the interface.
UVM Tutorials