Constraint to generate an array of random numbers where a certain value is repeated fixed number of times

Lets assume I have the below class:

class numberGen;
int i;
rand bit[7:0] arr[100];

function new();
i = 5;
endfunction

endclass

I want to write a constraint so that 10 elements of the array arr have the value of 5, if i call randomize() on an object of the class numberGen, can someone help me with the constraint?

I am able to achieve the above by adding code in post_randomize function but have failed to do so with just a constraint.

Appreciate your help!

In reply to nachiketag:

class numberGen;
   int i,j;
   rand bit[7:0] arr[100];
   function new();
      i = 5; j =10;
   endfunction
   constraint pick_ij { arr.sum(item) with (int'(item == i)) == j;}
endclass : numberGen

In reply to dave_59:

In reply to nachiketag:

class numberGen;
int i,j;
rand bit[7:0] arr[100];
function new();
i = 5; j =10;
endfunction
constraint pick_ij { arr.sum(item) with (int'(item == i)) == j;}
endclass : numberGen

Hi Dave,

“with” is getting really confusing without having any descriptions in LRM.
Can you please help me understanding difference between below 2 statements?

  1. constraint pick_ij { arr.sum(item) with (int’(item == i)) == j;}
    Output of 1) is → number of i equal to j. This statement has really nothing to do with sum.

  2. constraint pick_ij { arr.sum(item) with (int’(item)) == j;}
    Output of 2) is → sum of arr equal to j.

There is vast difference between output of above 2 statements, but it’s really confusing why and how.

Thanks,
Kavish

In reply to shahkavish77:

All you have to do is unroll the sum method
1)

 ( int'(arr[0] == i) + int'(arr[1] == i) + ... + int'(arr[99] == i) ) ==j;

 ( int'(arr[0]) + int'(arr[1]) + ... + int'(arr[99]) ) ==j;

In reply to dave_59:

Got it, Dave. Thanks, as always :)

In reply to dave_59:

[quote]In reply to shahkavish77:

Hi dave,

i have a doubt

All you have to do is unroll the sum method
1)

 ( int'(arr[0] == i) + int'(arr[1] == i) + ... + int'(arr[99] == i) ) ==j;

 ( int'(arr[0]) + int'(arr[1]) + ... + int'(arr[99]) ) ==j;

Thank you

In reply to sasi_8985:

Hi all,

I had tried below code and i am getting an error like this:-

xmsim: *W,SVRNDF (./testbench.sv,39|17): The randomize method call failed. The unique id of the failed randomize call is 0.
Observed simulation time : 0 FS + 0
xmsim: *W,RNDOCS: These constraints contribute to the set of conflicting constraints:

  constraint number { count_five(a) == five;} (./testbench.sv,9)

xmsim: *W,RNDOCS: These variables contribute to the set of conflicting constraints:


Var_Name               Type   Status        Current_Value          Source                   
--------------------------------------------------------------------------------------------
a                      (U8)   SOLVED EARLY  <array>                ./testbench.sv ; line 5
count_five( .a( a ) )  (S32)  SOLVED EARLY  0 (0x0)                ./testbench.sv ; line 9

'{'h0, 'h0, 'h0, 'h0, 'h0, 'h0, 'h0, 'h0, 'h0, 'h0}
xmsim: *W,RNQUIE: Simulation is complete.
xcelium> exit
TOOL:	xrun	20.09-s003: Exiting on Mar 07, 2021 at 02:18:36 EST  (total: 00:00:01)
class ab;
  
  rand bit [0:7] a[10];    // the array variable to be constrained
  
  parameter five = 5;
  
  constraint number { count_five(a) == five;}  // this constraint tells to keep the count of 
                                               // element '5' five times
  function int count_five(bit [0:7] a[10]);
    
    for(int i = 0;i<=9; i++)
      begin
        if(a[i] == 5)
          begin
            count_five = count_five + 1;//when ever a '5' element occur increment count_five
          end
        
        $display(count_five,i);
      end
    
    
  endfunction
  
endclass


module tb;
  
  ab a1;
  
  initial
    begin
      a1 = new;
      a1.randomize();
      $display("%p",a1.a);
    end
  
  endmodule

kindly explain me why there is conflict

In reply to sasi_8985:

Arguments to a fucntion in a Constraint are implicitly solved before any other constraint .

In your case since argument to the function is a , random variable ‘a’ is solved first .

As variable ‘a’ has no separate constraint


Eg ::  constraint SEPARATE_CONSTRAINT {  a.sum() with ( int'( item == 5 ) )  ==  5  ;  }  
   

variable ‘a’ is essentially unconstrained i.e it takes any value within its valid range i.e Each element can have a value between 0 and 255 .

So if the value is such that occurrence of 5 in Unpacked array doesn’t occur 5 times , the Constraint Fails

In reply to sasi_8985:

Yes the constraint in itself will work. There is No need for calling function from constraint.

here’s how the constraint is unrolled ::

(1) Since we have a.sum() , addtition operator ‘+’ is used

(2) item refers to element of a i.e a[0] , a[1] , a[2] … a[9]

So  the  resultant  expression  is  :: 

int’( a[0] == 5 ) + int’( a[1] == 5 ) + … + int’( a[9] == 5 ) == 5 ;

 Result  of  comparison  operator '=='  is  either 1'b0 / 1'b1 . 

The ONLY way randomization is successful is when there would be ( any ) 5 elements
in ‘a’ having element value as 5 .

Refer LRM 18.5.8.2 for more info .

In reply to ABD_91:

got it thank you.

In reply to dave_59:

In reply to shahkavish77:
All you have to do is unroll the sum method

 ( int'(arr[0] == i) + int'(arr[1] == i) + ... + int'(arr[99] == i) ) ==j;

 ( int'(arr[0]) + int'(arr[1]) + ... + int'(arr[99]) ) ==j;

why do we always cast the item to be an int when item refers to the actual array element. In the above example discussed in the thread the array element is an 8bit type which is good to hold values from 0-255.

Are we doing this to hold the sum of all the elements which if done may exceed an 8bit value and we are casting an int only to cover all possible scenarios? Even if this is the case I have seen wrong results when we don’t cast to an int type for item even if dealing with a sum < 255.

Please clarify as it has been very hard to find good info on the same. Thanks again as always. Here is another example which fails without a cast to int


class packet;
  rand bit[3:0] add[$];
       
  
  //constraint address_range { foreach(add[i])add[i] inside {[10:20]};}
  constraint s {
    add.size inside {[6:8]};
   
    
    //(add.sum() with (int'(item))) ==7;//works
    
    (add.sum() with (item)) ==7;//fails
  }
endclass

module constr_inside;
  initial begin
    packet pkt;
    pkt = new();
    
    $display("------------------------------------");
    repeat(1) begin
      pkt.randomize();
      $display("size = %0d",pkt.add.size);
      foreach(pkt.add[i])$display("element i value = %0d",pkt.add[i]);
    end
    $display("------------------------------------");
  end
endmodule

In reply to hsam:

This is because the result of the sum method has the same type as the elements of the array, which in your example is only 4 bits. You need 5 bits to hold the sum of two 4-bit numbers, 6 bits to hold the sum of four 4-bit numbers, and so on. When using a with expression, the result is the same type as that expression.

In reply to dave_59:

I tried the following code on edaplayground with all simulators .

class uni_con;
  rand int arr[5];
  rand int ref_arr[5];

  
  constraint c1 {
    foreach(arr[i]){
      arr[i] > 0;}
      
      arr.sum(item) with (int'(item) == 10) == 5;
    
  }

Got following error:

testbench.sv(34): randomize() failed due to conflicts between the following constraints:
# 	testbench.sv(12): c1 { (1'((arr[0] == 10) + (arr[1] == 10) + (arr[2] == 10) + (arr[3] == 10) + (arr[4] == 10)) == 5); }
# Given:
# 	bit signed [31:0] arr[0]
# 	bit signed [31:0] arr[1]
# 	bit signed [31:0] arr[2]
# 	bit signed [31:0] arr[3]
# 	bit signed [31:0] arr[4]
# ** Note: (vsim-7106) Use vsim option '-solvefailtestcase[=filename]' to generate a simplified testcase that will reproduce the failure.
# ** Warning: (vsim-7084) No solutions exist which satisfy the specified constraints; randomize() failed.

Can you please help me understand this.

In reply to JGu:

You want count the number of time (item == 10). The result of that expression is a single bit, so you need to cast that equality to a wider result.

arr.sum(item) with (int'(item == 10)) == 5;

In reply to dave_59:

Oh! Thanks a lot Dave.

In reply to dave_59:

Hi Dave,

Is there difference between sum() and sum(item)?

In reply to Atresh:

In reply to dave_59:
Hi Dave,
Is there difference between sum() and sum(item)?

More characters, easier to read.

In reply to dave_59:

Hi Dave,
i thought of a solution in a slightly different way, i am trying to check if size of queue returned by find_index method with elements having value 5 should equal 5. I get below error,

what is wrong with my approach?

constraint arr_con_1 {(arr.find_index() with (item == 5)).size() == 5;}

VCS:
Error-[SE] Syntax error
Following verilog source has syntax error :
“testbench.sv”, 14: token is ‘.’
constraint arr_con_1 {(arr.find_index() with (item == 5)).size() == 5;}

Questa:
** Error: (vlog-13069) testbench.sv(14): near “.”: syntax error, unexpected ‘.’.

In reply to jsakhare:

What you are trying to do is known as chaining method calls and is not currently legal in SystemVerilog. 0002735: Ballot Comment #48: Chaining of method calls - Accellera Mantis

What if the values of i and j have to be the minimum and maximum element in the array and they have to occur exactly once. How do we go forward with that, i tried using .max and .min functions inside the constraint, but it doesn’t work.