Can we have an array of custom modules? - verilog

Can we have an array of instances for a custom module?
For example: we can have input [15:0] a; - this creates a bus. Can we do same thing for custom modules, i.e. DFF [15:0] d;, where DFF is a custom module?
Here I intend to create 16 instances of the DFF module.

Verilog arrays of instances were added in Verilog-1995 (IEEE 1364-1995). They can be used with gates, user-defined primitives, and modules. Generates, which are more powerful but also more complex, were added in Verilog-2001.
Here is an example array of module instances:
DFF d[15:0] (clk, DFF_i, DFF_o);
For each port connection, if the size matches that of the formal parameter then it is connected to every instance. Otherwise each instance is connected to a part-select (or bit-select) of the expression.

it is not possible to do this directly (update: now after mark4o's answer I know that there is a way), but what you can do is using the generate statement to create multiple instances of your custom module and hook them up to your signals. Should look something like this:
wire DFF_i[15:0];
wire DFF_o[15:0];
generate
genvar i;
for (i=0; i<15; i=i+1) begin : dff
custom i_custom(
.clk(clk)
,.input(DFF_i[i])
,.output(DFF_o[i])
);
end
endgenerate
Otherwise there are probably some possibility during synthesis to use the correct custom modules, but I'm not an expert there.
Cheers,
Daniel

Related

Verilog Difference Between Regular wire and wire[] + Period in front of variable name

I have two questions regarding Verilog HDL.
What is the difference between regular wire and, for example, wire[31:0]?
What does it mean when a variable has a period in front of it? (e.g. .clk (clk 0))
For 1st question,
wire a; //a is one bit.
wire [31:0] a; //a is 32 bit.
As for 2nd question, it's way of instantiation a sub-module in a main module. Suppose you have the following module,
module arith(
A,
B
);
And you want to instantiate it in a top module. Then,
arith uut1 (
.A(A_in_topmodule),
.B(B_in_topmodule)
);
Read in detailed about various instantiation methods in Verilog here.

What is the purpose of this module?

module InoutConnect(
.X1(internal),
.X2(internal)
);
parameter width = 1;
inout [ width - 1 : 0 ] internal;
endmodule // InoutConnect
In the above code what is the format used,
I know that while instantiating the module .x1 is use to match the variable name but what about module definition.
What does it mean here?
it is called explicit port declaration, meaning that the external world will know this port by its explicit names, X1 and X2 in your case, though internally the same port will be known as internal in your case.
So, in your example you connect both ports to the same internal variable (looks bad to me :)) Though, this is one of the possible uses, in particular if you need to identical output ports. The other example is remapping internal structs or arrays to multiple potrts:
module m(
output .arr1(array[2:0]),
output .arr2(array[7:3]),
input logic [7:0] input_array
)
logic [7:0] array;
...
always_ff #(posedge clk)
array <= input_array;
...
endmodule
So, above you can use your array as the whole internally, but it will have a different representation in the external world.
See 23.2.2.2 ANSI style list of port declarations for more info.
The InoutConnect module is used to create an alias between two different signal names. For example
wire [7:0] color;
wire [7:0] colour;
InoutConnect #7 a1(color,colour);
Now, color and colour are two names for the same signal.
SystemVerilog added the alias construct to do the same thing without needed to create a separate module.

Instantiate vector of custom modules in Verilog with additional parameters

I have a custom module in Verilog that takes several inputs and a few parameters.
module modA (
input inp1, input inp2, ... output out);
parameter my_addr;
...
endmodule
For various reasons associated with the specific hardware that I'm using, I need to create many instances of this module, each time with a different parameter (because my_addr corresponds to a specific location in memory that I am then accessing from the host). Moreover, I would like an easy way to access all of the outputs. I thought of doing something like
wire [9:0] outputs;
modA #(.my_addr) all_modA[9:0](.inp1(inp1), .inp2(inp2), .out(outputs));
So then I would have a vector of elements of all_modA, and the nth element of outputs would correspond to the nth instantiation of modA. That sounds like it would work well, except I need to pass a unique address to each instantiation. When I was just doing one instantiation at a time, it was quite easy to just define a parameter, but I don't see how I could pass a unique identifier each time.
Is there any way to accomplish this? The problem is, if I use a for loop, then I don't see how I can instantiate each modA with a unique identifier. If I don't use a for loop, then I'm not sure how to add a unique identifier.
You can use a generate block over here. Generate blocks are evaluated during elaboration of the design. They do not execute at simulation time and the result is determined before the simulation begins. Therefore, all expressions in generate schemes shall be constant expressions, deterministic at elaboration time.
Give different values to my_addr according to the requirement. Also, you can apply some label identifier to begin-end block. This as an optional feature for generate blocks, but very highly recommended. By doing so, a unique hierarchical path can be seen to every instance of modA is different for each module.
For your code, I have created a testbench that instantiates the module with changing value of my_addr and outputs bus driving the out signal.
module modA #(parameter int my_addr) (input inp1, input inp2,output out);
initial $display("%m: %d",my_addr);
endmodule
module top();
wire [9:0] outputs;
genvar i; // generate iterator
generate
for(i=0;i<9;i++) begin: some_identifier
// my_addr = i+1 for every module
modA #(.my_addr(i+1)) all_modA(.inp1(inp1), .inp2(inp2), .out(outputs[i])); // Multiple modules
end
endgenerate
endmodule
For more information, refer to IEEE 1800-2012 Section 27. Similar questions can be found here and here.

