62 UVM Interview Questions and Answers With Code (2026)
In short: UVM interview questions test whether you understand how a UVM testbench actually works: how the factory builds parts, how uvm_config_db passes settings, how phases and objections start and stop a test, how a sequence item reaches the driver, and how monitors feed scoreboards. Good answers are short, precise and backed by a few lines of code.
- What it is: 62 UVM interview questions and answers grouped by area, from basics to debug and scenario questions, each short enough to say out loud in under a minute.
- What changed in 2026: UVM is still IEEE 1800.2-2020, but Accellera keeps shipping library updates (2020-3.2 is listed for August 2026), and interviewers now ask how you use AI tools in your verification work.
- The most asked topics: factory overrides,
uvm_config_db, phases and objections, the sequencer to driver handshake, analysis ports, active vs passive agents and RAL. - The catch: memorized definitions fail the first follow-up. Interviewers ask “why” and “what breaks if”, so build one small testbench yourself.
- The rule: answer in one sentence first, then add the detail or code only if asked.
Why UVM interview questions still matter in 2026
If you are interviewing for an ASIC or SoC design verification role in 2026, you will get UVM questions. Not maybe. Almost every DV loop has at least one round that walks through a testbench and asks how its pieces talk to each other.
The reason is simple. UVM is the common language of verification teams. The 2022 Wilson Research Group study called Accellera UVM “the predominant standard” for IC/ASIC testbenches, and a Sigasi summary of the 2024 study puts UVM adoption on IC/ASIC projects close to 80%.
Demand for the skill is real too. The 2022 study found demand for IC/ASIC verification engineers growing at a 6.2% CAGR from 2007 to 2022, against about 2.7% for design engineers. On processor projects, 5 verification engineers per designer is not unusual.
And the pressure on teams is rising. The 2024 IC/ASIC trend report (597 participants) found only 14% of projects reached first silicon success, the lowest in two decades. Teams want people who can build and debug a testbench on day one, which is exactly what UVM interviews try to measure.
This page is the 2026 refresh of the original UVM interview questions post on this site. It keeps the classic questions, fixes a few answers that were wrong or outdated, adds debug and scenario questions, and shows how to use AI tools to practice. Every question now has a level tag, and the key answers show real output from Synopsys VCS.
What the industry data says about UVM and verification jobs
| Source | What was reported | How to read it |
|---|---|---|
| Wilson Research Group, 2022 (Siemens) | Accellera UVM is “the predominant standard” for IC/ASIC testbenches | UVM knowledge is a baseline skill, not a bonus |
| Sigasi summary of the 2024 study | UVM close to 80% adoption on IC/ASIC projects; 75% of IC/ASIC projects behind schedule; 47% of verification engineer time spent on debug | Debug questions are not filler. They match how the job is actually spent |
| 2024 IC/ASIC trend report | Only 14% of projects reached first silicon success; n=597 | Teams are under pressure and want engineers who find bugs early |
| Wilson Research Group, 2022, part 8 | Verification engineer demand grew at 6.2% CAGR vs 2.7% for design (2007 to 2022) | Steady hiring demand for DV roles |
| 2026 Functional Verification Study, executive findings (Sep 2026) | 604 participants (320 IC/ASIC, 284 FPGA); first silicon success still declining; most projects behind schedule | The 2024 trend did not reverse in 2026 |
| AI in Functional Verification, 2026 data | 82.8% of 604 participants report AI use beyond evaluation or pilots; only 9.0% say AI is broadly integrated across the flow | Expect a question about how you use AI, and expect follow-ups on how you check its output |
“I have long preached that UVM allows engineers to create modular, reusable, randomized self-checking testbenches.” That is Tom Fitzpatrick of Siemens EDA, who has worked on UVM since its start, writing on Verification Horizons. Those four words, modular, reusable, randomized, self-checking, are a good frame for almost every answer below.
How UVM interviews work, and one picture to keep in your head
Most UVM interviews have three layers. First, definitions (“what is a sequencer?”). Second, mechanics (“what happens between start_item() and item_done()?”). Third, scenarios (“your test ends at time 0, why?”). Freshers get mostly layer one and two. Experienced candidates get mostly layer three.
The fastest way to sound clear in all three layers is to keep one analogy in your head. Think of a UVM testbench as a restaurant kitchen:
- Sequence item: one order slip.
- Sequence: the list of orders for the evening.
- Sequencer: the ticket rail that decides which slip goes to the cook next.
- Driver: the cook who turns a slip into a real dish (pin activity on the DUT), then shouts “done” before taking the next slip.
- Monitor: the person at the pass who writes down every dish that actually leaves the kitchen.
- Scoreboard: the head chef who compares each dish against the recipe.
- Factory: the staffing agency that can send a different cook to the same station without changing the menu.
- config_db: the notice board where the manager pins instructions everyone can read.
Once you see the roles this way, the handshake and the overrides stop feeling abstract. Use the analogy to explain, then switch to the real API names. Interviewers like both.
The UVM testbench diagram interviewers ask you to draw
“Draw a UVM testbench” is one of the most common opening questions. This is the version to draw: test on top, env inside, agents inside the env, analysis paths going sideways to the scoreboard and coverage.
| Component | Base class | Job in one line | Common follow-up |
|---|---|---|---|
| Test | uvm_test | Picks the sequences, config and overrides for one scenario | Why do overrides go in the test’s build_phase? |
| Env | uvm_env | Builds and connects agents, scoreboards and coverage | How do you reuse it at the next level? |
| Agent | uvm_agent | Bundles sequencer, driver, monitor for one interface | Active vs passive? |
| Sequencer | uvm_sequencer #(T) | Arbitrates between sequences, hands items to the driver | lock vs grab? arbitration modes? |
| Driver | uvm_driver #(T) | Turns items into pin wiggles | get_next_item vs get? |
| Monitor | uvm_monitor | Turns pin activity back into items and broadcasts them | Why no checking in the monitor? |
| Scoreboard | uvm_scoreboard | Compares actual against expected | How do you handle out-of-order responses? |
| Coverage | uvm_subscriber #(T) | Samples covergroups from observed items | Where do you sample, and why there? |
For the full build of each part, see typical UVM testbench architecture and the how to build a UVM environment series.
How a UVM test runs, step by step
Many “why” questions become easy once you can narrate one test from start to end. Here is the sequence of events:
- The top module instantiates the DUT and interface, puts the virtual interface into
uvm_config_db, then callsrun_test(). run_test()reads+UVM_TESTNAME, asks the factory to create the test, and names ituvm_test_topunder the implicit rootuvm_top.build_phaseruns top-down: the test sets overrides and config, then creates the env, which creates agents, which create drivers and monitors.connect_phaseruns bottom-up: driver ports connect to sequencer exports, monitor analysis ports connect to scoreboard and coverage imps.end_of_elaboration_phaseandstart_of_simulation_phaserun: a good place to print the topology.run_phasestarts in every component at the same time. The test raises an objection and starts a sequence on the sequencer.- Items flow: sequence to sequencer to driver to pins. The monitor sees the pins and writes items to the scoreboard and coverage.
- The test drops its objection. After any drain time, all run-time phases end.
extract_phase,check_phase,report_phaseandfinal_phaserun. The scoreboard reports leftovers, and the report server prints the error count.
Study by level: which UVM interview questions to learn first
The questions below stay grouped by topic, because real interviews jump between topics. Each one carries a level tag under its heading. If you are short on time, learn by level instead: every number in this table jumps straight to its question.
| Level | Who it is for | Questions | Learn these first |
|---|---|---|---|
| Beginner (19) | Freshers, first DV role | 1, 2, 3, 4, 5, 6, 7, 9, 10, 12, 13, 18, 22, 23, 26, 27, 39, 43, 44 | 2, 10, 13, 22, 26 |
| Intermediate (29) | 1 to 4 years | 8, 11, 14, 15, 17, 19, 20, 24, 28, 29, 30, 31, 34, 35, 36, 37, 40, 41, 42, 46, 47, 50, 51, 52, 53, 54, 55, 56, 57 | 20, 28, 31, 41, 53 |
| Advanced (14) | Senior and lead roles | 16, 21, 25, 32, 33, 38, 45, 48, 49, 58, 59, 60, 61, 62 | 32, 33, 45, 58, 60 |
A tip that works at every level: read the question, answer out loud in one sentence, then check. If a Beginner question needed more than one sentence, come back to it tomorrow.
Several answers below now end with Tested on VCS: real output from Synopsys VCS 2025.06 with UVM 1.2, run on 12 Nov 2026. The test files are small enough to rebuild yourself, which is the best interview prep there is.
Revise one topic group a day. For each question, try to answer out loud before reading the answer, then compare.
UVM interview questions: basics (1 to 9)
1. What is UVM and why is it used?
Level: Beginner
UVM (Universal Verification Methodology) is a standard SystemVerilog class library plus a set of rules for building testbenches. It is standardized as IEEE 1800.2-2020, and Accellera ships the reference library. Teams use it because everyone gets the same structure, so parts can be reused across projects, swapped through the factory and configured without editing code. More in advantages of UVM over plain SystemVerilog.
2. What is the difference between uvm_object and uvm_component?
Level: Beginner
uvm_object | uvm_component | |
|---|---|---|
| Lifetime | Created and thrown away any time during the run | Built once at the start, lives for the whole test |
| Hierarchy | No parent, no fixed place in the tree | Has a parent and a full hierarchical path |
| Phases | No phases | Has build, connect, run and the other phases |
| Examples | Sequence items, sequences, config objects | Driver, monitor, agent, env, test |
| Registration | `uvm_object_utils | `uvm_component_utils |
Constructor shape is a follow-up favorite: an object takes new(string name = ""), a component takes new(string name, uvm_component parent).
3. How is uvm_sequence_item different from uvm_transaction?
Level: Beginner
uvm_sequence_item extends uvm_transaction. It adds what an item needs to travel through a sequencer: a handle to its parent sequence, the sequencer it runs on, and the sequence and transaction IDs used to route responses. Build all stimulus items from uvm_sequence_item.
4. What is the difference between create() and new()?
Level: Beginner
new() always builds exactly the class you name. type_id::create() asks the factory, which may return a derived class if an override is set. Use create() for anything you might want to replace later. More in create vs new.
drv = my_driver::type_id::create("drv", this); // factory can swap it
drv = new("drv", this); // factory is bypassed
5. What is the difference between copy(), clone() and create()?
Level: Beginner
create()builds a new, empty object through the factory.copy(rhs)copies fields fromrhsinto an object that already exists.clone()does both: creates a new object and copies into it. It returns auvm_object, so you$castthe result.
my_item a, b;
a = my_item::type_id::create("a");
b = my_item::type_id::create("b");
b.copy(a); // b must already exist
$cast(b, a.clone()); // new object, then copy
Follow-up: is copy() deep or shallow? It calls your do_copy(), so it is as deep as you write it. If the item holds a handle to another object, copy that object too, or two items will share it. See shallow copy vs deep copy.
6. What is the difference between get_name() and get_full_name()?
Level: Beginner
get_name() returns the short name, for example "drv". get_full_name() returns the path from the top, for example "uvm_test_top.env.agt.drv". Use the full name in messages so you know which of 8 identical drivers printed it.
7. What does print() call, and what is convert2string() for?
Level: Beginner
print() uses a uvm_printer and calls your do_print() (or field macros) to print a formatted table. convert2string() is a plain function you write to return a one-line string, handy inside `uvm_info. The original 2021 version of this post said print() calls convert2string(). It does not; implement both for any item you debug often.
8. Field macros or do_copy/do_compare: which should you use?
Level: Intermediate
Field macros (`uvm_field_int and friends) are quick to write but generate a lot of code and run slower, because every copy, compare and print walks the field list at run time. Many teams write do_copy(), do_compare() and convert2string() by hand for high-traffic items. A good answer: macros for small, low-traffic classes; hand-written methods for items that flow millions of times per test.
9. What is uvm_root, and who is the parent of uvm_test?
Level: Beginner
uvm_root is the implicit top of every UVM hierarchy and the phase controller. You never instantiate it; UVM creates one instance, reachable as uvm_top (or uvm_root::get()). The test is created by run_test() with the name uvm_test_top and its parent is uvm_top. Any component created with a null parent also lands under uvm_top.
UVM interview questions: phases and objections (10 to 17)
10. What are the UVM phases, and in what order do they run?
Level: Beginner
| Group | Phases | Type |
|---|---|---|
| Build | build_phase, connect_phase, end_of_elaboration_phase, start_of_simulation_phase | Functions, zero time |
| Run | run_phase, plus 12 optional run-time phases in parallel: pre_reset to post_shutdown (reset, configure, main, shutdown, each with pre_ and post_) | Tasks, consume time |
| Cleanup | extract_phase, check_phase, report_phase, final_phase | Functions, zero time |
Analogy: putting on a play. Build the stage, connect the lights, raise the curtain (run), then count tickets and write the review (extract, check, report). Read UVM phasing and how UVM phasing is triggered.

