How to determine the size of a multi-dimensional dynamic array in a constraint?

Hi,

I’m trying to randomly distribute a payload array throughout a scatter gather list, defined as follows.

    rand byte sgl[][][16];

    rand byte unsigned payload[];
    rand int  unsigned payload_desc[];

    constraint C_PAYLOAD_DISTRIBUTION {
        payload_desc.size == sgl.size;
        payload_desc.sum with (longint'(item)) == payload.size;
    }

I can use the above constraint, but this only constrains payload_desc.size to have the size of the outer dimension of the array.

What I really need is to be able to determine the total size of all the dynamic dimensions in the array, like this.

    function int total_size(sgl_t x);
        foreach (x[i,]) begin
            total_size += x[i].size;
        end
        return total_size;
    endfunction

And then write the constraint as follows

    constraint C_PAYLOAD_DISTRIBUTION {
        payload_desc.size == total_size(sgl);
        payload_desc.sum with (longint'(item)) == payload.size;
    }

But, as I believe the function is always called before the constraint is resolved, this doesn’t work, i.e. total_size always returns 0.

Can anybody see an alternative way to achieve this?

Dale

In reply to dshanley:

Randomization method can not create a dynamic array by it self. Therefore function ‘total_size’ return zero (a default value of int total_size).

A array sql should be created by constraint; sql.size.

A solution

// Purpose: 
// Conclusion:
module top;

  typedef byte sgl_t[][][16];

  // Class
  class myclass;
    rand byte sgl[][][16];
 
    rand byte unsigned payload[];
    rand int  unsigned payload_desc[];

    // Array creation
    constraint c_sgl_size {  sgl.size == 5;
                             payload.size == 15;

                             foreach(sgl[i])  {
                               sgl[i].size == 2;
                             }

                           }


    function int total_size(sgl_t x);
           foreach (x[i,]) begin
               total_size += x[i].size();
           end
           return total_size;
    endfunction

    constraint C_PAYLOAD_DISTRIBUTION {
        solve sgl before payload_desc;
        payload_desc.size == total_size(sgl);
        payload_desc.sum with (longint'(item)) == payload.size;
    }

    function void post_randomize();

      $display("payload_desc size = %d ", payload_desc.size());

      $display("sgl size = %d ", sgl.size());
      foreach(sgl[i,]) begin
        $display("sgl[%1d].size= %d ", i, sgl[i].size);
      end

      foreach(payload_desc[i]) begin
        $display("payload_desc[%1d]= %d ", i, payload_desc[i]);
      end
    endfunction: post_randomize

  endclass // myclass

  initial 
  begin
    myclass c;

    c= new();
    if(!c.randomize()) begin
      $display("Randomize fail ");
    end
    else begin
      $display("Randomize Pass");
    end
  end
endmodule // top;

In reply to prashant.kaushik:

Hi,

Thanks for your help, but it still doesn’t work for me.

The total_size function always returns 0 and the solver fails.

The “solve sgl before payload_desc;” doesn’t appear to have any effect.

If I hack the total_size function to return, say 3. Then the solver passes as expected.

module top;

  typedef byte sgl_t[][][16];

  // Class
  class myclass;
    rand byte sgl[][][16];

    rand byte unsigned payload[];
    rand int  unsigned payload_desc[];

    // Array creation
    constraint c_sgl_size {  sgl.size == 5;
                             payload.size == 15;

                             foreach(sgl[i,,])  {
                               sgl[i].size == 2;
                             }

                           }


    function int total_size(sgl_t x);
           foreach (x[i,]) begin
               total_size += x[i].size();
           end
           return total_size;
           //return 3;
    endfunction

    constraint C_PAYLOAD_DISTRIBUTION {
        solve sgl before payload_desc;
        payload_desc.size == total_size(sgl);
        payload_desc.sum with (longint'(item)) == payload.size;
    }

    function void post_randomize();

      $display("payload_desc size = %d ", payload_desc.size());

      $display("sgl size = %d ", sgl.size());
      foreach(sgl[i,]) begin
        $display("sgl[%1d].size= %d ", i, sgl[i].size);
      end

      foreach(payload_desc[i]) begin
        $display("payload_desc[%1d]= %d ", i, payload_desc[i]);
      end
    endfunction: post_randomize

  endclass // myclass

  initial
  begin
    myclass c;

    c= new();
    if(!c.randomize()) begin
      $display("Randomize fail ");
    end
    else begin
      $display("Randomize Pass");
    end
  end
endmodule // top;

In reply to dshanley:

My example is working in Questa 10.3d and 10.4c, without hacking ‘return value’ of function.

One of the output is:
ayload_desc size = 10

sgl size = 5

sgl[0].size= 2

sgl[1].size= 2

sgl[2].size= 2

sgl[3].size= 2

sgl[4].size= 2

payload_desc[0]= 0

payload_desc[1]= 0

payload_desc[2]= 5

payload_desc[3]= 0

payload_desc[4]= 10

payload_desc[5]= 0

payload_desc[6]= 0

payload_desc[7]= 0

payload_desc[8]= 0

payload_desc[9]= 0

Randomize Pass

It seems me that there should be a tool issue.

In reply to prashant.kaushik:

try the following with the tmpArr and without using any function ‘total_size’ also…
then, it seems to be working fine…

module top;

typedef byte sgl_t[16];

// Class
class myclass;
rand byte sgl[16];

rand byte unsigned payload[];
rand int  unsigned payload_desc[];

rand int tmpArr[];

// Array creation
constraint c_sgl_size {  sgl.size == 5;
                         payload.size == 15;
                        **tmpArr.size == sgl.size;**

                         foreach(sgl[i])  {
                           sgl[i].size == 2;
                        **tmpArr[i] == sgl[i].size;**
                         }

                       }


constraint C_PAYLOAD_DISTRIBUTION {
    solve sgl before payload_desc;
  **payload_desc.size == tmpArr.sum with (int'(item));**
    payload_desc.sum with (longint'(item)) == payload.size;
}

function void post_randomize();

  $display("payload_desc size = %d ", payload_desc.size());

  $display("sgl size = %d ", sgl.size());
  foreach(sgl[i,]) begin
    $display("sgl[%1d].size= %d ", i, sgl[i].size);
  end

  foreach(payload_desc[i]) begin
    $display("payload_desc[%1d]= %d ", i, payload_desc[i]);
  end
endfunction: post_randomize

endclass // myclass

initial
begin
myclass c;

c= new();
if(!c.randomize()) begin
  $display("Randomize fail ");
end
else begin
  $display("Randomize Pass");
end

end
endmodule // top;

In reply to prashant.kaushik:

I agree it looks like a tool issue, I’m using vcs_mx/K-2015.09-SP2.
If I use vinod’s suggested workaround, it works OK.

Thanks for your help

In reply to vinod cheedella:

Thanks,

Your suggestion works for me - reproduced here, as I’d spotted a typo in your c_sgl_size constraint.

module top;

typedef byte sgl_t[][][16];

// Class
class myclass;

    rand byte sgl[][][16];

    rand byte unsigned payload[];
    rand int  unsigned payload_desc[];
    rand int  tmpArr[];

    // Array creation
    constraint c_sgl_size {  sgl.size == 5;
                             tmpArr.size == sgl.size;
                             payload.size == 15;

                             foreach(sgl[i,,])  {
                                 sgl[i].size == 2;
                                 tmpArr[i] == sgl[i].size;
                             }
                           }

    constraint C_PAYLOAD_DISTRIBUTION {
        payload_desc.size == tmpArr.sum with (int'(item));
        payload_desc.sum with (longint'(item)) == payload.size;
    }

    function void post_randomize();

        $display("payload_desc size = %d ", payload_desc.size());
        $display("sgl size = %d ", sgl.size());

        foreach(sgl[i,]) begin
            $display("sgl[%1d].size= %d ", i, sgl[i].size);
        end

        foreach(payload_desc[i]) begin
            $display("payload_desc[%1d]= %d ", i, payload_desc[i]);
        end

    endfunction: post_randomize

endclass // myclass

initial
begin
    myclass c;

    c= new();
    if(!c.randomize()) begin
        $display("Randomize fail ");
    end
    else begin
        $display("Randomize Pass");
    end
end

endmodule // top;

Here is the output,

payload_desc size = 10
sgl size = 5
sgl[0].size= 2
sgl[1].size= 2
sgl[2].size= 2
sgl[3].size= 2
sgl[4].size= 2
payload_desc[0]= 12
payload_desc[1]= 1
payload_desc[2]= 1
payload_desc[3]= 1
payload_desc[4]= 0
payload_desc[5]= 0
payload_desc[6]= 0
payload_desc[7]= 0
payload_desc[8]= 0
payload_desc[9]= 0
Randomize Pass

In reply to dshanley:

Sorry, just noticed that you actually didn’t have a typo.