Part 6 · Agents & Protocol IP · Intermediate
SoC Integration with Passive Agents: Firmware and Fabric Observability
Patterns for inserting passive protocol VIP into complex SoC environments where DUT, firmware, or emulation infrastructure already owns traffic generation.
Integration motivation
At SoC level, many buses are already active due to firmware boot, CPU execution, DMA engines, and interconnect arbiters. Passive VIP lets verification observe these real flows without perturbing ownership.
This is especially valuable for protocol compliance, ordering checks, and performance coverage in software-driven scenarios where testbench-generated traffic would be unrealistic.
[SOC][VIP] ownership-aware integration
interfaces owned by TB stimulus:
keep ACTIVE (directed protocol tests)
interfaces owned by DUT/firmware:
set PASSIVE (observe only)
interfaces shared by phases:
consider mode switch across tests, not within one run[UVM] SoC-level mixed topology
boot_env
active_jtag_agent -> reset/config scripts
passive_axi_m0_agent -> cpu master stream
passive_axi_m1_agent -> dma master stream
passive_apb_agent -> csr transactions from firmware
passive_irq_agent -> interrupt pulse observeMode choice should follow interface ownership, not convenience.
Passive VIP enables verification during software-driven scenarios.
Mixed active/passive is expected in realistic SoC benches.
Wiring patterns for passive fleets
Create reusable env helpers that instantiate passive agent arrays, bind virtual interfaces, and connect analysis paths to scoreboards and coverage subscribers.
class soc_env extends uvm_env;
`uvm_component_utils(soc_env)
axi_agent axi_mon_agts[NUM_AXI_MASTERS];
axi_agent_cfg axi_cfgs[NUM_AXI_MASTERS];
noc_scoreboard noc_sb;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
noc_sb = noc_scoreboard::type_id::create("noc_sb", this);
foreach (axi_mon_agts[i]) begin
axi_cfgs[i] = axi_agent_cfg::type_id::create($sformatf("axi_cfg%0d", i));
axi_cfgs[i].is_active = UVM_PASSIVE;
axi_cfgs[i].vif = axi_if_array[i];
uvm_config_db#(axi_agent_cfg)::set(
this, $sformatf("axi_mon_agts[%0d]", i), "cfg", axi_cfgs[i]
);
axi_mon_agts[i] = axi_agent::type_id::create($sformatf("axi_mon_agts[%0d]", i), this);
end
endfunctionfunction void connect_phase(uvm_phase phase);
super.connect_phase(phase);
foreach (axi_mon_agts[i]) begin
axi_mon_agts[i].mon.ap.connect(noc_sb.axi_inputs[i]);
end
endfunction[AGT][SOC] integration checklist
build:
cfg arrays created and indexed
mode forced to PASSIVE
vif arrays bound one-to-one
connect:
each mon.ap connected exactly once
scoreboard channels aligned with instance index
coverage subscriber connected per traffic classUse env helper loops to avoid per-instance copy-paste errors.
Keep index mapping consistent from interface arrays to scoreboard channels.
Connect each monitor output intentionally to avoid silent drops.
Firmware-coexistence concerns
Firmware-driven activity introduces bursty timing, clock gating, and low-power transitions. Passive monitors must handle these dynamics without false protocol violations.
[VIP] firmware coexistence considerations
boot phase:
high register write density
reset exits and clock enables
runtime phase:
sparse control traffic
periodic DMA bursts
low-power phase:
clock stop/start
interface quiescent windows
monitor policy:
detect legal idle windows
gate checks by power/clock state if requiredif (!power_domain_on) begin
// Skip protocol assertions while domain is off
return;
end
if (clock_gated && !allow_gated_activity) begin
// Expect no transfers; report only unexpected toggles
end[SOC][MON] false-positive reducers
1) synchronize monitor sampling to active clocking
2) integrate reset/power state awareness
3) classify expected traffic windows (boot/runtime/idle)
4) separate protocol errors from environment-state noise
5) annotate transactions with phase contextAdd power/clock awareness for realistic SoC passive monitoring.
Differentiate legal idle from missing-observation bugs.
Tag traffic by software phase for clearer triage.
SoC passive debug playbook
Mixed software and hardware activity can hide root causes. Use layered diagnostics: topology/mode first, interface visibility next, then protocol reconstruction and checker behavior.
[SOC][VIP] debug ladder
layer 1: mode and topology
- passive agents instantiated?
- any accidental active duplicates?
layer 2: signal visibility
- correct vif bindings?
- clocks/resets valid?
layer 3: decode correctness
- monitor reconstructs fields correctly?
- transaction boundaries valid?
layer 4: consumer health
- scoreboard input receives traffic?
- coverage bins increment?[AGT] common SoC passive regressions
symptom likely cause
----------------------------------------------------------------
traffic seen in waves, no monitor events vif connected to wrong instance
only some channels observed array index misalignment
protocol errors only in low power missing state gating
sporadic duplicate transactions double monitor attachment`uvm_info("SOC_PASSIVE_SUMMARY",
$sformatf("axi_mon[%0d] mode=%s vif=%p", i, axi_cfgs[i].is_active.name(), axi_cfgs[i].vif),
UVM_LOW)Key takeaways
Passive VIP is a key enabler for software-driven SoC verification.
Scalable integration depends on disciplined array indexing and routing.
Power/clock awareness is mandatory to avoid noisy passive checkers.
Layered debug quickly separates ownership, visibility, and decode issues.
Common pitfalls
Attaching passive agents late without validating vif/index alignment.
Ignoring low-power states and over-reporting protocol violations.
Mixing active and passive ownership on one interface inadvertently.
Treating firmware traffic variability as monitor instability.