← Design Verification Interviews

Interview Question · Code Writing

An In-Order Scoreboard

L0 FresherL1 Junioruvmscoreboard

The Question

The interviewer asks

Write a scoreboard for a pipelined DUT whose results leave in the same order as the inputs went in.

Reveal the Model Answer

Give the scoreboard two analysis imps: one for inputs and one for results. On each input, compute the expected result with a reference function and push it onto a queue. On each result, pop the front of the queue and compare. In check_phase, report any expected results still waiting. A result that arrives while the queue is empty is also an error.

Checking Ends After the Work, Then Observation EndsAn in-order scoreboard for an incrementer, following the last input, 48. Prediction and comparison are two roles inside one scoreboard.
Checking ends after the work, then observation endsAn in-order scoreboard for an incrementer, following the last input, 48. Prediction and comparison are two roles inside one scoreboard. observation Accepted input Input monitorpublishes x = 48 inline model Predict write_in computes 48+ 1 queue Expected queue 49 waits for itsobserved result observation Observed output Output monitorpublishes y = 49 comparison Compare write_out checks andcounts a pair test owner Test owns the end Required work, then aquiet window accepted xenqueue 49oldest predictionobserved ychecked countpending count
  1. One obligation remains75 ns (illustrative)

    The final accepted input creates prediction 49. Two earlier pairs have been checked, but this prediction is still pending.

    Follow the calls, values and waits
    1. data x = 48: Accepted input → Predict
    2. data expected 49: Predict → Expected queue
    3. Waiting: Expected queue — 49 is still owed
  2. Close the source80 ns (illustrative)

    The only sequence has ended and the driver returns the bus to idle. The test still owns its objection because one accepted request is unanswered.

    Follow the calls, values and waits
    1. data pending = 1: Expected queue → Test owns the end
    2. Waiting: Test owns the end — waiting for required checks
  3. Finish the comparison95 ns (illustrative)

    The observed 49 meets the oldest prediction, 49. write_out removes the prediction, compares the values and increments checked before it returns.

    Follow the calls, values and waits
    1. data observed 49: Observed output → Compare
    2. data expected 49: Expected queue → Compare
    3. data checked = 3: Compare → Test owns the end
    4. Waiting: Test owns the end — watching two more edges
    5. Released: Expected queue
  4. Close observation120 ns (illustrative)

    The quiet window: monitors keep sampling at 105 and 115 ns, so an extra result would still reach write_out. The test drops its objection at the following falling edge.

    Follow the calls, values and waits
    1. data pending = 0: Expected queue → Test owns the end
    2. data checked = 3: Compare → Test owns the end
    3. Released: Test owns the end
Read the diagram as text
  • Accepted input: Input monitor publishes x = 48
  • Predict: write_in computes 48 + 1
  • Expected queue: 49 waits for its observed result
  • Observed output: Output monitor publishes y = 49
  • Compare: write_out checks and counts a pair
  • Test owns the end: Required work, then a quiet window
  • Accepted input → Predict: accepted x
  • Predict → Expected queue: enqueue 49
  • Expected queue → Compare: oldest prediction
  • Observed output → Compare: observed y
  • Compare → Test owns the end: checked count
  • Expected queue → Test owns the end: pending count

Arrows carry transaction data or completion facts, not connect() calls. A counted comparison can still be a mismatch; reports determine pass/fail.

Predict on input, compare on output, and check the queue at the end.
`uvm_analysis_imp_decl(_in)
`uvm_analysis_imp_decl(_out)
class incr_sb extends uvm_scoreboard;
  `uvm_component_utils(incr_sb)
  uvm_analysis_imp_in  #(incr_item,   incr_sb) in_imp;
  uvm_analysis_imp_out #(incr_result, incr_sb) out_imp;
  bit [7:0] expected[$];
  // new() creates both imps
  function void write_in(incr_item t);
    expected.push_back(t.x + 1);              // the reference model
  endfunction
  function void write_out(incr_result r);
    if (expected.size() == 0) begin
      `uvm_error("SB", $sformatf("y=%0d with no input waiting", r.y))
      return;
    end
    if (r.y != expected.pop_front())
      `uvm_error("SB", $sformatf("y=%0d is wrong", r.y))
  endfunction
  function void check_phase(uvm_phase phase);
    if (expected.size() != 0)
      `uvm_error("SB", $sformatf("%0d results never arrived", expected.size()))
  endfunction
