Implementing randc behavior using regular constraints in SystemVerilog

In SystemVerilog, variables declared with the randc keyword are random-cyclic variables that cycle through all the values in a random permutation of their declared range. 

For eg: consider  a 2 bit variable declared as     randc bit [1:0] y;

Every time this variable is randomized,  the values are iterated over the possible range (in this case 0,1,2,3)  and no value will be repeated until the range is completely iterated. 

One common questions asked in interviews is to implement this behavior without using randc variables.

Here is one implementation that I can think off .  The example shows a “N”  bit vector  which is randomized.   The concept is simple.  Each time a value is generated, it is maintained in a list and the next generation picks a unique value for the variable which does not match the existing list.   The list is then deleted once the maximum number of possible values are generated  which mimics the completion of one iteration of randc variable.

module test;
  parameter N =10; 
  typedef bit[N-1:0] my_type;
  my_type randc_var;
  my_type gen_done[$];
  function automatic my_type get_randc();
    bit succ =0;
    while(!succ) begin
      succ =  std::randomize(randc_var) with 
{ unique {randc_var,gen_done};}; end //If success push to queue gen_done.push_back(randc_var); if(gen_done.size() == 2**N) begin gen_done.delete(); end return randc_var; endfunction initial begin for (int i=0; i <1000; i++) begin $display("randc[%0d] = %0d", i, get_randc()); end end endmodule

A follow on question  for above code:  Why  is there a  need for automatic function? 

Alternatively you can implement the same using   a  rand  variable inside a class and writing a similar constraint  as part of the class.   In that case,  you can push the randomized value into the list  in the post_randomize() function.   And once the  list reaches maximum possible values, the list can be deleted so that iterating over values starts again

class  randc_test;
  parameter N =10; 
  typedef bit[N-1:0] my_type;
  my_type randc_var;
  my_type gen_done[$]; //queue of items done
  constraint randc_var_c {  unique {randc_var,gen_done};};

  function void post_randomize();
    gen_done.push_back(randc_var);
    if(gen_done.size() == 2**N) begin
      gen_done.delete();
    end  
   endfunction
 endclass 
error

Enjoy this blog? Please spread the word :)