Skip to main content

Module 4 — Randomization

VLSI Verification  •  SystemVerilog Series

Module 4 — Randomization

Constrained-random stimulus generation: rand vs randc, constraint blocks, soft and inline constraints, how the constraint solver actually works, and the pre/post_randomize hooks.

🧩 Intermediate ⏱ ~24 min read 💻 Code Examples Included

36rand

Declaring a class property rand marks it as randomizable — its value is chosen by the constraint solver whenever randomize() is called on the object, uniformly across its legal range (subject to constraints).

SystemVerilog
class packet; rand bit [7:0] addr; rand bit [31:0] data; rand bit parity; endclass packet p = new(); if (!p.randomize()) $display("randomize FAILED"); else $display("addr=%0h data=%0h", p.addr, p.data);
⚠️ Always Check the Return Value

randomize() returns 0 if the constraints are unsatisfiable (over-constrained). Not checking the return value is a frequent bug source — a silently failed randomize() leaves the old (or default) values in place, and the test proceeds with unintended data.

37randc

randc (random-cyclic) guarantees every value in the variable's range is produced exactly once before any value repeats — useful for exhaustively cycling through a small set of IDs or opcodes without collisions.

SystemVerilog
class id_gen; randc bit [2:0] id; // 3 bits -> 8 possible values (0-7) endclass id_gen g = new(); repeat (8) begin g.randomize(); $display("id=%0d", g.id); // prints all 8 values 0-7 in some random // permutation, NO repeats until all 8 seen end
Aspectrandrandc
RepetitionCan repeat any timeNo repeats until full cycle exhausted
Best ForData fields, addresses, general stimulusSmall enumerated sets: IDs, opcodes, priorities
Practical LimitAny widthTypically kept small (≤ a few bits) — cycle grows exponentially with width
📘 Note

randc is only supported on class properties (not module-level variables) and works best on small-width fields — a 16-bit randc would need to track 65536 values per cycle, which is impractical.

38Constraints

A constraint block restricts the legal solution space for rand variables — the solver picks values that satisfy every active constraint simultaneously.

SystemVerilog
class packet; rand bit [7:0] addr; rand bit [15:0] len; rand bit is_write; // simple range constraint constraint c_addr_range { addr inside {[8'h00:8'hEF]}; } // weighted distribution constraint c_len_dist { len dist { [1:64] := 70, // 70% weight -- small packets [65:1500] := 30 }; // 30% weight -- large packets } // conditional / implication constraint constraint c_write_len { is_write -> len < 256; // only applies when is_write == 1 } // relational constraint across two fields constraint c_align { addr[1:0] == 2'b00; } // word-aligned addr endclass
💡 Interview Tip

-> is a soft implication used inside a constraint block (constraint-level implication), distinct from the assertion implication operators covered in Module 6. Both mean "if left side true, right side must hold," but they apply in very different contexts.

39Soft Constraints

A soft constraint expresses a default/preferred value that can be silently overridden by any other hard constraint (or another soft constraint with higher priority) — useful for providing sensible defaults without hard-locking a field.

SystemVerilog
class config_obj; rand int burst_len; // soft default -- prefers 4, but can be overridden constraint c_default { soft burst_len == 4; } endclass config_obj cfg = new(); cfg.randomize(); // burst_len = 4 (soft constraint honored) cfg.randomize() with { burst_len == 8; }; // inline HARD constraint wins // -- burst_len = 8, soft is overridden
⚠️ Soft vs Soft Conflicts

When multiple soft constraints on the same variable conflict, the last one declared/applied wins (in textual/inheritance order) — hard constraints always take priority over any soft constraint regardless of order.

40Inline Constraints

The randomize() with {...} syntax adds extra constraints for just that one call, without modifying the class definition — useful for test-specific scenario tweaks.

SystemVerilog
packet p = new(); // inline constraint adds to (ANDs with) existing class constraints p.randomize() with { addr == 8'h10; len inside {[100:200]}; }; // randomizing only specific fields, others held fixed p.addr = 8'hAA; p.randomize(len, is_write); // only 'len' and 'is_write' are randomized; // 'addr' stays at 8'hAA (rand_mode aware) // disabling randomization of a field entirely for this object p.addr.rand_mode(0); // addr excluded from all future randomize() calls
💡 Where Used

Inline constraints are the standard way UVM sequences customize a transaction per test — e.g. req.randomize() with { addr == cfg.base_addr; } — without having to write a new transaction subclass for every scenario.

41Constraint Solver

SystemVerilog's constraint solver treats all active hard constraints as a system of equations/inequalities and finds a solution satisfying all of them simultaneously — it does not simply try constraints one at a time.

