Part 6 · Agents & Protocol IP · Intermediate

cfg Active/Passive Switch: Runtime Policy Through Configuration

Reliable switch mechanics using cfg objects, config_db injection, and validation hooks to keep mode transitions deterministic across tests.

Switch design principles

The active/passive switch should be deterministic per test run. Choose mode in build configuration, not ad hoc during run_phase, so topology and ownership stay stable.

Expose switch policy through cfg fields, then validate resolved outcomes before simulation traffic begins.

diagram
[UVM][AGT] deterministic switch model

input knobs:
  cfg.is_active
  env-level defaults
  test-level overrides

decision point:
  agent build_phase

output:
  fixed component topology for entire run
diagram
[VIP] switch policy table

test type                         suggested mode
------------------------------------------------------------
protocol directed stimulus        ACTIVE
software boot observability       PASSIVE
mixed emulation bring-up          mostly PASSIVE
single-interface fault isolation  ACTIVE for target, PASSIVE for observers
  • Resolve mode once before topology is built.

  • Keep switch inputs explicit and reviewable.

  • Avoid dynamic mode mutation inside running phases.


Configuration plumbing patterns

A common approach is env-owned cfg creation plus test-owned policy updates. This keeps object lifetimes clear and minimizes config_db string fragility.

systemverilog
class chip_env extends uvm_env;
  `uvm_component_utils(chip_env)
  apb_agent_cfg apb_cfg;
  apb_agent     apb_agt;

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    apb_cfg = apb_agent_cfg::type_id::create("apb_cfg");
    apb_cfg.is_active = UVM_ACTIVE; // env default
    apb_cfg.vif = apb_vif;

    uvm_config_db#(apb_agent_cfg)::set(this, "apb_agt", "cfg", apb_cfg);
    apb_agt = apb_agent::type_id::create("apb_agt", this);
  endfunction
endclass
systemverilog
class fw_boot_test extends uvm_test;
  `uvm_component_utils(fw_boot_test)
  chip_env env;

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    env = chip_env::type_id::create("env", this);
    // Switch APB agent to monitor-only in this scenario
    env.apb_cfg.is_active = UVM_PASSIVE;
  endfunction
endclass
diagram
[AGT] plumbing do/don't

do:
  pass cfg object through config_db once
  mutate cfg field in tests for scenario policy
  keep mode close to related knobs

don't:
  duplicate mode in both cfg and raw config_db key
  mix enum and integer representations
  apply late overrides after agent build
  • One cfg object per agent instance keeps policy coherent.

  • Test-level switch should modify cfg before child builds occur.

  • Avoid dual-source mode knobs that can diverge.


Validation gates and policy assertions

Add reusable validation helpers to enforce legal mode combinations. This turns integration mistakes into immediate build failures.

systemverilog
function void validate_agent_modes();
  if (cpu_apb_cfg.is_active == UVM_PASSIVE && requires_tb_boot_sequence)
    `uvm_fatal("MODE", "cpu_apb must be ACTIVE for tb boot sequence")

  if (dma_axi_cfg.is_active == UVM_ACTIVE && firmware_also_drives_dma)
    `uvm_fatal("MODE", "dma_axi cannot be ACTIVE when firmware owns DMA traffic")
endfunction
diagram
[SOC] policy validation examples

rule A:
  control plane bus active in directed register tests

rule B:
  DUT-master interfaces remain passive during firmware tests

rule C:
  no interface has more than one active driver owner

rule D:
  critical monitors always instantiated regardless of mode
diagram
[VIP][AGT] pre-run mode report

agent instance           resolved mode   owner
--------------------------------------------------------
cpu_apb_agent            ACTIVE          testbench
dma_axi_agent            PASSIVE         firmware/DUT
pcie_rc_agent            ACTIVE          testbench
noc_stream_agent[0..3]   PASSIVE         DUT fabric

print this table every run for reproducibility
  • Convert mode assumptions into explicit validation checks.

  • Emit a mode report table before run_phase starts.

  • Fail fast on ownership conflicts instead of warning.


Switch-related debugging patterns

Most switch bugs are precedence bugs. Investigate where final mode was set last, then verify that component creation matched that resolved value.

diagram
[UVM] precedence debug trail

1) cfg constructor default
2) env-level assignment
3) test-level assignment
4) config_db set/get path
5) agent build log
6) topology print

first unexpected value identifies culprit layer
diagram
[AGT] signature failures

symptom                                 likely root cause
----------------------------------------------------------------
agent logs ACTIVE but no driver exists  stale cfg pointer / wrong instance path
agent logs PASSIVE unexpectedly          broad wildcard override
topology mismatch with logs              multiple cfg objects for one instance
mode differs across reruns               non-deterministic late assignment
systemverilog
`uvm_info("MODE_TRACE",
  $sformatf("instance=%s cfg=%p mode=%s",
            get_full_name(), cfg, cfg.is_active.name()),
  UVM_MEDIUM)

Key takeaways

  • Active/passive switching should be build-time deterministic and policy-driven.

  • Cfg-object plumbing with early overrides yields stable, auditable behavior.

  • Validation gates catch illegal ownership combinations before stimulus runs.

  • Precedence tracing resolves most switch bugs quickly.

Common pitfalls

  • Late mode mutation after build causing topology/config disagreement.

  • Overlapping wildcard config_db rules with unclear specificity.

  • Maintaining separate mode copies in multiple objects.

  • Treating ownership conflicts as warnings instead of hard failures.