HomeProblemsTheoryUVM
Intermediate2 min readChapter 8

Agents & Environments

Build reusable agents that bundle driver/monitor/sequencer, and environments that compose multiple agents.

Agents & Environments

Agents and environments are the organizational backbone of a UVM testbench. They provide structure, reusability, and modularity.


The Agent

A UVM agent encapsulates everything needed to interact with one interface:

systemverilog
class apb_agent extends uvm_agent; `uvm_component_utils(apb_agent) apb_sequencer sequencer; apb_driver driver; apb_monitor monitor; function new(string name, uvm_component parent); super.new(name, parent); endfunction function void build_phase(uvm_phase phase); super.build_phase(phase); // Monitor is ALWAYS created monitor = apb_monitor::type_id::create("monitor", this); // Driver & sequencer only in ACTIVE mode if (get_is_active() == UVM_ACTIVE) begin sequencer = apb_sequencer::type_id::create("sequencer", this); driver = apb_driver::type_id::create("driver", this); end endfunction function void connect_phase(uvm_phase phase); if (get_is_active() == UVM_ACTIVE) driver.seq_item_port.connect(sequencer.seq_item_export); endfunction endclass

Configuring Active vs Passive

systemverilog
// In the environment's build_phase: // Make the slave agent passive (monitor only) uvm_config_db#(uvm_active_passive_enum)::set( this, "slave_agent", "is_active", UVM_PASSIVE );

The Environment

The environment composes multiple agents and connects them to verification components:

systemverilog
class soc_env extends uvm_env; `uvm_component_utils(soc_env) apb_agent apb_agt; axi_agent axi_agt; soc_scoreboard scoreboard; soc_coverage coverage; function new(string name, uvm_component parent); super.new(name, parent); endfunction function void build_phase(uvm_phase phase); super.build_phase(phase); apb_agt = apb_agent::type_id::create("apb_agt", this); axi_agt = axi_agent::type_id::create("axi_agt", this); scoreboard = soc_scoreboard::type_id::create("scoreboard", this); coverage = soc_coverage::type_id::create("coverage", this); endfunction function void connect_phase(uvm_phase phase); // Wire monitors to scoreboard apb_agt.monitor.ap.connect(scoreboard.apb_export); axi_agt.monitor.ap.connect(scoreboard.axi_export); // Wire monitors to coverage apb_agt.monitor.ap.connect(coverage.apb_export); endfunction endclass

Hierarchical Environments

Environments can contain other environments for complex SoC verification:

text
soc_env ├── cpu_subsystem_env │ ├── axi_agent (active) │ └── cpu_scoreboard ├── peripheral_env │ ├── apb_agent (active) │ ├── spi_agent (passive) │ └── periph_scoreboard └── soc_scoreboard (top-level checking)

Reusability in Action

Write an APB agent once, use it in every project:

systemverilog
// Project A — SoC verification class soc_env extends uvm_env; apb_agent apb_agt; // Same agent reused! // ... endclass // Project B — Peripheral verification class periph_env extends uvm_env; apb_agent apb_agt; // Same agent — zero rework! // ... endclass

Best Practices

PracticeWhy
One agent per interfaceAPB agent, AXI agent, SPI agent, etc.
Agent = self-containedNo external dependencies
Environment = compositionConnect agents to scoreboards and coverage
Use config_db for configurationActive/passive, interface handles
Keep hierarchy shallow2-3 levels is usually enough