SystemVerilog
class demo; rand int a, b, c; // solved together as a joint system, NOT sequentially constraint c1 { a < b; } constraint c2 { b < c; } constraint c3 { a + b + c == 30; } endclass // solve...before -- controls RELATIVE ORDER for variables that // have inter-dependent constraints, without fully decoupling them class ordered_demo; rand bit mode; rand int value; constraint c_mode_first { solve mode before value; // solver picks 'mode' first, then 'value' // conditioned on that mode -- improves // distribution quality for dependent fields mode -> value < 100; !mode -> value >= 100; } endclass
📘 How It Actually Works

Internally, the solver converts constraints to a normalized form and uses techniques based on constraint satisfaction / SAT-like solving to find a valid assignment, rather than naive trial-and-error. This is why deeply nested or highly cross-dependent constraints can slow down randomization noticeably as the solver space grows.

🚫 Over-Constraining

If constraints are mutually contradictory (e.g. a < b and b < a both active), randomize() returns 0. Debugging this typically means using the simulator's constraint solver diagnostics/tracing to identify which constraint block is unsatisfiable.

42pre_randomize

pre_randomize() is a built-in callback automatically invoked immediately before the solver runs — useful for setting up state or dynamically enabling/disabling constraints ahead of randomization.

SystemVerilog
class packet; rand bit [7:0] addr; int randomize_count; function void pre_randomize(); randomize_count++; $display("about to randomize, call #%0d", randomize_count); // e.g. dynamically toggle a constraint based on external state if (randomize_count > 5) c_addr_range.constraint_mode(0); // disable a constraint block endfunction constraint c_addr_range { addr inside {[8'h00:8'h0F]}; } endclass
📘 Note

You never call pre_randomize() yourself — the simulator calls it automatically as part of every randomize() invocation. Overriding it in a subclass is common when a derived transaction needs extra setup before its fields are chosen.

43post_randomize

post_randomize() is the counterpart callback, automatically invoked immediately after a successful randomization — typically used to derive/compute non-random fields (like a CRC/checksum) from the values the solver just chose.

SystemVerilog
class packet; rand bit [7:0] addr; rand bit [31:0] data; bit [7:0] crc; // NOT rand -- derived after randomization function void post_randomize(); crc = compute_crc(addr, data); // runs automatically after fields are set $display("post_randomize: computed crc=%0h", crc); endfunction function bit[7:0] compute_crc(bit[7:0] a, bit[31:0] d); return a ^ d[7:0] ^ d[15:8] ^ d[23:16] ^ d[31:24]; endfunction endclass
💡 pre_randomize vs post_randomize

Use pre_randomize() to influence what gets randomized (setup/constraint toggling); use post_randomize() to react to what was chosen (derived fields, logging, sanity checks). Both must be declared as functions taking no arguments and returning void.

🎯 Module 4 Recap

  • rand allows repeats; randc cycles through every value once before repeating — best for small ID/opcode sets.
  • constraint blocks are solved jointly, not sequentially — the solver finds one assignment satisfying all active hard constraints at once.
  • soft constraints set overridable defaults; any hard constraint (or a later soft one) wins over an earlier soft constraint.
  • Inline randomize() with {...} adds test-specific constraints for a single call without touching the class definition.
  • solve...before influences the order variables are resolved for better distribution on dependent fields — it doesn't fully decouple the system.
  • pre_randomize()/post_randomize() are automatic callbacks for setup-before and derive-after logic around every randomize() call.

📚 Next up — Module 5: Functional Coverage (covergroup, coverpoint, cross coverage, bins, ignore bins, illegal bins)

↑ Back to Table of Contents

Comments

Popular posts from this blog

Module 1 — SystemVerilog Basics

