← Design Verification Interviews

Interview Question · Concept

The Randomize Call That Failed Quietly

L1 Juniorsystemverilograndomizationconstraints

The Question

The interviewer asks

The class says len inside {[1:16]} and a test calls void'(p.randomize() with { len > 20; }). What happens?

Reveal the Model Answer

The constraints contradict each other, so randomize() returns 0 and every random variable keeps its previous value. With the result cast away, the test sends the old packet again as if it were new. No checker complains, because that packet is legal. Always test the return value and turn a 0 into an error naming the object and the call.

Every Call Fails, and the Old Burst Goes Out Again
012345randomize() returnedbeats requested316beats driven3first failed call
  1. Cycle 0

    The first call returns 1, and the burst it chose, with 3 beats, is driven.

  2. Cycle 1

    The test asks for 16 beats, but the class allows 1 to 8. randomize() returns 0 and leaves the old values in place.

  3. Cycle 5

    Every later call fails the same way, and nobody checks the return value. The same burst with 3 beats goes out again and again.

One column per transaction. The driver sends whatever the object holds.

Self-Check

Tick each key point you covered in your answer.

What Interviewers Listen For (Junior)

A good junior answer says the call returns 0 and the variables keep their old values. It adds that every call needs its result checked.

Cross-Questions

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

