Constraint randomization of an array

Hi

I am aware of randomizing the size of an array but if I want to have the elements of the array to sum up to <1000, how do I do it?

rand int arr[];
rand len arr_size;

constraint c_arr{

   arr_size <10;
   arr.size()==arr_size;

>> elements of the array?

}//endconstraint

The 1800-2012 LRM added the ability to use the array reduction methods in a constraint. This is already supported in recent releases of Questa. Be very careful using signed data types in a constraint to prevent unwanted negative numbers and overflow that will give you results that satisfy the constraints but not normally what you are expecting.

rand int arr[];
constraint c_arr{
   arr.size() < 10;
   arr.sum() inside {[1:1000]); // if you want a positive result
   foreach(arr[i]) arr[i] inside ([0:1000]};
}

In reply to dave_59:

I have seen that there was a problem with the sum (WWW.TESTBENCH.IN - Systemverilog Randomization) and to be safe you had to use:
“with (item+32b’b0)”. That is to say, you had to sum a zero value of 32 bits to force a casting with the intern item in the sum loop. See below


rand int arr[];
constraint c_arr{
   arr.size() < 10;
   arr.sum with (item+32b'b0) inside {[1:1000]); // if you want a positive result
   foreach(arr[i]) arr[i] inside ([0:1000]};
}


Now, i see that in your example you will not have problems because the type of arr is int arr; which is already 32bits, and the sum will not be saturated.

Cut/Saturating means that, when the sum overflows the bitwidth for your local sum constraint variable (in your example arr) then this is not seen by the sum constraint because the sum in the internal constraint will be cut and will only compare with the constraint the “bits cut”/bitwidth defined by your local variable,
e.g.


rand logic [1:0] arr[];
constraint c_arr{
   arr.size() < 10;
   arr.sum inside {[1:1000]); // WRONG SUM constraint in case 
   //This is wrong because if constraint solver tries a combination that sums e.g. 16='b10000, then constraint solver will see only the LSB 2 bits due to the logic[1:0] arr[] type 16='b100**00**=>2'b00=0 and will think that was a valid combination for your constraints since "0" meets constraint:  arr.size() < 10;

   //arr.sum with (32'(item)) inside {[1:1000]); // if you want a CORRECT constraint
   foreach(arr[i]) arr[i] inside ([0:1000]};
}

converting the item variable in 32bits (or more) ensure that all sum possible combinations tried by the constraint solver will be seen correctly by the constraint solver (<10) ).

Lastly, if you are interested on dynamic array constraints you can see the following post.
https://verificationacademy.com/forums/systemverilog/constraints-dynamic-array#answer-58425

In reply to Jonathan_Alvarez:

Hi Jonathan,

You can do the way you presented. Instead of adding, you can go with doing something like

arr.sum with int`(item)

In reply to Jonathan_Alvarez:

That problem is due to the fact that the resulting value from
array.sum()
has the same type as each element in the array. That means it does not handle overflow unless you change type of each element being summed. My example does not have that problem because I was constraining the value of each element to a relatively small value that would never overflow.

I was exposing a slightly different problem that you can have anytime you deal with signed values in arithmetic expressions. most people forget that negative numbers can form valid solutions. So you either need to keep everything unsigned, or place constraints to keep the values positive.

In reply to dave_59:

Hi Dave,

That problem is due to the fact that the resulting value from array.sum() has the same type as each element in the array. That means it does not handle overflow unless you change type of each element being summed. My example does not have that problem because I was constraining the value of each element to a relatively small value that would never overflow.

Can you elaborate on this ?

Thanks,
Madhu

In reply to mseyunni:
Let’s say you have

rand bit [3:0] arr[5];

This means that each element of
arr
can have the value 0-15. Since the sum() method returns a value that is the same type of each element, that means
arr.sum()
can only return a value between 0-15. However the maximum possible sum is 5x15=75 which requires at least 7 bits to represent. So you would have to write
arr.sum() with ( 7’(item) )
to get a result without overflowing. However, if if you constrain each element to 3 or less, the maximum sum is 5x3=15, and that does not overflow the element type.

In reply to dave_59:

Thank you Dave for the explanation.

In reply to dave_59:

Hi Dave,

I’m trying to constrain an array that has a sum of 2048.

rand bit [11:0] vf;
constraint c_vf_queues {
vf.size == 248;
vf.sum == 2048;
foreach (vf[i]) vf[i] inside {[0:2048]};
}

I can’t get the individual values in the array to sum to 2048.
All the values are too large.

Thank you,
George

In reply to gnich:

As i commented in a previous comment, maybe, the problem you have is due to the intern 32bit item value used in systemverilog to perform the sum.
In your case “vf” is a bit variable of 12 bits. Systemverilog “sum”-function uses the intern “item” 32bit variable. The casting in the constraint of “sum” must be done to allow a proper constraint.

Could you try to replace the


vf.sum == 2048;

with


vf.sum with (item+32b'b0) == 2048; 

Let me know, if that works.
Best regards,

In reply to Jonathan_Alvarez:
Or use

vf.sum with (32'(item)) == 2048;

In reply to Jonathan_Alvarez:

I’m using a Cadence simulator.
I get a constraint error using vf.sum (32’(item)) == 2048.
I tried vf.sum (item+32’b0) == 2048, but I get a constraint error.

Here’s my code.


``` verilog
class rand_vf_queues extends uvm_object;

   rand bit [7:0]  vf_size;
   rand bit [11:0] vf[];
   
   constraint c_num_vf   {vf_size == 248;} 

   constraint c_vf_queues {
			 vf.size == 248;
			 vf.sum == 2048;
                         foreach (vf[i]) {
			   vf[i] inside {[0:2048]};
                         }
                        
   }

 
   function new (string name = "");
   endfunction // new

   function void post_randomize();
      int sum_vf = 0;
      `uvm_info(get_type_name(), $psprintf("vf_size = %0d, total_qctl_queues = %0d",vf_size,total_qctl_queues), UVM_LOW)
      for(int i=0; i<vf_size; i++) begin
        `uvm_info(get_type_name(), $psprintf("VF[%0d] = %0d",i,vf[i]), UVM_LOW)
	 sum_vf = sum_vf + vf[i];
      end
      `uvm_info(get_type_name(), $psprintf("VF.SUM() = %0d, sum_vf = %0d",vf.sum(),sum_vf), UVM_LOW)
   endfunction        

endclass // rand_vf_queues


> Here's partial display results showing the end of the array values and sum_vf. Notice VF.SUM() has maxed out to 2048 but the actual sum_vf is much larger.

``` verilog
[0ns] reporter: VF[242] = 1455
[0ns] reporter: VF[243] = 19
[0ns] reporter: VF[244] = 469
[0ns] reporter: VF[245] = 353
[0ns] reporter: VF[246] = 946
[0ns] reporter: VF[247] = 2038
[0ns] reporter: VF.SUM() = 2048, sum_vf = 256000

