Part 6 · Agents & Protocol IP · Intermediate

build_phase Conditional: Deterministic Active/Passive Construction

Implement robust mode-gated construction in build_phase, including cfg precedence, instance-specific mode control, and topology assertions.

Mode resolution strategy

Resolve mode exactly once in build_phase from cfg (or explicit override policy), then build the topology accordingly. Do not recompute mode ad hoc in later phases.

diagram
[UVM][AGT] mode precedence pattern

1) cfg-provided mode (preferred)
2) explicit top-level override (if project policy allows)
3) default mode with warning

once resolved:
  freeze topology decisions for this instance
diagram
[AGT] why one-time resolution

if mode shifts after build:
  child topology no longer matches behavior assumptions
  null-handle/runtime contention bugs appear
  • Treat mode as structural decision, not dynamic runtime toggle.

  • Log effective mode for every agent instance.

  • Document precedence policy clearly in wrapper code.


Conditional build implementation

systemverilog
function void build_phase(uvm_phase phase);
  super.build_phase(phase);
  if (!uvm_config_db#(axi_cfg)::get(this, "", "cfg", cfg))
    `uvm_fatal("NOCFG", "axi_cfg missing")

  is_active = cfg.is_active;
  ap = new("ap", this);
  mon = axi_monitor::type_id::create("mon", this);
  uvm_config_db#(axi_cfg)::set(this, "mon", "cfg", cfg);

  if (is_active == UVM_ACTIVE) begin
    sqr = axi_sequencer::type_id::create("sqr", this);
    drv = axi_driver::type_id::create("drv", this);
    uvm_config_db#(axi_cfg)::set(this, "drv", "cfg", cfg);
  end
  else begin
    sqr = null;
    drv = null;
  end

  `uvm_info("AGT_MODE",
    $sformatf("%s mode=%s", get_full_name(),
      (is_active == UVM_ACTIVE) ? "ACTIVE" : "PASSIVE"),
    UVM_LOW)
endfunction
diagram
[UVM][AGT] topology assertions

ACTIVE:
  sqr != null && drv != null && mon != null

PASSIVE:
  sqr == null && drv == null && mon != null
  • Explicitly null absent handles in passive mode.

  • Forward cfg only to children that exist.

  • Use deterministic mode logs for triage.


Mixed-instance deployment

One env often hosts mixed mode instances of the same agent class. Each instance gets independent cfg object and mode value.

systemverilog
function void build_phase(uvm_phase phase);
  super.build_phase(phase);

  i2c_cfg host_cfg = i2c_cfg::type_id::create("host_cfg");
  i2c_cfg dev_cfg  = i2c_cfg::type_id::create("dev_cfg");

  void'(uvm_config_db#(virtual i2c_if)::get(this, "", "host_vif", host_cfg.vif));
  void'(uvm_config_db#(virtual i2c_if)::get(this, "", "dev_vif",  dev_cfg.vif));

  host_cfg.is_active = UVM_ACTIVE;
  dev_cfg.is_active  = UVM_PASSIVE;

  uvm_config_db#(i2c_cfg)::set(this, "host_agt", "cfg", host_cfg);
  uvm_config_db#(i2c_cfg)::set(this, "dev_agt",  "cfg", dev_cfg);

  host_agt = i2c_agent::type_id::create("host_agt", this);
  dev_agt  = i2c_agent::type_id::create("dev_agt", this);
endfunction
diagram
[AGT] mixed deployment outcome

host_agt:
  drives + observes

dev_agt:
  observes only

same class reused with instance-specific cfg

Key takeaways

  • Mode-gated build should be deterministic and instance-specific.

  • Structural decisions belong in build_phase and remain stable thereafter.

  • Mixed active/passive deployment is a first-class architecture pattern.

  • Topology assertions catch mode bugs before run-phase traffic.

Common pitfalls

  • Using one shared cfg across multiple instances and leaking mode values.

  • Creating active children unconditionally then disabling behavior later.

  • Re-evaluating mode in run_phase and diverging from built topology.

  • Skipping mode logs and losing quick visibility in regressions.