11. Why is build_phase top-down while connect_phase is bottom-up?
Level: Intermediate
A parent must exist before it can build its children, so build_phase runs from the test downward. connect_phase runs bottom-up so that every child is fully built and its own ports are wired before the parent connects children together.
Analogy: A manager must be hired before they can hire a team (build, top-down). Each room’s phone line is tested before the switchboard joins the rooms together (connect, bottom-up).
12. Why are some phases functions and others tasks?
Level: Beginner
Functions cannot consume simulation time; tasks can. Building and connecting happen at time zero, so they are functions. Driving a DUT takes clock cycles, so run_phase and the run-time phases are tasks.
13. What is an objection, and why do we need it?
Level: Beginner
An objection is a shared counter that tells UVM “I am still busy, do not end this phase”. A phase ends when the count drops back to zero. Analogy: the last person to leave the office turns off the lights.
task run_phase(uvm_phase phase);
phase.raise_objection(this); // count = 1, phase stays open
seq.start(env.agt.sqr);
phase.drop_objection(this); // count = 0, phase may end
endtask
Forget to raise: the test ends at time 0. Forget to drop: the test hangs until the timeout. Raise objections in the test or in top-level sequences, not in every driver and monitor, because thousands of raise and drop calls slow the run. See how to terminate a UVM test with objections.
14. What is drain time?
Level: Intermediate
Extra time UVM waits after the last objection drops, so in-flight transactions can finish and reach the scoreboard.
phase.get_objection().set_drain_time(this, 100ns);

15. How do you add a simulation timeout?
Level: Intermediate
Use uvm_top.set_timeout() in code or +UVM_TIMEOUT on the command line. The old set_global_timeout() is deprecated.
initial uvm_top.set_timeout(10ms, 1); // 1 = command line may override
// or on the command line: +UVM_TIMEOUT=10000000,YES
16. What is phase_ready_to_end() used for?
Level: Advanced
It is a callback that runs when all objections for a phase have dropped and the phase is about to end. A component can raise an objection again inside it to delay the end, for example until its scoreboard queue is empty. Drop it later from a forked thread.
17. How does a UVM simulation actually end?
Level: Intermediate
Each run-time phase ends when its objection count reaches zero and drain time passes. When all run-time phases are done, UVM runs extract, check, report and final, then calls $finish (unless finish_on_completion is cleared). A sequence can manage its own objection with set_automatic_phase_objection(1), which replaced the old starting_phase pattern. See raise and drop objections automatically.
UVM interview questions: factory and config_db (18 to 25)
18. How do you register a class with the factory, and why?
Level: Beginner
Use `uvm_component_utils(name) for components and `uvm_object_utils(name) for objects (the _param_ versions for parameterized classes). Registration makes type_id::create() work and lets a test replace the class with a derived one without touching the env. See the UVM factory explained.
19. What is a factory override?
Level: Intermediate
It tells the factory: “when someone asks for class A, give them class B instead”. B must extend A. Set it before the object is created, which in practice means in the test’s build_phase before the env is built.
// In the test's build_phase, BEFORE env is created
my_driver::type_id::set_type_override(err_driver::get_type());
env = my_env::type_id::create("env", this);
Analogy: You tell the staffing agency: whenever we ask for a cook, send a pastry chef instead. The kitchen’s code never changes.
20. What is the difference between a type override and an instance override?
Level: Intermediate
A type override replaces every instance of a class. An instance override replaces only objects created at a matching hierarchical path. If both match, the instance override wins.
// Every my_driver in the testbench
my_driver::type_id::set_type_override(err_driver::get_type());
// Only the driver under env.agt_a (path relative to "this")
my_driver::type_id::set_inst_override(err_driver::get_type(), "env.agt_a.drv", this);
Analogy: A type override means every request for a cook gets the pastry chef. An instance override means only station 3 does. If both rules fit station 3, the station rule wins.
Tested on VCS (Synopsys VCS 2025.06, UVM 1.2, 12 Nov 2026): a type override for every drv_a, an instance override for e.agt1.drv, and one component built before either.
early is drv_a
e.agt0.drv is drv_b
e.agt1.drv is drv_c
item, no context is item_a
item, context special is item_b

