How to write a module with variable number of ports in Verilog

11,180

Solution 1

There are no variable number of ports in SystemVerilog, but you could use a port that is a parameterized array.

module my_module #(int LENGTH, DEPTH)(
    input clk,
    input rst_n,
    input [LENGTH-1:0] data[DEPTH]
);
//...
endmodule

Otherwise, you would need to use a script to generate the code.

Solution 2

Use a two dimensional input with a parameterized size. Added a generate for loop that can be used to set signals individually. Although many operations can be done with smart array operations.

module my_module #(SIZE, LENGTH)(
    input clk,
    input rst_n, 
    input [SIZE-1:0][LENGTH-1:0] data_in_array,
    output [SIZE-1:0][LENGTH-1:0] data_out_array
);
genvar N;
generate for (N=0; N<SIZE; N++) begin :la_coolOps
    //Do cool operations here. For example instantiate a module for every data_in
end
//...
endmodule

Edit: As Mehran Torki points out: The syntax above will work for SystemVerilog only. Verilog does not allow for multiple packed arrays. Use input [LENGTH*SIZE-1:0] data_in_array.

Solution 3

I would add to these other answers that ports are just groupings of wires. While having 3, 1-bit wires named a, b, and c might be easier to read and understand, there is no physical/logical difference between a single, 3-bit wire abc, where abc[0] corresponds to a, abc[1] corresponds to b, and abc[2] corresponds to c.

So, you can always just expand or shrink a single (or multiple) signal(s) to get however many bits you need. It may not be as neat, but it will work. In the receiving module, you can then part-select the bus in whatever manner you like. So, you could have one really long wire the shrinks or expands (wire [(SOME_PARAM*8)-1:0] my_input_wire), or with SystemVerilog an array (wire [7:0] my_input_wire[0:SOME_PARAM-1])

If this is just testbench/verification code, the other thing you could do in SystemVerilog is use a dynamic array

Solution 4

As others said, there is no direct way to do this, but another workaround is to use SystemVerilog interfaces, where you define all the inputs that you want in the interface definition and inside the module only use the ones that correspond to the parameter. Below is a sample:

module my_module #(LENGTH)(
       input clk;
       input rst_n;
       output o;
       interface i_data;
    );
    logic outValue;

    generate
        case (LENGTH) //Based on the value of LENGTH, use corresponding data
            1: outValue = i_data.data_1;
            2: outValue = i_data.data_1 + i_data.data_2;
            3: outValue = i_data.data_1 + i_data.data_2 + i_data.data_3;
        endcase 
    endgenerate

    always @(posedge clk) begin
    if (~rst_n)
        o <= '0;
    else
    begin
        o <= outValue;
    end

endmodule

You can still use a parameterized array for data and a for-generate loop if your outputs are similar.

Share:
11,180
Scott
Author by

Scott

Updated on June 17, 2022

Comments

  • Scott
    Scott almost 2 years

    I would like to write a module with a variable number of inputs, i.e. depending on some parameter, the result would be:

    module my_module #(LENGTH)(
        input clk,
        input rst_n,
        input [LENGTH-1:0] data_1
    );
    //...
    endmodule
    

    or

    module my_module #(LENGTH)(
        input clk,
        input rst_n,
        input [LENGTH-1:0] data_1,
        input [LENGTH-1:0] data_2,
        input [LENGTH-1:0] data_3
    );
    //...
    endmodule
    

    Would it be possible to do this in Verilog or Systemverilog or would I have to write a script, let's say in Python, in order to generate the code for a specific module with fixed number of inputs? (it might be more than 1000 inputs)