Understanding Array Reduction methods

Hi Moderators,

I am trying variation of array reduction method sum in a constraint to understand it’s equivalent expression in each scenario. Here is my attempt

Assume that out of C1 to C7 there is only one constraint active

Have listed my queries in the edalink

Thanks

A1) According to 7.12.4 Iterator index querying, the index type can be either an int or, for an associative array, it’s the same as the type of the array index.
A2) Since addition has precedence over equality, the parentheses don’t affect the result.
A3) Concatenation {} may have the lowest precedence, but the operands of a concatenation are all self-determined. This means that the width of the expression inside the concatenation is determined independently of the right-hand side of the equality. Consequently, the addition is evaluated in the context of a 2-bit width, which has a maximum value of 3, and this value can never equal 10. Therefore, this constraint always fails.
A4) This constraint is equivalent to 1+1+1+1+1, which evaluates to 5. Since 5 is a non-zero value, the constraint considers it a success. A constraint that always evaluates to a non-zero value is considered a non-constraint.
A5) This constraint is equivalent to the expression 0+0+0+0+0, which evaluates to 0. Since the constraint considers a zero value as a failure, it fails.

Thanks Dave.

Two follow up questions

(QA) Consider the following example from 1800-2023 section 18.5.7.2

class C;
rand bit [7:0] A[];
constraint c1 {A.size == 5;}
constraint c2 {A.sum() with (int'(item)) < 1000;}
endclass

The constraint c2 will be interpreted as

( int'(A[0])+int'(A[1])+int'(A[2])+int'(A[3])+int'(A[4]) ) < 1000;

Based on A3, shouldn’t concatenation operator be part of equivalent expression ?

LRM should mention the equivalent expression for c2 as 

{ (int'(A[0])+int'(A[1])+int'(A[2])+int'(A[3])+int'(A[4])) } < 1000;

In above example although the int’ cast avoids the overflow,

the following example illustrates requirement of concatenation operator

class C_new;
rand bit [7:0] A[];
constraint c1_new {A.size == 5;}
constraint c2_new {A.sum() with (item) < 1000;} // No int' cast
endclass

As per my understanding equivalent expression for c2_new wouldn't be ::

( A[0]+A[1]+A[2]+A[3]+A[4] ) < 1000;

Similar to constraint C4 in my edalink,
due to RHS 32' cast would be used for each element causing randomization to succeed

c2_new should be equivalent to { (A[0]+A[1]+A[2]+A[3]+A[4]) } < 1000;

(QB) For C6 and C7 why does the with expression (0 / 1) appear 5 times (same as size) ?

My understanding was that the presence of keywords like item / item.index within

with clause results in iteration through each element / index .

Hence in such cases the with expression appears size number of times

As C6 and C7 don’t have either of these 2 keywords, I expected with expression (0 / 1) to appear only once

Yes, the concatenation operator should be part of the equivalent expression for clarity. However, the LRM section 7.12.3 Array reduction methods does say:

The method returns a single value of the same type as the array element type or, if specified, the type of the expression in the with clause.

Iteration happens regardless of the presence or absence of the item or index keywords

I realized we had a similar discussion in an older thread

Hi Dave,

An additional question on the related topic

As per LRM the repeat operator in concatenation operation is required to be constant.

Hence I can see the following repeat operator $size(arr) works as unpacked dimension is fixed

 class Fixed_Arr;
    
  rand bit[2:0] arr[4];
    
  constraint SUM { arr.sum() with ( int'(item) ) == { $size(arr){1'b1} }; }
    
 endclass

[Q6] If arr were defined as dynamic array, how do I make the SUM constraint work ?

class Dyn_Arr;
    
  rand bit[2:0] arr[$];
    
  constraint SIZE { arr.size() inside {[3:6]}; }
    
  constraint SUM { arr.sum() with ( int'(item) ) == { arr.size(){1'b1} }; }
    
endclass

You don’t need to concatenation here; use the shift operator instead.

constraint SUM { arr.sum() with ( int'(item) ) == (1 << arr.size() ) - 1 ; }

Hi Dave,

In the following code how would '1 be interpreted ?

bit [63:0] arr[5];
                   
  initial begin
    repeat(5) begin      
      if( !std::randomize(arr) with { arr.sum() with (70'(item)) == '1; } )
        $display("Fails");
    end  
  end
  1. Would '1 be 32’hFFFF_FFFF or 70’h3F_FFFF_FFFF_FFFF_FFFF ?

As per LRM

An unsized unsigned single-bit value can be specified by preceding the single-bit value with an apostrophe( ’ ), but without the base specifier.

All bits of the unsized value shall be set to the value of the specified bit.

In a self-determined context, it shall have a width of 1 bit.

  1. What does the last line from the above quote mean ? When would '1 use width of 1-bit ?

A self-determined context refers to an operand whose type remains unaffected by any external expression. For example, when we have $displayh( 0 + (‘1 << ‘1) );, it displays ffffffffe. This is because the result of the shift operation is incorporated into an addition expression that is being added to a 32-bit signed decimal number, 0. The left-hand side (LHS) of the shift operation is not self-determined and becomes 32’hffffffff, while the shift amount on the right-hand side (RHS) is self-determined and becomes 1’b1.

In your example '1 becomes 70’h3F_FFFF_FFFF_FFFF_FFFF .

Thanks Dave

As 0 is 32-bit, LHS of shift operator would be 32’hFFFF_FFFF

On changing it to

Due to 0 being 64-bit, LHS operator would be 64’FFFF_FFFF_FFFF_FFFF

In the std::randomize the equivalent expression is

{ 70’(arr[0]) + 70’(arr[1]) + 70’(arr[2]) + 70’(arr[3]) + 70’(arr[4]) } == '1

Operands of concatenation operator are self-determined meaning the sum is calculated independent of bit width of RHS.

However I am curious why does RHS ‘1 use the 70-bit width from LHS ( in presence of concatenation operator on LHS ) ?

Is it due to total sum being 70-bits wide ? Due to which the final expression would be

70’( total_sum ) == '1.

As the expression isn’t self-determined, RHS takes 70-bit width => Is this reasoning correct ?

It’s correct. The type of the resulting self-determined expression can be used to determine the type of another expression it’s a part of.