What IfProve ItBreak ItCompare

  1. The Randomize Call That Failed Quietly
  2. CompareSoft Defaults vs Hard DefaultsL1 Junior

    Compare constraint dflt { soft len == 8; } with constraint dflt { len == 8; } when a test calls randomize() with { len == 3; }.

    Reveal the Model Answer

    The soft default yields: the call succeeds with len = 3. The hard default conflicts with the inline constraint, so the call returns 0. Write defaults that tests are expected to override as soft, and rules the hardware requires as hard.

    Hard Rules Hold, Soft Rules Give WayHow the solver treats the hard and soft blocks of a class burst_txn. Arrows show constraints reaching the solver and the value it assigns; dashed pulses are inline constraints passed with the call.
    Hard rules hold, soft rules give wayHow the solver treats the hard and soft blocks of a class `burst_txn`. Arrows show constraints reaching the solver and the value it assigns; dashed pulses are inline constraints passed with the call. inline Inline request randomize() with { ...} hard Hard: legal addr[1:0] == 0, beats1 to 8 soft Soft: defaults soft beats == 4 solver Solver hard rules must hold;soft rules give way derived class short_burst its own blockdefaults: soft beats== 2 field beats the value chosen replaces defaultsassigns
    1. No request

      With no inline rule, nothing conflicts, so the solver keeps the soft default and the base class gives 4 beats.

      Follow the calls, values and waits
      1. data beats 1 to 8: Hard: legal → Solver
      2. data beats == 4: Soft: defaults → Solver
      3. data 4: Solver → beats
    2. The request wins

      with { beats == 2; } conflicts only with the soft default. The solver drops the default for this call, without a message, and assigns 2 beats.

      Follow the calls, values and waits
      1. call beats == 2: Inline request → Solver
      2. data beats 1 to 8: Hard: legal → Solver
      3. data 2: Solver → beats
    3. A hard rule never gives way

      A request for 12 beats breaks the hard range, and a hard rule is never dropped. The call returns 0, and beats keeps its old value, 2.

      Follow the calls, values and waits
      1. call beats == 12: Inline request → Solver
      2. data beats 1 to 8: Hard: legal → Solver
    4. A derived default

      short_burst declares a block with the same name, defaults, which replaces the base block. Its soft default, 2 beats, is the one the solver keeps.

      Follow the calls, values and waits
      1. data beats == 2: short_burst → Solver
      2. data beats 1 to 8: Hard: legal → Solver
      3. data 2: Solver → beats
    Read the diagram as text
    • Inline request: randomize() with { ... }
    • Hard: legal: addr[1:0] == 0, beats 1 to 8
    • Soft: defaults: soft beats == 4
    • Solver: hard rules must hold; soft rules give way
    • short_burst: its own block defaults: soft beats == 2
    • beats: the value chosen
    • Inline request → Solver
    • Hard: legal → Solver
    • Soft: defaults → Solver
    • short_burst → Solver: replaces defaults
    • Solver → beats: assigns

    Keep protocol rules hard. A soft rule is right only for a preference that any test may override.

    RUNVerilator · simulator service
    Edit the code, then run it
    Expected: soft default, test asks for 3: ok=1 len=3 hard default, test asks for 3: ok=0

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "A soft constraint is a weaker hint the solver may ignore at random."

    A soft constraint holds whenever it can. It is dropped only when it conflicts with a hard one or with a later, higher-priority soft one.

    Source IEEE 1800-2017 §18.5.14

  3. What IfTwo Soft Constraints That DisagreeL1 JuniorL2 Mid-Level

    What if two soft constraints conflict, one in the base class and one inline?

    Reveal the Model Answer

    Soft constraints have priorities. Between two soft ones, the derived, inline or later one wins, and the other is dropped. So an inline soft len == 4 beats a base class soft len == 8. A hard constraint still beats both.

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "Conflicting soft constraints make randomize() fail."

    Soft constraints never cause a failure among themselves. The lower-priority one is dropped; only hard conflicts fail.

    Source IEEE 1800-2017 §18.5.14.1

  4. What IfFinding the Conflict Among Thirty Constraint BlocksL2 Mid-Level

    Asked if the class has many constraint blocks

    A class with thirty constraint blocks fails to randomize in one test. How do you find the conflict?

    Reveal the Model Answer

    Read the tool's unsatisfied-constraint report first, if it gives one; it often names the blocks involved. Otherwise switch blocks off with constraint_mode(0) and bisect until the call succeeds. Then look at what the last disabled block fights with, including the test's inline with clause and any field frozen by rand_mode(0).

    Self-Check

    Tick each key point you covered in your answer.

    Spec Misquote

    "The standard requires the simulator to print which constraints conflict."

    The standard only requires the call to return 0. Any report is a tool feature, worded differently on each simulator.

    Source IEEE 1800-2017 §18.6.3

  5. Break ItA Field Frozen by an Earlier TestL1 JuniorL2 Mid-Level

    An error test froze addr with rand_mode(0) to force an illegal address. The next test reuses the object and every randomize() call fails. Why?

    log
    test1: addr.rand_mode(0); addr = 41   // directed error case
    test2: randomize() returned 0, addr=41
    test2: randomize() returned 0, addr=41
    Reveal the Model Answer

    rand_mode(0) lasts until someone turns it back on. So addr is still fixed state, and its value 41 breaks the hard rule addr < 32. Every call fails and leaves 41. Restore rand_mode(1) when the directed case ends, or give each test a fresh object.

    Freezing a Field, Switching a Block OffOne transaction object t. Arrows show what the test sets, what the solver reads and what it assigns. Dashed pulses are calls from the test, solid tokens are values, and outlined markers are return values.
    Freezing a field, switching a block offOne transaction object `t`. Arrows show what the test sets, what the solver reads and what it assigns. Dashed pulses are calls from the test, solid tokens are values, and outlined markers are return values. test Test sets modes, callsrandomize() field addr random unlessrand_mode(0) constraint constraint legal addr[1:0] == 0, beats1 to 8 solver Solver solves only therandom fields field beats random rand_modeconstraint_moderandomize()valuerules, when onassigns
    1. Freeze addr

      The test writes 0xFC into addr and calls rand_mode(0). From now on the solver treats addr as a fixed number.

      Follow the calls, values and waits
      1. call addr = FC, rand_mode(0): Test → addr
    2. Later calls

      Each later call solves only beats, with the rules applied to the frozen 0xFC. Every call succeeds, addr reads fc, and rand_mode() reports 0.

      Follow the calls, values and waits
      1. call randomize(): Test → Solver
      2. data FC: addr → Solver
      3. data legal: constraint legal → Solver
      4. data beats: Solver → beats
      5. return 1: Solver → Test
    3. A frozen illegal value

      The test writes 8'h41 into the field, which is still frozen. The solver may not change it, the alignment rule cannot hold, and the call returns 0.

      Follow the calls, values and waits
      1. call addr = 41: Test → addr
      2. call randomize(): Test → Solver
      3. data 41: addr → Solver
      4. data legal: constraint legal → Solver
      5. return 0: Solver → Test
    4. Rules switched off

      rand_mode(1) makes addr random again, and legal.constraint_mode(0) switches off every rule in legal. The misaligned request for 12 beats at 0x41 now succeeds.

      Follow the calls, values and waits
      1. call rand_mode(1): Test → addr
      2. call constraint_mode(0): Test → constraint legal
      3. call addr == 41, beats == 12: Test → Solver
      4. data beats 12: Solver → beats
      5. return 1: Solver → Test
    5. Rules back on

      With legal switched back on, the same request for 0x41 fails again. A negative test should restore the block as soon as its burst is made.

      Follow the calls, values and waits
      1. call constraint_mode(1): Test → constraint legal
      2. call addr == 41: Test → Solver
      3. data legal: constraint legal → Solver
      4. return 0: Solver → Test
    Read the diagram as text
    • Test: sets modes, calls randomize()
    • addr: random unless rand_mode(0)
    • constraint legal: addr[1:0] == 0, beats 1 to 8
    • Solver: solves only the random fields
    • beats: random
    • Test → addr: rand_mode
    • Test → constraint legal: constraint_mode
    • Test → Solver: randomize()
    • addr → Solver: value
    • constraint legal → Solver: rules, when on
    • Solver → beats: assigns

    Modes belong to one object and last until you change them back, unlike randomize() with, which ends with the call.

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "rand_mode(0) applies to the next call only."

    It is a persistent switch on the field. The twin's second test still sees the frozen value and fails until the mode is restored.

    Run It

    Test 1 freezes addr at 41; test 2 randomizes the same object.

    RUNVerilator · simulator service
    Edit the code, then run it
    Expected: ok=0 addr=41 FAIL: rand_mode(0) is still in force, so randomize kept 41 and could not meet addr < 32
    See the Fix
    class req;
      rand bit [7:0] addr;
      constraint c { addr < 32; }
    endclass
    module tb;
      req r = new;
      int ok;
      initial begin
        // test 1: a directed out-of-range address for an error case
        r.addr.rand_mode(0);
        r.addr = 41;
        // test 2 starts with the same object
        r.addr.rand_mode(1);                 // the fix: hand the field back to the solver
        ok = r.randomize();
        $display("ok=%0d addr=%0d", ok, r.addr);
        if (ok == 1 && r.addr < 32) $display("PASS: the field was random again");
        else $display("FAIL: rand_mode(0) is still in force, so randomize kept 41 and could not meet addr < 32");
      end
    endmodule
    

    Prints: PASS: the field was random again

  6. Prove ItSolve 5.1.6: The Packet That Kept Its Old LengthSimulator-graded

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

    Open Problem 5.1.6

