farhad01 Posted April 18, 2013 Report Share Posted April 18, 2013 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 Quote Link to comment Share on other sites More sharing options...
zcahana Posted April 18, 2013 Report Share Posted April 18, 2013 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 farhad01 1 Quote Link to comment Share on other sites More sharing options...
farhad01 Posted April 18, 2013 Author Report Share Posted April 18, 2013 Thanks Zvi for your solution, but your solution requires passing the size of argument with it. It is too bad that SV is a rich language but it lacks such a trivial feature as already found in VHDL. Quote Link to comment Share on other sites More sharing options...
zcahana Posted April 18, 2013 Report Share Posted April 18, 2013 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. farhad01 1 Quote Link to comment Share on other sites More sharing options...
David Long Posted April 19, 2013 Report Share Posted April 19, 2013 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 farhad01 1 Quote Link to comment Share on other sites More sharing options...
farhad01 Posted April 21, 2013 Author Report Share Posted April 21, 2013 Thanks Dave for your interesting solution. It is cool that we can use C++ to add new functions to a SV testbench. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.