Constraint Randomization Interview Question

Hi,
Can someone help me to code constraint for below scenario.
Constraint for 32 bit address, to generate continuous 10 bits as 0 and remaining bits as 1.

Thanks in advance.

In reply to Ammu786:
Not what you asked, working on the continuous 10 bits a

class c; 
  rand bit[31:0] v;  
  constraint ct12 {$countones(v)==12;}
  // $countones (expression) returns the number of ONEs in a bit vector expression. 
endclass 

module m; 
    c c1=new(); 

  initial begin 
    repeat(5) begin
    if (!randomize(c1)) $error();
      $display("c1.v= %b", c1.v);
      ai_12: assert($countones(c1.v)==12) 
          else  $display("ERROR c1.v= %b, countones= %d", c1.v, $countones(c1.v));
    end
  end
endmodule  
/* sim results 

# c1.v= 01010001000101000100110010001011
# c1.v= 01000100001110000101100011010001
# c1.v= 00111111010000001010001000010100
# c1.v= 10100110100100100001010001100100
# c1.v= 01001110100000101011010000100100 */    

Ben Cohen
http://www.systemverilog.us/ ben@systemverilog.us
** SVA Handbook 4th Edition, 2016 ISBN 978-1518681448
…

  1. SVA Package: Dynamic and range delays and repeats SVA: Package for dynamic and range delays and repeats | Verification Academy
  2. Free books: Component Design by Example FREE BOOK: Component Design by Example … A Step-by-Step Process Using VHDL with UART as Vehicle | Verification Academy
    Real Chip Design and Verification Using Verilog and VHDL($3) https://rb.gy/cwy7nb
  3. Papers:

