Part 6 · Agents & Protocol IP · Intermediate
is_active Knob: Ownership, Defaults, and Override Precedence
How to model, set, and validate uvm_active_passive_enum configuration so agents reliably instantiate in the intended mode.
Why the knob matters
The is_active setting is the top-level policy switch that controls whether an agent drives pins. A wrong value changes testbench behavior drastically: traffic may disappear entirely or accidental dual-driving may occur.
Treat mode selection as part of interface ownership architecture. The environment should define sane defaults while tests can override intentionally for scenario-specific needs.
[UVM][AGT] configuration ownership chain
project policy default
-> env-level cfg
-> optional test override
-> agent build decision
recommended precedence:
test override > env override > agent default[AGT] mode contract
UVM_ACTIVE:
create sequencer + driver + monitor
allow sequences to generate traffic
UVM_PASSIVE:
create monitor only
prohibit driver ownership of vifSet explicit default mode in cfg object constructors.
Apply overrides before agent build_phase executes.
Log final resolved mode per agent instance at UVM_LOW/UVM_MEDIUM.
Canonical cfg object pattern
Keep mode inside the agent configuration object so all behavioral knobs travel together. This avoids split-brain configuration between raw config_db keys and object fields.
class protocol_agent_cfg extends uvm_object;
`uvm_object_utils(protocol_agent_cfg)
// Core mode switch
uvm_active_passive_enum is_active = UVM_ACTIVE;
// Typical adjacent knobs
bit has_coverage = 1;
bit checks_enable = 1;
int unsigned monitor_verbosity = UVM_LOW;
// Interface handle (often set by env)
virtual protocol_if vif;
function new(string name = "protocol_agent_cfg");
super.new(name);
endfunction
endclassclass protocol_agent extends uvm_agent;
`uvm_component_utils(protocol_agent)
protocol_agent_cfg cfg;
protocol_driver drv;
protocol_sequencer sqr;
protocol_monitor mon;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if (!uvm_config_db#(protocol_agent_cfg)::get(this, "", "cfg", cfg))
`uvm_fatal("CFG", "protocol_agent_cfg not found")
mon = protocol_monitor::type_id::create("mon", this);
if (cfg.is_active == UVM_ACTIVE) begin
sqr = protocol_sequencer::type_id::create("sqr", this);
drv = protocol_driver::type_id::create("drv", this);
end
`uvm_info("AGT_MODE",
$sformatf("%s mode=%s", get_full_name(), cfg.is_active.name()),
UVM_LOW)
endfunction
endclass[VIP][AGT] cfg placement pattern
env build:
create cfg per agent instance
set vif handles and defaults
set cfg in config_db under agent path
agent build:
get cfg
instantiate components by cfg.is_active
publish final mode logSingle cfg object keeps mode and adjacent knobs consistent.
Agent should fatal when cfg missing; silent defaults hide integration mistakes.
Mode decisions should happen once in build_phase, not dynamically later.
Override strategies and guardrails
Large environments need controlled override points. Use pattern-based config_db only where necessary and prefer object field updates in test build hooks for readability and traceability.
class soc_base_test extends uvm_test;
`uvm_component_utils(soc_base_test)
soc_env env;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
env = soc_env::type_id::create("env", this);
// Example: keep CPU control bus active
env.cpu_apb_cfg.is_active = UVM_ACTIVE;
// Example: force fabric probes passive
env.fabric_axi_cfg.is_active = UVM_PASSIVE;
endfunction
endclass// Optional wildcard override (use sparingly)
initial begin
uvm_config_db#(uvm_active_passive_enum)::set(
null,
"*.dma_axi_agent*",
"is_active",
UVM_PASSIVE
);
end[UVM] guardrails for safe overrides
1) prefer cfg-object edits over wildcard strings
2) if wildcard used, constrain path narrowly
3) print resolved mode table at end_of_elaboration
4) fail build if forbidden combinations detected
5) document per-agent mode rationale in env notesUse wildcard config_db only as an integration escape hatch.
Prefer deterministic per-instance cfg handles for maintainability.
Add environment-level validation pass to detect illegal mode combos.
Validation and debugging checklist
Mode bugs are easy to detect if you instrument early. Check creation counts, presence/absence of seq_item links, and any monitor-only assumptions before stimulus starts.
function void end_of_elaboration_phase(uvm_phase phase);
super.end_of_elaboration_phase(phase);
uvm_top.print_topology();
endfunction[AGT] expected topology by mode
active agent:
protocol_agent
mon
sqr
drv
passive agent:
protocol_agent
mon
(no sqr, no drv)[VIP][AGT] mode sanity matrix
symptom probable cause
----------------------------------------------------------------
no stimulus in active test cfg resolved to PASSIVE
driver null dereference code assumes drv exists in PASSIVE
double-driven interface two ACTIVE agents on same vif
monitor silent in passive deployment vif not assigned to monitor cfg
unexpected sqr in passive topology unconditional sqr createKey takeaways
Treat is_active as a first-class architectural control with explicit ownership.
Centralize mode in cfg objects and resolve before agent component creation.
Deterministic precedence and logging eliminate most mode ambiguity bugs.
Topology inspection is the fastest way to validate final mode resolution.
Common pitfalls
Hidden defaulting when cfg get() fails and agent continues anyway.
Overusing wildcard overrides that unintentionally affect extra instances.
Conditionally creating monitor by mode; monitor should exist in both modes.
Ignoring mode validation until run_phase when failures are noisier.