endclass

Self-Check

Tick each key point you covered in your answer.

What Interviewers Listen For (Fresher)

A good fresher answer draws the input stream, the queue and the result stream before writing code. It names the reference function that computes each expected result.

Cross-Questions

Where the interviewer goes next. Open a node to practise that follow-up.

WhyWhat IfProve ItCompare

  1. An In-Order Scoreboard
  2. WhyA Result with Nothing ExpectedL1 Junior

    Why treat a result that arrives with an empty queue as an error, rather than skipping it?

    Reveal the Model Answer

    It means the DUT produced a result nobody asked for, or the input monitor missed a transfer. Both are real bugs. Skipping the result would hide a spurious output and could shift every later comparison.

    Self-Check

    Tick each key point you covered in your answer.

  3. CompareComparing Transactions: Equality vs compare()L1 Junior

    Compare exp == act with exp.compare(act) when the expected and actual items are class objects.

    Reveal the Model Answer

    On class handles, == asks whether both handles point to the same object. Two separate objects with equal fields are not equal under ==. compare() calls the item's do_compare(), which compares the fields you chose. That also lets you leave out fields the DUT may legally change.

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "== on two transactions compares their fields."

    For class handles it compares references. It is true only when both handles name the same object.

    Source IEEE 1800-2017 §8.4

  4. What IfFields the DUT May ChangeL2 Mid-Level

    What if the DUT may legally return a different value in one field, such as a timestamp?

    Reveal the Model Answer

    Leave that field out of do_compare(), or check it against a range instead of one value. Write down in the item why the field is skipped. A silent skip that nobody documents later hides a real bug in that field.

    Self-Check

    Tick each key point you covered in your answer.

  5. Prove ItSolve 7.4.1: FIFO Expected QueueSimulator-graded

    Show it, don't just say it: this Silicon Lab problem is graded by the simulator.

    Open Problem 7.4.1

What People Get Wrong

Common wrong answers and why they fail. Run It shows the wrong belief failing on a real simulator.

Misconception

"One variable can hold the expected value."

A pipeline holds several items at once. The next input overwrites the expected value before the earlier result arrives. The twin, two items deep, reports two false mismatches.

Run It

The scoreboard's two write functions, called in the order a pipeline two items deep produces.

RUNVerilator · simulator service
Edit the code, then run it
Expected: mismatch: y=11, expected 21 mismatch: y=21, expected 31 FAIL: a second input overwrote the expected value before its result arrived
See the Fix
// The scoreboard's two write() functions, called in the order a pipeline two items deep produces them.
class sb;
  bit [7:0] expected[$];              // the fix: a queue, one entry per item in flight
  int mismatches, checked;
  function void write_in(bit [7:0] x);
    expected.push_back(x + 1);
  endfunction
  function void write_out(bit [7:0] y);
    bit [7:0] want;
    if (expected.size() == 0) begin $display("unexpected y=%0d", y); mismatches++; return; end
    want = expected.pop_front();
    checked++;
    if (y != want) begin mismatches++; $display("mismatch: y=%0d, expected %0d", y, want); end
  endfunction
endclass
module tb;
  sb s = new();
  initial begin
    s.write_in(10);  s.write_in(20);
    s.write_out(11); s.write_in(30);
    s.write_out(21); s.write_out(31);
    if (s.mismatches == 0 && s.expected.size() == 0)
      $display("PASS: %0d results checked in order, none left waiting", s.checked);
  end
endmodule

Prints: PASS: 3 results checked in order, none left waiting

Missed Corner

"If no mismatch fired, every result was checked."

A DUT that drops its last result causes no comparison at all. Only an end-of-test check on the queue size finds the missing result.

Source Lesson U7.3 example: check_phase reports the results still waiting (uvm-core 2020.3.1 on Verilator 5.052)

Wrong Altitude

"Compare inside the monitor; it sees the result anyway."

Then the monitor needs the reference model, and every passive copy at SoC level carries a check it cannot configure. Keep the monitor a reporter and compare in one place.

Learn It, Then Prove It