Randomization is one of the key features in SystemVerilog, especially when it comes to functional verification. It allows verification engineers to create various randomized test scenarios that can explore edge cases and corner cases that might not be covered by directed testing. Randomized testing helps to identify bugs that could be missed otherwise, leading to more robust and comprehensive verification.
In this article, we’ll explore the concept of randomization in SystemVerilog, the rand and randc keywords, different randomization modes, and key functions like pre_randomize and post_randomize. We’ll also look at how constraints help control randomization and make the process more efficient and targeted.
What is Randomization?
In SystemVerilog, randomization is the process of assigning random values to variables, allowing you to simulate a wide range of scenarios in your testbench. Randomization enables the testbench to automatically create different inputs and configurations, thus testing the Design Under Test (DUT) under various conditions without manually specifying each case.
There are two main types of randomization:
- Unconstrained randomization: The values are completely random.
- Constrained randomization: The values are random, but they follow specific rules or constraints set by the verification engineer. We will know more about constraints in next chapters. For now, we will focus on randomization only.
rand and randc Keywords
SystemVerilog provides two main keywords for randomization: rand and randc.
rand Keyword
The rand keyword is used to declare random variables. These variables will get random values when the randomize() function is called. The values generated are pseudo-random, meaning that they will follow the same pattern of randomization unless you use a seed to change it.
Example:
class packet;
rand bit [7:0] pkt_id; // Random variable declaration
rand bit [31:0] data;
function void display();
$display("Packet ID: %0d, Data: %0h", pkt_id, data);
endfunction
endclass
module test;
initial begin
packet p = new();
p.randomize(); // Randomize the fields
p.display(); // Display the randomized values
end
endmodule
Output:
Packet ID: 163, Data: 5966088f
randc Keyword
The randc keyword declares random variables that cycle through all possible values before repeating any of them. This means that each value is used exactly once in a cycle before the random generator starts reusing values.
Example:
class packet;
randc bit [3:0] pkt_id; // Cyclic random variable (will cycle through 0-15)
function void display();
$display("Packet ID: %0d", pkt_id);
endfunction
endclass
module test;
initial begin
packet p = new();
repeat(16) begin
p.randomize(); // Each pkt_id value will appear once
p.display();
end
end
endmodule
In this example, the randc variable pkt_id will take on each value from 0 to 15 before repeating any value.
Output
Packet ID: 1
Packet ID: 2
Packet ID: 0
Packet ID: 4
Packet ID: 3
Packet ID: 15
Packet ID: 9
Packet ID: 14
Packet ID: 10
Packet ID: 8
Packet ID: 12
Packet ID: 11
Packet ID: 13
Packet ID: 5
Packet ID: 6
Packet ID: 7
Randomization Modes in SystemVerilog
There are different randomization modes that give you more control over the randomization process.
randomize() Method
The randomize() method is the primary way to randomize a class’s fields in SystemVerilog. When called, it assigns random values to all random variables within the object, adhering to any constraints defined.
Example: p.randomize();
Selective Randomization
You can also selectively randomize specific fields of an object by using an inside block, which allows you to specify which variables to randomize.
Example:
p.randomize() with {
pkt_id inside {1, 2, 3}; // Randomize pkt_id within the set {1, 2, 3}
};
rand_mode() in System Verilog
The rand_mode() method is used in SystemVerilog to control the randomization of class variables that are declared with the rand or randc keywords. By default, all variables marked as rand or randc are randomized when the randomize() method is called. However, there are situations where you might not want a specific variable to be randomized in a particular test case, and you want to hold its value constant.
The rand_mode() method takes a boolean argument:
rand_mode(1): Enables randomization for the variable (default behavior).rand_mode(0): Disables randomization for the variable, meaning its value will not change during randomization.
Syntax:
object.variable.rand_mode(0); // Disables randomization for 'variable'
object.variable.rand_mode(1); // Enables randomization for 'variable'
Example: Basic Usage of rand_mode()
Let’s start with a basic example where we use rand_mode() to disable and enable randomization for a particular variable.
class packet;
rand bit [7:0] pkt_id; // Random variable
rand bit [31:0] data; // Random variable
function void display();
$display("Packet ID: %0d, Data: %0h", pkt_id, data);
endfunction
endclass
module test;
initial begin
packet p = new();
// Randomize all variables (default behavior)
p.randomize();
p.display();
// Disable randomization for pkt_id
p.pkt_id.rand_mode(0); // pkt_id will not be randomized
p.randomize();
p.display(); // pkt_id remains the same, only data changes
// Enable randomization for pkt_id again
p.pkt_id.rand_mode(1);
p.randomize();
p.display(); // Both pkt_id and data will be randomized
end
endmodule
Explanation:
- Initially, both
pkt_idanddataare randomized. - We then disable randomization for
pkt_idby callingp.pkt_id.rand_mode(0). Now, whenrandomize()is called, onlydatais randomized, whilepkt_idremains unchanged. - We later re-enable randomization for
pkt_idwithp.pkt_id.rand_mode(1). After this, bothpkt_idanddatawill be randomized again.
Output:
Packet ID: 84, Data: e757f99d
Packet ID: 84, Data: 275f13e3
Packet ID: 225, Data: ec5ef9fd
Limitations and Considerations of rand_mode()
While rand_mode() provides flexibility, there are some considerations and limitations to be aware of:
- Only Works for
randandrandcVariables: Therand_mode()method is applicable only to variables declared with therandorrandckeyword. Non-random variables will not be affected. - Does Not Influence Constraints: Disabling randomization for a variable using
rand_mode(0)does not affect any constraints associated with that variable. If the variable has constraints, they will simply be ignored whenrand_mode(0)is applied. - Global Effects: The
rand_mode()setting affects the variable globally across all calls torandomize(). If you want to selectively enable or disable randomization for a single call, you’ll need to reset therand_mode()setting before the next randomization cycle.
pre_randomize and post_randomize Methods
The pre_randomize() and post_randomize() functions are special methods provided by SystemVerilog. They can be overridden in a class to execute code before and after randomization.
pre_randomize(): Called automatically just before the randomization process.post_randomize(): Called automatically just after the randomization process.
These functions are useful for initialization and post-processing tasks.
Example:
class packet;
rand bit [7:0] pkt_id;
rand bit [31:0] data;
function void pre_randomize();
$display("Before randomization: pkt_id = %0d, data = %0h", pkt_id, data);
endfunction
function void post_randomize();
$display("After randomization: pkt_id = %0d, data = %0h", pkt_id, data);
endfunction
endclass
module test;
initial begin
packet p = new();
p.randomize(); // pre_randomize() and post_randomize() will be called automatically
end
endmodule
In this example, the pre_randomize() function will print the values of pkt_id and data before randomization, and post_randomize() will print the values after randomization.
Output:
Before randomization: pkt_id = 0, data = 0
After randomization: pkt_id = 163, data = 5966088f
srandom Function: Setting the Random Seed
By default, SystemVerilog generates the same random sequence if the same seed is used. If you want to control the seed, use the srandom() function to set the random seed manually.
Example:
int seed = 12345;
p.srandom(seed); // Set the seed to 12345 for deterministic randomization
p.randomize();
Using srandom() allows you to reproduce specific random sequences for debugging or regression testing.