← Design Verification Interviews
Interview Question · Code Writing
Handing the Interface to the Driver
The Question
The interviewer asks
Write the code that gets this interface instance from the top module to the driver.
interface bus_if (input logic clk);
logic valid, ready;
logic [7:0] data;
endinterface
// Get this interface instance, in the top module, to the driver inside
// uvm_test_top.env.agt.drv.You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
In the top module, before run_test, call uvm_config_db #(virtual bus_if)::set(null, "uvm_test_top.env.agt.*", "vif", bus);. In the driver's build_phase, call get(this, "", "vif", vif) with the same type. If it returns 0, stop with uvm_fatal. A class cannot hold an interface instance, only a virtual interface: a handle that points to one.
bus is pin activity through that handle.Read the diagram as text
- bus: bus_if instance, built before time 0
- top module: Calls set before run_test; the scope covers every component in agt
- uvm_config_db: Entry: that scope, field vif, type virtual bus_if
- agt.drv: build_phase: get(this, "", "vif", vif); uvm_fatal if it returns 0
- agt.mon: The same get; samples the pins through vif
- top module → uvm_config_db: set
- uvm_config_db → agt.drv: get returns the handle
- uvm_config_db → agt.mon: get returns the handle
- agt.drv → bus: drives through vif
The interface is static and exists before any class. Classes receive a handle that points to it, never the interface itself.
module tb;
bit clk;
bus_if bus (clk);
dut u_dut (.clk(clk), .valid(bus.valid), .ready(bus.ready), .data(bus.data));
initial begin
uvm_config_db #(virtual bus_if)::set(null, "uvm_test_top.env.agt.*", "vif", bus);
run_test();
end
endmodule
class bus_driver extends uvm_driver #(bus_item);
virtual bus_if vif;
function void build_phase(uvm_phase phase);
if (!uvm_config_db #(virtual bus_if)::get(this, "", "vif", vif))
`uvm_fatal("NOVIF", {"no bus_if for ", get_full_name()})
endfunction
endclassSelf-Check
Tick each key point you covered in your answer.
What Interviewers Listen For (Fresher)
A good fresher answer writes the set and the get with the same type. It explains why a class needs a virtual interface, which is a handle to the real interface.
What Interviewers Listen For (Junior)
A good junior answer scopes the set to one agent and checks the return value of get. It moves the handle into an agent config object.
Cross-Questions
Where the interviewer goes next. Open a node to practise that follow-up.
WhyWhat IfProve ItCompareScale It
- Handing the Interface to the Driver
-
WhyWhy a Class Needs a Virtual InterfaceL0 Fresher
Why can't the driver class just instantiate
bus_ifitself?2:30You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
Interfaces and modules are static: they are built at elaboration, before time 0. Classes are created during simulation. So a class cannot instantiate an interface. It holds a virtual interface, which is a variable that points at an interface instance someone else built.
Each Driver Reaches the Port It Was GivenWithout UVM: arrows from the top module carry a virtual interface handle into a constructor. Arrows from a driver are drives through that handle to real pins. Illustrative sequenceCallValueReturnWaiting- The instances exist first
rd_if port0 (clk);andrd_if port1 (clk);are part of the elaborated design. They exist before time 0 and never move. - Hand each driver its portt=0 (illustrative)
The top module passes
port0tod0andport1tod1. Each constructor stores a handle; no signals are copied.Follow the calls, values and waits
- data handle: port0: tb module → d0: rd_driver
- data handle: port1: tb module → d1: rd_driver
- A driver with no portt=0 (illustrative)
d2is built withnull. Its handle refers to nothing until something assigns it.Follow the calls, values and waits
- data null: tb module → d2: rd_driver
- Waiting: d2: rd_driver — vif == null
- Both drivers sendt=7 (illustrative)
Forked, both drivers wait for the edge at 5 and drive through
vif.cb. With output skew 2, each pin changes at t=7, on that driver's own port.Follow the calls, values and waits
- data rvalid=1, rdata=0a: d0: rd_driver → port0
- data rvalid=1, rdata=1b: d1: rd_driver → port1
- Two ports, two beatst=15 (illustrative)
At the edge at 15 the module prints
port0 carries 0aandport1 carries 1b. - The null check reports
d2.send()checksviffirst and printsdrv2: no interface configured; nothing sentinstead of failing on a null handle.Follow the calls, values and waits
- Waiting: d2: rd_driver — no interface configured
Read the diagram as text
- tb module: knows which port each driver gets
- d0: rd_driver: vif refers to port0
- d1: rd_driver: vif refers to port1
- d2: rd_driver: vif is null
- port0: rd_if instance
- port1: rd_if instance
- tb module → d0: rd_driver: new(.., port0)
- tb module → d1: rd_driver: new(.., port1)
- tb module → d2: rd_driver: new(.., null)
- d0: rd_driver → port0: vif.cb drives
- d1: rd_driver → port1: vif.cb drives
One driver class serves any number of ports. Which pins a driver reaches is decided by the handle it was given.
Self-Check
Tick each key point you covered in your answer.
Misconception
"Virtual means the interface is abstract, like a virtual method."
Here virtual means a reference to a real instance, not an unimplemented one.
Source IEEE 1800-2017 §25.9
- The instances exist first
-
What IfA Virtual Interface That Is Still NullL0 FresherL1 Junior
What if the driver's virtual interface handle is still null when
run_phasestarts?2:30You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
The first access through it is a null access, and the simulation stops there. Usually the
getin build failed and nobody checked its return value. Check the return ofuvm_config_db::get, and calluvm_fatalwith the path when it fails. Then the log names the missing set.Self-Check
Tick each key point you covered in your answer.
Misconception
"If the get fails, UVM stops the test for me."
getjust returns 0 and leaves the handle null. Without a check, the failure appears later, at the first access.Source uvm-core 2020.3.1 (IEEE 1800.2 library) source, base/uvm_config_db.svh
-
CompareGetting the Interface Once per AgentL1 Junior
Compare each component getting the interface itself with the agent getting it once and passing it down.
2:30You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
When each of the driver and monitor calls
get, there are two lookups and two places a path can be wrong. When the agent gets its config object, which holds the handle, it assignsdrv.vifandmon.vifitself. Then only one path must match, and a passive agent simply skips the driver.One Handle in, Two Handles OutOne configuration object per agent, passed down one layer at a time. Each arrow is one setor oneget; agetreturns a handle and leaves the entry in place.Illustrative sequenceCallValueReturnWaiting- Test build_phase
The test fills
chip_env_cfgand its two agent objects, then sets the parent object once, for"env".Follow the calls, values and waits
- data chip_env_cfg handle: chip_test → config db: "env"
- Env build_phase: get
The environment gets the parent object.
Follow the calls, values and waits
- data chip_env_cfg handle: config db: "env" → chip_env
- Env build_phase: set
It sets
cfg.port_afor"port_a"andcfg.port_bfor"port_b", names relative to itself.Follow the calls, values and waits
- data cfg.port_a handle: chip_env → config db: "port_a", "port_b"
- data cfg.port_b handle: chip_env → config db: "port_a", "port_b"
- Agent build_phase
Each agent gets its own object, copies
is_activefrom it and builds its children.Follow the calls, values and waits
- data cfg.port_a handle: config db: "port_a", "port_b" → port_a
- data cfg.port_b handle: config db: "port_a", "port_b" → port_b
- A run-time change5–10 ns (illustrative)
The test clears
checks_onin port_b's object at 5 ns. port_b reads 0 at 10 ns, with no newsetorget.
Read the diagram as text
- chip_test: Creates chip_env_cfg and one incr_agent_cfg per port
- config db: "env": Entry cfg = chip_env_cfg handle
- chip_env: Knows only its own children
- config db: "port_a", "port_b": Entries cfg.port_a and cfg.port_b
- port_a: lane 0, UVM_ACTIVE
- port_b: lane 1, UVM_PASSIVE
- chip_test → config db: "env": set for "env"
- config db: "env" → chip_env: get returns handle
- chip_env → config db: "port_a", "port_b": set, relative names
- config db: "port_a", "port_b" → port_a: get
- config db: "port_a", "port_b" → port_b: get
No layer names a grandchild. Renaming
port_bchanges only the environment.Self-Check
Tick each key point you covered in your answer.
Half-Truth
"The monitor and driver must each get it, for reuse."
Reuse comes from the agent's config object. Child components that look up their own paths are harder to move.
Source Verification Academy, UVM Cookbook, Connections to DUT Interfaces (PDF p72)
- Test build_phase
-
Prove ItSolve 6.4.1: Give Each Driver Its Own BusSimulator-graded
Show it, don't just say it: this Silicon Lab problem is graded by the simulator.
-
Scale ItDriving a DUT Without a Virtual InterfaceL3 Senior
Your bench must also run on an emulator, where class code cannot touch signals directly. How do you split it?
2:30You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
Put all signal activity in a bus functional model inside the interface or a module, with tasks such as
drive(item). The class side calls those tasks through a handle, an abstract class or the virtual interface. On the emulator, that pin-level half is compiled into hardware, and only transactions cross the boundary.Self-Check
Tick each key point you covered in your answer.
Wrong Altitude
"Keep
@(posedge vif.clk)in the driver; the emulator will handle it."For co-emulation the class side must be untimed: clock waits and delays are not allowed there. Timing lives in the synthesizable BFM.
Source Verification Academy, UVM Cookbook, Emulation/SeparateTopLevels (PDF p411)
What People Get Wrong
Common wrong answers and why they fail.
Misconception
"Give the driver class an interface port, like a module."
Classes have no ports. A class can only hold a virtual interface variable that refers to an instance.
Source IEEE 1800-2017 §25.9
Missed Corner
Calls get and ignores its return value.
The handle stays null, and the bench crashes much later at the first vif. access, far from the real cause.
Source Verification Academy, UVM Cookbook, Resources/config db: always check that get succeeded (PDF p140)
Half-Truth
"Put the interface handle in a package variable instead."
It works for one bus. With two instances of the agent, both read the same global, and reuse is gone.