← Design Verification Interviews
Interview Question · Debug
An Override That Did Nothing
The Question
The interviewer asks
Your error test sets a type override from fifo_driver to err_driver. The log still shows the normal driver. The env builds it with drv = new("drv", this);. Why?
UVM_INFO @ 0: reporter [RNTST] Running test err_test...
uvm_test_top.env.drv is a fifo_driver
UVM_ERROR : 0You 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
Calling new() runs the constructor directly, so the factory never sees the request and cannot substitute anything. Only type_id::create() asks the factory, which checks for overrides before it builds. The override was registered correctly, and nothing warned, because nobody asked for that type. Create every component and object that a test might replace with create().
fifo_driver to err_driver.Read the diagram as text
- env build_phase: Builds drv, declared as fifo_driver
- new(): new("drv", this) runs the constructor directly
- type_id::create: Asks the factory for a fifo_driver
- Factory: Instance overrides first, then type overrides
- fifo_driver: Built: the override is never seen
- err_driver: Built: the type override wins
- env build_phase → new(): the bug
- new() → fifo_driver: constructs
- env build_phase → type_id::create: the fix
- type_id::create → Factory: request
- Factory → err_driver: override found
The override sits in the factory. Only a call that goes through the factory can find it.
Self-Check
Tick each key point you covered in your answer.
What Interviewers Listen For (Junior)
A good junior answer points at the new() call within seconds. It rewrites that line as type_id::create("drv", this).
What Interviewers Listen For (Mid-Level)
A good mid-level answer explains what create does inside: it asks the factory, which checks for overrides. It also adds a review rule or lint check that bans new() for components.
Cross-Questions
Where the interviewer goes next. Open a node to practise that follow-up.
WhyWhat IfProve ItCompare
- An Override That Did Nothing
-
WhyWhat Create Does UnderneathL2 Mid-Level
Why does
type_id::create()see the override whennew()cannot? What happens inside 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
type_idis a small proxy class that the utils macro adds for each registered type. Itscreate()calls the factory with that proxy, the parent and the name. The factory looks for an instance override that matches the full path, then a type override. It builds the winner and casts it back to the requested type.Four Requests to the FactoryA test registers an instance override for one driver and a type override for an item. Arrows show calls: overrides registered, create calls, and the factory's lookups in its two tables. Illustrative sequenceCallValueReturnWaiting- Register firstbuild (illustrative)
err_testregisters both overrides before it callssuper.build_phase. Thethisargument turns"env.port1.drv"intouvm_test_top.env.port1.drv.Follow the calls, values and waits
- call set_inst_override: err_test → Factory
- call set_type_override: err_test → Factory
- Port 0 asks for a driverbuild (illustrative)
The path is
uvm_test_top.env.port0.drv. No instance override matches it, and no type override namesincr_driver, so the factory builds anincr_driver.Follow the calls, values and waits
- call create("drv"): port0 agent → Factory
- call port0.drv? no: Factory → Instance overrides
- call incr_driver? no: Factory → Type overrides
- data incr_driver: Factory → port0 agent
- Port 1 asks for a driverbuild (illustrative)
The path
uvm_test_top.env.port1.drvmatches the instance override. A matching instance override wins, so the factory builds anerr_driver.Follow the calls, values and waits
- call create("drv"): port1 agent → Factory
- call port1.drv? yes: Factory → Instance overrides
- data err_driver: Factory → port1 agent
- An item through the factoryend of elaboration (illustrative)
create("made")matches no instance override, then finds the type override forincr_item. The run printscreate: wrap_item, x=255.Follow the calls, values and waits
- call create("made"): end_of_elaboration → Factory
- call made? no: Factory → Instance overrides
- call incr_item? yes: Factory → Type overrides
- data wrap_item, x=255: Factory → end_of_elaboration
- An item made with newend of elaboration (illustrative)
new("raw")never asks the factory, so no override can reach it. The run printsnew: incr_item, x=0.
Read the diagram as text
- err_test: build_phase
- port0 agent: create("drv", this)
- port1 agent: create("drv", this)
- end_of_elaboration: create("made"), new("raw")
- Factory: instance first, then type
- Instance overrides: uvm_test_top.env.port1.drv
- Type overrides: incr_item: wrap_item
- err_test → Factory: register
- port0 agent → Factory: create
- port1 agent → Factory: create
- end_of_elaboration → Factory: create
- Factory → Instance overrides: path matches?
- Factory → Type overrides: type matches?
The factory decides the class at each create call, from the path and the requested type.
Self-Check
Tick each key point you covered in your answer.
Misconception
"The override edits the class, so even
new()builds the new type."Classes cannot change at run time. The factory only chooses which class to build when it is asked.
Source uvm-core 2020.3.1 (IEEE 1800.2 library) source, base/uvm_registry.svh, uvm_component_registry::create
- Register firstbuild (illustrative)
-
Prove ItSolve U15.2.1: The Poison Test with a Short LedgerSimulator-graded
Show it, don't just say it: this Silicon Lab problem is graded by the simulator.
-
What IfAn Override That Is Not a SubclassL2 Mid-Level
What if the override names a class that is not derived from the requested type?
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 factory builds the override class, then casts it back to the requested type. The cast fails, because the new class is not a subclass. The uvm-core library then stops the run with a fatal error at that
createcall. So an override must name a class derived from the original.Self-Check
Tick each key point you covered in your answer.
Misconception
"An override can name any class with the same fields."
The factory casts the result back to the requested type. A class outside that type's hierarchy fails the cast.
Source uvm-core 2020.3.1 (IEEE 1800.2 library) source, base/uvm_registry.svh (FCTTYP)
-
CompareFactory Override vs a Configuration KnobL2 Mid-Level
Compare a factory override with a configuration knob such as
inject_errors = 1. Which would you use for an error-injecting driver?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
A knob changes values inside one class, so the base driver needs an
iffor every behaviour any test might want. An override swaps in a derived class with new behaviour, leaving the base driver clean. Use knobs for numbers like delays and lengths. Use an override when the behaviour itself changes, such as corrupting parity.Self-Check
Tick each key point you covered in your answer.
Half-Truth
"Knobs are always simpler."
They are simpler at first. After ten tests each add a flag, the base driver is full of branches that every test pays for.
Source Accellera, UVM 1.1 User's Guide, §3.1.2 Defining Control Fields ("Knobs") (PDF p41)
-
What IfAn Override Set in the Run PhaseL1 Junior
What if the test registers the driver override in
run_phaseinstead ofbuild_phase?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 driver was built during the build phase, so it keeps its class. An override registered in
run_phasestill affects objects created later, such as sequence items. So the same line can work for items and silently fail for components.The Rule Must Exist When the Item Is CreatedArrows show calls to the factory, the returned item and its trip to the pins. The first steps follow a test that sets its override in build. The last steps follow a separate run that sets it too late. Illustrative sequenceCallValueReturnWaiting- Install the rulebuild: 0 ns (illustrative)
boundary_testselectsboundary_itembefore the sequence starts.Follow the calls, values and waits
- call override family_item → boundary_item: boundary_test.build → Factory
- Create the selected itemrun: 0 ns (illustrative)
The unchanged sequence requests
family_item. The factory returns aboundary_item; itsprepare()chooses ff.Follow the calls, values and waits
- call create family_item: one_seq.body → Factory
- return boundary_item object: Factory → Created item
- Check the limit15 ns (illustrative)
The monitor observes x=ff, parity=0, y=00 and error=0. The DUT check and the boundary test’s goal both pass.
Follow the calls, values and waits
- data x=ff → y=00: Created item → Observed pins
- Start a fresh late runfault run: 0 ns (illustrative)
This separate run has no override yet. The sequence receives a
family_item;prepare()chooses 10.Follow the calls, values and waits
- call create family_item: one_seq.body → Factory
- return family_item object: Factory → Created item
- Waiting: late test: after start — inside super.exercise() until 20 ns
- The wrong case still worksfault run: 15 ns (illustrative)
x=10 produces y=11 with error=0. That is a correct DUT result, but the test intended to exercise ff.
Follow the calls, values and waits
- data x=10 → y=11: Created item → Observed pins
- A later rule cannot change itfault run: 20 ns (illustrative)
start()returns at 20 ns, then the late test installs its override. The observed input remains 10, socheck_phasereports TEST_GOAL.Follow the calls, values and waits
- call override family_item → boundary_item: late test: after start → Factory
- Released: late test: after start
Read the diagram as text
- boundary_test.build: Install the item override
- one_seq.body: Asks for family_item
- late test: after start: Install the same rule after the work
- Factory: Looks up the rule at create()
- Created item: Its class is fixed at creation
- Observed pins: Monitor samples at 15 ns
- boundary_test.build → Factory: set override
- one_seq.body → Factory: create("item")
- Factory → Created item: new item
- Created item → Observed pins: prepare, drive, observe
- late test: after start → Factory: set override
Both runs use the same environment and sequence. Only the test’s override timing changes.
Self-Check
Tick each key point you covered in your answer.
Misconception
"It will apply at the next phase."
Nothing rebuilds components. Overrides act only at create time.
Source Accellera, UVM 1.1 User's Guide, §6.2.3 (PDF p140)
- Install the rulebuild: 0 ns (illustrative)
What People Get Wrong
Common wrong answers and why they fail. Run It shows the wrong belief failing on a real simulator.
Misconception
"Registering the class with the factory macro is enough for overrides to apply."
Registration lets the factory build the class. The factory still only acts when the code asks it, through create().
Run It
The interview's env and test, with a line that reports which class was built.
uvm_test_top.env.drv is a fifo_driver FAIL: new() never asks the factory, so the type override was ignoredSee the Fix
`timescale 1ns/1ns
`include "uvm_macros.svh"
import uvm_pkg::*;
class fifo_driver extends uvm_driver #(uvm_sequence_item);
`uvm_component_utils(fifo_driver)
function new(string name, uvm_component parent); super.new(name, parent); endfunction
endclass
class err_driver extends fifo_driver; // injects parity errors
`uvm_component_utils(err_driver)
function new(string name, uvm_component parent); super.new(name, parent); endfunction
endclass
class fifo_env extends uvm_env;
`uvm_component_utils(fifo_env)
fifo_driver drv;
function new(string name, uvm_component parent); super.new(name, parent); endfunction
function void build_phase(uvm_phase phase);
drv = fifo_driver::type_id::create("drv", this); // the fix: ask the factory
endfunction
endclass
class err_test extends uvm_test;
`uvm_component_utils(err_test)
fifo_env env;
function new(string name, uvm_component parent); super.new(name, parent); endfunction
function void build_phase(uvm_phase phase);
fifo_driver::type_id::set_type_override(err_driver::get_type());
env = fifo_env::type_id::create("env", this);
endfunction
function void end_of_elaboration_phase(uvm_phase phase);
$display("%s is a %s", env.drv.get_full_name(), env.drv.get_type_name());
if (env.drv.get_type_name() != "err_driver") $display("FAIL: new() never asks the factory, so the type override was ignored");
else $display("PASS: create() asked the factory and got the override");
endfunction
endclass
module tb;
initial run_test("err_test");
endmodule
Prints: uvm_test_top.env.drv is a err_driver PASS: create() asked the factory and got the override
Missed Corner
"Set the override wherever is convenient, even after the env is built."
An override changes only create calls made after it is registered. Components that already exist keep their class.
Source Accellera, UVM 1.1 User's Guide, §6.2.3 Component Overrides (PDF p140-141)
Buzzword Without Mechanism
"The factory is a design pattern for making objects."
That names the pattern without the mechanism. What matters is substitution: a test changes which class create() returns, by type or by instance path.