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.
[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
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[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:
// 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);[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 namesPath 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.