Verilog · Chapter 8.2 · System Tasks & Functions
$random in Verilog — Random Number Generation
The random system function is Verilog's pseudorandom number generator, returning a 32-bit signed integer drawn from an internal stream. Every constrained-random testbench, stress-test stimulus, and randomised delay rides on it or one of its cousins such as urandom, urandom range, and the distribution functions. The call looks trivial, but it carries subtleties every verification engineer trips on once. These include the signedness of the return value and how it breaks simple modulo range restriction, the seed contract for reproducible runs, the reproducibility discipline that regressions depend on, the per-context stream rule that differs between plain Verilog and SystemVerilog, and the distribution functions for non-uniform draws. This page walks through each one so your random stimulus is both varied and repeatable.
Foundation18 min readVerilog$random$urandomVerificationTestbenchConstrained Random
Chapter 8 · Section 8.2 · System Tasks & Functions
1. The Engineering Problem
A verification engineer writes a stress test for an 8-bit ALU. The goal: hit every opcode + operand combination across thousands of cycles to catch corner-case bugs. The naive approach:
module alu_stress_tb;
reg [7:0] a, b;
reg [2:0] op;
integer i;
initial begin
for (i = 0; i < 10000; i = i + 1) begin
a = $random;
b = $random;
op = $random % 8; // restrict to 0..7
#1;
// ... check result ...
end
$finish;
end
endmoduleThe test runs. The opcode histogram comes back skewed — opcode 0 fires twice as often as the others. The engineer suspects a stuck-bit on the opcode register. Three hours of debugging later, the ALU is fine. The bug is in $random % 8 — $random returns a signed 32-bit value, and the modulo of a negative number in Verilog is implementation-defined. Half the time the modulo result is -N, and the engineer's op register sees a wrong-signed value that wraps to a different bucket.
The right fix uses the unsigned variant:
op = $urandom_range(7, 0); // uniform unsigned 0..7This page covers the randomization family in depth — the $random mechanism, the seed contract, the negative-modulo trap, the $urandom / $urandom_range upgrades that fix the trap by construction, the seven distribution functions for non-uniform draws, and the reproducibility discipline every regression suite depends on.
2. Anatomy of $random
The simplest random source.
2.1 Syntax
integer r;
r = $random; // bare call — uses an internal global seed
r = $random(seed); // seeded call — uses the explicit seed, updates itThe return type is a 32-bit signed integer (-2³¹ to 2³¹-1).
2.2 Semantics
- Pseudorandom, not truly random. The same seed produces the same stream — this is what makes reproducible regressions possible.
- Signed return. The bare
$randomcall can return negative values; this is the source of the% Ndistribution-bias trap. - Seeded form mutates the seed.
$random(seed)advances the seed in place — the variable's value changes after each call, walking through the pseudorandom stream. - Unseeded form uses a global hidden seed. All
$randomcalls without an explicit seed share one global stream; the stream's initial value is implementation-defined (typically 0 or a fixed constant per simulator vendor).
2.3 The signedness contract
integer r;
r = $random;
$display("r = %0d (could be negative)", r);
$display("r = %h (always 32 hex digits)", r);
$display("r = %b (always 32 bits)", r);
// Cast to unsigned 32-bit for typical use
reg [31:0] u;
u = $random;
$display("u = %h (high bit interpretation differs by tool)", u);When assigned to an integer (signed), the value retains its signedness; when assigned to reg [31:0] (unsigned), the bit pattern is identical but the interpretation drops sign. The distinction matters for %d printing and for arithmetic — r % N does NOT behave like u % N when r is negative.
3. Mental Model
4. The Seed Contract
The seed is the random stream's primary key. Two forms.
4.1 The hidden global seed (bare $random)
initial begin
integer i;
for (i = 0; i < 5; i = i + 1)
$display("%0d", $random); // uses hidden global seed
endThe hidden global seed is shared across every bare $random call in the simulation. Two independent always blocks both calling bare $random interleave their consumption — the order depends on event scheduling and isn't guaranteed across runs even with no source change.
4.2 The explicit-seed form ($random(seed))
initial begin
integer i;
integer seed = 42; // reproducible — same seed every run
for (i = 0; i < 5; i = i + 1)
$display("%0d", $random(seed));
end
// Output (vendor-dependent, but identical run-to-run with seed=42):
// 303379748
// -1064739199
// -1748305800
// 1543339977
// -1129508905$random(seed) walks an explicit stream. The seed variable is mutated by each call. Critically, each initial/always/task that owns its own seed variable gets its own stream — independent from the hidden global stream and from other explicit streams.
4.3 Reproducibility discipline
// In every regression-grade testbench
module my_tb;
integer seed;
initial begin
// Read seed from command line, default to 0
if (!$value$plusargs("SEED=%d", seed))
seed = 0;
$display("Using seed = %0d", seed);
// ... use $random(seed) or $urandom(seed) throughout ...
end
endmoduleRun with vsim +SEED=12345 my_tb to fix a specific seed; rerun with the same seed to reproduce any bug found. Most production regression suites log the seed of every failing run so it can be replayed bit-identically.
5. The Negative-Modulo Trap
The most common $random bug in production code.
integer r;
reg [2:0] op;
r = $random; // signed: could be -2³¹ to +2³¹-1
op = r % 8; // INTENDED: 0..7 uniform
// ACTUAL: -7..7 — values 1..7 each from positive
// AND negative source rangesThe Verilog standard leaves the sign of (-7) % 8 implementation-defined. Most simulators return -7; some return +1. Either way, assigning the result to an unsigned register either wraps or sign-extends — the histogram is no longer uniform.
The historic Verilog-2001 fix:
r = $random;
if (r < 0) r = -r; // make positive
op = r % 8; // now uniform 0..7But this still has bias — the value r = -2³¹ cannot be negated (overflows back to itself), so the smallest bucket gets one fewer chance.
The modern fix (Verilog-2005 / SystemVerilog):
op = $urandom_range(7, 0); // unsigned, uniform, by constructionAlways prefer $urandom_range for bounded random values.
6. $urandom and $urandom_range
Verilog-2005 added the unsigned random variants.
6.1 $urandom
reg [31:0] u;
u = $urandom; // unsigned 32-bit, [0, 2³²-1]
u = $urandom(seed); // seeded — same contract as $random(seed)Returns a 32-bit unsigned integer. The signed-return trap of $random is gone — every value is in [0, 2³²-1]. The seed contract is identical.
6.2 $urandom_range
reg [7:0] byte;
reg [3:0] nibble;
integer idx;
byte = $urandom_range(255, 0); // [0, 255] uniform
nibble = $urandom_range(15); // [0, 15] uniform — min defaults to 0
idx = $urandom_range(99, 50); // [50, 99] uniform — inclusive both endsReturns a uniform unsigned value in [min, max] (inclusive). Distribution is uniform by construction — no modulo arithmetic, no bias.
The argument order is (max, min) (most-significant first); the min argument defaults to 0 if omitted.
6.3 The upgrade rule
| Old pattern (avoid) | New pattern (prefer) |
|---|---|
$random % N | $urandom_range(N-1, 0) |
($random & 'h7F) (bit-mask to 7 bits) | $urandom_range(127, 0) |
($random % (max - min + 1)) + min | $urandom_range(max, min) |
r = $random; if (r<0) r=-r; | $urandom |
Every legacy $random % pattern has a clean $urandom_range replacement that's both shorter and bias-free.
7. Distribution Functions
IEEE 1364-2005 §17.9.2 defines seven distribution functions for non-uniform draws. All take a seed as the first argument and return an integer.
| Function | Distribution | Extra arguments | Use case |
|---|---|---|---|
$dist_uniform | Uniform | start, end | Same as $urandom_range but Verilog-2001-portable |
$dist_normal | Gaussian | mean, std_dev | Modelling jitter, noise |
$dist_exponential | Exponential | mean | Inter-arrival times for traffic generation |
$dist_poisson | Poisson | mean | Event-count modelling |
$dist_chi_square | Chi-square | degrees_of_freedom | Statistical-test stimulus |
$dist_t | Student's t | degrees_of_freedom | Statistical-test stimulus |
$dist_erlang | Erlang | k_stage, mean | Queueing-theory simulations |
7.1 Example — Gaussian jitter stimulus
module jitter_stimulus;
integer seed = 42;
real jitter_ps;
integer i;
initial begin
for (i = 0; i < 10; i = i + 1) begin
// Mean 0, std dev 50 ps
jitter_ps = $dist_normal(seed, 0, 50);
$display("cycle %0d: jitter = %0d ps", i, jitter_ps);
end
end
endmodule$dist_normal(seed, 0, 50) draws an integer from a Gaussian with mean 0 and standard deviation 50. The vast majority of values land in [-150, +150] (±3σ); rare values exceed.
7.2 Example — Exponential inter-arrival times
module packet_generator;
integer seed = 7;
integer delay_cycles;
integer i;
initial begin
for (i = 0; i < 5; i = i + 1) begin
// Average 20 cycles between packets
delay_cycles = $dist_exponential(seed, 20);
#(delay_cycles) generate_packet();
end
end
endmodule$dist_exponential(seed, 20) draws an integer from an exponential distribution with mean 20 — useful for memoryless traffic models (most packets close together, occasional long gaps).
8. Visual Explanation
Three figures cover the randomization model.
8.1 Visual A — randomization family tree
The functions at a glance.
Randomization family
data flow8.2 Visual B — the negative-modulo bias
Why $random % 8 is biased and $urandom_range(7, 0) is not.
8.3 Visual C — seed contract
Hidden global vs explicit per-context streams.
9. The Reproducibility Discipline
Every working regression suite enforces three rules.
9.1 Always use an explicit seed in production tests
integer seed;
initial begin
if (!$value$plusargs("SEED=%d", seed))
seed = 0; // explicit default — not the hidden global
$display("[tb] seed = %0d", seed);
// ... $random(seed), $urandom(seed), $urandom_range(...) ...
end$value$plusargs("SEED=%d", seed) reads +SEED=12345 from the simulator's command line. If not provided, defaults to 0.
9.2 Log the seed on every failing run
always @(posedge clk) begin
if (test_failed) begin
$display("[FAIL] seed=%0d cycle=%0d ...", seed, $time);
$finish(1);
end
endA failed regression-suite run that doesn't print the seed cannot be replayed. Always log it.
9.3 One seed per process / per context
// Each always block owns its own seed → independent streams.
integer seed_stim, seed_check;
initial seed_stim = 100;
initial seed_check = 200;
always @(posedge clk) begin
stim_value <= $urandom(seed_stim);
end
always @(posedge clk) begin
if ($urandom_range(99, 0) < 5) // 5% probability
inject_glitch();
endSharing one seed across multiple contexts couples their streams — adding a call in one context shifts the others. Per-context seeds keep the streams independent.
10. Industry Use Cases
Five patterns where the randomization family shows up in production.
10.1 Constrained-random stimulus generation
The canonical workload. Every verification suite generates millions of random transactions:
reg [31:0] addr;
reg [31:0] data;
reg [1:0] burst_len;
integer seed = 42;
always @(posedge clk) begin
addr <= $urandom(seed) & 32'hFFFF_FFFC; // word-aligned
data <= $urandom(seed);
burst_len <= $urandom_range(3, 0);
end10.2 Random delays in handshake testbenches
Inserting random delays between handshake phases exposes timing bugs:
initial begin
repeat (100) begin
// Random think time before driving valid
#($urandom_range(20, 1));
valid <= 1;
@(posedge clk iff ready);
valid <= 0;
end
end10.3 Statistical-distribution stimulus
Modelling realistic traffic patterns requires non-uniform distributions:
// Gaussian jitter on a 10 ns clock
real jitter_ps;
integer seed = 7;
always @(posedge nominal_clk) begin
jitter_ps = $dist_normal(seed, 0, 25); // mean=0, sigma=25ps
#(jitter_ps / 1000.0) actual_clk = 1;
end10.4 Random opcode generation for ALU / CPU verification
Cover every opcode + operand combination:
reg [7:0] a, b;
reg [2:0] op;
integer seed = 99;
initial begin
repeat (10000) begin
a = $urandom_range(255, 0);
b = $urandom_range(255, 0);
op = $urandom_range(7, 0);
@(posedge clk);
end
end10.5 Bug-replay via seed logging
When a regression finds a failure, the seed is logged with the failure record. The same test rerun with +SEED=<logged_value> reproduces the exact failure for debugging.
11. Common Mistakes
Six pitfalls that catch every verification engineer at least once.
11.1 $random % N biased distribution
The §5 trap. $random returns signed; % N is biased. Use $urandom_range(N-1, 0) instead.
11.2 Forgotten seed → irreproducible regression
// No seed handling — every run produces different results
always @(posedge clk)
stim <= $random;A failure on Tuesday's regression run cannot be replayed Wednesday. Always read a seed from $value$plusargs and log it.
11.3 Seed shared across contexts couples streams
integer seed = 0;
always @(posedge clk_a) x = $random(seed); // consumes from seed
always @(posedge clk_b) y = $random(seed); // consumes from seed
// Adding any extra $random(seed) in clk_a's block shifts clk_b's stream.One seed per context. Independent streams stay independent.
11.4 Vendor-portable seed assumption
// Seed 42 in VCS produces sequence A
// Seed 42 in Xcelium produces sequence B — different algorithmPseudorandom algorithms are not standardised. Same seed across vendors produces different streams. Reproducibility is vendor-scoped.
11.5 $random in synthesisable RTL
always @(posedge clk)
state <= $random; // wrong tool — $random is simulation-only$random is non-synthesisable. Synthesis tools strip it or warn. For RTL pseudorandom generators, instantiate an LFSR or a Galois polynomial — not a system task.
11.6 $urandom_range(0, 7) vs $urandom_range(7, 0)
The argument order is (max, min). Reversing produces unexpected behaviour — most simulators silently swap, but some return constants.
x = $urandom_range(0, 7); // ambiguous — depends on tool's swap behaviour
x = $urandom_range(7, 0); // canonical — max first, min secondStick to (max, min). Set min = 0 to omit the second argument.
12. Debugging Lab
Three randomization debug post-mortems
Pitfall 1 — opcode histogram skewed by negative modulo
module alu_stress;
reg [7:0] a, b;
reg [2:0] op;
integer seed = 42;
integer count[8];
integer i;
initial begin
for (i = 0; i < 100000; i = i + 1) begin
op = $random(seed) % 8; // intend uniform 0..7
count[op] = count[op] + 1;
end
for (i = 0; i < 8; i = i + 1)
$display("op[%0d] = %0d", i, count[i]);
$finish;
end
endmodule
// Output (representative — values depend on vendor):
// op[0] = 25012
// op[1] = 10718
// op[2] = 10742
// op[3] = 10833
// op[4] = 10689
// op[5] = 10691
// op[6] = 10719
// op[7] = 10596
// Bucket 0 has ~2.3x the count of the others.A constrained-random ALU test running 100,000 cycles shows opcode 0 firing roughly twice as often as opcodes 1..7. The engineer suspects a stuck-bit on the opcode register or a clock-domain crossing bug. Investigation reveals the ALU and the opcode register are fine — the issue is in the stimulus generator.
$random returns a SIGNED 32-bit value. When the value is negative, "% 8" in Verilog returns a NEGATIVE result (the sign of modulo follows the dividend). The assignment "op = (negative % 8)" then sign-extends or wraps depending on the simulator — typically producing 0.
Specifically: when $random returns -8, -16, -24 (multiples of 8 in the negative range), "% 8" returns 0. Combined with the positive 8, 16, 24 also mapping to 0, bucket 0 receives roughly double the mass.
The fix is $urandom_range(7, 0) — produces uniform unsigned values by construction, without any modulo step.
module alu_stress;
reg [7:0] a, b;
reg [2:0] op;
integer count[8];
integer i;
initial begin
for (i = 0; i < 100000; i = i + 1) begin
op = $urandom_range(7, 0); // uniform 0..7, by construction
count[op] = count[op] + 1;
end
for (i = 0; i < 8; i = i + 1)
$display("op[%0d] = %0d", i, count[i]);
$finish;
end
endmodule
// Output (now uniform — each bucket within 1% of 12500):
// op[0] = 12534
// op[1] = 12498
// op[2] = 12477
// op[3] = 12511
// ...Pitfall 2 — failing regression run cannot be replayed
module my_tb;
reg [31:0] stim;
always @(posedge clk)
stim <= $random; // uses hidden global seed
always @(posedge clk) begin
if (some_failure_condition) begin
$display("FAIL at t=%0t", $time);
$finish(1);
end
end
endmodule
// Tuesday: regression run fails at cycle 47,213 — bug filed.
// Wednesday: engineer reruns the test to reproduce. Test passes —
// no failure at cycle 47,213 or anywhere else.
// The bug "vanished" because the stimulus is no longer reproducible.A regression run finds a failure at cycle 47,213 and files a detailed bug report. The engineer reruns the same test the next day to capture waveforms — the test passes cleanly. Rerunning the regression suite ten times produces ten different sequences; the bug appears in some runs and not others. The team concludes the test is "flaky".
The bare $random call uses the simulator's hidden global seed. The seed's initial value can vary between runs depending on simulator options, system time, command-line flags, or process scheduling. Each run produces a DIFFERENT stimulus sequence — the failure at cycle 47,213 was driven by one specific sequence that doesn't reproduce.
The test isn't flaky; the stimulus isn't reproducible. The bug is real but unreplayable without a deterministic seed.
The fix is to read an explicit seed from $value$plusargs, default to a known value, log it on every run, and use $random(seed) or $urandom(seed) throughout.
module my_tb;
reg [31:0] stim;
integer seed;
initial begin
if (!$value$plusargs("SEED=%d", seed))
seed = 0;
$display("[tb] seed = %0d", seed);
end
always @(posedge clk)
stim <= $urandom(seed); // walks the seed deterministically
always @(posedge clk) begin
if (some_failure_condition) begin
$display("FAIL at t=%0t seed=%0d", $time, seed);
$finish(1);
end
end
endmodule
// Now: every failing run logs its seed.
// To replay: vsim +SEED=<logged_value> → bit-identical sequence.
// The "flakiness" was lost reproducibility, not a real bug.Pitfall 3 — adding a $random call shifted unrelated streams
module two_drivers;
integer seed = 42;
reg [7:0] addr, data;
reg valid;
always @(posedge clk) begin
addr <= $random(seed); // consumes from seed
data <= $random(seed); // consumes from seed
valid <= $random(seed) % 2; // consumes from seed
end
// Some time later, engineer adds debug instrumentation:
always @(posedge clk) begin
if ($random(seed) % 100 < 5) // 5% chance to inject glitch
inject_glitch();
end
endmodule
// Before the debug code was added: regression passed.
// After: same test fails at cycle 8,193 — but ONLY when the debug
// instrumentation is present. Disabling the debug code makes the test
// pass again. The team thinks the "debug" code has a real bug.A regression test passes before adding a piece of debug instrumentation that uses $random for occasional event injection. After adding the instrumentation, the test fails consistently at cycle 8,193 — but with the instrumentation disabled, the test passes. The team suspects the debug code itself is buggy.
The two always blocks SHARE the same "seed" variable. Each $random(seed) call mutates the seed in place. Before the debug code was added, the seed advanced 3× per cycle (addr, data, valid). After: 4× per cycle.
Adding ANY $random(seed) call SHIFTS the position in the stream that subsequent calls see. The addr / data / valid streams are now offset from what they were before — the test's stimulus is fundamentally different, even though the test code looks the same.
The fix is to give each independent context its own seed variable. Independent streams stay independent regardless of what other contexts do.
module two_drivers;
integer seed_stim = 42;
integer seed_debug = 99;
reg [7:0] addr, data;
reg valid;
always @(posedge clk) begin
addr <= $random(seed_stim);
data <= $random(seed_stim);
valid <= $random(seed_stim) % 2;
end
always @(posedge clk) begin
if ($urandom_range(99, 0) < 5) // 5% chance
inject_glitch();
// Uses its OWN stream — independent of seed_stim.
end
endmodule
// Now: addr/data/valid streams are insensitive to changes in the
// debug code. Adding/removing $urandom_range calls in the debug
// always block doesn't shift the stim stream. Streams are decoupled.13. Coding Guidelines
Six rules teams converge on.
$urandom_range(max, min)for bounded uniform draws. Never$random % N. The unsigned variant is uniform by construction.- Always read the seed from
$value$plusargs. Default to a known value (0 or 1). Log the seed at simulation start and on every failing event. - One seed per independent context. Don't share a seed across
alwaysblocks that should produce independent streams. - Use
$random/$urandomonly in testbench code. Wrap in`ifdef SIMULATIONif the file is shared with RTL. Synthesisable pseudorandom generators use LFSRs, not system tasks. - Pick the right distribution function. Uniform →
$urandom_range; Gaussian →$dist_normal; Exponential (memoryless intervals) →$dist_exponential. Most testbenches use uniform; reach for$dist_*only when the workload demands a specific shape. - Document the seed source. Comment whether a seed is a fixed magic number (reproducible smoke test), a
$plusargsargument (production regression), or a global counter (multi-test independence).
14. Interview Q&A
15. Exercises
Three exercises that turn $random into reflex.
Exercise 1 — Spot the bias
For each snippet, identify whether the distribution is uniform or biased, and explain why.
// Snippet A
reg [3:0] r;
r = $random % 16;
// Snippet B
reg [3:0] r;
r = $urandom_range(15, 0);
// Snippet C
reg [3:0] r;
r = $urandom & 4'hF;
// Snippet D
reg [3:0] r;
r = $random; if (r < 0) r = -r;
r = r % 16;
// Snippet E
reg [6:0] r; // 0..127
r = $random % 100; // intend 0..99Hints. Signed-modulo bias, power-of-two boundaries, the -2³¹ overflow edge case, modulo of non-power-of-two ranges.
Exercise 2 — Add reproducibility
Convert this irreproducible testbench into a regression-grade one (reads +SEED=, defaults to 0, logs the seed at startup and at every failing event).
module sloppy_tb;
reg [7:0] a, b;
reg [2:0] op;
initial begin
repeat (1000) begin
a = $random;
b = $random;
op = $random % 8;
@(posedge clk);
if (golden(a, b, op) !== dut_result)
$display("FAIL at t=%0t", $time);
end
$finish;
end
endmoduleWhat to produce. The rewritten module that (a) reads the seed from $value$plusargs, (b) defaults to 0, (c) uses $urandom(seed) / $urandom_range, (d) logs the seed at startup, (e) logs the seed AND the failing-cycle's randomised inputs at every FAIL event.
Exercise 3 — Pick the right distribution
For each requirement, recommend the best function call.
| # | Requirement |
|---|---|
| 1 | Uniform random 8-bit byte |
| 2 | Uniform random integer in [50, 100] |
| 3 | Random delay 10-50 cycles, uniform |
| 4 | Random delay with mean 20 cycles, exponentially distributed (memoryless) |
| 5 | Clock jitter with mean 0, σ=25 ps, Gaussian |
| 6 | Random 1-out-of-N selection with N=7 |
| 7 | 5% probability event injection |
| 8 | Random opcode from {ADD, SUB, AND, OR, XOR, NOP} (uniform) |
What to produce. Function name and exact arguments for each.
16. Summary
$random is Verilog's pseudorandom number generator — a 32-bit signed pseudorandom integer drawn from an internal stream. The signed-return trap is what motivates the entire upgrade chain to $urandom and $urandom_range.
The four functions:
$random— 32-bit signed; legacy form; uses hidden global seed unless$random(seed)form.$urandom— 32-bit unsigned; modern replacement for$random.$urandom_range(max, min)— uniform unsigned in[min, max]; the working engineer's default.$dist_*family — seven non-uniform distribution functions ($dist_normal,$dist_exponential,$dist_poisson,$dist_chi_square,$dist_t,$dist_erlang,$dist_uniform).
The seed contract:
- Bare
$randomuses a hidden global seed shared across all call sites. Not reproducible by default. $random(seed)uses an explicit seed variable, mutated in place. Reproducible by construction.- Each independent context should own its own seed variable — sharing couples streams.
- Pseudorandom algorithms are not standardised — same seed across vendors produces different streams. Reproducibility is vendor-scoped.
The reproducibility discipline:
- Read seed from
$value$plusargs("SEED=%d", seed)with a known default. - Log the seed at simulation start and on every failing event.
- One seed per context to keep streams independent of unrelated code changes.
The upgrade rule:
| Old pattern (avoid) | New pattern (prefer) |
|---|---|
$random % N | $urandom_range(N-1, 0) |
($random & mask) | $urandom_range(max, 0) for power-of-two only |
r = $random; if (r<0) r=-r; r %= N; | $urandom_range(N-1, 0) |
The day-to-day discipline:
$urandom_range(max, min)for bounded uniform. Never$random % N.- Read the seed from a plusarg, default to a known value, log it. Replayable regressions only.
- One seed per context. Independent streams.
$randomis not synthesisable. Wrap in\ifdef SIMULATION`. Use LFSRs for RTL pseudorandom.- Reach for
$dist_*when the workload demands a non-uniform shape. Uniform is overwhelmingly the common case.
The next three sub-pages close Chapter 8: 8.3 Time Functions covers $time / $realtime / $stime, 8.4 Conditional Simulation covers the assertion-and-severity layer ($error, $warning, $fatal), and 8.5 Simulation Control closes the chapter with $finish / $stop / $exit.
Related Tutorials
- System Tasks & Functions — Chapter 8; the parent overview of the eight functional families.
- $display vs $monitor vs $strobe vs $write — Chapter 8.1; the display family that prints randomised stimulus.
- Conditional Compilation — Chapter 7.4; the
\ifdef SIMULATION` discipline that gates every random call.