What People Get Wrong

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

Misconception

"A failed randomize leaves garbage, so the bad packet would be obvious."

The old values stay, and they were legal. The twin sends the previous length again and nothing looks wrong.

Run It

A legal call, then a contradictory one with the result discarded.

RUNVerilator · simulator service
Edit the code, then run it
Expected: sending len=4 FAIL: the failed call kept the old length, so the old packet went out as a new one
See the Fix
class pkt;
  rand int unsigned len;
  constraint legal { len inside {[1:16]}; }
endclass
module tb;
  pkt p = new;
  initial begin
    void'(p.randomize() with { len == 4; });            // the first packet
    if (!p.randomize() with { len > 20; })
      $display("PASS: randomize returned 0 and the test reported it before sending");
  end
endmodule

Prints: PASS: randomize returned 0 and the test reported it before sending

Tool as Truth

"post_randomize() ran, so randomization succeeded."

The standard calls it only after a successful solve. Verilator 5.052 also calls it after a failed call, so it proves nothing there; the return value is the only reliable signal.

Source Lesson 5.6 simulator note (4 post_randomize calls after 3 successes and 1 failure on Verilator 5.052)

Half-Truth

"Make every constraint soft so randomize never fails."

Then a test can silently override a legality rule and generate illegal traffic. Soft suits defaults; legality must stay hard.

Learn It, Then Prove It