← Design Verification Interviews
Interview Question · Code Writing
The Driver Loop and Item Done
The Question
The interviewer asks
Write the driver loop that takes items from the sequencer. What breaks if item_done() is missing?
class bus_driver extends uvm_driver #(bus_item);
virtual bus_if vif;
task run_phase(uvm_phase phase);
// Write the loop: take an item, drive it on vif, then ...?
endtask
endclassYou 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
Loop forever: call seq_item_port.get_next_item(req), drive the item on the interface, then call seq_item_port.item_done(). get_next_item waits until a sequence's item is granted. item_done tells the sequencer the item is finished, which lets the sequence's finish_item return. Without it, the sequence waits forever in finish_item. The next get_next_item also reports an error every time.
- The sequence asks first0 ns (illustrative)
The sequence calls
start_itemand waits. The driver is keeping the bus idle for two falling edges and has not asked for anything.Follow the calls, values and waits
- call start_item(it): incr_seq.body → Sequencer
- Waiting: incr_seq.body — in start_item: no driver asking
- Waiting: Driver — idle until 20 ns
- The driver asks: grant20 ns (illustrative)
The driver calls
get_next_item. Now a driver is asking, so the sequencer grants the waiting sequence andstart_itemreturns.Follow the calls, values and waits
- call get_next_item(req): Driver → Sequencer
- return grant: Sequencer → incr_seq.body
- Waiting: Driver — in get_next_item
- Released: incr_seq.body
- Released: Driver
- Randomize late, then hand over20 ns (illustrative)
The sequence randomizes x=29 and calls
finish_item. The sequencer passes that same object to the driver, andget_next_itemreturns it.Follow the calls, values and waits
- call finish_item(it): incr_seq.body → Sequencer
- data item 1: x=29: incr_seq.body → Sequencer
- data item 1: x=29: Sequencer → Driver
- Waiting: incr_seq.body — in finish_item until item_done
- Released: Driver
- Drive the pins30 ns (illustrative)
At the next falling edge the driver sets
validandx. Simulation time passes only here, while the sequence waits.Follow the calls, values and waits
- data valid=1, x=29: Driver → Incrementer
- Done: finish_item returns40 ns (illustrative)
The driver reads y=30, clears
validand callsitem_done.finish_itemreturns in the same time step.Follow the calls, values and waits
- data y=30: Incrementer → Driver
- call item_done(): Driver → Sequencer
- return finish_item returns: Sequencer → incr_seq.body
- Released: incr_seq.body
- Item 2 in the same time step40 ns (illustrative)
The driver asks again at once, and the sequence's next
start_itemis granted at 40 ns. In steady state the handshake costs no simulation time.Follow the calls, values and waits
- call get_next_item(req): Driver → Sequencer
- call start_item(it): incr_seq.body → Sequencer
- return grant: Sequencer → incr_seq.body
Read the diagram as text
- incr_seq.body: start_item, randomize, finish_item
- Sequencer: Grants a waiting sequence to an asking driver
- Driver: get_next_item, drive, item_done
- Incrementer: y = x + 1
- incr_seq.body → Sequencer: start_item / finish_item
- Driver → Sequencer: get_next_item / item_done
- Driver → Incrementer: valid, x
- Incrementer → Driver: y
The driver pulls; the sequence never pushes. Each side blocks until the other side acts.
The sequence asks at 0 ns but is granted at 20 ns, when the driver first calls get_next_item.
task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req); // wait for a granted item
@(posedge vif.clk);
vif.valid <= 1; vif.data <= req.data;
do @(posedge vif.clk); while (!vif.ready);
vif.valid <= 0;
seq_item_port.item_done(); // finish_item in the sequence returns
end
endtaskSelf-Check
Tick each key point you covered in your answer.
What Interviewers Listen For (Fresher)
A good fresher answer writes get, drive and done inside a forever loop. It says that item_done() is what lets the sequence move on.
What Interviewers Listen For (Junior)
A good junior answer explains when to use get() instead. It keeps randomization in the sequence, not in the driver.
Cross-Questions
Where the interviewer goes next. Open a node to practise that follow-up.
WhyWhat IfProve ItCompare
- The Driver Loop and Item Done
-
WhyWhy Randomize After Start ItemL1 Junior
Why do sequences randomize the item after
start_item()and not before?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
start_item()returns when the sequencer grants this sequence the driver. Randomizing after that, "late randomization", lets the constraints use the latest state, such as a FIFO level a monitor just reported. Randomizing earlier could pick values that were true when the item was made but are stale when it is driven.Self-Check
Tick each key point you covered in your answer.
Half-Truth
"The order does not matter."
It does not change legality. It changes which state the constraints see, which matters for reactive stimulus.
Source Verification Academy, UVM Cookbook, Sequence API: late randomization (PDF p209)
-
What IfA Randomize That Fails After Start ItemL1 JuniorL2 Mid-Level
What if
randomize()fails afterstart_item()returns? What must the sequence still do?2:30You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
The sequencer has granted this sequence, and the driver waits for the item. If the sequence never calls
finish_item(), the driver waits forever and the test hangs. So check the return value, report an error, and either finish the item or end the test. A failed call leaves the fields at their old values.Self-Check
Tick each key point you covered in your answer.
Misconception
"A failed randomize just sends new legal values anyway."
The fields keep their old values. Sent unchecked, the item may repeat or break the protocol.
Source Lesson 5.1 key points
-
CompareThe uvm_do Macros vs Start ItemL1 Junior
Compare the
uvm_domacros with writingstart_item,randomizeandfinish_itemyourself.2:30You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
The macros hide create, start, randomize and finish in one line. That is short, but you cannot see or change the steps, and a failed randomize is easy to miss. Writing the three calls makes each step visible, so you can check
randomize()and add code in between. Many teams ban the macros for that reason.Self-Check
Tick each key point you covered in your answer.
Misconception
"The macros are faster at run time."
They expand to the same calls. The choice is about readability and control, not speed.
Source uvm-core 2020.3.1 (IEEE 1800.2 library) source, macros/uvm_sequence_defines.svh:
uvm_do isuvm_create plus `uvm_rand_send (start_item, randomize, finish_item) -
What IfThe Handshake on a Pipelined BusL2 Mid-Level
Asked if they mention a pipelined bus
What if the bus is pipelined, with a new address every clock while earlier data is still coming back?
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
Calling
item_doneonly after the data returns would leave the address phase idle. Callitem_done()when the address phase is accepted, so the sequence can send the next item. Return the data later withput_response(), carrying the request's IDs. One thread drives addresses and another collects data.Two Items in Flight, Two Milestones EachArrows are calls and returned transactions. Follow item 1 and item 2: each driver worker thread carries its own item through the address and data phases. Illustrative sequenceCallValueReturnWaiting- Handoff of item 1 (0 ns)
Worker A takes the semaphore key and calls
get(). The sequence'sfinish_itemfor item 1 returns at once, so it starts preparing item 2.Follow the calls, values and waits
- call get(1): Worker A → Address semaphore
- data key: Address semaphore → Worker A
- call get(): Worker A → Sequencer
- data item 1: Sequence: send thread → Sequencer
- data item 1: Sequencer → Worker A
- Waiting: Worker B — waiting for the key
- Released: Sequence: send thread
- Item 1's address accepted (5 ns)
The memory accepts item 1's address phase at the 5 ns edge. Worker A clears
avalid, then returns the key.Follow the calls, values and waits
- data addr 1: Worker A → Memory pins
- return key: Worker A → Address semaphore
- Released: Worker B
- Handoff of item 2 (5 ns)
Worker B takes the key and item 2 and starts its address phase while worker A is in item 1's data phase.
Follow the calls, values and waits
- call get(1): Worker B → Address semaphore
- data key: Address semaphore → Worker B
- call get(): Worker B → Sequencer
- data item 2: Sequence: send thread → Sequencer
- data item 2: Sequencer → Worker B
- Waiting: Worker A — data phase of item 1
- Released: Sequence: send thread
- Completion of item 1 (15 ns)
Worker A reads
rdataafter the data edge, builds a response withset_id_infoand callsput. At the same edge the memory accepts item 2's address.Follow the calls, values and waits
- data rdata 1: Memory pins → Worker A
- return rsp 1: Worker A → Sequence: collect thread
- data addr 2: Worker B → Memory pins
- Released: Sequence: collect thread
- Released: Worker A
- Handoff of item 3 (15 ns)
Worker B returns the key; worker A, free again, takes it and item 3.
Follow the calls, values and waits
- return key: Worker B → Address semaphore
- call get(1): Worker A → Address semaphore
- data key: Address semaphore → Worker A
- call get(): Worker A → Sequencer
- data item 3: Sequence: send thread → Sequencer
- data item 3: Sequencer → Worker A
- Waiting: Worker B — data phase of item 2
- Released: Sequence: send thread
- Serial before completionbefore 15 ns (serial) (illustrative)
In the serial alternative, finish_item stays blocked until the data phase completes at 15 ns.
Follow the calls, values and waits
- data item 1: Sequence: send thread → Sequencer
- Waiting: Sequence: send thread — in finish_item until 15 ns
- Released: Worker A
- Released: Worker B
Read the diagram as text
- Sequence: send thread: start_item, finish_item per item
- Sequencer: One request handshake at a time
- Address semaphore: One key
- Worker A: Item 1: address 0-5 ns, data 5-15 ns
- Worker B: Item 2: address 5-15 ns, data 15-25 ns
- Sequence: collect thread: get_response loop
- Memory pins: Address phase and data phase overlap
- Sequence: send thread → Sequencer: finish_item(item)
- Worker A → Sequencer: get(): handoff of item 1
- Worker B → Sequencer: get(): handoff of item 2
- Worker A → Address semaphore: holds key 0-5 ns
- Worker B → Address semaphore: holds key 5-15 ns
- Worker A → Memory pins: drives item 1
- Worker B → Memory pins: drives item 2
- Worker A → Sequence: collect thread: put(rsp): completion
Handoff (the worker's
get) and completion (itsput) are separate events. The semaphore covers request selection and the address phase only.Self-Check
Tick each key point you covered in your answer.
Misconception
"
item_donemust mean the whole transfer is complete."It means the driver is ready for the next item. On a pipelined bus that point comes before the data.
Source Verification Academy, UVM Cookbook, Driver/Pipelined (PDF p255-258)
- Handoff of item 1 (0 ns)
-
Prove ItSolve U6.1.1: Keep a Two-Clock Memory BusySimulator-graded
Show it, don't just say it: this Silicon Lab problem is graded by the simulator.
-
Prove ItSolve U4.3.1: The Burst Driver That Outran Its ReceiverSimulator-graded
Show it, don't just say it: this Silicon Lab problem is graded by the simulator.
What People Get Wrong
Common wrong answers and why they fail. Run It shows the wrong belief failing on a real simulator.
Misconception
"The next get_next_item() moves on by itself."
The sequencer still waits for item_done. The twin's sequence finishes no items, and every repeated call logs an error.
Run It
A driver loop without item_done, and a 200 ns watchdog so the hang still ends.
t=200 driven=19 finished=0 FAIL: without item_done the sequence waits forever in finish_itemSee the Fix
`timescale 1ns/1ns
`include "uvm_macros.svh"
import uvm_pkg::*;
class bus_item extends uvm_sequence_item;
`uvm_object_utils(bus_item)
rand bit [7:0] data;
function new(string name = "bus_item"); super.new(name); endfunction
endclass
class four_items extends uvm_sequence #(bus_item);
`uvm_object_utils(four_items)
int finished;
function new(string name = "four_items"); super.new(name); endfunction
task body();
repeat (4) begin
req = bus_item::type_id::create("req");
start_item(req);
void'(req.randomize());
finish_item(req);
finished++;
end
endtask
endclass
class bus_driver extends uvm_driver #(bus_item);
`uvm_component_utils(bus_driver)
int driven;
function new(string name, uvm_component parent); super.new(name, parent); endfunction
task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req);
#10 driven++; // drive the pins
seq_item_port.item_done(); // the fix: tell the sequencer this item is finished
end
endtask
endclass
class hs_test extends uvm_test;
`uvm_component_utils(hs_test)
uvm_sequencer #(bus_item) sqr;
bus_driver drv;
function new(string name, uvm_component parent); super.new(name, parent); endfunction
function void build_phase(uvm_phase phase);
sqr = uvm_sequencer #(bus_item)::type_id::create("sqr", this);
drv = bus_driver::type_id::create("drv", this);
endfunction
function void connect_phase(uvm_phase phase); drv.seq_item_port.connect(sqr.seq_item_export); endfunction
task run_phase(uvm_phase phase);
four_items seq = four_items::type_id::create("seq");
phase.raise_objection(this);
fork
seq.start(sqr);
#200; // a watchdog, so a hang still ends
join_any
$display("t=%0t driven=%0d finished=%0d", $time, drv.driven, seq.finished);
if (seq.finished < 4) $display("FAIL: without item_done the sequence waits forever in finish_item");
else $display("PASS: all four items completed the handshake");
phase.drop_objection(this);
endtask
endclass
module tb;
initial run_test("hs_test");
endmodule
Prints: t=40 driven=4 finished=4 PASS: all four items completed the handshake
Half-Truth
"get() and get_next_item() are the same."
get() takes the item and completes the handshake at once, so the sequence moves on before the item is driven. That is fine only when nothing waits for the result.
Source Verification Academy, UVM Cookbook, Driver/Sequence API: get_next_item and get (PDF p213-215)
Wrong Altitude
"Randomize the item in the driver, just before driving it."
Scenario control belongs to the sequence. Randomize between start_item and finish_item, so constraints can depend on the current state.
Source Verification Academy, UVM Cookbook, Sequence API: late randomization (PDF p209)