rand and randc. Understanding exactly how each one picks values is what lets you predict — and control — how thoroughly your stimulus covers the scenarios you care about.SystemVerilog makes a class property randomizable with one of two qualifiers: rand or randc. Both apply the same way to plain variables, arrays, queues, and dynamic arrays — see SystemVerilog Array Randomization in Class for constraining array and queue sizes. The difference covered here is entirely in how repeated values are handled.
6 min read | Intermediate Level
What You'll Learn
- How
randdistributes values uniformly across its range, with repeats allowed - How
randccycles through every legal value once before any value repeats - Why
randcproperties are solved before other random variables - The practical limits of using
randcon wide variables
rand: Uniformly Distributed, Repeats Allowed
rand works the same whether the property is a scalar, a queue, or a dynamic array:
class Packet;
rand int count;
rand byte master [$];
rand bit [7:0] data [];
...
endclass
Here's the simplest case — a single 3-bit scalar, randomized 10 times in a row. randomize() is called on the class object and randomizes every rand (and randc) property it finds inside that object:
class Packet;
rand bit [2:0] data;
endclass
module tb;
initial begin
Packet pkt = new ();
for (int i = 0 ; i < 10; i++) begin
pkt.randomize ();
$display ("itr=%0d data=0x%0h", i, pkt.data);
end
end
endmodule
Output
run -all; # KERNEL: itr=0 data=0x7 # KERNEL: itr=1 data=0x2 # KERNEL: itr=2 data=0x2 # KERNEL: itr=3 data=0x1 # KERNEL: itr=4 data=0x2 # KERNEL: itr=5 data=0x4 # KERNEL: itr=6 data=0x0 # KERNEL: itr=7 data=0x1 # KERNEL: itr=8 data=0x5 # KERNEL: itr=9 data=0x0 # KERNEL: Simulation has finished. There are no more test vectors to simulate.
Notice that 0x2 and 0x1 each repeat multiple times across the 10 iterations. Variables declared rand are standard random variables whose values are uniformly distributed over their range: data is a 3-bit unsigned value with a legal range of 0 through 7, so with no constraints in place, every value in that range has an equal 1-in-8 chance on every single call to randomize() — including a chance of repeating the value from the call before it.
Quick Check
Q: You call randomize() on a rand variable five times in a row and get the exact same value every time. Is something broken?
Show Answer
No — rand makes no promise against repeats. Each call is an independent, uniformly distributed pick across the legal range, so five identical results in a row are just an unlikely (but valid) outcome, not a bug.
randc: Cycles Through Every Value Before Repeating
Swap rand for randc and the declaration syntax doesn't change at all — only the value-selection behavior does:
class Packet;
randc int count;
randc byte master [$];
randc bit [1:0] data [];
...
endclass
Variables declared randc are random-cyclic: they cycle through every value in their range before any particular value repeats. We'll reuse the same class from above with one change — make data a randc variable:
class Packet;
randc bit [2:0] data;
endclass
module tb;
initial begin
Packet pkt = new ();
for (int i = 0 ; i < 10; i++) begin
pkt.randomize ();
$display ("itr=%0d data=0x%0h", i, pkt.data);
end
end
endmodule
Output
run -all; # KERNEL: itr=0 data=0x6 # KERNEL: itr=1 data=0x3 # KERNEL: itr=2 data=0x4 # KERNEL: itr=3 data=0x7 # KERNEL: itr=4 data=0x0 # KERNEL: itr=5 data=0x1 # KERNEL: itr=6 data=0x5 # KERNEL: itr=7 data=0x2 # KERNEL: itr=8 data=0x5 // Start of a new sequence # KERNEL: itr=9 data=0x0 # KERNEL: Simulation has finished. There are no more test vectors to simulate.
All eight values in the range 0 through 3'h7 are exhausted (itr=0 through itr=7) before any value repeats. At itr=8 a new cycle begins with a fresh, independently shuffled order — that's why 0x5 is allowed to show up again right away.
randc properties are solved before other random (rand) properties within the same object. This guarantees the cyclic behavior holds regardless of whatever the object's rand properties end up constrained to.
Where Is randc Used?
randc is useful when you need to guarantee coverage of a small legal set rather than just a random sample of it — for example, cycling through a small set of requester IDs when testing a round-robin arbiter, so every requester is guaranteed a turn instead of being left out by chance.
Quick Check
Q: Can the value that ends one randc cycle be the same as the value that starts the next cycle?
Show Answer
Yes. randc only guarantees no repeats within a single cycle — each cycle is shuffled independently, so a back-to-back repeat right across the cycle boundary is legal.
Common Beginner Mistakes
Mistake #1: Choosing randc for wide variables
As a randc variable's bit width grows, the solver has to remember an entire permutation of every legal value before it can start a new cycle. Why? This makes randc impractical for wide buses or large counters; reserve it for small fields such as short IDs, small mode selects, or opcode-style fields.
Mistake #2: Assuming rand won't repeat back-to-back
New users sometimes expect two consecutive calls to randomize() to always produce different values for a rand property. Why? rand is uniformly distributed with no memory of previous picks, so identical back-to-back values are a normal, expected outcome — not a sign of a stuck solver.
Mistake #3: Leaving a rand array or queue's size unconstrained
A dynamic array or queue declared rand has its length randomized too, unless you constrain it. Why? Without a size constraint you can end up with an empty array on one run and an unexpectedly large one on the next. See SystemVerilog Array Randomization in Class for how to constrain array and queue sizes.
Practice Exercise
Challenge: Watch randc Exhaust a Small Range
Declare a class property data as randc bit [1:0] (legal range 0 to 3) and randomize it 4 times in a row, printing the iteration number and value each time.
Hint
With only 4 legal values and randc, the first 4 iterations are guaranteed to produce each value exactly once — you just won't know the order until you run it.
Solution
class Packet;
randc bit [1:0] data;
endclass
module tb;
initial begin
Packet pkt = new ();
for (int i = 0 ; i < 4; i++) begin
pkt.randomize ();
$display ("itr=%0d data=0x%0h", i, pkt.data);
end
end
endmodule
Run it and you'll see all four values — 0x0, 0x1, 0x2, and 0x3 — appear exactly once across the 4 iterations, in some random order. Run it again with a different seed and the order changes, but the guarantee (every value exactly once before any repeat) does not.
Summary
In this tutorial, you learned:
randdistributes values uniformly across the legal range, and repeats are allowed on any callrandccycles through every legal value exactly once before any value can repeat, then starts a new independently shuffled cyclerandcproperties are solved before other random variables in the same objectrandandrandcapply the same way to arrays, queues, and dynamic arrays — the dedicated Array Randomization article covers constraining their sizes- Keep
randcfor small ranges; wide variables make full-cycle tracking impractical
Continuing the Randomization Chapter
Continue with pre_randomize and post_randomize, disable randomization, and randcase. For more on how the solver orders and prioritizes variables, see SystemVerilog solve before.