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