Part 3 · Factory & Configuration · Intermediate

config_db vif Wiring: Paths, Forwarding, and Modports

Detailed config_db wiring for virtual interfaces — path conventions, agent forwarding, modport-specific virtual types, and config-object vif fields.

Path convention reference

diagram
[CONFIG] vif path conventions

  from top (context=null):
    "uvm_test_top.env.apb.*"     agent subtree
    "uvm_test_top.env"           env reads named vif
    "uvm_test_top.env.apb.drv"   direct to driver (avoid — bypasses agent)

  from agent (context=this):
    ""                           get vif set by parent/top
    "*"                          forward to all children
    "drv"                        forward to driver only

  field name: "vif" (convention) or "apb_vif" (named, env-level)

Modport-specific virtual interfaces

For clocking-block access, publish and consume modport-specific virtual types. The type on set and get must match exactly.

systemverilog
// Publish driver modport from top
uvm_config_db#(virtual apb_if.drv_mp)::set(
  null, "uvm_test_top.env.apb.drv", "vif", apb_if_i);

class apb_driver extends uvm_driver;
  virtual apb_if.drv_mp vif;

  task drive_addr(bit [31:0] addr);
    @(vif.cb);
    vif.cb.paddr <= addr;
  endtask
endclass
diagram
[HDL][CONFIG][UVM] modport typing

  set: virtual apb_if.drv_mp
  get: virtual apb_if.drv_mp      clocking block access

  set: virtual apb_if
  get: virtual apb_if.drv_mp      type mismatch, get fails

  pattern: publish modport type matching consumer's access needs

Vif in config object pattern

Combine vif with other agent policy in a config object — set once, agent reads cfg and extracts vif:

systemverilog
class apb_config extends uvm_object;
  `uvm_object_utils(apb_config)
  uvm_active_passive_enum is_active = UVM_ACTIVE;
  virtual apb_if vif;
  int unsigned timeout_ns = 1000;
  function new(string name = "apb_config"); super.new(name); endfunction
endclass

// top sets vif into config before run_test
apb_config acfg = apb_config::type_id::create("acfg");
acfg.vif = apb_if_i;
uvm_config_db#(apb_config)::set(null, "uvm_test_top.env.apb", "cfg", acfg);

// agent build_phase
if (!uvm_config_db#(apb_config)::get(this, "", "cfg", cfg))
  `uvm_fatal("CFG", "apb_config missing")
vif = cfg.vif;
if (vif == null)
  `uvm_fatal("NOVIF", "cfg.vif is null")
diagram
[CONFIG] vif delivery options

  Option A — direct vif set/get:
    set(null, path, "vif", if_i)  get("", "vif", vif)
    simple, explicit

  Option B — vif inside config object:
    set(null, path, "cfg", acfg) where acfg.vif = if_i
    bundles vif with agent policy, one get()
  • Option A is standard for VIP with minimal config objects.

  • Option B scales when vif and policy are always set together.

  • If using Option B, top must assign acfg.vif before set — not in agent.

Key takeaways

  • Match modport types exactly between set and get.

  • Agent forwarding with set(this, "*", "vif", vif) is the reuse pattern.

  • Config object can carry vif — validate cfg.vif != null after get.

Common pitfalls

  • Publishing full interface type but consuming modport type.

  • Setting vif on config object in agent instead of top/test.

  • Forwarding vif before successful get — propagates null to children.