Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • Start Here6
  • SystemVerilog Language Foundations28
  • Object-Oriented SystemVerilog for Verification30
  • Constraint Randomization — Interview-Critical Deep Dive36
    • Randomization Basics: rand, randc & randomize()
    • Constraint Operators & Expressions
      • inside, Ranges & Set Membership
      • dist: Weighted Distributions
      • Implication, if/else and solve...before
      • soft Constraints
    • Dynamic Constraint Control
    • Randomizing Arrays and Queues
    • How the Constraint Solver Works
    • Debugging Randomization Failures
    • Interview Drills — Constraints and Randomization Q&A
  • SystemVerilog Assertions — Interview-Critical Deep Dive40
  • Functional Coverage in SystemVerilog22
  • Testbench Architecture in SystemVerilog23
  • Advanced Language & Integration25
  • Senior & Interview Preparation21
  • Principal-Level Verification28
Loading lesson

‹Constraint Operators & Expressions
  1. Topics
  2. SystemVerilog
  3. Constraint Randomization — Interview-Critical Deep Dive
  4. Constraint Operators & Expressions
  5. inside, Ranges & Set Membership

Part 3 · Constraint Randomization · Intermediate

inside, Ranges & Set Membership

Set membership with inside, ranges, negation, open ranges and array sets.

