Part 3 · Factory & Configuration · Intermediate

Multi-Instance vif Pattern: Distinct Handles Per Agent

Multi-port SoC patterns — separate interface instances, scoped config_db paths, env-level distribution, and avoiding cross-agent vif leaks.

The multi-instance problem

A SoC testbench may have multiple identical bus ports — two APB masters, four AXI ports, etc. Each agent needs its own virtual interface handle pointing to a different interface instance. A single broad set path gives every agent the same vif.

diagram
[HDL] multi-instance top

  apb_if apb0_i ──► DUT port 0
  apb_if apb1_i ──► DUT port 1

  WRONG:
    set(null, "uvm_test_top.env.*", "vif", apb0_i)
     both apb0_agent and apb1_agent get apb0_i

  RIGHT:
    set(null, "uvm_test_top.env.apb0.*", "vif", apb0_i)
    set(null, "uvm_test_top.env.apb1.*", "vif", apb1_i)

Top module multi-instance publish

systemverilog
module top;
  logic clk;
  apb_if apb0_i(.pclk(clk));
  apb_if apb1_i(.pclk(clk));
  dut u_dut(.apb0(apb0_i), .apb1(apb1_i));

  initial begin
    uvm_config_db#(virtual apb_if)::set(
      null, "uvm_test_top.env.apb0.*", "vif", apb0_i);
    uvm_config_db#(virtual apb_if)::set(
      null, "uvm_test_top.env.apb1.*", "vif", apb1_i);
    run_test();
  end
endmodule
diagram
[CONFIG] multi-instance map

  apb0_i ──► path env.apb0.* ──► apb0_agent.drv.vif
  apb1_i ──► path env.apb1.* ──► apb1_agent.drv.vif

  agent names in env must match path segments (apb0, apb1)

Env-level distribution alternative

Alternative: top sets named vifs on env; env reads each and fans out to the matching agent:

systemverilog
// top.sv — named handles on env
uvm_config_db#(virtual apb_if)::set(null, "uvm_test_top.env", "apb0_vif", apb0_i);
uvm_config_db#(virtual apb_if)::set(null, "uvm_test_top.env", "apb1_vif", apb1_i);

// env build_phase
virtual apb_if apb0_vif, apb1_vif;
void'(uvm_config_db#(virtual apb_if)::get(this, "", "apb0_vif", apb0_vif));
void'(uvm_config_db#(virtual apb_if)::get(this, "", "apb1_vif", apb1_vif));
uvm_config_db#(virtual apb_if)::set(this, "apb0.*", "vif", apb0_vif);
uvm_config_db#(virtual apb_if)::set(this, "apb1.*", "vif", apb1_vif);
apb0 = apb_agent::type_id::create("apb0", this);
apb1 = apb_agent::type_id::create("apb1", this);
diagram
[HDL][CONFIG][UVM] env-owned distribution

  top ──set(env, apb0_vif)──► [CONFIG]
  top ──set(env, apb1_vif)──► [CONFIG]
  env ──set(apb0.*, vif)───►   [CONFIG]
  env ──set(apb1.*, vif)───►   [CONFIG]
  apb0.drv ──get(vif)──►       [UVM]

  use when top should not know agent hierarchy names
  • Path segment must match agent instance name in env (apb0, apb1).

  • Env-owned distribution hides agent naming from top — good for reusable envs.

  • Never use env.* with one vif when agents need different interfaces.

Key takeaways

  • One set path per interface instance — scope to agent subtree.

  • Agent instance names in env must align with config_db path segments.

  • Env-level fan-out keeps top simple for reusable verification environments.

Common pitfalls

  • Both agents under env.* with same vif key — wrong interface or race.

  • Renaming agent in env without updating top set paths.

  • Parameterized interfaces with same type but different instances — path is the differentiator.