# How to properly use packed 2D arrays as input and outputs of verilog task?

In a part of my verilog project, I am assigning a data to register M[i] by reading from register N[j]. I have written and simulated the code in verilog without any problem. As this particular pattern is repeated many times in a module, I'd like to convert it into a task. But I'm getting compilation errors when using a 2D array of registers as input and output of the task. Below is a sample code that illustrates the problem.

timescale 1 ns/100 ps
module test(clk, rst_n);
input clk, rst_n;
reg [1:0] idx1;
reg [2:0] idx2;
reg [15:0] M[3:0];
reg [15:0] N[7:0];

always @(posedge clk or negedge rst_n) begin
idx1 <= rst_n ? (idx1 + 1) : 0;
idx2 <= rst_n ? (idx2 + 1) : 0;
end

always @(posedge clk or negedge rst_n) begin
if(~rst_n) begin : reset_registers
integer i;
for(i = 0; i < 4; i = i+1) M[i] = 0;
for(i = 0; i < 8; i = i+1) N[i] = i;
end
else begin
M[idx1] <= N[idx2];
end
end
endmodule


The module compiles and simulates as expected now. I would like to convert the segment M[idx1] <= N[idx2]; to a task. So, the new code using a task is:

timescale 1 ns/100 ps
module test(clk, rst_n);
input clk, rst_n;
reg [1:0] idx1;
reg [2:0] idx2;
reg [15:0] M[3:0];
reg [15:0] N[7:0];

always @(posedge clk or negedge rst_n) begin
idx1 <= rst_n ? (idx1 + 1) : 0;
idx2 <= rst_n ? (idx2 + 1) : 0;
end

always @(posedge clk or negedge rst_n) begin
if(~rst_n) begin : reset_registers
integer i;
for(i = 0; i < 4; i = i+1) M[i] = 0;
for(i = 0; i < 8; i = i+1) N[i] = i;
end
else begin
copy(idx1, idx2, M, N);
end
end

task copy;
input [1:0] x1;
input [2:0] x2;
output reg [15:0] A[3:0];
input [15:0] B[7:0];
begin
A[x1] <= B[x2];
end
endtask
endmodule


I am getting the following errors when trying to compile it using modelsim:

# -- Compiling module test
# ** Error: D:\projects\test.v(21): Illegal task output argument.
# ** Error: D:\projects\test.v(21): (vlog-2110) Illegal reference to memory "B".
#
# ** Error: D:\projects\test.v(21): Illegal LHS of assignment.
# ** Error: D:\projects\test.v(21): (vlog-2110) Illegal reference to memory "N".
#
# C:/modeltech64_10.2c/win64/vlog failed.


Can someone please advise how to use the registers properly in a task? Exactly what is making the statements illegal? Is it even possible to something like this using a task, or is there other way around? Thank you.

## 2 Answers

You need to be using SystemVerilog to have unpacked arrays as arguments to a task. And the task as you have written it does not do the same thing as the code without the task. That is because the output array A is uninitialized and you are only setting the value indexed by x1.

• Thank you @dave_59 . Little confusion here- The output array A takes Array M as argument, which is already initialized. Does it mean that the task makes extra registers for A instead of just using the already existing registers M which is already initialized? In that case, is it the correct practice to use the task to generate a combinatorial output c_M and assign it as M <= c_M in my always block? – Shafeey Jul 4 '16 at 9:03
• input arguments get copied into the task upon entry to the task, and outputarguments get copied _out_of the task upon exit. You would need an inout argument for the copy to happen upon entry and exit of the task. And I don't think that would by synthesizable. – dave_59 Jul 4 '16 at 13:38

As far as I know, Verilog does not support multi-dimensional arrays at input or output ports.

So as @dave_59 suggested, you can either shift to System Verilog to do so, or if you want to implement the task within Verilog you can merge the 2-d array as a 1-d array like [15:0] A [3:0] will be A [63:0] with A[15:0] = 1st row, A[31:16] = 2nd row and so on..., but that would increase the effort and no of lines of code, in your particular case.

Also, The Tasks can use global variables as well, so you can do this if it solves your purpose:

task copy;
begin
M[idx1] <= N[idx2];
end
endtask


and call the task by copy();

Also you can make a separate module with just the task having 2-d arrays as parameters and instead of calling a task, you can just call the module with different parameters.