1
\$\begingroup\$

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.

\$\endgroup\$
0
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ 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? \$\endgroup\$ – Shafeey Jul 4 '16 at 9:03
  • \$\begingroup\$ 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. \$\endgroup\$ – dave_59 Jul 4 '16 at 13:38
0
\$\begingroup\$

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.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.