What is the difference between reg and wire in a verilog module?

When are we supposed to use reg and when are we supposed to use wire in a verilog module?
I have also noticed sometimes that a output is declared again as a reg. E.g reg Q in a D flip flop. I have read this somewhere - "The target output of procedural assignment statements must be of reg data type."
What are procedural assignment statements?
I have thoroughly googled this but was not able to find a clear explanation.
Wire:-
Wires are used for connecting different elements. They can be treated as physical wires. They can be read or assigned. No values get stored in them. They need to be driven by either continuous assign statement or from a port of a module.
Reg:-
Contrary to their name, regs don't necessarily correspond to physical registers. They represent data storage elements in Verilog/SystemVerilog. They retain their value till next value is assigned to them (not through assign statement). They can be synthesized to FF, latch or combinatorial circuit. (They might not be synthesizable !!!)
Wires and Regs are present from Verilog timeframe. SystemVerilog added a new data type called logic to them. So the next question is what is this logic data type and how it is different from our good old wire/reg.
Logic:-
As we have seen, reg data type is bit mis-leading in Verilog. System Verilog's logic data type addition is to remove the above confusion. The idea behind is having a new data type called logic which at least doesn't give an impression that it is hardware synthesizable. Logic data type doesn't permit multiple drivers. It has a last assignment wins behavior in case of multiple assignments (which implies it has no hardware equivalence). Reg/Wire data types give X if multiple drivers try to drive them with different values. Logic data type simply assigns the last assignment value. The next difference between reg/wire and logic is that logic can be both driven by assign block, output of a port and inside a procedural block like this
logic a;
assign a = b ^ c; // wire style
always (c or d) a = c + d; // reg style
MyModule module(.out(a), .in(xyz)); // wire style
Procedural blocks refers to always, always_ff, always_comb, always_latch, initial etc. blocks. While procedural assignment statements refers to assigning values to reg, integer etc., but not wires(nets).
wire elements must be continuously driven by something, and cannot store a value. Henceforth, they are assigned values using continuous assignment statements.
reg can be used to create registers in procedural blocks. Thus, it can store some value.
reg elements can be used as output within an actual module declaration. But,reg elements cannot be connected to the output port of a module instantiation.
Thus, a reg can drive a wire as RHS of an assign statement. On the other way round, a wire can drive a reg in as RHS of a procedural block.
For clear idea about declaration of reg or wire, refer the image below:
So, whenever inferring to sequential logic, which stores/holds some value, declare that variable/port as reg. Here, Q is a reg inside a module, but while instantiating this module inside some other module, then this port must be connected to a wire.
Remember, wire can only infer to combinational logic, while reg can infer to either combinational or sequential logic.
Dave's blog is a good source for detailed information. For further information, refer to synthesizing difference and Verilog wire-reg links.
Simple difference between reg and wire is, the reg is used in combinational or sequential circuit in verilog and wire is used in combinational circuit
reg is used to store a value but wire is continuely driven some thing and wire is connected to outport when module initialization but reg is con not connected

Why is there no assign statement in this Verilog function?

Coming from a C++ background I'm starting to learn Verilog. This code describes four inputs going into two AND gates. The outputs from those two AND gates go into an OR gate. The output from the OR gate is the final output.
// a user-defined AND gate
module my_and2 (in, out);
input [1:0] in;
output out;
assign out = in[1]&in[0];
endmodule
// a user-defined OR gate
module my_or2 (in, out);
input [1:0] in;
output out;
assign out = in[1]|in[0];
endmodule
// the AND-OR logic built on top of the user-defined AND and OR gates
module and_or (in_top, out_top);
input [3:0] in_top;
output out_top;
wire [1:0] sig;
// instantiate the gate-level modules
my_and2 U1 (.in(in_top[3:2]),.out(sig[1]));
my_and2 U2 (.in(in_top[1:0]),.out(sig[0]));
my_or2 U3 (.in(sig),.out(out_top));
endmodule
The first two modules make sense to me. However, the last one doesn't. The first two modules have an assign statement at the end to set the value for the output variable. However, the last one doesn't. Why is that?
Verilog is 'event driven'. When writing verilog, think in terms of sensitivity lists.
In your example of the AND gate, you've the expression assign out = in[1]&in[0];. Your expression is said to be sensitive to in[0] and in[1]. This means that any time in[0] or in[1] change, the expression will be recomputed, and the value of out will be updated.
So in your toplevel module and_or, you're basically building a big tree of expressions that are sensitive to the outputs of the preceding expressions. This tree is, of course, built using the module connections. So a change in the value of one of the inputs to this toplevel module will ripple through all expressions in its 'logic cone'.
To drive the inputs you'll need higher level testbench module driving signals into your and_or module. This will supply inputs spaced out in time which will trigger the expressions in and below and_or. If not, your sim will have no events, so no expressions will trigger and the sim will time-out at 0ps because it is 'event starved'.
PS: for your AND gate expression, assign out = &in; will work too... (reduction AND operator)
out_top is driven by the U3 instance output.
To put things simply, I like to think instantiation as just connecting wires.
Modules are blocks of digital circuits. You AND and OR gate modules are where magic happens. You already understand that part. By instantiating those modules, it's like you're connecting the input wires of your top level module with inputs of two blocks AND module. Then taking the outputs of them and taping them to the input wire sticking out of your OR block. And finally you're connecting the output of OR block to the output signal wire of top level.

Resources