SV Constraint :: Address must be aligned to the size of the transfer

Hi All,
If AxSize is ‘N’ then the address must be aligned to 2**N
Eg: For AxSize == 2 then address[1:0] == 0 i.e aligned to 4-byte
For AxSize == 3 then address[2:0] == 0 i.e aligned to 8-byte
Thus lower ‘AxSize’ bits are 0’s i.e Address[ (AxSize-1):0] == 0

   //  Declaration of address and axsize random variables

    rand  bit[11:0] axaddr;  // In reality Address Width is 32 bit i.e [31:0]
        
    randc bit[2:0] axsize; 

I was trying different possible solutions

(Solution 1) Intention is to constraint axaddr[ (axsize-1):0 ] to all zeroes

constraint Addr_Aligned1 {      
      
                              // axaddr[ (axsize-1):0 ] == 0; // Error-[IRIPS] Illegal range in part select
                              
                               foreach( axaddr[i] )
                               {
                                 // if( i inside { [0:(axsize-1)] } ) // [Q] What if axsize == 0 ? What will result of ( axsize - 1 )
  be ?
                                 if( i < axsize )
                                 {
                                   axaddr[i] == 0; 
                                 }  
                               }                                                                  
                             }  

[Q1] If I change if - constraint to :: if( i inside { [0:(axsize-1)] } ) and add in-line constraint ::
if( obj.randomize() with { axsize == 0; } ) ,
I observe that the o/p is tool dependent.
When axsize is 0 , what would be the upper bound of [0:(axsize-1)] ? Will it be all ones ?
Is the result dependent on the type ( signed/unsigned ) of “i” ?

(Solution 2) Intention is to constraint axaddr & ( '1 << axsize ) ( which gives result as axaddr[ (axsize - 1) : 0 ] ) as 0

 rand bit[2:0] local_axsize ; // helper variable
    
    function bit[2:0] No_of_Zeroes( bit[2:0] ip );     
      No_of_Zeroes = '1; // All Ones      
      return( No_of_Zeroes << ip );      
    endfunction  
    
    constraint Addr_Aligned2  {       
                                           
                                local_axsize == No_of_Zeroes(axsize);                          
                               
                                ( axaddr & local_axsize ) ; // Need help here. Should there be RHS ?
     
                              }

Result of ( axaddr & local_axsize ) is 12-bit with lower ‘axsize’ no. of bits as 0.
One valid solution is axsize == 0 and axaddr as unconstrained ( including 0x0 )
i.e each address would be aligned to 1-byte
However axsize == 0 and axaddr == 0 won’t be picked via constraint axaddr & local_axsize ( as result is 0 ). The intention is that axsize == 0 and axaddr == 0 should also be picked as a possible solution.

[Q2] How should I use result of local_axsize in order to constraint axaddr accordingly ?

[Q3] Any suggestions for alternative solution are welcome as well

Use a mask

constraint align {
  ( axaddr & ( 1'b1 << axsize ) - 1 ) == '0;
}

You could use modulo operator:

constraint aligned{
axaddr % (2**axsize) == 0;
}

1 Like

Thank you both Dave and Kranthi.
@dave_59 a question regarding above foreach constraint

foreach( axaddr[i] )
 {
     if( i inside { [0:(axsize-1)] } ) // confusion here                
    {
         axaddr[i] == 0; 
     }  
  }    

[Q] If axsize is chosen as 0 , would there be any constraint on axaddr ?
Since (axsize-1) would be -1 shouldn’t there be a warning/error message ?
( as the range for inside operator must be [low:high] )

If axsize ==0, then there is no constraint on axaddr, which is the correct thing to do.

Yes I do agree but I was curious on how the constraint solver interprets the if-constraint

if( i inside { [0:(axsize-1)] } )

I tried the following

module tb;  
  bit[11:0] axaddr;        
  bit[2:0] axsize ; // Defaults to 0
    
  initial begin
    foreach( axaddr[i] )  
     if( i inside { [0:(axsize-1)] } )      
       $display("i is %0d N (axsize-1) is %0h",i,(axsize-1));             
  end  
endmodule  

I observe “(axsize-1) is ffffffff” i.e result is 32-bit (even though width of axaddr is 12-bit )

LRM 12.7.3 mentions

When loop variables are used in expressions other than as indices to the designated array, they are auto-cast into a type consistent with the type of index. For fixed-size and dynamic arrays, the auto-cast type is int .

Since the iterator argument “i” is int type i.e 32-bit signed type result of (axsize-1) would be FFFF_FFFF.
However shouldn’t this constraint all the bits of axaddr to 0 ? ( as the if condition would be always true )

 rand  bit[11:0] axaddr;  // In reality Address Width is 32 bit i.e [31:0]        
 randc bit[2:0] axsize;

constraint Addr_Aligned1 {      
      
        // Assuming 'axsize' is 0  via in-line constraint                            
           foreach( axaddr[i] )
         {
            if( i inside { [0:(axsize-1)] } ) // Always true as i is inside {[0:FFFF_FFFF] } 
           {
               axaddr[i] == 0; // Shouldn't this constraint all bits to 0's ?
            }  
          }                                                                  
       }

A 2nd possibility I see is that the inside constraint is ignored as range isn’t [low:high] thereby leaving axaddr unconstrained.
However I don’t observe any warning message for the invalid range.

I observe that the o/p is tool depended edalink

Yes, even experienced users like me get caught by the mixing of signed and unsigned types. So for axsize==0 all axaddr bits would be set to 0.

This is why we strongly encourage people to put in minimal,complete reproducible examples to get the best responses.

1 Like

This made me realize that the range for the inside operator is still [low:high] due to result of (axsize-1) being 32-bit unsigned.
As axsize is bit type i.e unsigned type, (axsize-1) would be 32’hFFFF_FFFF i.e unsigned.
Hence the if-constraint would always be true and axaddr would be constrained to 12’b0.