Udemy courses by Srinivasan Venkataramanan (http://cvcblr.com/home.html)
https://www.udemy.com/course/sva-basic/
https://www.udemy.com/course/sv-pre-uvm/

In reply to Ammu786:


class c; 
  
  rand bit[31:0] v;  
  
  rand int int1 , int2 ;
  
  constraint  LOW_BOUND     {  int1  inside { [ 0 : 31 ] } ; }
  
  constraint  UPPER_BOUND   {  int2  inside { [ 0 : 31 ] } ; }
  
  constraint  DIFF          {  int2 ==  int1  +  9 ;  }  // Range of  Indexes  is  10  !!
  
  // constraint ct12 { $countones(v) == ( 32 - 10 ) ; }  // Can be Skipped  !!
  
  constraint  VAL  {     foreach( v[i] )
                        {   
                          if( i inside { [ int1 : int2 ] } ) 
                            v[ i ] == 0 ;
                          else
                            v[ i ] == 1 ;
                        }
                   }
  
    function  void  post_randomize() ;
    $display(" int1  is  %0d , int2 is %0d" , int1 , int2) ;
    endfunction
                    
endclass 
 
module m; 
    c c1=new(); 
 
  initial begin 
    repeat(5) begin
      if (! c1.randomize() ) $display(" XXX FAILS !! XXX ");
      $display("c1.v= %b", c1.v);
      
    end
  end
endmodule  

1 Like

In reply to ABD_91:
Good solution, thank you.
Added an assertion


module m; 
  c c1=new(); 
  initial begin 
    repeat(15) begin
      if (!randomize(c1)) $display(" XXX FAILS !! XXX ");
      $display("c1.v= %b", c1.v);
      ai_12: assert($countones(c1.v)==22) 
      else  $display("ERROR c1.v1= %b, countones= %d", c1.v, $countones(c1.v));
    end
  end
endmodule
// simulation 

#  int1  is  1 , int2 is 10
# c1.v= 11111111111111111111100000000001
#  int1  is  8 , int2 is 17
# c1.v= 11111111111111000000000011111111
#  int1  is  16 , int2 is 25
# c1.v= 11111100000000001111111111111111
#  int1  is  15 , int2 is 24
# c1.v= 11111110000000000111111111111111
#  int1  is  1 , int2 is 10
# c1.v= 11111111111111111111100000000001
#  int1  is  17 , int2 is 26
# c1.v= 11111000000000011111111111111111
#  int1  is  22 , int2 is 31
# c1.v= 00000000001111111111111111111111
#  int1  is  15 , int2 is 24
# c1.v= 11111110000000000111111111111111
#  int1  is  11 , int2 is 20
# c1.v= 11111111111000000000011111111111
#  int1  is  10 , int2 is 19
# c1.v= 11111111111100000000001111111111
#  int1  is  22 , int2 is 31
# c1.v= 00000000001111111111111111111111
#  int1  is  3 , int2 is 12
# c1.v= 11111111111111111110000000000111
#  int1  is  22 , int2 is 31
# c1.v= 00000000001111111111111111111111
#  int1  is  14 , int2 is 23
# c1.v= 11111111000000000011111111111111
#  int1  is  20 , int2 is 29
# c1.v= 11000000000011111111111111111111
 

In reply to ben@SystemVerilog.us:
It was pointed ot on LinkedIn that “This would fail if int1 is greater than 22. Ex: if int1 is 25, would int2 become 34 or it would wrap around and have the value 2?”
Changing the Low bound constraint for int1 fixes this.

int1 is 22 , int2 is 31

c1.v= 00000000001111111111111111111111


class c; 
  rand bit[31:0] v;  
  rand int int1 , int2 ;
  constraint  LOW_BOUND     {  int1  inside { [ 0 : 22 ] } ; }
  constraint  UPPER_BOUND   {  int2  inside { [ 0 : 31 ] } ; }
  constraint  DIFF          {  int2 ==  int1  +  9 ;  } 
  // constraint ct12 { $countones(v) == ( 32 - 10 ) ; }  // Can be Skipped  !!
  constraint  VAL  {     foreach( v[i] )
                        { 
                          if( i inside {[int1:int2] } ) 
                            v[ i ] == 0 ;
                          else
                            v[ i ] == 1 ;
                        }
                   }
    function  void  post_randomize() ;
    $display(" int1  is  %0d , int2 is %0d" , int1 , int2) ;
    endfunction
endclass 

In reply to ben@SystemVerilog.us:

Hi Ben ,

As the constraints are solved in conjunction with each other ,
the constraint solver would implicitly ensure that max value of int1 is 22 .

If int1 were to be chosen as 25 the constraint :: ( int2 == int1 + 9 )

would Never be Successful as int2 can’t be greater than 31 !!

( due to constraint UPPER_BOUND )

Another way is to check this is using in-line constraint ::


if (! ( c1.randomize() with { int1 == 25 ; } ) ) $display(" XXX FAILS !! XXX ");

This ALWAYS Fails due to Conflicting Constraint UPPER_BOUND and DIFF

In reply to ABD_91:

The solver would ensure that max value of int1 is 22 .
If int1 is chosen as 25 the constraint :: ( int2 == int1 + 9 )
would Never be Successful as int2 can’t be greater than 31 !!

Excellent point. The question then is, why not limit the low bound to 22
constraint LOW_BOUND { int1 inside { [ 0 : 22 ] } ; }
Doesn’t it make it more readable or understandable?
It fooled me and another user.

In reply to ABD_91:

The solver would ensure that max value of int1 is 22 .
If int1 is chosen as 25 the constraint :: ( int2 == int1 + 9 )
would Never be Successful as int2 can’t be greater than 31 !!

Excellent point. The question then is, why not limit the low bound to 22
constraint LOW_BOUND { int1 inside { [ 0 : 22 ] } ; }
Doesn’t it make it more readable or understandable?
It fooled me and another user.

In reply to ben@SystemVerilog.us:

I agree it would better to constraint max value of int1 to 22 to make it more readable .

I tried an alternate solution ::


class c; 
 
  rand bit[31:0] v;  
 
  rand int int1 ;
 
  constraint  LOW_BOUND     {  int1  inside { [ 0 : 22 ] } ; }
 
  constraint ct22 { $countones(v) == ( 32 - 10 ) ; }  
 
  constraint  VAL  {     foreach( v[i] )  //  Iterates  from  31  to  0 .
                        {   
                             if( i == int1 ) 
                         {  v[ i+:10 ] ==  10'h0 ;  }  //  Issue  here , not  sure  why      
                        }
                   }
 
endclass 
 
module m; 
    c c1=new(); 
 
  initial begin 
    repeat(5) begin
      if (! c1.randomize() ) $display("  Randomization fails ");
      $display("c1.v= %b", c1.v);
 
    end
  end
endmodule  

//  When  Max( int1 )  is  22 , v[ 22 +: 10 ]  == 10'h0  i.e  v[ 31:22 ] == 10'h0 ;

//  When  Min( int1 )  is  0 , v[ 0 +: 10 ]  == 10'h0  i.e  v[ 9:0 ] == 10'h0 ;


This throws Randomization Failure on some Simulators while it works on others .

Any suggestions ?

In reply to Ammu786:

module test;
class gen;
       bit [31:0] pattern = 32'hFFFF_FC00;
  rand bit [31:0] value;
  rand bit [4:0]  rotate;
  constraint c { value == (pattern << rotate | pattern >> 32-rotate);  } // circular rotate
endclass
  gen h =new;
  initial repeat (10) begin
    assert(h.randomize());
    $display("%2d %b", h.rotate, h.value);
  end
endmodule

Depending on your definition of “consecutive” you may want to limit rotate < 23.
[br]
In reply to Have_A_Doubt:
Because sometimes v[i+:10] is out of range.

1 Like

In reply to dave_59:

Since I constraint the max value of int1 to 22 , v[22 +: 10] i.e v[ 31 : 22 ]

Even for the min. value as 0 the range would be v[ 0+:10 ] i.e v [ 9:0 ] .

As these are Valid Index range I am confused why and when ( for which value of int1 ) does the Out of range Occur ?

Won’t the if condition ensure that the Indexes are within Valid range ?

In reply to Have_A_Doubt:

Because the constraint solver is going to iterate over v[i] before knowing what the range of int1 could be. if you rewrote the constraint as

constraint  VAL  { foreach( v*)  //  Iterates  from  31  to  0 .
                     if(  i < 23 && i == int1 ) 
                        v[ i+:10 ] ==  10'h0 ;  
                 }

The i<23 acts as a constraint guard and prevents references to invalid ranges. (LRM section [i]18.5.13 Constraint guards*)

1 Like

In reply to dave_59:

Thanks for the clarification Dave .

The constraint expression ( without constraint guard ) is equivalent to ::


constraint  VAL  { 
                    
                (  ( 31 == int1 )  &&   ( v[ 31 +: 10 ] ) ) ==  10'h0 ;  

                (  ( 30 == int1 )  &&   ( v[ 30 +: 10 ] ) ) ==  10'h0 ;  
 
                (  ( 29 == int1 )  &&   ( v[ 29 +: 10 ] ) ) ==  10'h0 ;
                
                     ............................

                (  ( 0 == int1 )  &&   ( v[ 0 +: 10 ] ) ) ==  10'h0 ;                 
                }

Although the left part ( i == int1 ) is False for index value 23 and upwards ,
the right part ( v[ i +:10 ] ) still has Out of bound indexes .

Hence we observe Randomization Failure

In reply to Have_A_Doubt:
So far we saw 2 solutions:

  1. With the foreach construct
  2. With a rotate

The following table lookup solution was provided to me by a colleague;
it is more efficient than solving many constraints.


class c; 
  rand int position;
  bit[31:0] data; 
  constraint ct12 {position inside {[0:22]};}
  const bit [0:22][31:0] lookup  = {32'b00000000001111111111111111111111, //0
				32'b10000000000111111111111111111111,
				32'b11000000000011111111111111111111,
				32'b11100000000001111111111111111111,
				32'b11110000000000111111111111111111,
				32'b11111000000000011111111111111111, //  5 
				32'b11111100000000001111111111111111,
				32'b11111110000000000111111111111111,
				32'b11111111000000000011111111111111,
				32'b11111111100000000001111111111111,
				32'b11111111110000000000111111111111, // 10
				32'b11111111111000000000011111111111,
				32'b11111111111100000000001111111111,
				32'b11111111111110000000000111111111,
				32'b11111111111111000000000011111111,
				32'b11111111111111100000000001111111,  // 15
				32'b11111111111111110000000000111111,
				32'b11111111111111111000000000011111,
				32'b11111111111111111100000000001111,
				32'b11111111111111111110000000000111,
				32'b11111111111111111111000000000011,  // 20
				32'b11111111111111111111100000000001,
				32'b11111111111111111111110000000000};	
   
   function void post_randomize();
        data= lookup[position];
        //$display("position=%d, data=%b", position, data);
   endfunction : post_randomize
endclass 

module m; 
  bit clk; 
  initial forever #5 clk=!clk;  
  c c1=new(); 

  initial begin 
     repeat(50) begin
		@(posedge clk) #2; 
         	if (!randomize(c1)) $error();
	        $display("%t position=%d, c1.data=%b", $realtime, c1.position, c1.data);

	        ai_12: assert($countones(c1.data))
            else  $display("ERROR val = %b, countones= %d", c1.data,         
                       $countones(c1.data));
     end
     $finish; 
  end
endmodule  
/*
                    7 position=          6, c1.data=11111100000000001111111111111111
#                   17 position=          6, c1.data=11111100000000001111111111111111
#                   27 position=         15, c1.data=11111111111111100000000001111111
#                   37 position=         19, c1.data=11111111111111111110000000000111
#                   47 position=          6, c1.data=11111100000000001111111111111111
#                   57 position=         16, c1.data=11111111111111110000000000111111
#                   67 position=          8, c1.data=11111111000000000011111111111111
#                   77 position=          3, c1.data=11100000000001111111111111111111
#                   87 position=          6, c1.data=11111100000000001111111111111111
#                   97 position=         21, c1.data=11111111111111111111100000000001
#                  107 position=          3, c1.data=11100000000001111111111111111111
#                  117 position=          9, c1.data=11111111100000000001111111111111
#                  127 position=         14, c1.data=11111111111111000000000011111111
#                  137 position=         14, c1.data=11111111111111000000000011111111
#                  147 position=          6, c1.data=11111100000000001111111111111111
#                  157 position=          7, c1.data=11111110000000000111111111111111
#                  167 position=          5, c1.data=11111000000000011111111111111111
#                  177 position=          1, c1.data=10000000000111111111111111111111
#                  187 position=         15, c1.data=11111111111111100000000001111111
#                  197 position=          6, c1.data=11111100000000001111111111111111
#                  207 position=         19, c1.data=11111111111111111110000000000111
.....
#                  237 position=          7, c1.data=11111110000000000111111111111111
#                  247 position=          0, c1.data=00000000001111111111111111111111
#                  257 position=          1, c1.data=10000000000111111111111111111111
#                  267 position=         20, c1.data=11111111111111111111000000000011 */ 

In reply to ben@SystemVerilog.us:

I feel Dave’ Solution is generic as in user could change the
non - random property ’ pattern ’ at run - time and we would see the new pattern .

For other solution user would need to change the constraints .

In reply to dave_59:
Hi All.,
Please go through below code, which generates a continues zero for 10 bits. and remaining bits as 1.
For this i have considered a variable to generate some random value within 0,21. why 21 because 21+10=31 which is msb bit(if it is more than 21 example., 22. 22+10=32 but msb bit is 31 where that will appear as only continues 9bit instead of 10 bit). So considere only till (0,21) in random range.
So, after getting the random range i have used the if condition for iterating for continues 10bit.

we any queries , please reply back.


//Constraint for 32 bit address, to generate continuous 10 bits as 0 and remaining bits as 1.

module top;
  class test;
    rand bit[31:0] addr;
    
    constraint cnst2{addr ==func();}  //using a func to accomplish continues 10bits as '0'
    
    function bit[31:0] func();
      bit[31:0] addr1;
      bit[4:0] val;
      bit[3:0] j;
      val=$urandom_range(0,21);   //considering range from (0,21). till 21 because (21+10=31) to achieve continues 10bit zeros.
      for(int i=0;i<32;i++)
        begin                      //in if condition.,
          if(i==val || i==(val+j)) //after val generating some random value, from that bit to continues 10bit assiging zero.
            begin
              addr1[i]=1'b0;
              if(j<9)
                begin
                 j++;
                end
            end
          else                    //remaining bits assigned with 1 in else condition.
            begin
            addr1[i]=1'b1;
            end
        end
      $display("val is %0d",val);
      $display("addr1 is %b",addr1);
      return addr1;
    endfunction
    
  endclass
  
  test t1;
  initial begin
    repeat(15) begin
    t1=new();
    t1.randomize();
      $display("addr is %b",t1.addr);
      $display("addr is %h",t1.addr);
  end
  end
endmodule

output:-

val is 6
addr1 is 11111111111111110000000000111111
addr is 11111111111111110000000000111111
addr is ffff003f
val is 4
addr1 is 11111111111111111100000000001111
addr is 11111111111111111100000000001111
addr is ffffc00f
val is 11
addr1 is 11111111111000000000011111111111
addr is 11111111111000000000011111111111
addr is ffe007ff
val is 9
addr1 is 11111111111110000000000111111111
addr is 11111111111110000000000111111111
addr is fff801ff
val is 9
addr1 is 11111111111110000000000111111111
addr is 11111111111110000000000111111111
addr is fff801ff
val is 10
addr1 is 11111111111100000000001111111111
addr is 11111111111100000000001111111111
addr is fff003ff
val is 15
addr1 is 11111110000000000111111111111111
addr is 11111110000000000111111111111111
addr is fe007fff
val is 4
addr1 is 11111111111111111100000000001111
addr is 11111111111111111100000000001111
addr is ffffc00f
val is 9
addr1 is 11111111111110000000000111111111
addr is 11111111111110000000000111111111
addr is fff801ff
val is 6
addr1 is 11111111111111110000000000111111
addr is 11111111111111110000000000111111
addr is ffff003f
val is 9
addr1 is 11111111111110000000000111111111
addr is 11111111111110000000000111111111
addr is fff801ff
val is 4
addr1 is 11111111111111111100000000001111
addr is 11111111111111111100000000001111
addr is ffffc00f
val is 14
addr1 is 11111111000000000011111111111111
addr is 11111111000000000011111111111111
addr is ff003fff
val is 18
addr1 is 11110000000000111111111111111111
addr is 11110000000000111111111111111111
addr is f003ffff
val is 17
addr1 is 11111000000000011111111111111111
addr is 11111000000000011111111111111111
addr is f801ffff
1 Like

Hi Dave,
To avoid the 0s wrapped around, I have added constraint on rotate

module test;
class gen;
       bit [31:0] pattern = 32'hFFFF_FC00;
  rand bit [31:0] value;
  rand bit [4:0]  rotate;
  constraint c { value == (pattern << rotate | pattern >> 32-rotate);
                rotate inside {[0:22]}; 	
               } // circular rotate
  
endclass
  gen h =new;
  initial repeat (20) begin
    assert(h.randomize());
    $display("%2d %b", h.rotate, h.value);
  end
endmodule

21 10000000000111111111111111111111
12 11111111110000000000111111111111
 4 11111111111111111100000000001111
 4 11111111111111111100000000001111
16 11111100000000001111111111111111
19 11100000000001111111111111111111
13 11111111100000000001111111111111
 3 11111111111111111110000000000111
 8 11111111111111000000000011111111
 6 11111111111111110000000000111111
19 11100000000001111111111111111111
16 11111100000000001111111111111111
10 11111111111100000000001111111111
17 11111000000000011111111111111111
 1 11111111111111111111100000000001
11 11111111111000000000011111111111
14 11111111000000000011111111111111
 9 11111111111110000000000111111111
14 11111111000000000011111111111111
10 11111111111100000000001111111111

Hi @dave_59,
Won’t this be a simpler solution?

class prac;
  rand bit [31:0] x;
    rand bit [4:0] rot;
  bit [31:0] val = 31'h000003FF;
  constraint ROT{rot inside {[0:22]};}
  constraint PAT{x==val<<rot;}
endclass
     

module tb;
  prac pr;   
  initial begin 
      	pr = new();
        repeat(5)
          begin
        	pr.randomize();
            $display("Value of Generated constraint is %032b",pr.x);
          end
    end
endmodule

As the requirement is for 10 consecutive zeros

function void post_randomize();
     x = ~x;
  endfunction