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
    • Dynamic Constraint Control
    • Randomizing Arrays and Queues
    • How the Constraint Solver Works
      • The Solution-Space Mental Model
      • Bidirectional Solving
      • randc Internals & Limits
      • Solver Performance
      • Solver FAQ: Determinism & Vendor Differences
    • 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

‹How the Constraint Solver Works
  1. Topics
  2. SystemVerilog
  3. Constraint Randomization — Interview-Critical Deep Dive
  4. How the Constraint Solver Works
  5. Solver Performance

Part 3 · Constraint Randomization · Intermediate

Solver Performance

Costly constraint shapes, measuring before fixing, and rewrites that keep every result legal.

On this page

    Why this matters

    A regression doubled in length after one constraint edit. The edit multiplied two rand fields, and every call now searched for factors.

    After this lesson you can: name the costly constraint shapes, measure solver time correctly, and rewrite a slow rule while proving the legal set is unchanged.

    What costs the most

    Ordinary verification constraints solve quickly on every engine. Cost rises with a few shapes, and it multiplies: a medium constraint inside a foreach over 1000 elements is 1000 medium constraints in one problem.

    Cost

    Shapes

    Cheap

    Equality, inside ranges, bit slices, add and subtract, multiply or divide by a constant

    Medium

    Implications, foreach over moderate arrays, small unique sets

    Costly

    A rand times a rand, modulo or divide by a rand, wide arithmetic, large tight unique sets

    Blow-up

    Webs of hundreds of coupled fields across objects, nested implications that multiply cases

    A constant multiply is a shift that range reasoning handles directly. A product of two rand fields is factoring, which needs search.

    Check yourself Why is a * 4 cheap but a * b costly?

    A constant multiply is a linear relation the solver propagates through ranges. A product of two random fields is factoring, which needs a search.

    Measure before fixing

    A slow solve shows up as wall-clock time growing while simulated time stands still. $realtime around randomize() measures simulated time, so it reads zero and says nothing about solver cost.

    Use the simulator's solver profile, which reports time per constraint block and the number of failed attempts. Retries are the most useful signal on any tool: a constraint that fails and re-solves often costs many times its nominal solve. Guessing the hot constraint by eye fails routinely.

    Verilator 5.048 hands each solve to an external SMT solver (z3 in this course's setup), so a constraint-heavy bench spends most of its time in that solver. Run the same bench with a few constraint blocks switched off by constraint_mode(0) to see which block costs the time.

    Common pitfall

    Timing randomize() with $realtime measures simulated time. The solver works in wall-clock time while simulated time stands still, so only a profile, or a wall-clock comparison between runs, answers which block is hot.

    Rewrites that keep every result legal

    Three rewrites remove most solver cost. Each one must keep the set of legal results, and a bench proves that before the rewrite is trusted.

    Slow shape

    Rewrite

    A product of two rand fields

    A table of legal pairs and a rand index into it

    Derivation the solver does not need to see

    Compute it in pre_randomize, so the solver reads a constant

    One giant coupled solve

    Staged randomize() calls with earlier results fixed

    Fields wider than the specification

    Narrow them: width inflates every arithmetic relation

    The bench checks the first two rewrites against the original rule: a pages and stride pair whose product must fit an 8 KiB buffer. The product form, the table form and a precomputed base address all solve 300 times, every result is checked, and three planted bad pairs prove the checker can fail.

    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
    27
    28
    29
    30
    localparam int LIMIT = 8192;                  // buffer bytes: pages * stride must fit
    
    class product_pair;                           // rand times rand: a hard shape for solvers
      rand bit [7:0]  pages, stride;
      rand bit [15:0] total;
      constraint c {
        pages != 0;
        stride inside {1, 2, 4, 8, 16, 32, 64, 128};
        total == 16'(pages) * stride;             // 16-bit multiply: no wrap
        total <= LIMIT;
      }
    endclass
    
    class table_pair;                             // pick a row of legal pairs instead
      rand bit [2:0] pick;
      bit [7:0] pages_tbl [8] = '{10, 20, 30, 40, 50, 60, 70, 80};
      bit [7:0] stride_tbl[8] = '{ 1,  2,  4,  8, 16, 32, 64, 64};
      function bit [7:0] pages();  return pages_tbl[pick];  endfunction
      function bit [7:0] stride(); return stride_tbl[pick]; endfunction
    endclass
    
    class region_txn;                             // procedural work before the solve
      rand bit [31:0] addr;
      bit [31:0] base;                            // plain field: a constant to the solver
      bit [31:0] region_tbl[4] = '{32'h0000_0000, 32'h1000_0000, 32'h2000_0000, 32'h3000_0000};
      function void pre_randomize();
        base = region_tbl[$urandom_range(3)];     // any procedural choice
      endfunction
      constraint c { addr inside {[base : base + 32'h0FFF]}; }
    endclass
    
    Terminal
    product form: last pair 64 x 32 = 2048
    table form: 8 of 8 rows used, every pair legal
    precomputed base: last addr 20000ce5 in region 20000000
    PASS: the product, table and precomputed forms all give only legal results; planted bad pairs are rejected

    The table form trades reach for speed: it can only produce the eight pairs it holds, while the product form can produce any legal pair. That is a coverage decision, so record it in the test plan rather than leaving it in a comment.

    Interview

    Name the expensive shapes first: rand times rand, modulo and divide by a rand, wide arithmetic, and cross-object webs. Then say: profile before fixing, and fix with tables, precomputation, narrower fields and staged calls, each checked for the same legal set.

    Check yourself A generation loop slows down 100 times after a constraint edit. What is the first step?

    Profile it: per-block solve time and retry counts. The hot constraint is rarely the one inspection suspects.

    Remember

    • Rand times rand, rand modulo and wide arithmetic are the costly shapes.

    • $realtime measures simulated time, which stands still during a solve.

    • Every rewrite must be checked against the original legality rule.

    Rule of thumb: profile first, rewrite second, prove the legal set third.

    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.

    The bench checks legality of the product, table and precomputed forms over 300 calls each; it does not measure speed, which depends on the machine.

    Related topics

    • Solver FAQ: Determinism and Vendor Differences

    Previous

    86 / 259

    Next: Solver FAQ: Determinism & Vendor Differences

    Up next

    Up nextSolver FAQ: Determinism & Vendor Differences

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • The Solution-Space Mental Model
    • Bidirectional Solving