Randcase Vs Randsequence in Systemverilog
Randcase:
Randcase is a case statement that randomly selects one of its branches just like a case statement in Verilog but here as its randcase so it will pick statements randomly. Randcase can be used in class or modules.
The randcase item expressions are non-negative integral values that constitute the branch weights.
An item weight divided by the sum of all weights gives the probability of taking that branch.
Let’s understand through the example below:
randcase
9 : x = 10;
5 : x = 11;
7 : x = 12;
endcase
In the above-mentioned example, the sum of all weights is 21; therefore, the probability of taking the first branch is (9/21) i.e. 0.428.
The probability of taking the second is (5/21) i.e. 0.238, and the probability of taking the third is (7/21) i.e. 0.333.
If a branch specifies a zero weight, then that branch is not taken. If all randcase_items specify zero weights, then no branch is taken and a warning can be issued.
The randcase weights can be arbitrary expressions, not just constants.
Let’s see another example
byte a, b;
randcase
a + b : x = 1;
a - b : x = 2;
a ^ ~b : x = 3;
12'b800 : x = 4;
endcase
In the above-mentioned example, the first three weight expressions are computed using 8-bit precision, and the fourth expression is computed using 12-bit precision. So, the resulting weights are added as unsigned values using 12-bit precision. The weight selection then uses an unsigned 12-bit comparison.
Each call to randcase statement will return a random number in the range from 0 to SUM.$urandom_range(0, SUM) is used to generate a random number.
program rand_case;
int a;
int itr_1, itr_2, itr_3;
initial begin
itr_1 = 0;
itr_2 = 0;
itr_3 = 0;
repeat(1000) begin
randcase
7 : a = 1;
3 : a = 2;
5 : a = 3;
endcase
if(a == 1) begin
itr_1++;
end
else if(a == 2) begin
itr_2++;
end
else if(a ==3) begin
itr_3++;
end
end
$display("itr_1 = %0d, itr_2 = %0d, itr_3 = %0d", itr_1, itr_2, itr_3);
$display("Probability: itr_1 = %0f, itr_2 = %0f, itr_3 = %0f", (itr_1/1000.0), (itr_2/1000.0), (itr_3/1000.0));
end
endprogram : rand_case
Randsequence:
The random sequence generator is useful for randomly generating structured sequences of stimulus such as instructions or network traffic patterns.
By randomizing a packet, it will generate the most unlikely scenarios which are not interested. This type of sequence of scenarios can be generated using randsequence.
randsequence is composed of one or more productions.
Each production contains a name and one or more production_list.
Production_list contains one or more production_item.
Production_items of production_list are further classified into terminals and non-terminals.
A terminal is an indivisible item that needs no further definition than its associated code block.
Ultimately, every non-terminal is decomposed into its terminals.
program rand_sequence();
initial begin
repeat(5) begin
randsequence( main )
main : one two three ;
one : {$write("one");};
two : {$write(" two");};
three: {$display(" three");};
endsequence
end
end
endprogram : rand_sequence
// Here production is "main".
// production "main" contain only one production_list with 3 production_items named "one", "two", "three".
// production_items "one", "two", "three" are terminals.
// When the "main" is chosen, it will select the sequence "one", "two" and "three" in order.
A single production can contain multiple production lists. Multiple Production lists separated by a | imply a set of choices, which the generator will generate randomly.
program rand_sequence();
initial begin
repeat(10) begin
randsequence( main )
main : one | two | three ;
one : {$display("one");};
two : {$display("two");};
three: {$display("three");};
endsequence
end
end
endprogram : rand_sequence
// Here "main" is production,
// "main" has 3 production_list, each production_list consist 1 production_item,
// 1st production_list has a production_item called "one",
// 2nd production_list has a production_item called "two",
// 3rd production_list has a production_item called "three",
// production_items "one", "two", "three" all are terminals.
In the above output, you can see that one, two, and three selected randomly.
By default procution_list is generated randomly, you can give a probability for a production_list generation.
The probability that a production list is generated can be changed by assigning weights to production lists.
The probability that a particular production list is generated is proportional to its specific weight.
The:= operator assigns the weight specified by the weight_specification to its production list.
A weight_specification must evaluate to an integral non-negative value.
Weight expressions are evaluated when their enclosing production is selected, thus allowing weights to change dynamically.
program rand_sequence();
int cnt_1,cnt_2,cnt_3;
initial begin
cnt_1 = 0;
cnt_2 = 0;
cnt_3 = 0;
repeat(1000) begin
randsequence( main )
main : one := 1 | two := 2 | three := 3;
one : {cnt_1++;};
two : {cnt_2++;};
three: {cnt_3++;};
endsequence
end
$display(" one %0d \n two %0d \n three %0d",cnt_1,cnt_2,cnt_3);
end
endprogram : rand_sequence
Production can be made conditional by means of an if..else production statement. The expression can be any expression that evaluates to a boolean value. If the expression evaluates to true, the production following the expression is generated, otherwise, the production following the optional else statement is generated.
Let’s understand with the example below
program rand_sequence();
int cnt_1,cnt_2,cnt_3;
reg on;
initial begin
on = 0;
cnt_1 = 0;
cnt_2 = 0;
cnt_3 = 0;
repeat(1000) begin
randsequence( main )
main : one three;
one : {if(on) cnt_1++; else cnt_2 ++; };
three: {cnt_3++;};
endsequence
end
$display(" one %0d \n two %0d \n three %0d",cnt_1,cnt_2,cnt_3);
end
endprogram : rand_sequence
Production can be selected from a set of alternatives using a case statement. Case expression is evaluated, and its value is compared against the value of each case-item expression, which is evaluated and compared in the order in which they are given.
The production associated with the first case-item expression that matches the case expression is generated.
If no matching case-item expression is found then the production associated with the optional default item is generated, or nothing if there is no default item. Case-item expressions separated by commas allow multiple expressions to share the production.
program rand_sequence();
initial begin
for(int i = 0 ;i < 10 ;i++)
begin
randsequence( main )
main : case(i%3)
0 : zero;
1, 2 : non_zero;
default : def;
endcase;
zero : {$display("zero");};
non_zero : {$display("non_zero");};
def : {$display("default");};
endsequence
end
end
endprogram : rand_sequence
The repeat production statement is used to iterate a production over a specified number of times.
program rand_sequence();
int cnt_1,cnt_2,cnt_3;
initial begin
cnt_1 = 0;
cnt_2 = 0;
cnt_3 = 0;
repeat(1000) begin
randsequence( main )
main : one | repeat(3) two | repeat(5) three ;
one : {cnt_1 ++; };
two : {cnt_2 ++; };
three: {cnt_3 ++; };
endsequence
end
$display(" one %d \n two %d \n three %d",cnt_1,cnt_2,cnt_3);
end
endprogram : rand_sequence