Implementing Randc Function in SystemVerilog without Actually Using Randc Variables

Hi, I would like to take a peek at randc variables today, and then talk about implementing it in a way with only rand variables.
 

For starter, let’s take a look at the definition of randc modifier. It’s defined in RFM 18.4.2.

Variables declared with the randc keyword are random-cyclic variables that cycle through all the values in a random permutation of their declared range. The basic idea is that randc randomly iterates over all the values in the range and that no value is repeated within an iteration. When the iteration finishes, a new iteration automatically starts.

For example, if we have the following variable

randc bit [1:0] y;

The variables y can take on the values 0, 1, 2, and 3. Each permutation, y is going to take on all the values before it moves to the next permutation.
 

There are a few things worth mentioning here based on my experience:

  1. Size limitation
  2. Different vendors may impose a limit on the maximum size of a randc variable. The size shall be no less than 8 bits, which means the value can only go up to 255 if we define it as unsigned. When we are dealing with large numbers, we have to figure something else to accomplish this.

  3. Constraint solver priority
  4. If we take the solution distribution into consideration, we have to watch closely over randc variables as well. Randc variables are solved before other random variables which can mess up the solution probability distribution and sometimes cause constraint failures.

 
An alternative way to implement the randc function without incurring the issues is listed below:

The basic idea is to add a queue. Within each permutation, all the generated values are pushed onto the queue, and the newly generated value should be different from all the values that are already stored in the queue. When the queue’s size reaches the number of values defined in each permutation, we clear the queue and start the next permutation.

We can use set membership in constraints to guarantee that the newly generated values are not already stored in the queue. We can perform the push and clear functions in the post_randomize function. The code is listed below:

program p1;

    class c1;

        //queue to store generated variables
        bit [1:0] q [$];

        rand bit [1:0] y;

        //set the membership
        //y should not be generated before
        constraint c {
            !(y inside {q});
        }


        function void post_randomize();
            q.push_front(y);

            //if the size equals to the number of all combinations, clear the queue
            if(q.size()==4)
                q.delete();

        endfunction

    endclass


    c1 c1_h;


    initial begin

        c1_h = new();

        repeat(20) begin
            if(c1_h.randomize())
                $display("y is %b",c1_h.y);
        end

    end

endprogram

 

That’s all I would like to share on this topic today. If you have any questions, please leave me a comment below. Thank you for reading.

One thought on “Implementing Randc Function in SystemVerilog without Actually Using Randc Variables

Leave a Reply

Your email address will not be published. Required fields are marked *