Randomizing MDA with constraints on count of entries

Hello,

I have a 3x3 array - Each entry in the array can be RED, GREEN or BLUE. Can I randomize the array such that the difference in number of RED/GREEN/BLUE is never more than one? I can achieve this using post randomize but I was wondering if I can do it within a constraint - can we use temporary variables (eg: to count each type) within a constraint?

Using function (like shown below) will not work but I’m pasting it here to hopefully make the intent clear

Thanks
AC

class rgb_matrix;
    typedef enum {RED, GREEN, BLUE} val_e;
    rand val_e mda[3][3];

    constraint check{
       count_check(mda) == 1'b0;
    }
    
function bit count_check(val_e val[3][3]);
    int num_red = 0;
    int num_green = 0;
    int num_blue = 0;
    bit fail = 1'b0;
      foreach (val[i,j]) begin
	 if (val[i][j] == RED) num_red++;
	 else if (val[i][j] == GREEN) num_green++;
         else if (val[i][j] == BLUE) num_blue++;
      end
      if (((num_red > num_blue) && (num_red-num_blue >1)) || (num_blue-num_red)>1)) fail = 1;
      if (((num_green > num_blue) && (num_green-num_blue >1)) || (num_blue-num_green)>1)) fail = 1;
      if (((num_red > num_green) && (num_red-num_green >1)) || (num_green-num_red)>1)) fail = 1;
      return (fail);
endfunction
endclass

There is no solution that would allow the difference between any of the RGB counts to be 1 or less. The best you could do is all a difference of 2.

let ABS(v1,v2) = v1>v2? v1-v2:v2-v1;
class rgb_matrix;
    typedef enum {RED, GREEN, BLUE} val_e;
    rand val_e mda[3][3];
   rand byte Rc, Gc, Bc;
   
   constraint c_sums {
      Rc == mda.sum(D1) with (D1.sum(D2) with (byte'(D2 == RED)));
      Gc == mda.sum(D1) with (D1.sum(D2) with (byte'(D2 == GREEN)));
      Bc == mda.sum(D1) with (D1.sum(D2) with (byte'(D2 == BLUE)));
   }
   constraint c_diff { ABS(Rc,Gc) <3; ABS(Rc,Bc) <3; ABS(Gc,Bc) <3; }
endclass : rgb_matrix

module top;
   rgb_matrix rgbs = new;

  initial repeat(10) begin
     assert(rgbs.randomize());
     $display("%p",rgbs);
  end
endmodule : top

In reply to dave_59:

Sorry I overlooked that while mapping my problem to this example (my problem would require only 2 of the differences to be <=1 which I should have articulated in this example). But your solution answers my question - Thanks a lot for the prompt response!

However I do get compile errors: Is there any switch I need to enable to support this code? I also tried with changing `default_nettype (to make sure it was not none)

Error-[IND] Identifier not declared
test.sv, 232
Identifier ‘D2’ has not been declared yet. If this error is not expected,
please check if you have set `default_nettype to none.

Error-[XMRE] Cross-module reference resolution error
test.sv, 233
Error found while trying to resolve cross-module reference.
token ‘sum’. Originating program ‘test’.
Source info: D1.sum(D2) with (byte’((D2 == BLUE)))

In reply to ac1122:

Sorry, this code works on Questa and this forum is not for help tool specific issues. I will say that other tools recognize this syntax.

In reply to dave_59:

Was anyone able to make this work on EDAPlayground? If yes, can you pls share the link? I see a bunch of errors referring to D1 and D2 and c_diff constraint.

Thanks in advance

In reply to ac1122:

Likely that your tool does not support function chaining (Guess that’s the right word for this) yet. Maybe try latest version or contact your vendor.

Srini
www.verifworks.com

In reply to Srini @ CVCblr.com:

This works for me after I checked with the tool vendor. Thanks again for your help Dave!

let ABS(v1,v2) = v1>v2? v1-v2:v2-v1;
class rgb_matrix;
 
     typedef enum {RED, GREEN, BLUE} val_e;
    rand val_e mda[3][3];
    rand int Rc[3],Gc[3], Bc[3];
    rand int RC,GC,BC;

   constraint c_sums {
     foreach(mda[i,]) {
           Rc[i] == mda[i].sum(D2) with (byte'(D2 == RED));
          Gc[i] == mda[i].sum(D2) with (byte'(D2 == GREEN));
           Bc[i] == mda[i].sum(D2) with (byte'(D2 == BLUE));
      }

      RC == Rc.sum();
      GC == Gc.sum();
      BC == Bc.sum();

      solve Rc before RC;
      solve Gc before GC;
      solve Bc before BC;
   }
 
   constraint c_diff { ABS(RC,GC) <3; ABS(RC,BC) <3; ABS(GC,BC) <3; }
function void post_randomize();
  for (int i=0;i<3;i++) begin
    for (int j=0;j<3;j++) begin
      $write(" %0s ", mda[i][j].name);
    end
    $display("");
  end
endfunction

class rgb_matrix;
  typedef enum {RED=0, GREEN, BLUE} val_e;
  val_e mda[3][3];
  rand val_e lst[9];

  constraint c_items {
    lst.sum with (int'(item)) inside { [8:10] };
  }
  
  function void post_randomize();
	int count = 0;
    foreach(mda[i,j]) 
      mda[i][j] = lst[count++];
  endfunction
      
endclass