Randomizing a dynamic array size

Hi,
I wish to create a random list of size 1 to 6. However I am getting a constraint inconsistent error since the solver creates an array with 0 length which violates my constraint. How do I solve this problem ?

Error-[CNST-CIF] Constraints inconsistency failure
test1.sv, 31
Constraints are inconsistent and cannot be solved.
Please check the inconsistent constraints being printed above and rewrite
them.

Here is my test case.

// Constraint class for dynamic array of object

class Object;
  rand int id;
endclass

class Objects;
  rand Object lst[];
  int size;

  constraint default_size {
    size > 0 && size < 6;
  }

  constraint default_lst {
    lst.size() == size;
  }

  function void post_randomize();
    lst = new[size];
    for(int i = 0; i < size; i++) begin
      lst[i].id = i;
    end
  endfunction

endclass

program test1;
  initial begin
    Objects objs = new();
    objs.randomize();
    $display("Allocated an array of size=%0d", objs.lst.size());
  end
endprogram

In reply to sanjeevs:

‘size’ isn’t declared as rand. Also, you don’t need ‘lst = new[size];’ in post_randomize().

Randomizing a dynamic array (or allocating space for it via new) won’t create any of the objects it’s supposed to hold. Since you know you need at most 6 objects, you need to initialize them in pre_randomize():


   function void pre_randomize();
    lst = new[6];
    foreach (lst[i])
      lst[i] = new();
  endfunction

You don’t need an intermediary size field:


  constraint default_size {
    lst.size() inside { [1:6] };
  }

When you constraint an array’s size, then the extra elements get thrown away, but more objects don’t get created. This is why we had to create 6.

You can also implement having the proper IDs as constraints:


  constraint propagate_ids {
    foreach (lst[i])
      lst[i].id == i;
  }

You have a number of problems with your code, the biggest one is you forgot to declare size as rand.


class Object;
   rand int id;
endclass

class Objects;
   rand Object lst[];
   rand int size; // you forgot to declare rand
   
   constraint default_size {
      size > 0 && size < 6;
   }
   
   constraint default_lst {
      lst.size() == size;
   }
   // A better way to write these constraints without size
    constraint size_c { lst.size() inside {[1:5]};}
   
   function void post_randomize();
      lst 	 = new[size];
      foreach (lst[i]) begin
	 lst[i]     = new; // need to construct each element
	 lst[i].id  = i;
      end
   endfunction
   
endclass

module test1; // don't use program blocks
   Objects objs; // declare static variables outside of initial blocks
   
   initial begin
      objs  = new;
      void'(objs.randomize()); // normally should check the result 
      $display("Allocated an array of size=%0d", objs.lst.size());
   end
endmodule : test1

In reply to dave_59:

Thanks everyone for the response.
I have fixed the code and it is fine now. I am not sure if doing pre-randomize of max size is better OR just doing a post randomize of correct size.
Please help DRY out the code…

class Object;
  rand int id;
endclass

class Objects;
  rand Object lst[];

  constraint default_lst {
    lst.size() > 0 && lst.size() < 6;
  }

  function void post_randomize();
    for(int i = 0; i < lst.size(); i++) begin
      lst[i] = new();
      lst[i].id = i;
    end
  endfunction

endclass

module test1;
  initial begin
    Objects objs = new();
    objs.randomize();
    $display("Allocated an array of size=%0d", objs.lst.size());
  end
endmodule
~

In reply to dave_59:

Hi Dave,

Please explain the behaviour for the array size of three. And why the constraint is not conflicting ?? And How it is generating a random output for a size of three ??
Please find the below snippet.

module array_size();

class A;

rand bit [7:0] a[$];
 int k;
constraint SIZE_SUM {
                        a.size == 3 && a.sum == 50;
                    }

function void post_randomize();
foreach(a[i])
  k = k + a[i];
$display("a size is %0d, METHOD ::  sum of a array is %0d, CALC :: k is %0d, array values are %0p",a.size,a.sum,k,a);
if(k == a.sum)
 $display("PASS");
k = 0;
endfunction

endclass : A


initial
begin
repeat(100)
begin
A b =new();
b.randomize();
end
end

endmodule

Output :-

output : for size 3

