Why Learn rand and randc? Every constrained-random testbench depends on picking legal values automatically instead of by hand, and SystemVerilog gives you two ways to do it: 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 rand distributes values uniformly across its range, with repeats allowed
  • How randc cycles through every legal value once before any value repeats
  • Why randc properties are solved before other random variables
  • The practical limits of using randc on 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

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

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:

  • rand distributes values uniformly across the legal range, and repeats are allowed on any call
  • randc cycles through every legal value exactly once before any value can repeat, then starts a new independently shuffled cycle
  • randc properties are solved before other random variables in the same object
  • rand and randc apply the same way to arrays, queues, and dynamic arrays — the dedicated Array Randomization article covers constraining their sizes
  • Keep randc for 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.

Did you find what you were looking for?

Quiz

Test Your Knowledge

1 of 5 Score: 0 / 5
Cron Job Starts