The last two lines answer Q21: the item created with a context path picked up the instance override, the one without did not. And early stayed drv_a, which is exactly the Q55 trap.
21. Can sequences and sequence items use instance overrides?
Level: Advanced
The old answer was “no, only components”. The precise answer: instance overrides match a path, and components always have one. Objects only match if you create them with a context path, for example my_item::type_id::create("req", null, get_full_name()) inside a sequence. Without a context, only a type override applies.
22. What is uvm_config_db and how do set() and get() work?
Level: Beginner
It is a typed database for passing settings, handles and virtual interfaces down the hierarchy without hard-coding paths.
// set(context, instance path, field name, value)
uvm_config_db#(int)::set(this, "env.agt", "num_pkts", 50);
// get(context, instance path, field name, variable)
if (!uvm_config_db#(int)::get(this, "", "num_pkts", num_pkts))
`uvm_fatal("CFG", "num_pkts not set")
The type parameter must match exactly on set and get, or the get fails silently and returns 0. Prefer one config object per agent over 20 separate ints. Deep dive: uvm_config_db and uvm_resource_db.
Analogy: A notice board. set() pins a note addressed to a path; get() looks for notes addressed to you. The note’s type is part of the address, so a note for int is invisible to someone looking for bit [7:0].
23. How do you pass a virtual interface to the driver?
Level: Beginner
The top module sets it, and each component gets it in build_phase.
// tb_top
initial begin
uvm_config_db#(virtual bus_if)::set(null, "uvm_test_top.*", "vif", bus_if_inst);
run_test();
end
// bus_driver
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if (!uvm_config_db#(virtual bus_if)::get(this, "", "vif", vif))
`uvm_fatal("NOVIF", "virtual interface not set")
endfunction
Why virtual? Classes cannot hold a real interface instance, only a handle to one. Step by step: passing a virtual interface with uvm_config_db and why we need a virtual interface.
24. If two components set() the same field, which value wins?
Level: Intermediate
During build_phase, the setting from the component higher in the hierarchy wins (the test beats the env). After build, or at the same level, the last set() wins. That is why a test can always override env defaults.
Analogy: During planning week (build), the manager’s note beats the team lead’s. After that, the newest note on the board wins.
Tested on VCS (Synopsys VCS 2025.06, UVM 1.2, 12 Nov 2026):
build: env set 2, test set 1 -> get returns 1 (ok=1)
build: get with type bit[7:0] -> ok=0, value=0
run: env set 3 after build -> get returns 3

The middle line is the Q22 warning in action: a get() with the wrong type fails and returns 0, with no error message. Always check the return value.
25. Can a lower component pass a handle up to a higher one through config_db?
Level: Advanced
It works, but it is not the recommended pattern. config_db is meant to flow top-down. To share something upward or sideways, let the parent create it and push it down, or use a TLM connection. Upward config_db traffic makes ordering bugs that only show up when build order changes.
UVM interview questions: sequences, sequencer and driver (26 to 38)
26. What is the difference between a sequence and a sequence item?
Level: Beginner
A sequence item is one transaction, such as one bus write. A sequence is a class whose body() creates, randomizes and sends a series of items, or starts other sequences. The item is the letter; the sequence is the person deciding which letters to write.
27. What are the steps to run a sequence, and is start() blocking?
Level: Beginner
- Create it through the factory.
- Configure or randomize it.
- Call
start()with the target sequencer.start()is blocking; it returns whenbody()finishes.
my_seq seq = my_seq::type_id::create("seq");
if (!seq.randomize()) `uvm_error("RAND", "seq randomize failed")
seq.start(env.agt.sqr);
28. How does an item travel from a sequence to the driver?
Level: Intermediate
This is the most important handshake in UVM, and the most asked question on this page:
// Sequence side
start_item(req); // 1. wait for the sequencer to grant
if (!req.randomize()) ... // 2. late randomization
finish_item(req); // 3. send, then wait for item_done
// Driver side
seq_item_port.get_next_item(req); // 4. receive the item
drive(req); // 5. wiggle pins
seq_item_port.item_done(); // 6. unblock finish_item()
Full walk-through: UVM sequencer and driver communication.

29. What is the difference between early and late randomization?
Level: Intermediate
Early: randomize first, then start_item(). Late: start_item() first, then randomize. Late is preferred because the item is randomized at the moment it is granted, so constraints can react to the latest DUT or scoreboard state.
Analogy: Early randomization is packing lunch the night before. Late randomization is packing it in the morning, once you know the weather.
30. What do pre_body() and post_body() do? Are they always called?
Level: Intermediate
They run just before and just after body(). They are skipped when the sequence is started with call_pre_post = 0, which is what happens for child sequences started with the `uvm_do family of macros.
31. Compare get_next_item(), try_next_item(), get() and peek().
Level: Intermediate
| Method | Blocks? | Removes item? | Needs item_done()? |
|---|---|---|---|
get_next_item() | Yes | Not until item_done() | Yes |
try_next_item() | No, returns null if nothing is ready | Not until item_done() | Yes, if an item was returned |
get() | Yes | Yes, immediately | No, handshake completes inside get() |
peek() | Yes | No, the same item stays | Must later be followed by get() |
try_next_item() is the one to mention for drivers that must drive idle cycles when no item is waiting.
Analogy: get_next_item() takes a ticket off the rail and holds it until you say done. get() takes it and says done at once. peek() reads it without taking it. try_next_item() glances at the rail and walks away if it is empty.
32. What is the difference between a pipelined and a non-pipelined driver?
Level: Advanced
A non-pipelined driver handles one transaction at a time: the sequence is blocked until the driver finishes driving. A pipelined driver accepts the next item while earlier ones are still in flight, which you need for protocols like AXI where address and data phases overlap.
// Non-pipelined: sequence waits for the whole transfer
forever begin
seq_item_port.get_next_item(req);
drive_transfer(req); // may take many clocks
seq_item_port.item_done();
end
// Pipelined: accept the next item once the address phase is done
forever begin
seq_item_port.get_next_item(req);
drive_addr_phase(req);
fork
begin
bus_item t = req; // keep a private handle per thread
drive_data_phase(t); // runs in the background
end
join_none
seq_item_port.item_done(); // sequence may send the next item now
end
Follow-up: in a pipelined driver, return responses with put_response() once the data phase completes, not in item_done().
33. How does a driver send a response back, and how is it routed?
Level: Advanced
Copy the request’s IDs into the response with set_id_info(), then send it with item_done(rsp) or put_response(rsp). The sequencer uses those IDs to route the response to the right sequence, even when 4 sequences share one sequencer. The sequence collects it with get_response(rsp).
seq_item_port.get_next_item(req);
drive(req);
rsp = bus_item::type_id::create("rsp");
rsp.set_id_info(req); // same sequence and transaction ID
rsp.data = vif.rdata;
seq_item_port.item_done(rsp); // response goes back to the right sequence
Trap: each sequence has a response queue (depth 8 by default). If a sequence never calls get_response(), the queue overflows and UVM reports an error. Either collect every response or switch on use_response_handler(1) and implement response_handler().
Analogy: Each sequence has a mailbox with 8 slots for replies. Never empty it, and the 9th reply bounces.
Tested on VCS (Synopsys VCS 2025.06, UVM 1.2, 12 Nov 2026): a sequence sends 10 items and never calls get_response(), while the driver returns a response for each.
80 driver: R8
UVM_ERROR @ 90: uvm_test_top.sqr@@s [uvm_test_top.sqr.s] Response queue overflow, response was dropped
90 driver: R9
UVM_ERROR @ 100: uvm_test_top.sqr@@s [uvm_test_top.sqr.s] Response queue overflow, response was dropped
The first 8 responses fit, then the 9th and 10th are dropped with an error. With get_response() called after each item, the same run ends with 0 errors.
34. What is the difference between lock() and grab()?
Level: Intermediate
Both give one sequence exclusive use of the sequencer. lock() waits its turn in normal arbitration and then holds the sequencer. grab() jumps the queue and takes the very next slot. Each has a matching release call, and forgetting it blocks every other sequence on that sequencer. Analogy: lock() is booking a meeting room in the normal queue; grab() is the CEO walking straight in. A classic use of grab() is an interrupt service sequence. One catch: grab() cannot break a lock() that is already held. It waits for the lock to be released, then goes ahead of the normal sequences.
Tested on VCS (Synopsys VCS 2025.06, UVM 1.2, 12 Nov 2026): sequence A runs normally, L asks for lock() at 5 ns, and G asks for grab() at 12 ns, with a driver that takes 10 ns per item.
0 driver: A0
5 L: asks for lock
5 L: lock granted
10 driver: L0
12 G: asks for grab
20 driver: L1
30 driver: L2
40 G: grab granted
40 driver: G0
50 driver: G1
60 driver: A1

35. What sequencer arbitration modes exist?
Level: Intermediate
UVM_SEQ_ARB_FIFO (default), UVM_SEQ_ARB_WEIGHTED, UVM_SEQ_ARB_RANDOM, UVM_SEQ_ARB_STRICT_FIFO, UVM_SEQ_ARB_STRICT_RANDOM and UVM_SEQ_ARB_USER. Set with sqr.set_arbitration(UVM_SEQ_ARB_STRICT_FIFO);. Priorities only matter in the weighted and strict modes. See UVM sequence arbitration.
36. What is the difference between m_sequencer and p_sequencer?
Level: Intermediate
m_sequencer is set automatically when a sequence starts. Its type is the generic uvm_sequencer_base, so you cannot reach your own fields through it. p_sequencer is a typed handle you get by adding `uvm_declare_p_sequencer(my_sequencer), which lets the sequence read fields of your custom sequencer such as config handles. Deep dive: m_sequencer vs p_sequencer.
Analogy: m_sequencer is a generic staff badge. p_sequencer is your own named badge, with the keys to your department’s cupboards.
37. What is a virtual sequence?
Level: Intermediate
A sequence that is not tied to one interface. It coordinates sequences on several sequencers, for example “configure through APB, then send traffic through AXI, then read status”. Analogy: an orchestra conductor who plays no instrument but tells each section when to start. Today most teams run virtual sequences on null and pass sequencer handles in, instead of building a virtual sequencer. Read virtual sequences and virtual sequencers.
38. How do you stop all sequences running on a sequencer?
Level: Advanced
Call sqr.stop_sequences(). It kills every sequence on that sequencer, but it does not know whether the driver is in the middle of an item. If the driver later calls item_done() for a killed sequence, you can get a fatal error. Make the driver reset-aware: on reset, stop sequences, finish or drop the current item cleanly, then restart. This is the core of reset testing with phase jump.
UVM interview questions: TLM, agents and scoreboards (39 to 45)
39. What are ports, exports and imps?
Level: Beginner
- Port: the side that calls a method, for example
put()orwrite(). - Imp: the side that implements the method.
- Export: a pass-through that forwards a connection from a parent to a child that holds the imp.
Analogy: the port is the plug on your device, the imp is the power station, and the export is the wall socket that passes power through. Read UVM TLM concepts.

40. How is an analysis port different from a normal TLM port?
Level: Intermediate
| Analysis port | TLM port (put/get) | |
|---|---|---|
| Connections | One to many (0, 1 or many subscribers) | One to one |
| Method | write(), a function, never blocks | put() / get() tasks can block |
| Typical use | Monitor broadcasting to scoreboard and coverage | Passing items between two components |
Follow-up: what if the scoreboard needs to wait inside write()? It cannot, because write() is a function. Put a uvm_tlm_analysis_fifo in between and read it with a blocking get() in run_phase.
41. Show a correct monitor to scoreboard connection.
Level: Intermediate
class bus_monitor extends uvm_monitor;
`uvm_component_utils(bus_monitor)
uvm_analysis_port #(bus_item) ap;
function new(string name, uvm_component parent);
super.new(name, parent);
ap = new("ap", this);
endfunction
// in run_phase, after collecting a transfer: ap.write(item);
endclass
class bus_scoreboard extends uvm_scoreboard;
`uvm_component_utils(bus_scoreboard)
uvm_analysis_imp #(bus_item, bus_scoreboard) imp;
function new(string name, uvm_component parent);
super.new(name, parent);
imp = new("imp", this);
endfunction
function void write(bus_item t); // called for every ap.write()
// compare t against the expected value
endfunction
endclass
// env connect_phase
agt.mon.ap.connect(scb.imp);
Trap: the monitor must create a new item object for every transfer. If it reuses one handle, the scoreboard’s queue ends up holding many pointers to the same, last-written item.

See it run, with three tested fixes, in UVM TLM explained (mistake 1).
42. How does a scoreboard receive from two monitors?
Level: Intermediate
Either use two uvm_tlm_analysis_fifo objects and read them in run_phase, or declare two imp types with `uvm_analysis_imp_decl:
`uvm_analysis_imp_decl(_exp)
`uvm_analysis_imp_decl(_act)
class bus_scoreboard extends uvm_scoreboard;
uvm_analysis_imp_exp #(bus_item, bus_scoreboard) exp_imp;
uvm_analysis_imp_act #(bus_item, bus_scoreboard) act_imp;
function void write_exp(bus_item t); /* push expected */ endfunction
function void write_act(bus_item t); /* compare actual */ endfunction
endclass

43. What is the difference between an active and a passive agent, and how do you set it?
Level: Beginner
An active agent builds a sequencer, driver and monitor, and drives stimulus. A passive agent builds only the monitor and observes. Block-level agents are often reused as passive agents at subsystem and SoC level, where real RTL drives the bus.
// In the env or test
uvm_config_db#(uvm_active_passive_enum)::set(this, "env.agt", "is_active", UVM_PASSIVE);
// In the agent build_phase (super.build_phase reads is_active)
mon = bus_monitor::type_id::create("mon", this);
if (get_is_active() == UVM_ACTIVE) begin
sqr = bus_sequencer::type_id::create("sqr", this);
drv = bus_driver::type_id::create("drv", this);
end
44. What is the difference between a monitor and a scoreboard?
Level: Beginner
The monitor observes: it turns pin activity into transactions and broadcasts them. The scoreboard judges: it compares what was observed against what was expected. Keep checking out of the monitor (beyond protocol checks) so the monitor can be reused anywhere, including as a passive agent at SoC level.
45. How do you build a scoreboard for out-of-order responses?
Level: Advanced
Key the expected items by an ID instead of a single queue. For AXI, use an associative array of queues indexed by transaction ID: order is kept within an ID but not across IDs. At check_phase, report anything still waiting, because a missing response is a bug too.
UVM interview questions: RAL (46 to 49)
46. What is UVM RAL, and what is frontdoor vs backdoor access?
Level: Intermediate
The Register Abstraction Layer is a model of the DUT’s registers and memories. Tests call reg.write() and reg.read() instead of building bus transactions by hand, so the same test works whether the registers sit behind APB, AXI or a custom bus.
- Frontdoor: the access goes over the real bus through an adapter. Slower, but it tests the bus path and decode logic.
- Backdoor: the access reads or writes the RTL register directly through its HDL path, in zero time. Fast, good for setup and end-of-test checks, but it skips the bus.
Read UVM RAL explained simply.
Analogy: Frontdoor is posting a letter through the mail room. Backdoor is walking into the office and changing the file yourself.
47. What are the desired and mirrored values, and what do set(), update(), mirror() and predict() do?
Level: Intermediate
| Method | What it does | Touches the DUT? |
|---|---|---|
set() | Changes the desired value in the model only | No |
update() | Writes to the DUT every register whose desired value differs from the mirror | Yes |
write() / read() | Real access; mirror updated from the result | Yes |
mirror() | Reads the DUT and optionally checks against the mirror (UVM_CHECK) | Yes |
predict() | Sets the mirror to a value you know the DUT now holds | No |
peek() / poke() | Backdoor read and write | Yes, through HDL path |
The desired value is what you want the register to hold. The mirrored value is what the model believes the DUT holds right now. Only set() makes the two differ: predict(), and every access that updates the model, sets both.
Tested on VCS (Synopsys VCS 2025.06, UVM 1.2, 12 Nov 2026): a register model with no bus, using only set() and predict().
after reset desired=0x00 mirrored=0x00 needs_update=0
set(0x5A) desired=0x5a mirrored=0x00 needs_update=1
predict(0x33) desired=0x33 mirrored=0x33 needs_update=0

48. What do the adapter and predictor do?
Level: Advanced
The adapter (uvm_reg_adapter) converts between register operations and bus items with reg2bus() and bus2reg(). The predictor (uvm_reg_predictor) listens to the bus monitor and updates the mirror for every access it sees, including accesses made by sequences that bypass RAL or by other masters such as a CPU at SoC level.
// env connect_phase: explicit prediction
reg_model.default_map.set_sequencer(apb_agt.sqr, apb_adapter);
reg_model.default_map.set_auto_predict(0); // turn off implicit prediction
apb_predictor.map = reg_model.default_map;
apb_predictor.adapter = apb_adapter;
apb_agt.mon.ap.connect(apb_predictor.bus_in); // predict from what really happened
Interview answer in one line: auto prediction trusts the access you made; explicit prediction trusts what the monitor saw. Use explicit prediction whenever anything else can touch the registers.
Analogy: The adapter is a translator between register language and bus language. The predictor is a clerk who watches every letter that actually leaves and updates the ledger.
49. Which built-in register sequences do you know?
Level: Advanced
uvm_reg_hw_reset_seq (checks reset values), uvm_reg_bit_bash_seq (walks 1s and 0s through every writable bit), uvm_reg_access_seq (frontdoor vs backdoor consistency) and uvm_mem_walk_seq for memories. Exclude registers that should not be touched, such as a soft reset register, with the NO_REG_TESTS or NO_REG_BIT_BASH_TEST resource.
UVM interview questions: callbacks and reporting (50 to 52)
50. What is a UVM callback, and how do you add one?
Level: Intermediate
A callback is a hook a component calls at a fixed point, so a test can add behavior without editing the component, for example corrupting a CRC in the driver for an error test.
// 1. Callback class with empty virtual hooks
class drv_cb extends uvm_callback;
`uvm_object_utils(drv_cb)
function new(string name = "drv_cb"); super.new(name); endfunction
virtual task pre_drive(bus_driver drv, bus_item req); endtask
endclass
// 2. In the driver: register the type and call the hook
class bus_driver extends uvm_driver #(bus_item);
`uvm_component_utils(bus_driver)
`uvm_register_cb(bus_driver, drv_cb)
// ... inside the drive loop:
// `uvm_do_callbacks(bus_driver, drv_cb, pre_drive(this, req))
endclass
// 3. In the error test: add a derived callback to one driver
class corrupt_cb extends drv_cb;
`uvm_object_utils(corrupt_cb)
function new(string name = "corrupt_cb"); super.new(name); endfunction
task pre_drive(bus_driver drv, bus_item req);
req.data[0] = ~req.data[0]; // flip one bit
endtask
endclass
// test end_of_elaboration_phase:
// corrupt_cb cb = new("cb");
// uvm_callbacks#(bus_driver, drv_cb)::add(env.agt.drv, cb);
Analogy: A hook on the kitchen wall. The cook always glances at it at the same step, and a test can hang an extra instruction there without retraining the cook.
51. Callbacks or factory override: which do you pick?
Level: Intermediate
Use a factory override when you want to replace a whole behavior (a different driver). Use a callback when you want to add a small hook at a known point, and maybe stack several hooks from different tests. Callbacks cost a little speed on every call, even when none are registered. Read callbacks vs factory.
52. What is a report catcher used for?
Level: Intermediate
A uvm_report_catcher intercepts messages before they print, so you can demote an expected UVM_ERROR to a warning in an error-injection test, or change its action. Example: UVM_ERROR demoter with uvm_report_catcher. Also useful: UVM macros, messaging and reporting.
UVM interview questions: debug (53 to 57)
These are the questions that separate people who have run real regressions from people who have read about them. They also match the data: debug took 47% of verification engineer time in the 2024 study summary cited above.
53. Your test ends at time 0. Why?
Level: Intermediate
No objection was raised in any run-time phase, so UVM saw nothing busy and ended the phase. Common causes: the objection is raised after a #0 or a clock wait, the sequence is started in main_phase but the objection is raised in run_phase of a different component, or the test’s run_phase never ran because of a typo in +UVM_TESTNAME.
54. Your sequence hangs on finish_item(). Why?
Level: Intermediate
The driver never called item_done(), the driver is not connected (drv.seq_item_port.connect(sqr.seq_item_export) is missing), or the agent is passive so no driver exists. A try_next_item() driver that loops without a clock wait can also starve the simulator.
55. Your factory override does nothing. Why?
Level: Intermediate
The class was built with new() instead of create(), the override was set after the component was built, the instance path does not match (print it with get_full_name()), or the replacement does not extend the original. Call uvm_factory::get().print() to see what is registered and overridden.
56. uvm_config_db::get() returns 0. How do you find out why?
Level: Intermediate
Run with +UVM_CONFIG_DB_TRACE to log every set and get. Check three things: the type parameter is identical on both sides (virtual bus_if vs virtual bus_if.drv_mp are different types), the path string matches the getter’s full name, and the field name matches exactly, including case. check_config_usage() at the end of build lists settings that nobody read.
57. Which UVM command-line switches do you use for debug?
Level: Intermediate
| Switch | What it shows |
|---|---|
+UVM_TESTNAME=<test> | Which test to run |
+UVM_VERBOSITY=UVM_HIGH | More `uvm_info messages |
+UVM_OBJECTION_TRACE | Every raise and drop, with the component |
+UVM_PHASE_TRACE | Every phase start and end |
+UVM_CONFIG_DB_TRACE | Every config_db set and get |
+UVM_MAX_QUIT_COUNT=10 | Stop after 10 errors instead of flooding the log |
+UVM_TIMEOUT=<time>,YES | Override the test timeout |
Add uvm_top.print_topology() in end_of_elaboration_phase to confirm what was really built. For a full method, see the practical verification debug guide.
UVM interview questions: advanced and scenario questions (58 to 62)
58. How do you handle a reset in the middle of a test?
Level: Advanced
Two common answers. One: make the driver and monitor reset-aware, so on reset they kill their threads, flush queues and wait for reset to drop, while the scoreboard clears its expected queues. Two: use phase jumping, phase.jump(uvm_reset_phase::get()), to send the run-time phases back to reset. Most teams prefer the first because phase jumping is easy to get wrong across many components. See reset testing using phase jump.
Analogy: A fire drill mid-shift: everyone stops, clears their station, waits for the all-clear, then starts again.
59. How do you handle interrupts in UVM?
Level: Advanced
A monitor or interface thread waits on the interrupt line and triggers a uvm_event (or writes an item). An interrupt service sequence waits for it, then grab()s the sequencer, reads and clears status through RAL, and ungrab()s. Details in how to handle interrupts in UVM.
60. How do you make a block-level env reusable at SoC level?
Level: Advanced
Put every knob in a config object, make every agent switchable to passive, keep checks in scoreboards rather than drivers, never use absolute paths, and let the parent env pass in shared handles (RAL model, clock and reset agents). At SoC level you instantiate the block env, set its agents to passive, and keep its scoreboards and coverage running on real traffic.
61. What changed between UVM 1.2 and IEEE 1800.2, and what is deprecated?
Level: Advanced
IEEE 1800.2 standardized the API and moved a few things around: for example, objections are no longer raised through starting_phase, and the factory and report server are reached through get() methods such as uvm_factory::get(). The current standard is IEEE 1800.2-2020, and Accellera’s latest library on its download page is 2020-3.2 (listed August 2026). Know these swaps:
| Old | Use instead |
|---|---|
set_config_int(), get_config_int() | uvm_config_db#(int)::set() and get() |
set_global_timeout() | uvm_top.set_timeout() or +UVM_TIMEOUT |
task run() | task run_phase(uvm_phase phase) |
phase.phase_done.set_drain_time() | phase.get_objection().set_drain_time() |
starting_phase.raise_objection() | set_automatic_phase_objection(1) or get_starting_phase() |
62. Your regression takes 9 hours. How do you speed it up?
Level: Advanced
Measure first with the simulator profiler. Then the usual wins: run regressions at UVM_LOW verbosity and keep $sformatf() calls inside the `uvm_info macro (the macro checks verbosity before it formats the string), replace field macros on hot items with hand-written methods, avoid raising objections per transaction, avoid wait loops that poll every delta, and kill tests early once coverage stops moving. On the regression side, rank tests by unique coverage and drop the ones that add nothing.
What interviewers check from the RTL and verification side
A UVM interview is not only about classes. Good interviewers check that you can connect the testbench to the RTL it is testing. Expect questions like these:
- Clocking blocks: why drive through a clocking block? It removes race conditions between testbench and RTL by sampling inputs just before the edge (
#1step) and driving outputs just after it. - Reset: what does your driver do while reset is low? It should hold the bus idle, and the monitor should not report transfers.
- Latency: if the DUT returns read data one cycle later, where does the monitor pick it up? This shows whether you understand the protocol, not just the API.
- X checks: where do you catch X on control signals? In interface assertions, so the bug fires at the exact cycle instead of as a scoreboard mismatch 500 cycles later.
- Spec to plan: how do you turn a spec section into checks, coverage and tests? See how to write a verification plan.
Where each interview topic sits in a UVM environment
When an interviewer jumps between topics, it helps to place each question on the diagram above. This table maps the topic to the component that owns it.
| Topic | Lives in | Phase where it matters |
|---|---|---|
| Factory overrides | Test | build_phase, before children are created |
| config_db set | Top module, test, env | Before or during build_phase |
| config_db get | Every component that needs settings | build_phase |
| Port connections | Agent and env | connect_phase |
| Objections | Test or top-level (virtual) sequence | run_phase or run-time phases |
| Sequence handshake | Sequence, sequencer, driver | run_phase |
| RAL model and predictor | Env (built once, shared) | build and connect_phase |
| End-of-test checks | Scoreboard | check_phase and report_phase |
A complete small UVM testbench you should be able to write from memory
Many interviews end with “write a driver” or “sketch a full testbench”. The cleanest way to prepare is to write this once, run it, and break it on purpose. The DUT is a 256 x 32-bit memory with a one-cycle read latency. Everything below fits in one file, and it was run on Synopsys VCS 2025.06 with UVM 1.2 (output below the code).
// ---------------- DUT ----------------
module mem_dut (input logic clk, rst_n, en, we,
input logic [7:0] addr,
input logic [31:0] wdata,
output logic [31:0] rdata);
logic [31:0] mem [256];
always_ff @(posedge clk or negedge rst_n)
if (!rst_n) begin
rdata <= '0;
foreach (mem[i]) mem[i] <= '0;
end else if (en) begin
if (we) mem[addr] <= wdata;
else rdata <= mem[addr]; // data valid one cycle later
end
endmodule
// ---------------- Interface ----------------
interface bus_if (input logic clk);
logic rst_n, en, we;
logic [7:0] addr;
logic [31:0] wdata, rdata;
clocking drv_cb @(posedge clk);
default input #1step output #1;
output en, we, addr, wdata;
input rdata;
endclocking
clocking mon_cb @(posedge clk);
default input #1step;
input en, we, addr, wdata, rdata;
endclocking
endinterface
package mem_pkg;
import uvm_pkg::*;
`include "uvm_macros.svh"
// ---------------- Item ----------------
class bus_item extends uvm_sequence_item;
`uvm_object_utils(bus_item)
rand bit we;
rand bit [7:0] addr;
rand bit [31:0] data;
function new(string name = "bus_item"); super.new(name); endfunction
function string convert2string();
return $sformatf("%s addr=0x%02h data=0x%08h", we ? "WR" : "RD", addr, data);
endfunction
endclass
// ---------------- Sequence ----------------
class rand_rw_seq extends uvm_sequence #(bus_item);
`uvm_object_utils(rand_rw_seq)
rand int unsigned n = 200;
constraint c_n { n inside {[50:500]}; }
function new(string name = "rand_rw_seq"); super.new(name); endfunction
task body();
repeat (n) begin
req = bus_item::type_id::create("req");
start_item(req); // wait for grant
if (!req.randomize() with { addr inside {[0:15], 255}; }) // small window: more read-after-write hits
`uvm_error("RAND", "item randomize failed")
finish_item(req); // wait for item_done
end
endtask
endclass
// ---------------- Driver ----------------
class bus_driver extends uvm_driver #(bus_item);
`uvm_component_utils(bus_driver)
virtual bus_if vif;
function new(string name, uvm_component parent); super.new(name, parent); endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if (!uvm_config_db#(virtual bus_if)::get(this, "", "vif", vif))
`uvm_fatal("NOVIF", "virtual interface not set")
endfunction
task run_phase(uvm_phase phase);
vif.drv_cb.en <= 0;
wait (vif.rst_n === 1);
forever begin
seq_item_port.get_next_item(req);
@(vif.drv_cb);
vif.drv_cb.en <= 1;
vif.drv_cb.we <= req.we;
vif.drv_cb.addr <= req.addr;
vif.drv_cb.wdata <= req.data;
@(vif.drv_cb);
vif.drv_cb.en <= 0; // one transfer every two cycles
seq_item_port.item_done();
end
endtask
endclass
// ---------------- Monitor ----------------
class bus_monitor extends uvm_monitor;
`uvm_component_utils(bus_monitor)
virtual bus_if vif;
uvm_analysis_port #(bus_item) ap;
function new(string name, uvm_component parent);
super.new(name, parent);
ap = new("ap", this);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if (!uvm_config_db#(virtual bus_if)::get(this, "", "vif", vif))
`uvm_fatal("NOVIF", "virtual interface not set")
endfunction
task run_phase(uvm_phase phase);
bus_item t;
forever begin
@(vif.mon_cb);
if (vif.rst_n !== 1 || !vif.mon_cb.en) continue;
t = bus_item::type_id::create("t"); // new object every transfer
t.we = vif.mon_cb.we;
t.addr = vif.mon_cb.addr;
if (t.we) t.data = vif.mon_cb.wdata;
else begin
@(vif.mon_cb); // read data is one cycle later
t.data = vif.mon_cb.rdata;
end
ap.write(t);
end
endtask
endclass
// ---------------- Agent ----------------
typedef uvm_sequencer #(bus_item) bus_sequencer;
class bus_agent extends uvm_agent;
`uvm_component_utils(bus_agent)
bus_sequencer sqr; bus_driver drv; bus_monitor mon;
function new(string name, uvm_component parent); super.new(name, parent); endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
mon = bus_monitor::type_id::create("mon", this);
if (get_is_active() == UVM_ACTIVE) begin
sqr = bus_sequencer::type_id::create("sqr", this);
drv = bus_driver::type_id::create("drv", this);
end
endfunction
function void connect_phase(uvm_phase phase);
if (get_is_active() == UVM_ACTIVE)
drv.seq_item_port.connect(sqr.seq_item_export);
endfunction
endclass
// ---------------- Scoreboard (reference model inside) ----------------
class mem_scoreboard extends uvm_scoreboard;
`uvm_component_utils(mem_scoreboard)
uvm_analysis_imp #(bus_item, mem_scoreboard) imp;
bit [31:0] model [bit [7:0]];
int unsigned n_wr, n_rd, n_err;
function new(string name, uvm_component parent);
super.new(name, parent);
imp = new("imp", this);
endfunction
function void write(bus_item t);
bit [31:0] exp;
if (t.we) begin model[t.addr] = t.data; n_wr++; return; end
n_rd++;
exp = model.exists(t.addr) ? model[t.addr] : '0; // memory resets to 0
if (t.data !== exp) begin
n_err++;
`uvm_error("SCB", $sformatf("%s expected 0x%08h", t.convert2string(), exp))
end
endfunction
function void report_phase(uvm_phase phase);
`uvm_info("SCB", $sformatf("writes=%0d reads=%0d errors=%0d", n_wr, n_rd, n_err), UVM_LOW)
if (n_rd == 0) `uvm_error("SCB", "no reads checked: test proves nothing")
endfunction
endclass
// ---------------- Coverage ----------------
class mem_cov extends uvm_subscriber #(bus_item);
`uvm_component_utils(mem_cov)
bus_item tr;
covergroup cg;
cp_kind : coverpoint tr.we { bins rd = {0}; bins wr = {1}; }
cp_addr : coverpoint tr.addr { bins first = {0}; bins low[] = {[1:15]};
bins last = {255}; }
cp_data : coverpoint tr.data { bins zero = {0}; bins ones = {32'hFFFF_FFFF};
bins other = default; }
x_kind_addr : cross cp_kind, cp_addr;
endgroup
function new(string name, uvm_component parent);
super.new(name, parent);
cg = new();
endfunction
function void write(bus_item t);
tr = t;
cg.sample();
endfunction
endclass
// ---------------- Env ----------------
class mem_env extends uvm_env;
`uvm_component_utils(mem_env)
bus_agent agt; mem_scoreboard scb; mem_cov cov;
function new(string name, uvm_component parent); super.new(name, parent); endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
agt = bus_agent::type_id::create("agt", this);
scb = mem_scoreboard::type_id::create("scb", this);
cov = mem_cov::type_id::create("cov", this);
endfunction
function void connect_phase(uvm_phase phase);
agt.mon.ap.connect(scb.imp);
agt.mon.ap.connect(cov.analysis_export);
endfunction
endclass
// ---------------- Test ----------------
class rand_test extends uvm_test;
`uvm_component_utils(rand_test)
mem_env env;
function new(string name, uvm_component parent); super.new(name, parent); endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
env = mem_env::type_id::create("env", this);
endfunction
function void end_of_elaboration_phase(uvm_phase phase);
uvm_top.print_topology();
endfunction
task run_phase(uvm_phase phase);
rand_rw_seq seq = rand_rw_seq::type_id::create("seq");
phase.raise_objection(this);
if (!seq.randomize()) `uvm_fatal("RAND", "seq randomize failed")
seq.start(env.agt.sqr);
phase.drop_objection(this);
endtask
endclass
endpackage
// ---------------- Top ----------------
module tb_top;
import uvm_pkg::*;
import mem_pkg::*;
logic clk = 0;
always #5 clk = ~clk; // 100 MHz
bus_if bif (clk);
mem_dut dut (.clk(clk), .rst_n(bif.rst_n), .en(bif.en), .we(bif.we),
.addr(bif.addr), .wdata(bif.wdata), .rdata(bif.rdata));
initial begin
bif.rst_n = 0;
repeat (5) @(posedge clk);
bif.rst_n = 1;
end
initial begin
uvm_config_db#(virtual bus_if)::set(null, "uvm_test_top.*", "vif", bif);
uvm_top.set_timeout(1ms, 1);
run_test("rand_test");
end
endmodule
Tested on VCS (Synopsys VCS 2025.06, UVM 1.2, 12 Nov 2026): the full file as shown above, with the default rand_test.
UVM_INFO testbench.sv(168) @ 2435: uvm_test_top.env.scb [SCB] writes=62 reads=57 errors=0
--- UVM Report Summary ---
** Report counts by severity
UVM_INFO : 5
UVM_WARNING : 0
UVM_ERROR : 0
UVM_FATAL : 0
The randomized sequence picked 119 items: 62 writes and 57 reads, and every read matched the model. The topology printout (from print_topology() in the test) also shows the driver’s built-in seq_item_port and rsp_port, and the sequencer’s seq_item_export: the two ends of the Q28 handshake.
Ways to use it for interview practice: remove item_done() and watch the hang; set the agent to UVM_PASSIVE and watch the null handle error in the test; move the override after create() and see it ignored. Each broken version is one interview question you will now answer from experience.
Assertion questions that come up in UVM interviews
Interviewers often ask where assertions belong in a UVM testbench. Short answer: protocol rules that are about cycles go in the interface (or in a module attached with bind); rules about data go in the scoreboard. Here are interface assertions for the memory bus above:
// Inside interface bus_if
property p_no_x_ctrl;
@(posedge clk) disable iff (!rst_n)
!$isunknown(en) && (en |-> !$isunknown({we, addr}));
endproperty
a_no_x_ctrl : assert property (p_no_x_ctrl)
else $error("X on en/we/addr");
property p_wdata_known;
@(posedge clk) disable iff (!rst_n) (en && we) |-> !$isunknown(wdata);
endproperty
a_wdata_known : assert property (p_wdata_known);
// The driver promises one transfer every two cycles: check it
a_no_b2b : assert property (@(posedge clk) disable iff (!rst_n) en |=> !en);
// Read data must be known in the cycle after a read
a_rdata_known : assert property (@(posedge clk) disable iff (!rst_n)
(en && !we) |=> !$isunknown(rdata));
c_read_after_write : cover property (@(posedge clk) disable iff (!rst_n)
(en && we) ##2 (en && !we && addr == $past(addr, 2)));
Common follow-ups: immediate vs concurrent assertions (see immediate vs concurrent assertions), what disable iff does during reset, and how to turn assertions off for an error test ($assertoff). More examples in SVA assertions with examples.
Functional coverage questions in UVM interviews
The usual questions: where do you sample coverage, why in a subscriber, and how do you know you are done? Sample from the monitor’s analysis port, never from the sequence, because the sequence knows what you asked for, not what the DUT actually did. The mem_cov class above is the standard pattern.
Second follow-up: “coverage is 100% but you still found a bug at SoC level. How?” Good answers: the coverage model missed a cross (read-after-write to the same address, back-to-back with reset), bins were too wide, or coverage was sampled on intent rather than observed traffic. Coverage is only as good as the plan behind it. See functional coverage options and coverage interview questions.
// A sharper bin set for the same model: track read-after-write to the same address
covergroup raw_cg with function sample(bit hit_same_addr, int unsigned gap);
cp_hit : coverpoint hit_same_addr { bins yes = {1}; }
cp_gap : coverpoint gap { bins b2b = {1}; bins near = {[2:4]}; bins far = {[5:$]}; }
x_raw : cross cp_hit, cp_gap;
endgroup
Checker, monitor and scoreboard strategy interviewers expect
- Monitors stay dumb and complete. They report every transfer, including errors and partial transfers, and do no expected-value checks.
- Protocol checks go in assertions in the interface or a bound checker module, so they fire at the exact cycle.
- Data checks go in the scoreboard, fed by a reference model (a SystemVerilog model, or C through DPI for complex math).
- End-of-test checks are mandatory. In
check_phase, report items still waiting in expected queues. A scoreboard that never fails because it never compared anything is the most common silent bug. - Count what you checked. Print reads, writes and compares in
report_phase; fail the test if the count is zero.
How to answer debug and failure triage questions
When an interviewer says “the test failed, walk me through it”, they want a method, not a guess. A good 5-step answer:
- Read the first error, not the last. Later errors are often echoes.
- Find the time of the first error and the component that reported it (
get_full_name()in every message helps here). - Decide: is it a testbench bug or an RTL bug? Check the monitor’s view of the pins against the waveform at that time.
- Rerun the same seed with higher verbosity,
+UVM_OBJECTION_TRACEor+UVM_CONFIG_DB_TRACEas needed, and waves only for the window that matters. - Write a short root cause and add a check or coverage point so the same class of bug cannot hide again.
This method is covered in depth in the practical verification debug guide and in debugging is an art, not a science.
How AI helps you prepare and practice for UVM interviews
AI is now part of the job, and that shows up in interviews. In the 2026 Wilson Research Group data, 82.8% of 604 participants reported AI use beyond evaluation or pilots, but only 9.0% described it as broadly integrated across the verification flow. So expect a question like “how do you use AI in your work, and how do you know its output is right?”
The vendor tools are moving fast too. Siemens announced the Questa One Agentic Toolkit on March 2, 2026 (early access), with agents for verification planning, lint, CDC and debug. Cadence showed its ChipStack AI Super Agent at COMPUTEX in June 2026, covering verification planning, simulation and debugging. Synopsys announced AgentEngineer on September 28, 2026, with a verification agent aimed at coverage closure and root-cause analysis, and general availability planned for the end of 2026. On the research side, UVM^2 (ICCAD 2025) generated UVM testbenches with an LLM and reported 87.44% code and 89.58% functional coverage on designs up to 1.6K lines.
None of that replaces knowing UVM. If anything, it raises the bar: you must be able to spot when generated code is subtly wrong. Here is how to use a general AI assistant to prepare:
- Mock interviewer: ask it to quiz you one question at a time and push back with follow-ups. This trains the “why” layer.
- Explain it back: paste your own answer and ask what is missing or wrong. Then check its claims against the IEEE 1800.2 LRM or your simulator’s UVM source.
- Broken code drills: ask it to write a UVM driver with one hidden bug, then find the bug yourself before asking for the answer.
- Log triage practice: paste a (non-confidential) UVM log from your own practice testbench and ask it to rank likely causes. Compare with what you find in the waves.
- Coverage holes: give it your covergroup and spec text, and ask which crosses or corner cases are missing.
Prompt 1 (mock interview):
"Act as a senior DV interviewer. Ask me UVM questions one at a time on
phases, objections, factory and config_db. After each answer, ask one
follow-up that tests WHY, then grade me 1 to 5 and say what I missed."
Prompt 2 (find the bug):
"Write a 40-line UVM driver for a valid/ready bus with exactly one bug
that would cause a hang or a missed transfer. Do not tell me the bug.
When I reply with my guess, tell me if I am right and why."
Prompt 3 (review my answer):
"Here is my answer to 'what is the difference between a type override
and an instance override'. List anything technically wrong or missing,
and quote the IEEE 1800.2 class or method names I should mention."
Prompt 4 (log triage):
"Here is a UVM log from my practice testbench. The test ended at time 0
with no errors. List the 5 most likely causes in order, and for each one
tell me which plusarg or print would confirm it."
Prompt 5 (coverage review):
"Here is my covergroup and a short spec of a 256-entry memory with a
one-cycle read latency. Which bins, crosses or transitions are missing
for a sign-off quality coverage model? Explain each in one line."
| Task | Good for AI | Must check by hand |
|---|---|---|
| Learning a concept | Plain explanations, analogies, quick quizzes | Exact method names and defaults against the LRM or UVM source |
| First-draft UVM code | Boilerplate: utils macros, constructors, build and connect | Handshake order, object creation per transfer, phase usage |
| SVA | Draft properties from a timing description | Run them in simulation or formal; check vacuity and reset behavior |
| Covergroups | Suggesting bins and crosses from a spec | Whether bins match the real spec and plan, and are reachable |
| Log triage | Ranking likely causes, suggesting plusargs | The waveform. AI cannot see what really happened |
| Mock interviews | Endless follow-ups, instant feedback | Its grading: it can mark a wrong answer right |
Guardrails that matter, and that interviewers like to hear:
- Never trust AI-written SVA or checkers until simulation or formal shows they fire on a bad case and stay quiet on a good one.
- Never paste confidential RTL, specs or logs into public AI tools. Use the tools your company approves, and follow its policy.
- Check every API name. LLMs mix UVM 1.1, 1.2 and IEEE 1800.2 calls, and invent methods that do not exist.
- Use AI to go faster on what you already understand, not to skip learning it. The interview will find the gap.
For the wider picture of AI across the verification flow, read AI in verification: methodology.
Common mistakes candidates make in UVM interviews
- Reciting definitions with no mechanism. “The sequencer arbitrates” is not an answer. “The sequencer grants
start_item()to one sequence at a time based on its arbitration mode” is. - Using UVM 1.1 answers. Mentioning
set_config_intorstarting_phaseas current practice is a red flag in 2026. - Mixing objects and components. Saying a sequence has a
build_phase, or giving a sequence item a parent. - No end-of-test thinking. Not knowing what happens to items still in flight when objections drop.
- Claiming 100% coverage means done. Coverage measures the plan, and plans have holes.
- Freezing on code. Not being able to write a 20-line driver by hand. Practice the testbench above until you can.
A limitation worth saying out loud: UVM is a methodology for simulation testbenches. It does not replace formal for control logic, or emulation for software-heavy SoC tests. Knowing where UVM stops is a strong senior answer. See formal verification: where to use it and why and Portable Stimulus (PSS) for what sits beside it.
Regression and performance questions
Senior interviews often move from “how does it work” to “how does it run at scale”. Be ready to talk about:
- Seeds: every failing test must be rerunnable with its seed. Log the seed in the first line of every test.
- Test ranking: merge coverage from a full regression, rank tests by unique contribution, and keep a short nightly list plus a full weekly run.
- Failure bucketing: group failures by first error message and component so 300 failures become 4 bugs.
- Speed: profile first; then reduce verbosity, hand-write hot methods, avoid per-item objections and polling loops (question 62 above).
- Pass criteria: zero UVM_ERROR and UVM_FATAL, scoreboard counts above zero, no leftover expected items, and no timeout.
Best practices for preparing UVM interview answers
- Build one small UVM testbench from scratch and run it. Nothing else teaches the handshake as well.
- Answer in one sentence first, then offer detail: “Do you want me to show the code?”
- Use the correct 2026 API names: IEEE 1800.2-2020 calls, not UVM 1.1 ones.
- For every concept, know one way it breaks: a missing
item_done(), a late override, a type mismatch in config_db. - Draw while you talk. A 30-second sketch of test, env, agent and scoreboard makes every later answer clearer.
- Tie answers to real numbers from your projects: how many agents, how many tests, how long a regression took.
- Prepare one debug story with a clear root cause and the check you added afterwards.
- Revise the SystemVerilog basics too: SystemVerilog interview questions come up in the same loop.
Project example: IP-level scenario question
Question: “You verify a UART IP with an APB register interface. A customer found that bytes are dropped when the RX FIFO is full and software reads status at the same time. Your 1,200-test regression passed. Why did UVM miss it, and what do you change?”
A strong answer: the scoreboard compared only bytes that came out, so a dropped byte looked like “nothing to compare”. The RX FIFO (16 entries) was never driven to full with a concurrent APB status read, because the sequences ran RX traffic and register reads in separate tests. Fix it in three places:
- Scoreboard: count bytes sent on the serial line and bytes read through APB; at
check_phase, the counts must match unless an overflow was flagged in the status register. - Virtual sequence: run RX traffic at max baud rate and a polling status sequence in parallel.
- Coverage: cross FIFO level (0, 1 to 14, 15, 16) with APB access type, so the hole shows up as an empty bin.
function void check_phase(uvm_phase phase);
if (n_rx_serial != n_rx_read + n_overflow_flagged)
`uvm_error("SCB", $sformatf("sent=%0d read=%0d overflow=%0d: bytes lost",
n_rx_serial, n_rx_read, n_overflow_flagged))
endfunction
Project example: subsystem-level scenario question
Question: “You have an AXI interconnect with 4 masters and 2 slaves. Each master has a block-level UVM agent. How do you build the subsystem env and the checking?”
A strong answer: reuse the block agents, 4 active masters and 2 active slave responders, all from one config object per agent. Put one scoreboard per slave port that predicts which master’s transaction should arrive, keyed by AXI ID and the ID bits the interconnect adds. Run traffic from a virtual sequence that starts all 4 master sequences in a fork...join, with a knob for address overlap so two masters hit the same slave in the same cycle. Coverage crosses master, slave, burst type and response (OKAY, SLVERR, DECERR).
task body(); // in the subsystem virtual sequence
foreach (m_sqr[i]) begin
automatic int k = i;
fork
begin
axi_rand_seq s = axi_rand_seq::type_id::create($sformatf("m%0d", k));
if (!s.randomize() with { overlap_pct == 30; }) `uvm_error("RAND", "fail")
s.start(m_sqr[k]);
end
join_none
end
wait fork; // all 4 masters done
endtask
Project example: SoC-level scenario question
Question: “At SoC level the CPU runs C firmware. How does your UVM environment fit in, and what do you reuse from block level?”
A strong answer: the CPU drives the buses now, so block agents on internal buses become passive; their monitors, scoreboards and coverage keep running on real traffic. Active UVM agents remain only on the chip pins (for example a UART or SPI model the firmware talks to). The RAL model, maybe 300+ registers across 12 IPs, is built once and shared; its explicit predictor watches the CPU bus monitor so the mirror stays correct when firmware writes registers. Firmware and UVM sync through a mailbox register or a shared memory word that a monitor watches, so a virtual sequence can say “wait until firmware reports DMA configured, then start traffic on the SPI pins”.
Mention the cost too: SoC tests run in hours, not minutes, so most coverage closure happens at IP level, and SoC tests target integration (connectivity, interrupts, clock and reset, end-to-end data paths). See key areas to consider during SoC verification.
A real project story: the candidate who knew every definition
This is a composite story built from patterns seen across many projects and hiring loops, not one specific person.
A candidate with three years of experience answered the first 10 questions perfectly: phases in order, all six arbitration modes, the exact signature of uvm_config_db::set(). Then the interviewer asked: “Your scoreboard reports zero errors on a test that should fail. What do you check first?”
Silence. Then a guess about verbosity. The answer they were looking for was simple: check that the scoreboard compared anything at all. Print the compare count, check the analysis connection in connect_phase, and check that the monitor creates a new item per transfer.
The next candidate had less experience but had built a small testbench at home and broken it on purpose. She answered with “I hit this once: my monitor reused one item handle, so every entry in my queue pointed to the last transfer”. She got the offer.
The pattern repeats across teams: definitions get you through the first 15 minutes, and having debugged real UVM code gets you the job.
Rapid-fire UVM interview questions (one-line answers)
Use these as a 10-minute warm-up before the interview.
- Default sequencer arbitration?
UVM_SEQ_ARB_FIFO. - Which phase runs top-down?
build_phase. All other function phases run bottom-up. - Is
write()a task or function? A function. It must not block. - Base class for a coverage collector?
uvm_subscriber #(T), which providesanalysis_exportandwrite(). - How many run-time phases run in parallel with
run_phase? 12. - What does
`uvm_declare_p_sequencercreate? A typedp_sequencerhandle, cast fromm_sequencer. - Where should overrides be set? In the test’s
build_phase, before creating the env. - How do you pick a test from the command line?
+UVM_TESTNAME=my_test. - What does
uvm_tlm_analysis_fifoadd? An unbounded buffer so a blockingget()can read analysis traffic. - What does
set_id_info()copy? Sequence ID and transaction ID, so the response is routed to the right sequence. - What standard defines UVM today? IEEE 1800.2-2020. SystemVerilog itself is IEEE 1800-2023.
- Which UVM library version is current? Accellera lists 2020-3.2 (August 2026) as its latest release.
These map to the full answers above. For bus-specific practice, see AXI interview questions.
Frequently asked questions about UVM interviews
What are the most important topics for a UVM interview?
The factory and overrides, uvm_config_db, phases and objections, the sequence to driver handshake, TLM and analysis ports, active vs passive agents, and RAL. Most interviews also include one or two debug scenarios, such as a test that ends at time 0 or a sequence that hangs, so prepare those as carefully as the definitions.
How should a fresher prepare for UVM interview questions?
Build one small UVM testbench from scratch, for example for a memory, FIFO or APB slave, and run it. Writing the driver, monitor, scoreboard and one sequence yourself answers half the common questions. Then break it on purpose and fix it, because interviewers love asking what goes wrong and why.
Is UVM still used in 2026?
Yes. UVM is the standard testbench methodology for ASIC verification, defined by IEEE 1800.2-2020, and Accellera released library version 2020-3.2 in August 2026. A 2024 study summary put UVM adoption on IC/ASIC projects close to 80%. The Wilson Research Group study has tracked Python-based flows like cocotb since 2022, but UVM remains the predominant standard.
What is the difference between get_next_item() and get() in UVM?
Both block until an item is ready. get_next_item() leaves the handshake open, so the driver must call item_done() when it finishes. get() completes the handshake immediately, so the sequence’s finish_item() returns before the item is actually driven. Most drivers use get_next_item().
Why does my UVM test end immediately at time 0?
Because no objection was raised in any run-time phase. UVM ends a phase as soon as the objection count is zero. Raise an objection in the test or in the top-level sequence before starting the work, drop it when the work is done, and run with +UVM_OBJECTION_TRACE to confirm.
How many UVM interview questions should I prepare?
Around 50 core questions cover nearly every first and second round, which is why this page has 62. Depth matters more than count: for each one, be able to give a one-line answer, a code snippet and one way it breaks in a real testbench.
Can I use AI to prepare for a UVM interview?
Yes, AI assistants make good mock interviewers and code reviewers, and the 2026 Wilson Research Group data shows most verification engineers now use AI in some form. Check every API name it gives you against the IEEE 1800.2 standard or a real simulator, and never paste confidential company code into public tools.
Summary
UVM interviews in 2026 test the same core ideas as five years ago: the factory, config_db, phases and objections, the sequencer to driver handshake, analysis ports and RAL. What has changed is the depth of the follow-ups and the new question about AI.
The candidates who do best can give a one-line answer, back it with 10 lines of code, and say what breaks if you get it wrong. Build the small testbench on this page, break it on purpose, and you will have most of those answers from your own experience.
Quick revision notes
- Objects are created and discarded; components are built once and have phases.
- Use
type_id::create(), nevernew(), for anything you may override. - Overrides go in the test’s
build_phase, before the env is created. build_phaseis top-down;connect_phaseand the other function phases are bottom-up.- No objection means the test ends at time 0; no drop means it hangs.
- Handshake:
start_item, randomize,finish_item; driverget_next_item, drive,item_done. - Analysis
write()is a function, one to many; use an analysis FIFO to block. - Monitors observe; scoreboards judge; assertions catch cycle-level protocol bugs.
- RAL: desired vs mirrored; explicit predictor when anything else can touch registers.
- config_db type must match exactly; trace with
+UVM_CONFIG_DB_TRACE. - Current standards: IEEE 1800.2-2020 (UVM), IEEE 1800-2023 (SystemVerilog).
Printable UVM interview prep checklist
- [ ] I can draw a UVM testbench (test, env, agent, scoreboard, coverage) in 30 seconds
- [ ] I can list the phases in order and say which are tasks
- [ ] I can explain objections, drain time and timeouts, with code
- [ ] I can set a type and an instance override and say where each goes
- [ ] I can pass a virtual interface with uvm_config_db and debug a failed get()
- [ ] I can write the sequence and driver handshake from memory
- [ ] I can explain pipelined drivers and response routing with set_id_info()
- [ ] I can write a monitor to scoreboard connection and a two-input scoreboard
- [ ] I can explain RAL frontdoor, backdoor, mirror and predictor
- [ ] I have one real debug story with a root cause
- [ ] I have built and broken a small UVM testbench myself
- [ ] I can explain how I use AI tools and how I check their output
Related reading on The Art of Verification
- AI in verification: methodology
- Practical verification debug guide
- Portable Stimulus (PSS) guide
- Typical UVM testbench architecture
- UVM sequencer and driver communication
- The UVM factory explained
- uvm_config_db and uvm_resource_db
- UVM RAL overview
- SystemVerilog interview questions
- Coverage interview questions
Learning path: from first UVM class to senior interview
- SystemVerilog OOP first: inheritance, polymorphism and virtual methods.
- Why UVM exists: advantages of UVM over SystemVerilog and testbench architecture.
- Build an env step by step: how to build a UVM environment.
- Core mechanics: phasing, objections, factory, config_db.
- Stimulus: sequencer and driver, arbitration, virtual sequences.
- Checking and registers: TLM, RAL, callbacks.
- Debug at scale: practical debug guide.
- Beyond UVM: AI in verification and PSS.
Sources and further reading
- IEEE 1800.2-2020, UVM Language Reference Manual (IEEE Standards)
- Accellera UVM downloads: library 2020-3.2 (Aug 2026), 2020-3.1 (Aug 2024)
- Accellera: IEEE 1800-2023 SystemVerilog available through the IEEE GET program
- 2024 Siemens EDA and Wilson Research Group IC/ASIC functional verification trend report (14% first silicon success, n=597)
- Sigasi: summary of the 2024 Wilson Research Group findings (75% behind schedule, 47% debug time, UVM near 80%)
- eeNews Europe: survey shows continued decline in first time right IC design (2024 study)
- 2026 Functional Verification Study: executive findings (Sep 2026, 604 participants)
- AI in Functional Verification: what the 2026 industry data reveals (82.8% and 9.0%)
- 2022 Wilson Research Group study, part 8 (engineer demand and ratios)
- 2022 Wilson Research Group study, part 10 (testbench methodology adoption)
- Tom Fitzpatrick, UVM: the value of flexibility (Verification Horizons, 2016)
- Digital Engineering: Siemens debuts agentic AI in Questa One (March 2026)
- EE Times India: Cadence ChipStack AI Super Agent (June 2026)
- Tom’s Hardware: Synopsys Autopilot platform and AgentEngineer (September 2026)
- UVM^2: an automated LLM-aided UVM machine for RTL verification (arXiv 2504.19959, ICCAD 2025)
- Verification Academy UVM Cookbook
- Doulos UVM resources
- ChipVerify: UVM sequencer

Useful..
Thank you 🙂
Very simple and useful content for verification
Thank you Kala. Really appreciate it.
Appreciate your effort to explain each question’s answers in detail and layman language.
Thanks, Mukund for your kind words. That really means a lot 🙂
Unique set of questions that I have come accross various blogs. Great effort in putting these questions together.
VERY VERY USEFULL