Jump to content

How to pass variable sized packed arguments to a task/function?


Recommended Posts

In SystemVerilog we can have dynamic unpacked arrays and they can be passed to a function/task. I was wondering if there is a way to pass dynamic packed arrays to a function/task. For example consider the following code:

 

module test;
  logic [3:0] A;
  logic [7:0] B;

  task automatic double(ref [3:0] val);
    val = val * 2;
    $display("%b",val);
  endtask

  initial begin
    A = 3;
    double(A);
    B = 5; 
    //double(; ** Error because of size mismatch
  end

endmodule

here the task can only have a 4-bit input argument so if B is passed an error occurs. I am interested to know if there is any way to pass packed arrays of different size to a task/function. In previous example if the arrays were unpacked I could use:

 

  task automatic double(ref val []);

 

but I have no idea what I should use for packed arrays. In VHDL having variable size input arguments is very easy. For example the same code can be written like this:

 

use std.textio.all;

entity test is
end entity;

architecture arch of test is

  procedure double(val: bit_vector) is
    variable temp : bit_vector(val'left downto val'right);
    variable l : line;
  begin
    temp := val sll 1;
    write(l,temp);
    writeline(output,l);
  end procedure;

begin

  process
    variable A : bit_vector(3 downto 0);
    variable B : bit_vector(7 downto 0);
  begin
    A := "0011";
    double(A);
    B := "00001111";
    double(;
    wait;
  end process;
  
end architecture;

I appreciate any idea on this.

 

Thanks

 

 

 

 

Link to comment
Share on other sites

I was wondering if there is a way to pass dynamic packed arrays to a function/task.

 

Well, there are no dynamic packed arrays in System Verilog.

 

If the logic of your function is independent of the width of the data, as in your example, then you can use a parameterized class that supply you with the required function.

 

For example:

 

 


class doubler #(int unsigned WIDTH = 1);

  static task double(ref [WIDTH-1:0] val);
    val = val * 2;
    $display("%b",val);
  endtask

endclass

module test;
  logic [3:0] A;
  logic [7:0] B;

  initial begin
    A = 3;
    doubler #(4)::double(A);
    B = 5; 
    doubler #(8)::double(;
  end

endmodule

Link to comment
Share on other sites

If you require to be unaware of the width of your vector, you can use this:

doubler #($bits(A))::double(A);

 

Yes, its quite a verbose (and ugly) syntax, but on the other hand, VHDL is quite verbose (and ugly  :)) as well...

 

Regarding SV lacking this feature - well, it does make sense to me, at least when considering simulators performance (static vs. dynamic arrays, optimization, etc...)

On the other hand, the language does enable you to use dynamic arrays. Moreover, you may quite easily convert them to packed vectors with the streaming operator.

Link to comment
Share on other sites

If you want to add "missing" features into a SV testbench, it can be very easy using DPI, provided you know basic C/C++ syntax.

 

For example, here is a version of your double task that takes an open array (assumed here to be a packed bit vector of any length). I haven't included any checking/error handling but even so, this should still be OK for up to 32-bit vectors.

#include "svdpi.h"

extern "C" {

int double_vec (svOpenArrayHandle h) {
  svBitVecVal *ptr;
  int size;
  int value;
  size = svSize(h,0);

  //get bit vector ptr from handle
  ptr = (svBitVecVal*)svGetArrayPtr(h);
  //convert to int
  value = bv_to_int(ptr,size);
  value *= 2;
  //write int back to bv
  int_to_bv(value,ptr,size);
  return 0;
}
} 

 

The functions to convert to/from int/bit vector could be something like:

 

int bv_to_int(const svBitVecVal* bv, int size) {
  int val = 0;
  int mask = 1;
  for (int i=0; i<size; i++){
      if (svGetBitselBit(bv,i) == sv_1)
          val |= mask;
      mask <<= 1;
  }
  return val;
}

void int_to_bv (int val, svBitVecVal* bv, int size) {
  int mask = 1;
  svBit b;
  for (int i=0; i<size; i++){
      b = (val & mask) ? sv_1 : sv_0;
      svPutBitselBit(bv,i,;
      mask <<= 1;
  }
}

 

You could declare and use the DPI function in SV as follows:

 

module top();
  import "DPI-C" task double_vec(inout bit[] vec);
 
  bit [7:0] vec8 = 8'd15;
  bit [15:0] vec16 = 16'd1234;
 
  initial begin
    $display ("vec8 = %0d, vec16 = %0d", vec8, vec16);  
    double_vec(vec8);
    double_vec(vec16);
    $display ("vec8 = %0d, vec16 = %0d", vec8, vec16);  
  end

endmodule: top
 

With simple uses of DPI such as this, most current SV simulators will automatically compile and link the SV and C/C++ code for you, e.g.

qverilog top.sv double.cpp 

 

Hope that gives you some ideas, even if it is a somewhat more complicated solution than you were hoping for!

 

Regards,

Dave

 

 


 


 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...