← Design Verification Interviews
Interview Question · Design
A Layered Testbench Before a Methodology
The Question
The interviewer asks
A team wants to move a block from pin-level directed tests to constrained random. Would you build a layered testbench in plain SystemVerilog first, or go straight to UVM? Defend the choice.
You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
Either way the bench needs the same layers. A driver and a monitor own the pins through an interface, a generator makes transactions, and a monitor feeds the scoreboard. Plain SystemVerilog first suits a small block or a team new to classes. Every handshake stays visible, and each layer maps onto a UVM agent later. For reusable IP, or a team that already has UVM in place, go straight to UVM. Otherwise you rebuild its factory, configuration and phasing by hand.
Read the diagram as text
- fifo_generator: directed, then seeded random
- req mailbox: mailbox #(fifo_op), bound 1
- fifo_driver: drives through drv_cb
- fifo: the design under test
- fifo_scoreboard: predicts with exp_q
- obs mailbox: mailbox #(fifo_obs)
- fifo_monitor: samples through mon_cb
- fifo_scenarios: counts the planned cases
- fifo_generator → req mailbox: put(op)
- req mailbox → fifo_driver: get(op)
- fifo_driver → fifo: pins
- fifo → fifo_monitor: pins
- fifo_monitor → obs mailbox: put(o)
- obs mailbox → fifo_scoreboard: check(o)
- obs mailbox → fifo_scenarios: sample(o)
Each layer talks to the next only through a mailbox or the interface, so any one of them can be replaced on its own.
Self-Check
Tick each key point you covered in your answer.
What Interviewers Listen For (Mid-Level)
A good mid-level answer names the layers and what crosses each boundary: pins below the driver, transactions above it. It keeps checking out of the driver.
What Interviewers Listen For (Senior)
A good senior answer makes the choice depend on reuse, team experience and schedule. It states what porting the plain bench to UVM will cost later.
Cross-Questions
Where the interviewer goes next. Open a node to practise that follow-up.
WhyProve ItBreak ItCompareScale It
- A Layered Testbench Before a Methodology
-
WhyWhy the Monitor Feeds the ScoreboardL2 Mid-Level
Why should the scoreboard get its transactions from a monitor instead of from the driver that sent them?
2:30You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
The driver reports what it meant to send; the monitor reports what actually appeared on the pins. A driver bug that drops or corrupts a beat is invisible if the scoreboard trusts the driver. A monitor also works in a passive agent, where no driver exists, so the same checking reuses at subsystem level.
Self-Check
Tick each key point you covered in your answer.
Misconception
"It is the same data, so taking it from the driver saves a component."
It is the same data only when the driver is correct, which is one of the things the bench should not assume.
Source Spear & Tumbush, SystemVerilog for Verification (3rd ed.), ch. 1.10 (PDF p58-62)
-
Break ItA Monitor That Reads at the EdgeL2 Mid-Level
Break it: the monitor reads DUT outputs directly at
@(posedge clk), with no clocking block. What can it get wrong?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 monitor and the DUT flops then run at the same edge. The monitor may read a value before or after another process writes it, so it can log the wrong cycle's data. A clocking block samples its inputs at a fixed point before the edge. Then every read is the value from before the edge.
Self-Check
Tick each key point you covered in your answer.
Misconception
"The monitor only reads, so it cannot race."
A read races with a write in another process at the same time. Their order is not defined, so the read can see either value.
Source IEEE 1800-2017 §4.7
-
CompareWhat UVM Adds to a Layered BenchL2 Mid-LevelL3 Senior
Compare a hand-built layered bench with a UVM one. What do you get from UVM that you would otherwise write yourself?
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
UVM adds a factory, so tests can swap classes without editing the bench. It adds a configuration database and phases with objections for start-up and end of test. It also gives standard TLM ports and one reporting system. The cost is a large library, a learning curve and slower compiles. A plain bench has none of that cost and none of that reuse.
Self-Check
Tick each key point you covered in your answer.
Half-Truth
"UVM makes the testbench find bugs faster."
It organises the bench; the checking, coverage and stimulus quality still decide what is found.
-
Prove ItSolve 7.7.3: Premature Test CompletionSimulator-graded
Show it, don't just say it: this Silicon Lab problem is graded by the simulator.
-
Scale ItReusing a Block Bench at Subsystem LevelL3 SeniorL4 Staff
Two blocks you verified separately are now connected in a subsystem. How much of each block bench do you reuse, and how?
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
At the internal boundary the drivers go away, because the other block drives those pins, so those agents become passive monitors. Their scoreboards and protocol checks keep running unchanged on real traffic. External interfaces keep active agents, and a subsystem scoreboard checks end-to-end behaviour from the outer monitors. Reuse is cheap only if the block benches kept checking out of the drivers.
The Same Block Environment, Twice, in a Subsystem BenchBlock B's input is now block A's output. Arrows into a bus are driving; arrows out of a bus are observing. Illustrative sequenceCallValueReturnWaiting- Configure
The test fills one
sub_env_cfg. The sub env handscfg.blk_atoblk_aandcfg.blk_btoblk_b; block B's agent config saysUVM_PASSIVE.More context
The first two lines of the run show the result: "blk_a UVM_ACTIVE agent builds: mon sqr drv" and "blk_b UVM_PASSIVE agent builds: mon".
Follow the calls, values and waits
- data sub_env_cfg: sub_test_base → sub env
- data cfg.blk_a: sub env → blk_a env (active)
- data cfg.blk_b (passive agent): sub env → blk_b env (passive)
- Drive A15 ns (illustrative)
Only block A's driver touches pins. It puts 16 on
extand the design takes it at 15 ns.More context
Block B has no driver, so nothing else drives the subsystem. Left active, block B builds a driver that takes nothing, and the
LINKcheck reports three results that never arrived.Follow the calls, values and waits
- data x = 16: blk_a env (active) → ext bus
- data x = 16: ext bus → Block A RTL
- Cross35 ns (illustrative)
Block A shows 17 on its result pins. Inside the subsystem that result is block B's input, taken at 35 ns.
More context
At the same edge block A's own comparator logs "35 ns blk_a y=17 matches". One value is A's output and B's input at once.
Follow the calls, values and waits
- data A result 17 = B input: Block A RTL → mid bus
- Observe B's input35 ns (illustrative)
Block B's monitor watches
midand feeds its own predictor and comparator, unchanged from the block bench.More context
B's monitor samples 17 at 35 ns, and its predictor expects 18. Nothing in block B's environment knows that its input came from block A.
Follow the calls, values and waits
- data A result 17 = B input: mid bus → blk_b env (passive)
- Waiting: blk_b env (passive) — expects 18 from block B
- Check B55 ns (illustrative)
B's result, 18, is checked at 55 ns.
More context
The log reads "55 ns blk_b y=18 matches". Each B result arrives 20 ns after the A result that fed it.
Follow the calls, values and waits
- Released: blk_b env (passive)
Read the diagram as text
- sub_test_base: Builds sub_env_cfg once
- sub env: Passes each block its cfg; compares A outputs with B inputs
- blk_a env (active): drv, sqr, mon, pred, cmp
- blk_b env (passive): mon, pred, cmp; no driver
- ext bus: tb.ext, at the subsystem pins
- Block A RTL: Shows y = x + 1
- mid bus: tb.dut.mid, internal
- sub_test_base → sub env: cfg
- sub env → blk_a env (active): cfg.blk_a
- sub env → blk_b env (passive): cfg.blk_b
- blk_a env (active) → ext bus: drives
- ext bus → Block A RTL: x
- Block A RTL → mid bus: result is B input
- mid bus → blk_b env (passive): observed
Two copies of one environment class. What changed is one config field and where the virtual interface points.
Self-Check
Tick each key point you covered in your answer.
What Interviewers Listen For (Staff)
A good staff answer plans block benches for subsystem reuse from the start. It names the rule that makes reuse cheap: checking lives in monitors, and agents can be active or passive.
Wrong Altitude
Proposes writing a fresh subsystem bench and dropping the block checks.
Block-level checks are the cheapest way to locate a failure at subsystem level. Without them, every mismatch becomes an end-to-end search.
- Configure
What People Get Wrong
Common wrong answers and why they fail. Run It shows the wrong belief failing on a real simulator.
Wrong Altitude
"Just use UVM."
At this level the interviewer wants the layers and the trade-off, not a library name. Saying what each layer owns is the answer; UVM is one way to package it.
Half-Truth
"The driver already sees the pins, so it should check the responses too."
The driver may check its own handshake, but data checks belong in a monitor and scoreboard. There they still run when the agent is passive, and they do not share the driver's mistakes.
Buzzword Without Mechanism
Lists "generator, driver, monitor, scoreboard" but cannot say what each one passes to the next.
The point of layering is the boundaries: transactions above the driver, pins below it, observed transactions into the scoreboard.
Missed Corner
Ends the test when the generator has sent its last transaction.
Transactions still inside the DUT are never compared. The twin ends early and leaves three unchecked.
Run It
Eight transactions through a three-stage DUT; the test ends when the generator finishes.
checked 5 of 8, 3 still in the scoreboard FAIL: the test ended with transactions still inside the DUT, so they were never checkedSee the Fix
module tb;
logic clk = 0;
always #5 clk = ~clk;
// A three-stage DUT that adds 1.
logic [7:0] in_d = 0, p1, p2, out_d;
logic in_v = 0, v1 = 0, v2 = 0, out_v = 0;
always @(posedge clk) begin
v1 <= in_v; p1 <= in_d;
v2 <= v1; p2 <= p1;
out_v <= v2; out_d <= p2 + 1;
end
// Scoreboard: expected values, in order.
int exp_q[$];
int checked = 0, errors = 0, e;
always @(posedge clk) if (out_v) begin
e = exp_q.pop_front();
if (out_d != e) errors++;
checked++;
end
initial begin
for (int i = 0; i < 8; i++) begin @(negedge clk); in_v = 1; in_d = i; exp_q.push_back(i + 1); end
@(negedge clk); in_v = 0;
// the fix: drain the scoreboard, with a bound so a hang still ends
for (int t = 0; t < 20 && exp_q.size() != 0; t++) @(posedge clk);
#1 $display("checked %0d of 8, %0d still in the scoreboard", checked, exp_q.size());
if (exp_q.size() != 0) $display("FAIL: the test ended with transactions still inside the DUT, so they were never checked");
else $display("PASS: every transaction was checked before the end");
$finish;
end
endmodule
Prints: checked 8 of 8, 0 still in the scoreboard PASS: every transaction was checked before the end