Part 11 · Senior Prep · Intermediate
Virtual Interface Interview Q&A
Model answers on virtual interface propagation from HDL top through config_db to driver, timing, and multi-interface scenarios.
Virtual interface propagation
Virtual interface questions test the HDL-to-UVM bridge — every senior candidate should draw top module → config_db → driver get without hesitation.
Q: Why do we need virtual interfaces in UVM?
[INT][SENIOR][UVM] MODEL ANSWER
Q: Why virtual interfaces?
A:
MECHANISM: SystemVerilog classes cannot contain static module interfaces; virtual
interface is a handle to hierarchical interface instance in module world.
MOTIVATION: UVM components are classes — they need a bridge to pin-level signals
defined in HDL modules without direct hierarchical reference.
WHEN: Every pin-wiggling driver/monitor needs virtual interface handle from
config_db set in HDL top or test wrapper module.
PITFALL: Passing interface directly as port to uvm_component — illegal in SV;
must use virtual interface indirection.
EXAMPLE: top module instantiates axi_if; run_test sets config_db in initial block; axi_driver
gets virtual axi_if handle and drives vif.awvalid.Q: Where should virtual interface be set?
[INT][SENIOR][UVM] MODEL ANSWER
Q: Where to set vif?
A:
MECHANISM: HDL top module (or uvm_initiator module) calls uvm_config_db#(virtual if_type)::set
before run_test() — typically in initial block or module constructor context.
MOTIVATION: Interface instance lives in module hierarchy — only module scope has
direct handle; must push into config_db before UVM build_phase consumes it.
WHEN: Set in top initial block before run_test. Alternative: test build_phase
if test module wraps interface (less common).
PITFALL: Set in agent build_phase — circular: agent needs vif to build driver but
agent is the one setting it; driver get in same phase fails.
EXAMPLE: tb_top: initial begin uvm_config_db#(virtual axi_if)::set(null,"*","vif", axi_if_inst);
run_test("smoke_test"); endQ: Where should driver get virtual interface?
[INT][SENIOR][UVM] MODEL ANSWER
Q: Where driver gets vif?
A:
MECHANISM: uvm_config_db#(virtual if_type)::get(this, "", "vif", vif) in driver
or agent build_phase — before run_phase pin activity.
MOTIVATION: Driver must hold vif before run_phase loop — get in build guarantees
handle available when run_phase starts.
WHEN: Agent build gets vif and assigns to driver.vif, or driver build gets
directly. Fatal if get fails — silent null causes obscure hang.
PITFALL: Get in run_phase first iteration — works but delays error if vif missing,
wastes debug time in phase trace before obvious null check.
EXAMPLE: agent.build: get vif, assign drv.vif = vif. driver.run_phase: drive on
vif.awvalid — vif guaranteed non-null from build.Q: Multiple interfaces — how do you avoid vif collision?
[INT][SENIOR][UVM] MODEL ANSWER
Q: Multiple interfaces without collision?
A:
MECHANISM: Use distinct field names ("tx_vif", "rx_vif") or scoped inst_path
("env.agt_tx", "env.agt_rx") instead of shared "vif" wildcard.
MOTIVATION: Wildcard set of single "vif" gives all agents same handle — TX agent
drives RX bus in multi-interface TB.
WHEN: Explicit per-agent set: set(null, "env.agt_tx", "vif", tx_if) and
set(null, "env.agt_rx", "vif", rx_if).
PITFALL: set(null,"*","vif", tx_if) — both agents get tx_if, rx monitor samples
wrong bus, scoreboard mismatch looks like DUT bug.
EXAMPLE: Dual AXI port DUT: agt_master and agt_slave each get distinct vif via
scoped inst_path — scoreboard matches correct bus pair.Key takeaways
Virtual interface bridges module interfaces to class components.
Set vif from HDL top before run_test; get in build_phase.
Distinct field names or scoped paths for multi-interface TBs.
Common pitfalls
Wildcard vif set with multiple interfaces — silent bus swap.
Get in run_phase instead of build — delayed fatal on missing vif.
Virtual interface edge cases
Q: typedef wrapper on virtual interface — why does it matter?
[INT][SENIOR][UVM] MODEL ANSWER
Q: typedef and virtual interface type match?
A:
MECHANISM: config_db parameterized type must match exactly between set and get —
typedef axi_vif_t = virtual axi_if differs from virtual axi_if if
different typedef names used inconsistently.
MOTIVATION: SV type equivalence is nominal for typedefs in some contexts — mismatch
causes get failure even when underlying interface identical.
WHEN: Define one typedef in shared package; use same typedef in set, get,
and driver member declaration.
PITFALL: Top sets virtual axi_if; driver gets using typedef alias from VIP package
— compile OK if wrong cast, get fails at runtime.
EXAMPLE: Common package: typedef virtual axi_if axi_vif_t; all set/get use
uvm_config_db#(axi_vif_t) — consistent match guaranteed.Q: How do you pass clock/reset handles alongside data interface?
[INT][SENIOR][UVM] MODEL ANSWER
Q: Clock/reset with data vif?
A:
MECHANISM: Separate config_db entries: "vif" for bus, "clk_vif" or clocking block
handle for timing. Or embed clocking modport in same interface.
MOTIVATION: Driver needs both signal access and clocking source — single vif with
clocking modport is cleanest pattern.
WHEN: Prefer interface with clocking block for driver clock sync. Separate
config only when clock is shared IP module interface.
PITFALL: Driver uses `posedge vif.clk without checking clk in same interface as
data — race if clk from different hierarchy path.
EXAMPLE: axi_if contains clocking cb @(posedge aclk); driver uses vif.cb.awvalid
for synchronous drive — one vif handle covers data + clock.// vif propagation — interview must-know
module tb_top;
axi_if axi_if_inst(.*);
initial begin
uvm_config_db#(virtual axi_if)::set(null, "env.axi_agt*", "vif", axi_if_inst);
run_test();
end
endmodule
// agent build
if (!uvm_config_db#(virtual axi_if)::get(this, "", "vif", vif))
`uvm_fatal("VIF", "no vif")Q: Virtual interface in block vs chip testbench?
[INT][SENIOR][UVM] MODEL ANSWER
Q: vif at block vs chip?
A:
MECHANISM: Block TB: one top sets vif for one DUT instance. Chip TB: wrapper module
sets array of vif or per-agent scoped set from generate loop.
MOTIVATION: Chip integrates block VIPs unchanged — only top wiring and config_db
scope change, not agent internals.
WHEN: Block: set(null, "env.agt*", "vif", vif). Chip: generate N interfaces,
set(null, $sformatf("env.agt[%0d]", i), "vif", vif_arr[i]).
PITFALL: Chip top uses block-level wildcard set — all agents get interface [0].
EXAMPLE: PCIe chip: 4 lanes, 4 vif handles, 4 scoped config_db sets — block VIP
agent code unchanged from single-lane block TB.Key takeaways
Typedef consistency between set/get/driver member is mandatory.
Clocking block in interface reduces separate clk config entries.
Chip TB changes only top wiring scope — not agent get pattern.
Common pitfalls
Typedef mismatch between set and get — runtime get failure.
Chip-level wildcard vif giving all agents same interface index.