← Design Verification Interviews
Interview Question · Code Reading
A Scoreboard Across a Mid-Test Reset
The Question
The interviewer asks
A test asserts reset while a result is inside the DUT, then sends more traffic. This scoreboard ignores reset. What does it report?
function void write_out(incr_result r);
bit [7:0] want;
if (r.reset) return; // reset is the design's business
if (expected.size() == 0) begin
`uvm_error("SB", $sformatf("y=%0d with no input waiting", r.y))
return;
end
want = expected.pop_front();
checked++;
if (r.y != want) begin
mismatches++;
`uvm_error("SB", $sformatf("y=%0d, expected %0d", r.y, want))
end
endfunctionYou 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
It reports a false mismatch. Reset destroyed the result for input 32, but its prediction, 33, stays at the front of the queue. The first result after reset, 81, is compared with 33. Then the prediction 81 waits forever, and the end check reports it missing. The scoreboard must treat reset as an event: count its open predictions as canceled and empty the queue.
The prediction outlives the result it predicted.
Self-Check
Tick each key point you covered in your answer.
What Interviewers Listen For (Mid-Level)
A good mid-level answer traces the queue through the reset. It predicts both errors: the false mismatch and the prediction left at the end.
What Interviewers Listen For (Senior)
A good senior answer also stops the sequences and makes the driver drop its item without item_done(). It checks that the reset really hit work in flight.
Cross-Questions
Where the interviewer goes next. Open a node to practise that follow-up.
WhyWhat IfProve ItBreak ItCompareScale It
- A Scoreboard Across a Mid-Test Reset
-
What IfThe Driver's Item When Reset ArrivesL2 Mid-Level
Asked if they fix only the scoreboard
What should the driver do with the item it was driving when reset arrived?
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
Stop driving it and drop it without calling
item_done().stop_sequences()has already emptied the sequencer's request FIFO. Anitem_done()after that finds no outstanding request, and uvm-core stops the run with a fatal error.What Each Stop Removes, with an Item in the DriverL has queued requests and its third item, L2, is in the driver. Arrows are calls and the item's path. The request FIFO holds the item the driver has taken but not finished. Read the diagram as text
- Test: Calls the stop
- Sequence L: Body in UVM_BODY
- Arbitration queue: L's waiting requests and locks
- Request FIFO: Holds L2 until item_done
- Driver: Working on L2 until 50 ns
- Test → Sequence L: seq.kill()
- Test → Arbitration queue: sqr.stop_sequences()
- Sequence L → Arbitration queue: requests
- Request FIFO → Driver: L2
- Arbitration queue → Request FIFO: flush
A kill removes one sequence's queued work and leaves the driver's item alone.
stop_sequences()also empties the request FIFO under a busy driver, so a lateritem_done()finds nothing.Self-Check
Tick each key point you covered in your answer.
Misconception
"Call
item_done()anyway, so the sequence is not left waiting."The sequence was killed and the request removed.
item_done()with no outstanding request is the fatal errorSQRBADITMDN.Source uvm-core 2020.3.1 (IEEE 1800.2 library) source, seq/uvm_sequencer.svh (item_done: SQRBADITMDN)
-
WhyWhy Item Done After a Flush Is FatalL2 Mid-Level
Why does an
item_done()afterstop_sequences()stop the run instead of being ignored?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
item_done()tells the sequencer that the driver finished the oldest outstanding request.stop_sequences()has removed every request, so nothing is left to finish. The sequencer treats that as a broken handshake and reports a fatal error. So on reset the driver drops its item without callingitem_done().Self-Check
Tick each key point you covered in your answer.
Half-Truth
"Always call
item_done(), or the sequence hangs."Normally yes, but after
stop_sequences()the request is gone. A late call has nothing to match.Source uvm-core 2020.3.1 (IEEE 1800.2 library) source, seq/uvm_sequencer.svh (item_done: SQRBADITMDN)
-
CompareReset as an Event vs a Phase JumpL3 Senior
Compare handling reset inside
run_phasewith jumping back toreset_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
Inside
run_phase, each component watches reset and cleans up its own state. A phase jump re-runs the reset and main phases for the whole phase domain. That only works if every component, including bought VIP, restarts cleanly from those phases. Many teams avoid phase jumping for that reason and treat reset as an event.Two Branches Between Start of Simulation and ExtractArrows show which phase starts after which. In this measured run the test objects in run_phasefor 10 ns and inreset_phasefor 20 ns. It objects inmain_phasefor 30 ns and inshutdown_phasefor 10 ns.Illustrative sequenceCallValueReturnWaiting- Both branches start0 ns (illustrative)
run_phaseandpre_reset_phasestart in the same time step.pre_resethas no objection, so it ends at once andreset_phasestarts.Follow the calls, values and waits
- call start run_phase: start_of_simulation → run_phase
- call start pre_reset: start_of_simulation → pre_reset .. post_reset
- Waiting: run_phase — test objects until 10 ns
- Waiting: pre_reset .. post_reset — reset objection until 20 ns
- run_phase has dropped, but waits10 ns (illustrative)
The test drops its
run_phaseobjection at 10 ns. The run phase does not end yet: it shares its successor, extract, with the schedule, and waits for it.Follow the calls, values and waits
- Waiting: run_phase — objections 0; waits for the schedule
- Released: run_phase
- Reset ends; main begins20 ns (illustrative)
The reset objection drops at 20 ns.
post_resetand the three configure phases have no objection, so they pass in zero time andmain_phasestarts at 20 ns.Follow the calls, values and waits
- call start pre_configure: pre_reset .. post_reset → pre_configure .. post_main
- Waiting: pre_configure .. post_main — main objection until 50 ns
- Released: pre_reset .. post_reset
- Main ends; shutdown begins50 ns (illustrative)
The main objection drops at 50 ns.
post_mainandpre_shutdownpass in zero time, andshutdown_phaseholds until 60 ns.Follow the calls, values and waits
- call start pre_shutdown: pre_configure .. post_main → pre_shutdown .. post_shutdown
- Waiting: pre_shutdown .. post_shutdown — shutdown objection until 60 ns
- Released: pre_configure .. post_main
- Both branches end60 ns (illustrative)
The shutdown objection drops at 60 ns. The run phase and
post_shutdownboth end at 60 ns, and extract starts.Follow the calls, values and waits
- return post_shutdown ended: pre_shutdown .. post_shutdown → extract
- return run_phase ended: run_phase → extract
- Released: pre_shutdown .. post_shutdown
- Released: run_phase
Read the diagram as text
- start_of_simulation: Last zero-time step
- run_phase: Objection 0-10 ns
- pre_reset .. post_reset: reset objection 0-20 ns
- pre_configure .. post_main: configure takes 0 ns; main 20-50 ns
- pre_shutdown .. post_shutdown: shutdown objection 50-60 ns
- extract: Starts when both branches end
- start_of_simulation → run_phase: starts at 0
- start_of_simulation → pre_reset .. post_reset: starts at 0
- pre_reset .. post_reset → pre_configure .. post_main: ends at 20
- pre_configure .. post_main → pre_shutdown .. post_shutdown: ends at 50
- pre_shutdown .. post_shutdown → extract: ends at 60
- run_phase → extract: ends at 60
The run phase ends at 60 ns, although its own objection dropped at 10 ns.
Self-Check
Tick each key point you covered in your answer.
What Interviewers Listen For (Senior)
A good senior answer names the condition for a phase jump: every component must support running its phases again. It treats reset as an event when bought VIP cannot do that.
- Both branches start0 ns (illustrative)
-
Break ItA Reset Test That Tests No ResetL2 Mid-LevelL3 Senior
How could a reset test pass without testing reset at all?
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
If reset arrives when nothing is in flight, the scoreboard has nothing to cancel, and even the broken scoreboard passes. Check that at least one prediction was canceled and one result was checked after reset. A ledger such as inputs = checked + canceled makes this visible in every run.
Accepted Work and an Offered Item Need Different TreatmentThis incrementer discards unfinished results on reset. The scoreboard cancels accepted work; the driver abandons an offer that never transferred. Illustrative sequenceCallValueReturnWaiting- Accept and predict45 ns (illustrative)
The input monitor observes 32 being accepted. The model predicts 33, so accepted work has an entry in the scoreboard.
Follow the calls, values and waits
- data expected 33: Accepted x = 32 → Expected y = 33
- Waiting: Expected y = 33 — Waiting for result 33
- Distinguish the offer50 ns (illustrative)
The driver is offering 48 when reset rises. No transfer accepted 48, so it creates no prediction and contributes nothing to the accepted count.
Follow the calls, values and waits
- Waiting: Offered x = 48 — No acceptance yet
- Apply this reset rule55 ns (illustrative)
Reset discards the pending DUT result. The scoreboard cancels 33 once; the driver abandons 48 while the test flushes the sequencer.
Follow the calls, values and waits
- data expected 33: Expected y = 33 → Canceled: 1
- data offer 48: Offered x = 48 → Drop the offer
- Released: Expected y = 33
- Released: Offered x = 48
- Demonstrate recovery85 ns (illustrative)
After reset falls at 70 ns, a new item 80 is accepted.
Follow the calls, values and waits
- data new item 80: Drop the offer → New x = 80
- Check the new result105 ns (illustrative)
Its result 81 is checked at 105 ns. Neither cancellation nor dropping 48 counts as a successful comparison.
Read the diagram as text
- Accepted x = 32: 45 ns: valid and ready are high
- Expected y = 33: One result still owed
- Canceled: 1: 55 ns: remove expected 33
- Offered x = 48: No ready/valid transfer
- Drop the offer: Lower valid; no item_done after flush
- New x = 80: Accepted at 85 ns; 81 checked at 105 ns
- Accepted x = 32 → Expected y = 33: predict
- Expected y = 33 → Canceled: 1: reset
- Offered x = 48 → Drop the offer: reset
- Drop the offer → New x = 80: restart
Arrows show bookkeeping and restart actions. Together with 16 → 17 before reset, the final ledger is 3 accepted = 2 checked + 1 canceled. Offered 48 is outside that ledger.
Self-Check
Tick each key point you covered in your answer.
- Accept and predict45 ns (illustrative)
-
Prove ItSolve U10.2.1: The Scoreboard That Remembered Through ResetSimulator-graded
Show it, don't just say it: this Silicon Lab problem is graded by the simulator.
-
Scale ItIndependent Reset DomainsL3 SeniorL4 Staff
Scale it: a chip has three reset domains that reset independently. How does the bench handle reset now?
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
Each agent and scoreboard listens to the reset of its own domain. A reset in one domain cancels only the predictions for traffic inside that domain. Traffic that crosses domains needs a written rule: is a request lost, retried or completed? Put that rule in the test plan and check it.
Self-Check
Tick each key point you covered in your answer.
What Interviewers Listen For (Staff)
A good staff answer first asks the architects for the rule on traffic that crosses reset domains. Then it maps each scoreboard to one reset domain.
What People Get Wrong
Common wrong answers and why they fail. Run It shows the wrong belief failing on a real simulator.
Misconception
"Reset is the design's business; the scoreboard does not need to know."
The design drops what it held, but the scoreboard still expects it. The twin compares the first result after reset with a prediction from before it.
Run It
The lesson U10.2 bench with a scoreboard that ignores reset.
35 ns scoreboard y=17 checked 50 ns test reset on 55 ns driver reset: drops x=48, no item_done 70 ns test reset off checked 2, mismatches 1, still waiting 1 FAIL: the scoreboard kept the prediction for a result that reset destroyedSee the Fix
`timescale 1ns/1ns
`include "uvm_macros.svh"
import uvm_pkg::*;
// The incrementer from U7 with a reset. It captures x at edge k (valid and ready both 1), is busy
// for two edges, and drives y = x + 1 with out_valid after edge k+1; monitors see it at edge k+2.
// Reset clears the busy count and drops a result still inside. STUCK_AFTER > 0 makes ready stay
// low for good after that many accepts (a hung design).
interface incr_if (input logic clk);
logic rst = 0;
logic valid = 0;
logic [7:0] x = 0;
logic ready;
logic out_valid = 0;
logic [7:0] y = 0;
endinterface
module incr_pipe #(parameter int STUCK_AFTER = 0) (incr_if bus);
logic [1:0] busy = 0;
logic staged = 0;
logic [7:0] stage = 0;
int taken = 0;
assign bus.ready = (busy == 0) && !bus.rst && !(STUCK_AFTER > 0 && taken >= STUCK_AFTER);
always @(posedge bus.clk) begin
bus.out_valid <= staged && !bus.rst;
bus.y <= stage;
staged <= bus.valid && bus.ready;
stage <= bus.x + 1;
if (bus.rst) busy <= 0;
else if (bus.valid && bus.ready) begin busy <= 2; taken <= taken + 1; end
else if (busy != 0) busy <= busy - 1;
end
endmodule
function automatic void log_event(string who, string what);
$display("%3d ns %-11s%s", $time, who, what);
endfunction
class incr_item extends uvm_sequence_item;
`uvm_object_utils(incr_item)
bit [7:0] x;
function new(string name = "incr_item"); super.new(name); endfunction
endclass
// What the monitor sees coming out; reset = 1 marks an edge with reset held.
class incr_result extends uvm_sequence_item;
`uvm_object_utils(incr_result)
bit [7:0] y;
bit reset;
function new(string name = "incr_result"); super.new(name); endfunction
endclass
// Sends the values in the queue, one item each.
class incr_seq extends uvm_sequence #(incr_item);
`uvm_object_utils(incr_seq)
bit [7:0] values[$];
string lane = "";
function new(string name = "incr_seq"); super.new(name); values = '{16, 32, 48}; endfunction
task body();
foreach (values[i]) begin
incr_item it = incr_item::type_id::create("it");
start_item(it);
it.x = values[i];
finish_item(it);
end
endtask
endclass
class incr_driver extends uvm_driver #(incr_item);
`uvm_component_utils(incr_driver)
virtual incr_if vif;
function new(string name, uvm_component parent); super.new(name, parent); endfunction
task run_phase(uvm_phase phase);
forever begin
@(negedge vif.clk);
if (vif.rst) begin // no new item while reset is held
vif.valid <= 0;
continue;
end
seq_item_port.try_next_item(req);
if (req == null) begin
vif.valid <= 0;
continue;
end
vif.valid <= 1;
vif.x <= req.x;
do @(posedge vif.clk); while (!vif.ready && !vif.rst);
if (vif.rst) begin // reset: the sequencer has forgotten this item
vif.valid <= 0;
log_event("driver", $sformatf("reset: drops x=%0d, no item_done", req.x));
continue;
end
seq_item_port.item_done();
end
endtask
endclass
class incr_monitor extends uvm_monitor;
`uvm_component_utils(incr_monitor)
virtual incr_if vif;
uvm_analysis_port #(incr_item) in_ap;
uvm_analysis_port #(incr_result) out_ap;
function new(string name, uvm_component parent);
super.new(name, parent);
in_ap = new("in_ap", this);
out_ap = new("out_ap", this);
endfunction
task run_phase(uvm_phase phase);
forever begin
@(posedge vif.clk);
if (vif.rst) begin // reset is part of what happened
incr_result r = incr_result::type_id::create("r");
r.reset = 1;
out_ap.write(r);
continue;
end
if (vif.valid && vif.ready) begin
incr_item t = incr_item::type_id::create("t");
t.x = vif.x;
in_ap.write(t);
end
if (vif.out_valid) begin
incr_result r = incr_result::type_id::create("r");
r.y = vif.y;
out_ap.write(r);
end
end
endtask
endclass
`uvm_analysis_imp_decl(_in)
`uvm_analysis_imp_decl(_out)
class incr_scoreboard extends uvm_component;
`uvm_component_utils(incr_scoreboard)
uvm_analysis_imp_in #(incr_item, incr_scoreboard) in_imp;
uvm_analysis_imp_out #(incr_result, incr_scoreboard) out_imp;
bit [7:0] expected[$];
int inputs, checked, canceled, mismatches;
function new(string name, uvm_component parent);
super.new(name, parent);
in_imp = new("in_imp", this);
out_imp = new("out_imp", this);
endfunction
function void write_in(incr_item t);
inputs++;
expected.push_back(t.x + 1);
endfunction
function void write_out(incr_result r);
bit [7:0] want;
if (r.reset) begin // the fix: the design dropped these results, so drop the predictions
canceled += expected.size();
expected.delete();
return;
end
if (expected.size() == 0) begin
`uvm_error("SB", $sformatf("result y=%0d with no input waiting", r.y))
return;
end
want = expected.pop_front();
checked++;
if (r.y != want) begin
mismatches++;
`uvm_error("SB", $sformatf("y=%0d, expected %0d", r.y, want))
end
else log_event("scoreboard", $sformatf("y=%0d checked", r.y));
endfunction
function void check_phase(uvm_phase phase);
if (expected.size() != 0)
`uvm_error("SB", $sformatf("%0d expected results never arrived", expected.size()))
endfunction
endclass
class reset_test extends uvm_test;
`uvm_component_utils(reset_test)
uvm_sequencer #(incr_item) sqr;
incr_driver drv;
incr_monitor mon;
incr_scoreboard sb;
virtual incr_if vif;
function new(string name, uvm_component parent); super.new(name, parent); endfunction
function void build_phase(uvm_phase phase);
sqr = uvm_sequencer #(incr_item)::type_id::create("sqr", this);
drv = incr_driver::type_id::create("drv", this);
mon = incr_monitor::type_id::create("mon", this);
sb = incr_scoreboard::type_id::create("sb", this);
if (!uvm_config_db #(virtual incr_if)::get(this, "", "vif", vif))
`uvm_fatal("NOVIF", "no virtual interface")
drv.vif = vif;
mon.vif = vif;
endfunction
function void connect_phase(uvm_phase phase);
drv.seq_item_port.connect(sqr.seq_item_export);
mon.in_ap.connect(sb.in_imp);
mon.out_ap.connect(sb.out_imp);
endfunction
task run_phase(uvm_phase phase);
incr_seq first = incr_seq::type_id::create("first");
incr_seq second = incr_seq::type_id::create("second");
second.values = '{80};
phase.raise_objection(this);
fork first.start(sqr); join_none
repeat (5) @(negedge vif.clk);
vif.rst <= 1; // reset in the middle of traffic
log_event("test", "reset on");
@(posedge vif.clk);
sqr.stop_sequences(); // kill the sequences, flush the sequencer
repeat (2) @(negedge vif.clk);
vif.rst <= 0;
log_event("test", "reset off");
second.start(sqr); // fresh traffic after reset
fork
wait (sb.expected.size() == 0);
#300; // give up: a result is still owed
join_any
phase.drop_objection(this);
endtask
function void report_phase(uvm_phase phase);
$display("checked %0d, mismatches %0d, still waiting %0d", sb.checked, sb.mismatches, sb.expected.size());
if (sb.mismatches == 0 && sb.expected.size() == 0)
$display("PASS: reset canceled %0d prediction, and the result after reset matched", sb.canceled);
endfunction
endclass
module tb;
bit clk;
always #5 clk = ~clk;
incr_if bus (clk);
incr_pipe dut (bus);
initial begin
uvm_config_db #(virtual incr_if)::set(null, "uvm_test_top", "vif", bus);
run_test("reset_test");
end
endmodule
Prints: 70 ns test reset off 105 ns scoreboard y=81 checked checked 2, mismatches 0, still waiting 0 PASS: reset canceled 1 prediction, and the result after reset matched UVM_ERROR : 0
Missed Corner
"Kill the sequences on reset and you are done."
Killing sequences stops new stimulus only. The driver may still hold an item, and the scoreboard still holds predictions. Each needs its own reset path.
Source Lesson U10.2 example: the driver drops x=48 and the scoreboard cancels one prediction
Half-Truth
"UVM has a reset phase, so a mid-test reset is handled for you."
reset_phase runs once, before the main phases. A reset during run_phase needs your own handling, or a phase jump that every component must support.