Issue with following dist Constraint

I was trying a few codes involving dist and inside ::


 //  CODE I
   rand int val ;
   int a = 10 , b = 20 , c = 21 , d = 30 ; // Can be changed at run-time 

   constraint V1 { val inside { [a:b] } ; }   
   constraint V2 { val inside { [c:d] } ; }


The above code has constraint failure ( Since V1 and V2 both can’t be true at same time )
Although the intention is to keep val between 1 to 20 , it should be specified as comma separated values i.e val inside { [a:b] , [c:d] } ;

Similar issue exists if I write dist constraint as follows ::


     // CODE II
   int a = 10 , b = 20 , c = 21 , d = 30 ;
   rand int val ;
   constraint V1 { val dist { [a:b] :/ 10 } ; }   
   constraint V2 { val dist { [c:d] :/ 20 } ; }
  
 
    // CODE III
    rand int value;
    int a[5], b[5];

function void pre_randomize() ;
  a = {1, 11, 21, 31, 41};
  b = {10, 20, 30, 40, 50};
endfunction


constraint c_value { 
                           foreach (a[i])
                       value inside { [a[i]:b[i]] } ; // Error !!
                    }
   

Since the Constraint gets unrolled into 5 different Constraints , the randomization fails !!

  
// Gets Unrolled into semicolon separated Constraints ( i.e 5 constraints !! )
 value inside { [1:10] } ; value inside { [11:20] }; value inside { [21:30] } ; value inside { [31:40] }; 

Now I am confused how does the following Constrained gets unrolled ?


rand int value;
int a[5], b[5];
int c[5];

function void pre_randomize() ;
  a = {1, 11, 21, 31, 41};
  b = {10, 20, 30, 40, 50};
  c = {30, 15, 10, 15, 30};
endfunction


constraint c_value { 
                             foreach (a[i])
                       value dist { [a[i]:b[i]] :/ c[i] }; // Error !!
                   }

[Q1] Randomization fails above . It seems like it gets unrolled into 5 semicolon separated constraints within c_value . Is my understanding correct ?

 
value inside { [1:10]:/ 30 } ; value inside { [11:20]:/ 15 }; value inside { [21:30]:/ 10 } ; value inside { [31:40]:/ 15 } ; 
value inside { [41:50]:/ 30 } ;
    

How can I change it to comma separated constraint ?

 
i.e value inside { [1:10]:/ 30 , [11:20]:/ 15 , [21:30]:/ 10 , [31:40]:/ 15 } , [41:50]:/ 30 } ;

In reply to ABD_91:

Your assumption is correct. For iterative constraints, each iteration gets ANDed together. For the simple case you can use a reduction or instead of foreach

constraint c_value { a.or() with (value inside { [a[i]:b[i]] } ); }

Applying weights from a variable sized array can get complicated. You might try

constraint c_value { a.or() with ( (value inside { [a[i]:b[i]] } ) dist {0:= c.sum(), 1:=c[i]} );  }

I didn’t verify the code or the math, but that might get you going in the right direction. You can also look at this link.

In reply to dave_59:

Hi Dave ,

I have a few questions ::


// Constraint to have val between 1 to 50 
constraint c_value { a.or(item) with ( val inside { [ a[item.index]:b[item.index] ] } ) ; } 

[1] Why use or() reduction operator ?

Since our goal is to have a comma separated constraint and inside operator evaluates to
( val inside {[1:10] } ) || ( val inside {[11:20] } ) || ( val inside {[21:30] } ) || ( val inside {[31:40] } ) || ( val inside {[41:50] } )

or() reduction operator helps us achieve the logical OR .
Is this the main reason to use or() reduction Operator ?

[2] I notice that using sum() reduction operator gives us val between 1 to 50 too .


  a.sum(item) with ( val inside { [ a[item.index]:b[item.index] ] } ) ; // Works as well !!   
    

[3] Is the expression specified within with ( val inside { [ a[item.index]:b[item.index] ] } ) the actual Constraint for the solver ?
i.e For solver to chose a value between [1:10] , [11:20] , … [41:50]

 I ask cos normally the result of the with() clause acts as an expression for the constraint solver to actually solve .
 eg :: array.sum() with (int'(item)) == 10 ; 

[4] When I use ::


     $display("%0d",obj.a.sum(item) with ( int' ( obj.val inside { [ obj.a[item.index]:obj.b[item.index] ] } ) ) ) // int'() cast used !!
    
 I notice an Output of 1 always ( Even if I use a.or(item) ... )  . 

Is it cos that although val unrolls into 5 Constraints separated by || , at a time val can only be inside a specific range ?

Eg : if val is chosen as 11 , only val inside [11:20} would return 1’b1 whereas the other 4 inside constraint would return 0 . So 32’b0 + 32’b1 + 32’b0 + 32’b0 + 32’b0 == 32’b1

[5] Regarding Applying weights from a variable sized array ::

Syntax 18-3 of LRM specifies syntax as :: 

expression_or_dist ::= expression [ dist { dist_list } ]

So can any expression be used on LHS of dist ? 

(a) Ternary Operator would work too ?
eg :

 
       constraint DIST { ( condition ) ? dist { ..  } : 1 ; } 
// If condition is false , the 1 would ensure constraint DIST returns true ( Non-zero ) 
          

(b) I tried using :


a.or(item) with ( ( val inside { [ a[item.index]:b[item.index] ] } ) dist { 1:/c[item] }  ) ;
     

Shouldn’t this work based on Syntax 18-3 of LRM ?

(c) I modified code to ::


a.or(item) with ( val dist { [ a[item.index]:b[item.index] ] :/ c[item.index] }  ) ;
  

This flashed an error :: " Feature is not yet supported: Usage of dist inside the property " on latest simulator ( 2020 version ) .

It does recognize it as a valid syntax .

In reply to ABD_91:

  1. Correct.
  2. sum() also work in your case because there are no overlapping ranges.
  3. I think you are over thinking it. All constraints get unrolled into a single Boolean expression that evaluates to 1’b1 or 1’b0.
  4. Same reason as 2)
  5. Correct. Just like the inside operator, dist returns 1’b1 or 1’b0.

And “not yet supported” means it does recognize it as valid sytax, but the tool has not implemented the feature yet.

In reply to dave_59:

Thanks Dave .