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

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)

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.

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.

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

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.

With System verilog we can import a package instead of having parameterization and define types in the package to be used in the portlist.
module mymodule
import mymodule_pkg::*;
(
input portlist_t portlist
);
endmodule
And define multiple copies of the package with different variants of the port list and compile whichever version is required. eg
package mymodule_pkg;
localparam LENGTH=5;
typedef struct packed {
logic [LENGTH-1:0] data_1,
logic [LENGTH-1:0] data_2,
logic [LENGTH-1:0] data_3
} portlist_t;
endpackage
As with the interface solution there will be situations where you run into issues, like having different iterations of the module instantiated together.

Related

What will the assign statements get synthesized as?

I am interested to know what will these lines synthesize to? I am designing a direct mapped cache and using assign to separate my index, offset and tag bits. Will it synthesize to a demultiplexer? I did not mention the whole code since I just want to know how the assign statements will look after synthesis. In 8085 programming, I had read the term as 'address demultiplexing" so it was confusing.
module cache
( input bit clk,
input bit rst,
input logic [15:0] address,
input logic valid_in,
input logic compare,
input logic wr,
input logic enable,
input logic write_through,
output logic dirty,
output logic [4:0] tag_out,
output logic [15:0] data_out,
output logic valid_out,
output hit
);
logic [7:0] index;
logic [1:0] offset;
logic [4:0] tag_in;
assign offset = address[1:0];
assign index = address[9:2];
assign tag_in = address[15:10];
endmodule
The above code will just simply get synthesized as wire's, since there are only assignments.
I am not sure what de-multiplexing logic you are trying to create, but generally for a de-multiplexer you need to have a select signal based on which you decode which output should be enabled.
An example for a 1:2 de-multiplexer logic is given below
module demux_1_2(
input [3:0] Q,
input Sel,
output reg [3:0] D1,
output reg [3:0] D2
);
always#(*)
begin
if(~Sel) begin
D1 = Q;
D2 = 0;
end else begin
D1 = 0;
D2 = Q;
end
end
endmodule
Since there are no Boolean or arithmetic operators on the RHS of the assign, these statements just become conveniently named references for part selects of the address input. This is the same thing that happens when you instantiate a module and connect to its ports - signals can go through a name change. In fact, you could have you could have written your address input port declaration as
input .address({tag_in,index,offset}),
You still connect the address port when instantiating this module, but inside the module, it only has tag_in, index, and offset available to reference, not address.
SystemVerilog has the alias construct to make it more obvious that you are just creating a convenient names for a signal, instead of declaring another set of signals and using the assign statement.
alias offset = address[1:0];
alias index = address[9:2];
alias tag_in = address[15:10];

call by reference in verilog code