What I would like to do is constrain all the values from 0-2048 and have the total array sum = 2048 and I want the possibility to have only a couple of the vf[i] to have a couple of indexes = > 0 and all the other indexes = 0.
i.e. vf[0] = 2000, vf[230] = 48, all other indexes will = 0.

In reply to gnich:

In reply to dave_59:

Only when I make vf[i] inside {[1:14]}; (2048/248 = 14) that I get what I want. The sum of vf[i] = 2048.

But I want values to exceed 14 in the array up to 2048, having the possibility of having only one index = 2048 and the other vf[i] =0.

In reply to gnich:

Both vf.sum (32’(item)) == 2048 and vf.sum (item+32’b0) == 2048 work for me. You’ll have to take it up with Cadence.

In reply to dave_59:

I was able to get this working using int’(item) when using Cadence.

class rand_vf_queues extends uvm_object;

   rand bit [7:0]  vf_size;
   rand bit [11:0] vf[];
   rand int queues;
   
   constraint c_num_vf      {vf_size == 248;}
   constraint c_num_queues  {queues == 2048;} 

   constraint c_vf_queues {
			 vf.size == vf_size;
			 vf.sum with (int'(item)) == queues;
                         foreach (vf[i]) {
			   vf[i] inside {[0:queues]};
                         }
                        
   }

 
   function new (string name = "");
   endfunction // new

endclass

In reply to gnich:

In reply to dave_59:
I was able to get this working using int’(item) when using Cadence.

class rand_vf_queues extends uvm_object;
rand bit [7:0]  vf_size;
rand bit [11:0] vf[];
rand int queues;
constraint c_num_vf      {vf_size == 248;}
constraint c_num_queues  {queues == 2048;} 
constraint c_vf_queues {
vf.size == vf_size;
vf.sum with (int'(item)) == queues;
foreach (vf[i]) {
vf[i] inside {[0:queues]};
}
}
function new (string name = "");
endfunction // new
endclass

Hi,

In Cadence tool I am getting the following output with the below code:
B2B_seq_array[0] === 1712505664
B2B_seq_array[1] === 1648995472
B2B_seq_array[2] === 1324445776
B2B_seq_array[3] === 3903987720

Code:

module tb;

class muneeb;
   
  rand int unsigned B2B_seq_array[];

    
  constraint sum_c { B2B_seq_array.sum with (int'(item)) ==40;}
  // I even tried the below constraint but still no sucess
  // constraint sum_c { B2B_seq_array.sum() with (32'(item)) == 40;}

  constraint b2b_array_c { B2B_seq_array.size() == 4; }
  
  constraint mm_c {              foreach(B2B_seq_array[i]) {
                                 (B2B_seq_array[i] % 8) == 0;   
                                 B2B_seq_array[i] != 0;   						
                          }
  
    }
    
endclass


  muneeb m1;

  initial
  begin
  m1 = new();
    if(!m1.randomize())
      $display("Randomizeation failed");
    else
        begin
          foreach(m1.B2B_seq_array[i])
            begin
            $display("B2B_seq_array[%0d]  === %0d",i,m1.B2B_seq_array[i]);
            end
        end
  end
endmodule

Can you please help me with this regard.

Thank you,

Regards,
Muneeb

In reply to muneebullashariff:

With the code that you have, you are casting an unsigned int to an signed int, you are getting negative numbers in your array. And in the code you commented out, the cast does nothing because a unsigned int is already 32 bits. There the problem is the sum is 32-bits, but you need more than 32 bits to hold the sum of 4 32-bit numbers.

The key to using the sum() method is to consider the maximum possible value of each element, and make sure you either constrain each element to a value that would not cause overflow, or cast the elements to a type that would not overflow.

In your example, you could:

  • Constrain each element inside the range [0:40]
  • Use longint’(item)
  • Declare the array with each element width of bit [5:0], and use int’(item)

Hi Dave,

I want to randomize my variables such that.

rand logic[7:0] d_addr;
rand logic[7:0] mem_data[4];

constraint dest_c {
d_addr inside {mem_data[0], mem_data[1],mem_data[2], mem_data[3]};
}

I get compilation error. Is there a way to express the above intent that is “d_addr” should attain any of the four values in mem_data array?

Thanks,
Abhiman

In reply to Abhiman:

It works for me. Can you share your error and give a complete minimal example.

Also, you should be able to shorten your constraint with

d_addr inside {mem_data};