How to randomize a int variable with 2 mandatory values?

I want to randomize a variable “a” such that even if I randomize this 2 times or more, I should get atleast 1 “maxval” and 1 “minval”.

For ex.

define aint 4 define bint 10

I want to randomize variable a only on the basis of aint (i.e only 4 times) and I am required that I should get atleast one "0" and one "10" (depending on the value of bint) and the rest two values of a can be between 0 and 10.

Please help.

In reply to Prat_0693:
The issue I see is that there is a sequence flow in your requirements.
Below is a solution based on my understanding of your requirements. Perhaps this can guide you into the approach you need.


import uvm_pkg::*; `include "uvm_macros.svh" 
class C;
	/* I want to randomize a variable "a" such that even if I randomize this 2 times or more, 
	 * I should get atleast 1 "maxval" and 1 "minval".
     For ex.  `define aint 4   `define 10 10
     I want to randomize variable a only on the basis of `aint (i.e only 4 times) 
     and I am required that I should get atleast one "0" and one "10" 
     (depending on the value of `10) and the rest two values of a can be between 0 and 10.
     [Ben] Not clear requirements.  Let me assume th following requirements: 
     1) within aint (e.g., 4) randomize calls, and within those 4 times, 
     2) there should be at least one 0 and one 10 */
     // `define aint 4
    // `define  10 10
	int count; 
	bit found_min; 
	bit found_max; 
   rand int unsigned  a;	
   function void do_randomize(); 
   	case (count)
   		0, 1 : begin :a01
   			  count += 1'b1;
   			  if (!randomize(a) with {a >=0; a<11;}) `uvm_error("MYERR", "This is a randomize error")
   			  if(a==0) found_min=1'b1; 
   			  if(a==10) found_max=1'b1;
   		    end   :a01 	
   		2,3 :  begin :a23
   			      if(!found_min && !found_max) begin 
   		    	    if (!randomize(a)  with 
   		    			{a dist {0:=1, 10:=1};
   		    			}) `uvm_error("MYERR", "This is a randomize error")
   		    	    if(a==0) found_min=1'b1; 
   		    	    if(a==10) found_max=1'b1;
   		    	  end
   		    	  else if(found_min && !found_max) begin 
   		    	  	if (!randomize(a)  with 
   		    	  			{a dist {0:=0, 10:=1};
   		    	  			}) `uvm_error("MYERR", "This is a randomize error")
   		    	    //if(a==0) found_min=1'b1; 
   		    	    if(a==10) found_max=1'b1;
   		    	  end
   		    	  else if(found_min && !found_max) begin 
   		    		if (!randomize(a)  with 
   		    				{a dist {0:=1, 10:=0};
   		    				}) `uvm_error("MYERR", "This is a randomize error")
   		    		if(a==0) found_min=1'b1; 
   		    		//if(a==10) found_max=1'b1;
   		    	   end   	
   		    	  else begin :a23e
   		    	  	if (!randomize(a)  with 
   		    			{ a dist {1'b1:=1, 1'b0:=3};
   		    			}) `uvm_error("MYERR", "This is a randomize error")
   		          
   		            if(count !=3) begin 
   		              if(a==0) found_min=1'b1; 
   		               if(a==10) found_max=1'b1;     		        
   		               count += 1'b1;
   		             end
   		            else begin 
   		              count=0;   		        
   		    	      found_min=1'b0; 
   		    	      found_max=1'b0;   		    	
   		    	    end 
   		           end :a23e
   		        end :a23
   		    default : $display("error in case"); 
   	endcase
   		    
     endfunction :do_randomize 
endclass


module top; 
	timeunit 1ns;     timeprecision 100ps;  
	bit clk;
	int a; 
	C c; 
	initial forever #10 clk=!clk;  
 
	initial begin 
	c=new(); 
		repeat(200) begin 
			@(posedge clk);   
			c.do_randomize(); 
			a=c.a; 
			$display("a %d, count %d, found_min %b, found_max %b", c.a, c.count, c.found_min, c.found_max);
			
		end 
		$stop; 
	end 
endmodule  

# a          3, count           1, found_min 0, found_max 0
# a          6, count           2, found_min 0, found_max 0
# a         10, count           2, found_min 0, found_max 1
# a          0, count           3, found_min 1, found_max 1
# a          0, count           0, found_min 0, found_max 0
# a          6, count           1, found_min 0, found_max 0
# a          3, count           2, found_min 0, found_max 0
# a          0, count           2, found_min 1, found_max 0
# a         10, count           2, found_min 1, found_max 1
# a          1, count           3, found_min 1, found_max 1
# a          0, count           0, found_min 0, found_max 0
# a          6, count           1, found_min 0, found_max 0
# a          2, count           2, found_min 0, found_max 0
# a          0, count           2, found_min 1, found_max 0
# a         10, count           2, found_min 1, found_max 1
# a          0, count           3, found_min 1, found_max 1
# a          1, count           0, found_min 0, found_max 0
# a          8, count           1, found_min 0, found_max 0
# a         10, count           2, found_min 0, found_max 1
# a          1, count           3, found_min 0, found_max 1
# a          0, count           0, found_min 0, found_max 0
# a          6, count           1, found_min 0, found_max 0
# a          4, count           2, found_min 0, found_max 0
# a          0, count           2, found_min 1, found_max 0
# a         10, count           2, found_min 1, found_max 1
 

Ben Cohen
http://www.systemverilog.us/ ben@systemverilog.us
For training, consulting, services: contact Home - My cvcblr


In reply to ben@SystemVerilog.us:

Ben’s solution doesn’t not take int account that the min and max values need to be seen by aint number of attempts (Prat_0693, it would help to use more descriptive variable names, like count for aint, and max_value for bint).

The easiest thing to do would be to generate the numbers in advance by putting them into a list.

class numbers;
  int count=4;
  int max_value=10;
  rand int list[];
  constraint c_range {foreach(list[ii]) list[ii] inside {[0:max_value]};}
  function void pre_randomize(); list = new[count]; endfunction
  function void post_randomize();
     list.sort();
     if (list[0] != 0) list[0] = 0;
     if (list[count-1] != max_value) list[count-1] = max_value;
     list.shuffle();
   endfunction
endclass

In reply to Prat_0693:

Here is a version to use randc cyclic random constraint.


import uvm_pkg::*; 
`include "uvm_macros.svh" 

`define aint 4
`define amax 10

class my_class extends uvm_object;
 
  randc int a; 
  constraint a_range {a inside {0,`amax, `amax+1, `amax+2};}

  rand int unsigned c, d; 
  constraint c_d_range { c inside {[1:`amax-1]};
                         d inside {[1:`amax-1]};
                       }
  
  
  function void post_randomize();
    case(a)
      `amax+1: a = c;
      `amax+2: a = d;
      default: begin end //Do nothting
    endcase
  endfunction  
  
endclass

module tb ();
  
  my_class my_obj;

  initial begin
    my_obj = new();
    for(int i=0; i< `aint*4; i++) begin
      void'(my_obj.randomize());
      $display("a%0d = %-0d", i%`aint, my_obj.a);
    end
  end
  
endmodule

simulation result as below:
a0 = 10
a1 = 0
a2 = 8
a3 = 6

a0 = 10
a1 = 9
a2 = 5
a3 = 0

a0 = 6
a1 = 10
a2 = 0
a3 = 5

a0 = 4
a1 = 10
a2 = 0
a3 = 7

In reply to Lina.Lin:
That is a clever solution using the randc. I like it!
Ben