On this page

    Why this matters

    A length constraint written as one big range let zero-length packets through for weeks. inside builds the exact set you mean, values and ranges together, and every extra constraint can only shrink it.

    After this lesson you can: write value sets with inside, ranges, negation, open $ bounds and arrays, and count the legal values before and after another constraint.

    Sets from values and ranges

    The inside operator restricts a variable to a set built from values and ranges. The statement x inside {[1:5], 10} means x is one of 1, 2, 3, 4, 5 or 10.

    The LRM requires a uniform pick over that set (IEEE 1800 18.5.10), which is the interview model. Real solvers only approximate it, so the bench checks membership and that every legal value appears, never exact shares.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // snippet: the class from the bench below
    class pkt;
      rand bit [7:0] len;
      rand bit [7:0] kind;
    
      // Ranges and discrete values mix freely in one set
      constraint len_c { len inside {[1:8], 16, 32, [64:67]}; }
    
      // Negation: kind may be anything EXCEPT 0 and the range 200..255
      constraint kind_c { !(kind inside {0, [200:255]}); }
    endclass

    The len set holds 8 + 1 + 1 + 4 = 14 values. The negated kind set excludes 1 + 56 values, leaving 199 legal values.

    Form

    Meaning

    Size here

    {[1:8], 16, 32, [64:67]}

    Union of two ranges and two values

    14

    !(kind inside {0, [200:255]})

    Full type range minus the listed set

    199

    Single value 16

    One member of the union

    1

    Negation, open ranges and arrays

    Negation inverts a set, which suits reserved-encoding exclusions. Open ranges with $ track the type bounds when widths change.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    // snippet: also in the bench below
    class addr_txn;
      rand bit [15:0] addr;   // unsigned: low dollar = 0, high dollar = 65535
      rand int        delta;  // signed: low dollar = most negative int
    
      constraint hi_region { addr inside {[16'h8000:$]}; }  // 0x8000..0xFFFF
      constraint neg_only { delta inside {[$:-1]}; }  // any negative int
    endclass

    For unsigned addr, low $ is 0 and high $ is 65535. For signed delta, low $ is the most negative int, so a floor of zero needs an explicit bound.

    Bound

    Unsigned field

    Signed field

    Low $

    Zero

    Most negative value of the type

    High $

    Largest value of the type

    Largest value of the type

    [$:-1]

    Every value: -1 becomes all-ones unsigned, so this is a no-op and likely a bug

    Every negative value

    design.sv
    1
    2
    3
    4
    5
    6
    7
    // snippet: also in the bench below
    class cfg_txn;
      int legal_ids[$] = '{3, 7, 11, 42};   // non-rand state: a runtime knob
      rand int id;
    
      constraint id_c { id inside {legal_ids}; }
    endclass

    The array form reads the current element values at each randomize call. This is standard (IEEE 1800 11.4.13): unpacked arrays in the set are expanded to their elements.

    Intersections decide the solution space

    Predict first len inside {[1:8], 16, 32, [64:67]} allows 14 values. A second constraint, len % 2 == 0, is added. How many values are legal now?

    8: 2, 4, 6, 8, 16, 32, 64 and 66. The two constraints intersect, so only values that pass both remain.

    Constraints intersect: each one can only shrink the set.

    Each added constraint intersects with the rest and never widens the space. An empty intersection makes randomize return 0 instead of picking a near value.

    Common pitfall

    Each syntax item does not get equal weight. A range of 1000 values against a single value is 1000 members against 1, not a 1:1 split.

    Interview

    Name the set size before discussing syntax. Follow-ups ask for the probability of each value, the exclusion form, and what $ means on a signed type.

    Check yourself What is the legal set of x inside {[1:5], 10}, and what does the interview model say about each value?

    Six values: 1, 2, 3, 4, 5 and 10. The interview model gives each about 1/6, because the default aims at uniform over the set, not over the two syntax items.

    Check yourself A second constraint removes every value of an inside set. What does randomize return?

    It returns 0. Constraints intersect, so an empty intersection has no solution to return.

    Testbench

    The three classes above, solved 3,000 times: every value stays in its set, all 14 lengths appear, the array set follows a change to legal_ids, and an inline len % 2 == 0 leaves exactly 8 values.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    class pkt;
      rand bit [7:0] len;
      rand bit [7:0] kind;
      // Ranges and discrete values mix freely in one set
      constraint len_c { len inside {[1:8], 16, 32, [64:67]}; }
      // Negation: kind may be anything EXCEPT 0 and the range 200..255
      constraint kind_c { !(kind inside {0, [200:255]}); }
    endclass
    
    class addr_txn;
      rand bit [15:0] addr;   // unsigned: low $ is 0, high $ is 65535
      rand int        delta;  // signed: low $ is the most negative int
      constraint hi_region { addr inside {[16'h8000:$]}; }
      constraint neg_only  { delta inside {[$:-1]}; }
    endclass
    
    class cfg_txn;
      int legal_ids[$] = '{3, 7, 11, 42};   // non-rand state: a run-time knob
      rand int id;
      constraint id_c { id inside {legal_ids}; }
    endclass
    
    Terminal
    len values seen: 14 of 14; with len % 2 == 0: 8 of 8
    PASS: 600 rounds stayed in every set, all 14 lengths appeared, and the intersection left exactly 8

    Project step

    Make every random PacketFIFO packet legal by construction: len inside 1 to 8, dest inside 0 to 2 (port 3 does not exist yet), and kind one of the three named values. Check every packet over 1,000 solves.

    One way to write it:

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    typedef enum bit [1:0] {DATA = 2'd0, CTRL = 2'd1, ERR = 2'd2} kind_e;
    
    class pkt_txn;
      rand kind_e    kind;
      rand bit [1:0] dest;
      rand bit [3:0] len;
      constraint c_len  { len inside {[1:8]}; }        // the spec: 1 to 8 payload bytes
      constraint c_dest { dest inside {[0:2]}; }       // port 3 does not exist yet
      constraint c_kind { kind inside {DATA, CTRL, ERR}; }
    endclass
    
    module tb_pkt_legal;
      pkt_txn p = new();
      int dests[int];
      initial begin
        repeat (1000) begin
          if (!p.randomize()) $fatal(1, "FAIL: randomize failed");
          if (p.len == 0 || p.len > 8 || p.dest == 3) $fatal(1, "FAIL: illegal packet len %0d dest %0d", p.len, p.dest);
          dests[int'(p.dest)]++;
        end
        $display("dest counts: 0=%0d 1=%0d 2=%0d", dests[0], dests[1], dests[2]);
        if (dests.num() != 3) $fatal(1, "FAIL: a legal dest never appeared");
        $display("PASS: 1000 packets, every one legal: len 1 to 8, dest 0 to 2");
        $finish;
      end
    endmodule
    Terminal
    dest counts: 0=373 1=332 2=295
    PASS: 1000 packets, every one legal: len 1 to 8, dest 0 to 2

    Remember

    • inside {[1:8], 16, 32} is the union of every listed value and range.

    • $ is the type's own bound: careful with signed fields.

    • Constraints intersect; an empty intersection makes randomize() return 0.

    Rule of thumb: count the legal set before you reason about its probabilities.

    How this was checked

    Run with Verilator 5.048 (--binary --timing) on 2026-10-18; every bench printed the PASS line shown. Verilator prints a harmless WIDTHTRUNC warning for if (!obj.randomize()), because randomize() returns an int, and an UNSATCONSTR warning when a solve fails on purpose. Icarus 13 does not support constraints.

    Related topics

    • Next: dist: Weighted Distributions

    Previous

    69 / 259

    Next: dist: Weighted Distributions

    Up next

    Up nextdist: Weighted Distributions

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Implication, if/else and solve...before
    • soft Constraints