Can I constrain a sum/function of array element sizes?

Hi,

Is there a way in UVM to constrain a function of array element sizes? I provided some code below, and I know I cannot use variables inside a constraint, but I think it explains what I want to do.


   rand t_byte_q  msg_queue[$];

   constraint c_msg_queue {
      int sum = 0;
      this.msg_queue.size() inside { [1:16] };
      foreach (this.msg_queue[i]) {
         
         sum += $ceil((2**10 / this.msg_queue.size()) / 32.0);
         sum < 32;
         this.msg_queue[i].size() > 63 ;
      }
   }

Some context:
I have a memory of 1024B with 32 slots of 32B and I want to randomize writing between 1 and 16 packets (messages) to it.
The length of the individual packets also has to be randomized between 64B up to the total memory space divided by the number of packets.
The tricky thing, however, is that any fragment of length between 0 and 32B will use a full 32B slot, and I need to keep the total number of required slots smaller than or equal to 32.
E.g.: A packet of 76B (32 + 32 + 12B) uses 3 slots in memory. Say the randomization chooses to have a total of 12 packets, if the memory space was used contiguously, I could limit the maximum size of elements to 1024/12 = 86. Since the packets are not written contiguously, 12*96 = 1152B, and I lose the end of the last packet.
Any way to constrain that?

In reply to jprochno:

You can use the sum() array reduction method instead of a foreach loop. For your tricky thing, use the modulo % operator; constraints cannot involve real expressions.

   constraint c_msg_queue {
      msg_queue.size() inside { [1:16] };
      msg_queue.sum(msg) with ((2**10 / msg.size() / 32) + (msg.size() % 32 !=0)) < 32;
      foreach (msg_queue[i]) msg_queue[i].size() > 63;
   }

I have found another question/answer on the forum in the meantime that pointed me to the solution below.


   rand t_byte_q  msg_queue[$];
   
   constraint c_msg_queue {
      this.msg_queue.size() inside { [1:16] };
      foreach (this.msg_queue[i]) {
         this.msg_queue[i].size() < (2**10 / this.msg_queue.size());
         this.msg_queue[i].size() > 32;
      }
      sum_pos(this.msg_queue) < 33;
   }

   function int sum_pos(t_byte_q  msg_queue[$]);
      sum_pos = 0;
      foreach(msg_queue[i])
         sum_pos += $ceil(msg_queue.size[i] / 32.0);
   endfunction


I tested your code and it throws an error for me. My code now does what I want, but I would like to understand what yours does :) What does the construct below ( sum(msg) with … ) mean?

msg_queue.sum(msg) with ((2**10 / msg.size() / 32) + (msg.size() % 32 !=0)) < 32;

In reply to jprochno:

See Section 7.12.3 Array reduction methods in the 1800-2017 LRM.

Do check your constraints with a number of random seeds and make sure you get the desired results.

Hi I am trying to constraint a sum of array without using a.sum() method. But code is not working.

Do you have any suggestion?

class c;
  rand logic [7:0] a [];
  constraint array_size {a.size() == 10;  }
    constraint array_items { 
      foreach(a[i]) a[i] < 10;
        
    }
 
  constraint sum_array_c {a_sum() == 10; }
  
    function int a_sum();
      a_sum = 0;
      foreach(a[i]) 
        a_sum += a[i] ;
 
    endfunction 
  
 
endclass
 
module test;
   initial begin
      c c1 = new();
 
      void'(c1.randomize());
 
     foreach(c1.a[i])
        $display("%0d ", c1.a[i]);
 
   end // initial begin
endmodule // test

I see below error

# testbench.sv(25): randomize() failed due to conflicts between the following constraints:
# 	testbench.sv(9): sum_array_c { (this.a_sum() == 10); }
# Where:
# 	this.a_sum() = 0

In reply to niravshah:

Please use code tags making your code easier to read. I have added them for you.

Two problems with your code involving a user defined function.

Random variables used by functions have their values chosen before calling the function. Once the function gets called, the output return value becomes a state variable. The constraint solver does not try to repeatedly call the function with new random inputs and fails if the remaining constraints cannot be met.

The other problem is your function has no inputs; it accesses the array a which is outside the scope of the function. That might be considered a side-effect. However, making the array an input will not get around the first problem.

The built-in sum() method is considered an iterative constraint and gets unrolled into a single expression for the constraint solver.

In reply to dave_59:

In reply to niravshah:
Please use code tags making your code easier to read. I have added them for you.
Two problems with your code involving a user defined function.
Random variables used by functions have their values chosen before calling the function. Once the function gets called, the output return value becomes a state variable. The constraint solver does not try to repeatedly call the function with new random inputs and fails if the remaining constraints cannot be met.
The other problem is your function has no inputs; it accesses the array a which is outside the scope of the function. That might be considered a side-effect. However, making the array an input will not get around the first problem.
The built-in sum() method is considered an iterative constraint and gets unrolled into a single expression for the constraint solver.

Thanks Dave for quick reply.
Here, either calling a a_sum() function in foreach loop or adding a in function argument is not solving the problem. And also passing arg by ref is not supported for such case.
I would appreciate if you can suggest further to make it work.

In reply to niravshah:

You cannot use a function for this kind of constraint.

See Is there an alternative to sum() Constraint | Verification Academy

In reply to dave_59:

In reply to niravshah:
You cannot use a function for this kind of constraint.
See Is there an alternative to sum() Constraint - SystemVerilog - Verification Academy

Hi Dave,

Thanks a lot. It is helpful