VLSI Verification  •  SystemVerilog Series Module 1 — SystemVerilog Basics A complete, example-driven walkthrough of SystemVerilog fundamentals: data types, variables vs nets, arrays of every flavor, strings, enums, structs, unions, and typedef — the building blocks every verification engineer needs before UVM. 🧩 Beginner → Intermediate ⏱ ~25 min read 💻 Code Examples Included 📑 Table of Contents Introduction to SystemVerilog Verilog vs SystemVerilog Data Types: 2-State vs 4-State Logic Variables and Nets Arrays: Packed vs Unpacked Dynamic Arrays Queues Associative Arrays Strings Enumerations Structures Unions Typedef 1 Introduction to SystemVerilog SystemVerilog (IEEE 1800) is a unified hardware description and verification language (HDVL). It extends Verilog (IEEE 1364) with powerful constructs for design (interfaces, always_comb/always_ff, enhanced d...

GPU Memory System & Interconnect: How Data Travels Inside a Modern GPU

GPU Memory System & Interconnect: How Data Travels Inside a Modern GPU Modern GPUs deliver incredible computing power by processing thousands of operations simultaneously. While compute cores often receive the spotlight, the real performance of a GPU depends heavily on how efficiently data moves between memory and compute units. A GPU memory system is designed to provide extremely high bandwidth while keeping latency as low as possible. This is achieved through a collection of specialized hardware components working together, including the Memory Controller, HBM/GDDR memory, Crossbar, Network-on-Chip (NoC), DMA Engine, PCIe Interface, and NVLink. In this article, we'll explore each component in detail and understand how they collectively enable high-performance parallel computing. Why Does GPU Memory Matter? Every GPU application—from gaming and graphics rendering to AI model training and scientific simulations—requires continuous movement of enormous amounts of data. For examp...

Clock Domain Crossing (CDC): A Complete Beginner's Guide to Metastability, Synchronizers & Safe Data Transfer

Clock Domain Crossing (CDC): A Complete Beginner's Guide to Metastability, Synchronizers & Safe Data Transfer Modern System-on-Chip (SoC) designs rarely operate with a single clock. Instead, different modules such as CPUs, GPUs, memory controllers, communication interfaces, and peripherals often run at different clock frequencies or even use completely independent clock sources . When data moves from one clock domain to another, timing uncertainty can cause serious problems such as metastability , data corruption , and unpredictable system behaviour . This challenge is known as Clock Domain Crossing (CDC) . CDC is one of the most important topics in ASIC Design , RTL Design , ASIC Verification , FPGA Design , and SoC Architecture . Every modern chip—from smartphones to automotive processors—uses CDC techniques to ensure reliable communication between multiple clock domains. In this article, we'll explore CDC fundamentals, metastability, synchronization techniques, asynchro...

AXI Verification Interview Questions and Real-World Debugging

AMBA Protocol Series · Part 10 of 10 AXI Verification Interview Questions and Real-World Debugging Common protocol violations, how to read them off a waveform, and a curated set of interview questions with concise, correct answers — the capstone of the core 10-day series. AMBA Protocol Series: From APB & AHB to AXI — A Complete Guide for VLSI Engineers This wraps up the core 10-day series. Everything here draws directly on Days 1–9 — if any answer below feels unfamiliar, that's a good signal for which earlier post to revisit. (If you want to go further, see the 20-day extended list at the end of this post.) In This Article Common Protocol Violations Debugging From a Waveform Interview Questions and Answers Series Recap Extending the Series 1. Common Protocol Violations VALID deasserted before handshake — a source drops VALID before READY ever went high (violates the Day 8 stabi...

Cache Basics and Cache Mapping Techniques

  Cache Basics and Cache Mapping Techniques  Modern processors execute billions of instructions every second. However, processor speed has increased much faster than main memory (RAM) speed. This difference, known as the memory wall , creates a performance bottleneck because the CPU often has to wait for data from slower memory. To solve this problem, computer systems use cache memory —a small, high-speed memory located between the CPU and the main memory. In this article, we will understand the fundamentals of cache memory, the principle of locality, cache organization, and the three major cache mapping techniques. What is Cache Memory? Cache memory is a small, high-speed memory that stores copies of frequently accessed data from the main memory. Since accessing cache is much faster than accessing RAM, the CPU first checks whether the required data is available in the cache. If the data is found in the cache, it is called a cache hit . Otherwise, the CPU fetches the dat...

Timing Basics in Static Timing Analysis (STA): Delay Models, Sequential Timing, and Wire Delays

Timing Basics in Static Timing Analysis (STA) Static Timing Analysis (STA) is one of the most important verification techniques used in modern VLSI design. Before a chip is manufactured, engineers must verify that every signal reaches its destination within the required clock period. Even if a design passes functional simulation, it may still fail after fabrication because of timing violations. Unlike simulation, Static Timing Analysis mathematically analyzes every timing path without applying input test vectors. This makes STA significantly faster and capable of analyzing millions of timing paths efficiently. Table of Contents What is Static Timing Analysis? Why STA is Required Propagation Delay Contamination Delay Cell Delay Models Combinational Gate Delay Sequential Timing Setup Time Hold Time Wire Delay RC Delay Model PVT Corners Worked Examples Interview Questions Key Takeaways What is Static Timing Analysis? Static Ti...

Computer Architecture Interview Question Part 1

Skip to content Computer Architecture Interview Series Part 1 · CPU Basics · RISC vs CISC · ISA 50 Most Asked Computer Architecture Interview Questions (Part 1) The foundational round every VLSI, ASIC, and CPU design interview opens with: instruction set architecture, RISC vs CISC trade-offs, Von Neumann vs Harvard design, registers, endianness, and the fetch-decode-execute cycle — explained the way interviewers actually expect you to answer.  40 Questions (Q1–Q40) ⌛ 22 min read  VLSI & Computer Architecture Interviews On this page Foundations of Computer Architecture RISC vs CISC — Core Differences Von Neumann, Harvard & the Semantic Gap Architecture Styles, Endianness & Registers ILP, VLIW, Superscalar & Amdahl's Law Register Files, Microcontrollers & the Fetch Cycle Tip...