I am trying to change a c++ code into verilog HDL.
I want to write a module that changes one of its inputs. (some how like call by reference in c++)
as I know there is no way to write a call by reference module in verilog (I can't use systemverilog)
Here is a code that I wrote and it works. are there any better ways to do this?!
my problme is that the register I want to be call by reference is a big array. this way duplicates the registers and has a lot of cost.
module testbench();
reg a;
wire b;
reg clk;
initial begin
a = 0;
clk = 0;
#10
clk = 1;
end
test test_instance(
.a(a),
.clk(clk),
.aOut(b)
);
always#(*)begin
a = b;
end
endmodule
module test(
input a,
input clk,
output reg aOut
);
always #(posedge clk) begin
if (a == 0)begin
a = 1;
aOut = a;
end
end
endmodule
Verilog is not a software programming language; it is a hardware description language. The inputs to a module are pieces of metal (wires, tracks, pins); the outputs from a module are pieces of metal. If you want a port that is both an input and an output you can use an inout. However, inout ports are best avoided; it is usually much better to use separate inputs and outputs.
A Verilog module is not a software function. Nothing is copied to the inputs; nothing is copied from the outputs. A Verilog module is a lump of hardware: it has inputs (pieces of metal carrying information in) and outputs (pieces of metal carrying information out).
Your are right to say that you can use either pass-by-copy or pass-by-reference in SystemVerilog. If you wish to pass a large data structure into a function or into/out of a task, then passing by reference may save simulation time.
By reference means by address, so to translate this to hdl directly you would either need to provide a way for the module to get on that bus and perform transactions based on that address.
Or better, if you need this as an input take each of the items in the struct and make individual inputs from them. If it is pass by reference because it is an output or is also an output, then you create individual outputs for each of the items in the struct. The module then distinguishes between the input version of that sub item and output version of that sub item.
my.thing.x = my.thing.x + 1;
becomes something like
my_thing_x_output = my_thing_x_input + 1;

Designing a 3-bit counter using T-flipflop

module tff(t,i,qbprev,q,qb);
input t,i,qbprev;
output q,qb;
wire q,qb,w1;
begin
assign w1=qbprev;
if(w1==1)begin
not n1(i,i);
end
assign q=i;
not n2(qb,i);
end
endmodule
module counter(a,b,c,cin,x0,x1,x2);
input a,b,c,cin;
output x0,x1,x2;
reg a,b,c,x0,x1,x2,temp,q,qb;
always#(posedge cin)
begin
tff t1(.t(1) ,.i(a),.qbprev(1),.q(),.qb());
x0=q;
temp=qb;
tff t2(.t(1) ,.i(b),.qbprev(temp),.q(),.qb());
x1=q;
temp=qb;
tff t3(.t(1) ,.i(c),.qbprev(temp),.q(),.qb());
x2=q;
a=x0;
b=x1;
c=x2;
end
endmodule
This is my code in verilog. My inputs are - the initial state - a,b,c and cin
I get many errors with the first of them being "w1 is not a constant" What doesn this mean?
I also get error "Non-net port a cannot be of mode input" But I want a to be an input!
Thank you.
Modules are instantiated as pieces of hardware. They are not software calls, and you can not create and destroy hardware on the fly therefore:
if(w1==1)begin
not n1(i,i);
end
With that in mind I hope that you can see that unless w1 is a constant parameter, and this is a 'generate if' What your describing does not make sense.
instance n1 is not called or created as required, it must always exist.
Also you have the input and output connected to i. i represent a physical wire it can not be i and not i. these need to be different names to represent different physical wires.
In your second module you have :
input a,b,c,cin;
// ...
reg a,b,c; //...
Inputs can not be regs as the warning says, just do not declare them as regs for this.
input a,b,c,cin;
output x0,x1,x2;
reg x0,x1,x2,temp,q,qb;

Form orthongonal group of busses from existing bus (instead of busses of the rows, busses of the columns)

I have inputs like this coming into a module:
input wire [31:0] row0_Q,
input wire [31:0] row1_Q,
...
input wire [31:0] row30_Q,
input wire [31:0] row31_Q
and want to form busses of the "columns" for lack of better terms. I can do it the long way:
assign col31 = {row31[31], row30[31], ... row1[31], row0[31]} ;
but it's a lot of typing. Is there an easier way?
There is no easy way within Verilog. Try creating a script to generate the code for you. You can have the code generated by your preferred programming language, then use an `include statement in your verilog file. Or you can go with an embedded route:
Perl had EP3 : http://metacpan.org/pod/Text::EP3::Verilog
Ruby has eRuby : http://www.tutorialspoint.com/ruby/eruby.htm
Python has prepro : http://corner-case.com/indproj/prepro.html
I'm sure something like it exists for other languages to. Such as Tcl, JavaScript, C, etc.
Concept is the same, just a difference in embedded language and tool used for conversion.
In this case, a double for-loop like the following will be needed:
foreach my $i (0..31) {
foreach my $j (0..31) {
printf("assign col%0d[%0d] = row%0d[%0d];\n", $i,$j, $j, $i);
}
}
With SystemVerilog you could redefine your module with arrayed input/output ports. It may add difficulty when instantiating, and a synthesizer my attempt flatten the array. But it could work. Verilog does not support this, SystemVerilog does.
module row2col #(parameter WIDTH=32) (
input wire [WIDTH-1:0] row [WIDTH],
output logic [WIDTH-1:0] col [WIDTH]
);
always_comb begin
foreach(row[i,j]) begin
col[j][i] = row[i][j];
end
end
endmodule : row2col

verilog : Instantiation of modules in generate block with variable inputs

I have just started with verilog and trying to implement a small block where I want to call a module inside the generate block but with variable parameters, like:
module abc(a,b,c,d)
input a,b;
output c,d;
generate
if(a=1) begin
xyz xyz1(a,b,c,d);
end
if(a=0) begin
efj xyz1(a,b,c,d);
endgenerate
endmodule
The values of a and b are changing at every clock cycle. I know we can only use constant values in generate block but how can I handle this? Is there any way out?
Looks like you need both modules simultaneously, so instantiate them without generate, but connect their outputs to the output of abc based on a's value:
module abc(a,b,c,d);
input a,b;
output reg c,d;
wire c1, d1, c2, d2;
xyz xyz1(a,b,c1,d1);
efj xyz2(a,b,c2,d2);
always #(*)
if (a==1) begin
c=c1; d=d1;
end
else begin
c=c2; d=d2;
end
endmodule
Also, you should use == operator, rather than = operator in the if statements.

Resources