Part 6 · Agents & Protocol IP · Intermediate
Passive Monitor-Only Agents: Observation Without Driving
Designing passive deployments that decode live DUT traffic, publish stable analysis streams, and remain reusable across subsystem and SoC environments.
Passive mode intent
Passive mode exists for interfaces the testbench does not own. Firmware, embedded controllers, or external BFMs may already drive signals; the UVM agent should only observe and publish transactions.
A good passive agent is not a reduced-quality fallback. It is a first-class observability component with robust protocol decoding, timestamping, and coverage hooks.
[AGT][MON] passive data path
DUT/bus activity
|
v
monitor samples interface signals
|
+--> reconstruct protocol_item
|
+--> analysis_port.write(item)
|
+--> scoreboard
+--> protocol checker
+--> coverage subscribers[VIP] why passive is powerful
no driving side effects
safe to attach to live firmware runs
enables protocol compliance checks
enables coverage collection from real traffic
usable at block, subsystem, and full-chip levelsPassive mode still requires a high-quality monitor implementation.
Protocol reconstruction quality determines checker/coverage value.
Keep publication latency and object cloning discipline explicit.
Monitor implementation details
Passive monitors need deterministic sampling points and robust transaction boundary detection. Use clocking blocks or explicit event sampling to avoid race conditions.
class protocol_monitor extends uvm_monitor;
`uvm_component_utils(protocol_monitor)
uvm_analysis_port #(protocol_item) ap;
protocol_agent_cfg cfg;
virtual protocol_if vif;
function new(string name, uvm_component parent);
super.new(name, parent);
ap = new("ap", this);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
vif = cfg.vif;
if (vif == null)
`uvm_fatal("VIF", "monitor vif is null")
endfunction
endclasstask run_phase(uvm_phase phase);
protocol_item tr;
forever begin
@(posedge vif.clk);
if (!vif.rst_n) continue;
if (vif.valid && vif.ready) begin
tr = protocol_item::type_id::create("tr");
tr.addr = vif.addr;
tr.data = vif.data;
tr.kind = vif.write ? PROTO_WRITE : PROTO_READ;
tr.timestamp = $time;
ap.write(tr);
end
end
endtask[MON] quality checklist
sampling:
consistent edge and reset filtering
reconstruction:
decode all required fields
include direction and metadata
publication:
clone if downstream mutation possible
emit one write per protocol transferPassive monitor must never drive interface signals.
Always include reset and protocol-invalid filtering.
Encode enough metadata for downstream scoreboards and coverage.
Passive deployment at scale
Full-chip environments may host dozens of passive instances. Standardize naming, instance indexing, and analysis routing so integration remains manageable.
[SOC][VIP] many-passive-agent topology
soc_env
passive_axi_agent[0] -> noc_sb.in_axi_ch0
passive_axi_agent[1] -> noc_sb.in_axi_ch1
passive_axi_agent[2] -> noc_sb.in_axi_ch2
passive_axi_agent[3] -> noc_sb.in_axi_ch3
passive_apb_agent -> csr_sb.in_apb
passive_stream_agent -> perf_cov.in_stream
pattern:
one monitor output channel per physical interfaceforeach (env.passive_axi_agent[i]) begin
env.passive_axi_cfg[i].is_active = UVM_PASSIVE;
env.passive_axi_cfg[i].vif = axi_vif[i];
end
foreach (env.passive_axi_agent[i]) begin
env.passive_axi_agent[i].mon.ap.connect(env.noc_sb.axi_in[i]);
end[AGT] passive scaling practices
1) keep cfg arrays aligned with vif arrays
2) emit instance id in each transaction
3) map each monitor stream to explicit scoreboard input
4) isolate per-instance protocol checker state
5) add per-interface coverage bins for balanced observabilityUse index-stable naming for easier triage in logs and waveforms.
Attach channel or port IDs to published transactions.
Avoid multiplexing unrelated monitor streams through one anonymous pipe.
Passive-specific debug
When passive pipelines fail, symptoms usually appear as missing transactions, malformed decodes, or poor alignment with expected firmware traffic. Debug by validating visibility first, decoding second.
[MON] passive triage order
1) confirm vif activity in waveform
2) confirm monitor sampling edge and reset gate
3) confirm transaction boundary detection logic
4) confirm ap.write invocation count
5) confirm subscriber connect_phase wiring
6) confirm downstream consumer accepts item[VIP][AGT] passive failure signatures
symptom likely issue
---------------------------------------------------------------
zero monitor transactions vif null or wrong interface
half-rate publication wrong sampling edge/clock domain
garbled fields decode packing mismatch
scoreboard receives nothing ap not connected
coverage flat despite traffic missing bins or wrong filter`uvm_info("MON_TRACE",
$sformatf("%s tr kind=%0d addr=0x%0h data=0x%0h t=%0t",
get_full_name(), tr.kind, tr.addr, tr.data, tr.timestamp),
UVM_HIGH)Key takeaways
Passive agents are production-grade observability tools, not secondary components.
Monitor reconstruction quality determines checker and coverage effectiveness.
Scalable passive deployment needs disciplined routing and instance metadata.
Debug passive pipelines by validating visibility before decode semantics.
Common pitfalls
Assuming passive mode means relaxed monitor implementation quality.
Dropping transaction metadata needed for per-interface attribution.
Combining multiple monitor streams without source tagging.
Ignoring sampling edge correctness across clocking block conventions.