a size is 3, METHOD :: sum of a array is 50, CALC :: k is 50, array values are '{'h9, 'h25, 'h4}
PASS
a size is 3, METHOD :: sum of a array is 50, CALC :: k is 562, array values are '{'hbb, 'hb4, 'hc3}
a size is 3, METHOD :: sum of a array is 50, CALC :: k is 306, array values are '{'h29, 'h4c, 'hbd}
a size is 3, METHOD :: sum of a array is 50, CALC :: k is 306, array values are '{'ha, 'hfd, 'h2b}
a size is 3, METHOD :: sum of a array is 50, CALC :: k is 562, array values are '{'hed, 'h84, 'hc1}
a size is 3, METHOD :: sum of a array is 50, CALC :: k is 306, array values are '{'h15, 'hff, 'h1e}
a size is 3, METHOD :: sum of a array is 50, CALC :: k is 306, array values are '{'hc3, 'h64, 'hb}
a size is 3, METHOD :: sum of a array is 50, CALC :: k is 562, array values are '{'h93, 'hfc, 'ha3}
a size is 3, METHOD :: sum of a array is 50, CALC :: k is 562, array values are '{'he8, 'h96, 'hb4}
a size is 3, METHOD :: sum of a array is 50, CALC :: k is 562, array values are '{'hba, 'hf4, 'h84}

output for size 5

a size is 5, METHOD :: sum of a array is 50, CALC :: k is 50, array values are '{'h0, 'h0, 'h0, 'h9, 'h29}
PASS
a size is 5, METHOD :: sum of a array is 50, CALC :: k is 50, array values are '{'h1, 'h0, 'h1, 'h6, 'h2a}
PASS
a size is 5, METHOD :: sum of a array is 50, CALC :: k is 50, array values are '{'h15, 'h0, 'h4, 'h0, 'h19}
PASS
a size is 5, METHOD :: sum of a array is 50, CALC :: k is 50, array values are '{'h0, 'h0, 'h0, 'h31, 'h1}
PASS
a size is 5, METHOD :: sum of a array is 50, CALC :: k is 50, array values are '{'h0, 'h2, 'hc, 'h0, 'h24}
PASS
a size is 5, METHOD :: sum of a array is 50, CALC :: k is 50, array values are '{'h1f, 'h2, 'h9, 'h0, 'h8}
PASS
a size is 5, METHOD :: sum of a array is 50, CALC :: k is 50, array values are '{'ha, 'h1d, 'h0, 'h0, 'hb}
PASS
a size is 5, METHOD :: sum of a array is 50, CALC :: k is 50, array values are '{'h27, 'h0, 'h0, 'h9, 'h2}
PASS
a size is 5, METHOD :: sum of a array is 50, CALC :: k is 50, array values are '{'h0, 'h0, 'h0, 'h27, 'hb}
PASS
a size is 5, METHOD :: sum of a array is 50, CALC :: k is 50, array values are '{'h1e, 'h1, 'h0, 'h13, 'h0}
PASS

In reply to rhariprasad:

It seems “sum” method treats every array’s element with signed value. When you calculate them with signed value, the result’s always correct (= 50).

To fix this, you can cast every element of array in sum function with unsigned value:


typedef int unsigned uint_t;
rand bit [7:0] a[$];
constraint SIZE_SUM {
  a.size() == 3;
  a.sum(x) with(uint_t'(x)) == 50;
}

Or add more constraint for every element of array:


rand bit [7:0] a[$];
constraint SIZE_SUM {
  a.size() == 3;
  a.sum() == 50;
  foreach(a[i]) {
    a[i] inside {[0:50]};
  }
}

In reply to chris_le:

Thanks a lot Chris.

Hi dave,
can you plaese explain why we can’t use program block here.

module test1; // don't use program blocks //why ?
   Objects objs; // declare static variables outside of initial blocks
   
   initial begin
      objs  = new;
      void'(objs.randomize()); // normally should check the result 
      $display("Allocated an array of size=%0d", objs.lst.size());
   end
endmodule : test1

In reply to Mohan Shyam:
http://go.mentor.com/programblocks

In reply to dave_59:

Dave, we would need to randomize each object of the array after creating it.

   function void post_randomize();
      lst 	 = new[size];
      foreach (lst[i]) begin
	 lst[i]     = new; // need to construct each element
         lst[i].randomize(); // in case there are other fields in the object class that needs to be randomized and not overwritten
	 lst[i].id  = i;
      end
   endfunction

In reply to h_g:

It wasn’t clear what the original poster wanted to do. You can do this all with one call to randomize() by pre constructing the array, and then the randomization will trim it down to the random array size.

This is probably what Tudor tried to say? Creating lst to max size (6) and all 6 objects, then let randomize trim it down according to constraints.

In reply to dave_59:

In reply to h_g:
It wasn’t clear what the original poster wanted to do. You can do this all with one call to randomize() by pre constructing the array, and then the randomization will trim it down to the random array size.

In reply to dave_59:

Hi Dave ,

I am confused as to how is that Dynamic Array is constructed ( using new ) after its been sized from a constraint ?

Shouldn’t they be constructed before ( in pre_randomize() with Max Size ) being Given a size ( from randomize() Function ) ?

Regards ,

AGIS

In reply to Etrx91:

Yes, that is the preferred way. But you can’t always do that with certain objects like those derived from umm_component. They cannot be deleted once constructed.