← Design Verification Interviews

Interview Question · Concept

Three Items, One Object

L1 JuniorL2 Mid-Levelsystemverilogmailboxesoop

The Question

The interviewer asks

A generator builds one packet object, then loops three times: set p.id, mb.put(p). The checker receives three packets that all have the last id. Why, and what is the rule?

Reveal the Model Answer

A mailbox of a class type stores handles, not copies. So all three entries point to the one object, and every receiver sees its final state. Construct a new object for each item, or clone it before put. The general rule: once a handle is published to another component, the sender must not modify that object again.

Three Puts, One Object
012data the generator meant112233handle in the mailboxopwrite_data driven33driver takes the first handle
  1. Cycle 0

    The generator writes 11 into its one object and puts the handle. Before the driver reads it, the same object is given 22 and then 33.

  2. Cycle 2

    All three handles refer to one object, so the driver sends 33 three times.

One column per operation. By the time the driver reads the object, the generator has overwritten it.

Self-Check

Tick each key point you covered in your answer.

What Interviewers Listen For (Junior)

A good junior answer spots shared handles from the symptom alone. It constructs a new object for each item.

Cross-Questions

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

WhyWhat IfProve ItBreak ItCompare

  1. Three Items, One Object
  2. CompareBounded vs Unbounded MailboxesL1 JuniorL2 Mid-Level

    Compare new() with new(1) for the mailbox between a generator and a driver.

    Reveal the Model Answer

    An unbounded mailbox lets the generator run far ahead of the driver. It may create thousands of items before the first one is sent, so stimulus cannot react to DUT state. A mailbox of size 1 blocks put until the driver takes the item, so the two stay close. Choose the bound to match how far ahead stimulus may be decided.

    Bounded Mailbox, new(2); the Driver Takes One Item Every Other Cycle
    01234567producerput 0, 1blockedput 2blockedput 3blockedput 4donenum()2consumer-get 0-get 1-get 2-a get makes room for put 2
    1. Cycle 0

      The mailbox starts empty. The producer puts items 0 and 1, and both places are full.

    2. Cycle 1

      The next put() finds the mailbox full and blocks. The producer waits.

    3. Cycle 2

      The consumer gets item 0. That makes room, and the blocked put(2) completes in the same cycle.

    4. Cycle 6

      Each get() lets exactly one put() through. The producer puts its last item, 4.

    5. Cycle 7

      The producer is done. Items 3 and 4 wait in the mailbox for the consumer's next two gets.

    One column per clock cycle. The producer can never be more than two items ahead.

    Self-Check

    Tick each key point you covered in your answer.

    Half-Truth

    "A bound of 1 means the generator and driver are fully synchronised."

    put returns once the driver has called get, not when the item is on the bus. The generator can still be one item ahead.

    Source IEEE 1800-2017 §15.4.3

  3. WhyWhy Channels Pass HandlesL1 Junior

    Why does SystemVerilog pass class handles around instead of copying objects?

    Reveal the Model Answer

    Objects can be large and can contain other objects. Copying on every hand-off would cost time and memory, and the right depth of copy differs from case to case. Handles make sharing cheap and explicit. The price is that the programmer decides when a real copy is needed.

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "Assigning b = a for objects calls a copy constructor, like C++."

    There is no implicit copy for class handles: b = a makes both names refer to one object. A copy needs new a or a written copy method.

    Source IEEE 1800-2017 §8.12

  4. What IfReusing One Object Safely in a MailboxL1 JuniorL2 Mid-Level

    What if the generator must reuse one object? How do you make the mailbox hand-off safe?

    Reveal the Model Answer

    Put a copy in the mailbox, not the working object. Write a copy method that copies every field, including nested objects. Then the consumer owns its item, and the next randomize() cannot change it. A new object per transaction is simpler, and it is the usual rule.

    Self-Check

    Tick each key point you covered in your answer.

    Half-Truth

    "A shallow copy with b = new a; is enough."

    It copies the top object's fields only. Nested objects stay shared, so the consumer can still see later changes.

    Source IEEE 1800-2017 §8.12

  5. Prove ItSolve 3.5.1: Exact-Count ConsumerSimulator-graded

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

    Open Problem 3.5.1

  6. Break ItPolling a Mailbox with Try GetL2 Mid-Level

    A checker loops on if (mb.try_get(t)) check(t); with no delay. How does this break the simulation?

    Reveal the Model Answer

    When the mailbox is empty, the loop never blocks. It spins forever in the same time step, so time can never advance. Use the blocking get, or add an event control such as waiting for the next clock when polling is really needed.

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "try_get waits a little when the mailbox is empty."

    It returns 0 at once without blocking; that is its purpose.

    Source IEEE 1800-2017 §15.4.6

What People Get Wrong

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

Misconception

"put() stores a copy of the object."

The mailbox holds whatever put was given, here a handle. The twin publishes one object three times and receives the last id three times.

Run It

One packet object reused for three put calls.

RUNVerilator · simulator service
Edit the code, then run it
Expected: received ids 2 2 2 FAIL: the mailbox holds three handles to one object, so every item shows the last id
See the Fix
class pkt;
  int id;
endclass
module tb;
  mailbox #(pkt) mb = new();
  int ids[$];
  initial begin
    pkt p = new();
    for (int i = 0; i < 3; i++) begin
      p = new();                 // the fix: a new object per item
      p.id = i;
      mb.put(p);
    end
    repeat (3) begin pkt r; mb.get(r); ids.push_back(r.id); end
    $display("received ids %0d %0d %0d", ids[0], ids[1], ids[2]);
    if (ids[0] == ids[2]) $display("FAIL: the mailbox holds three handles to one object, so every item shows the last id");
    else $display("PASS: three objects, three ids");
  end
endmodule

Prints: received ids 0 1 2 PASS: three objects, three ids

Misconception

"Use a queue instead of a mailbox; queues copy."

A queue of class handles also stores handles. The channel type does not matter; the object ownership does.

Source IEEE 1800-2017 §8.4

Half-Truth

"A mailbox is just a queue with a different name."

Its get blocks while empty, and a bounded mailbox blocks put when full, which gives backpressure between processes. A queue does neither.

Source IEEE 1800-2017 §15.4

Learn It, Then Prove It