The aim of this article is to help clear any confusion for beginners when using verilog wire and reg data types between modules. We'll start with the basic rules for both.
The simple wire rules are:
The simple reg rules are:
This illustration will help show what connections are possible:
The verilog for two simple modules to demonstrate connecting wires are:
`include "innermodule.v" module top; wire w_inputForInnerModule; wire w_outputFromInnerModule; InnerModule innermodule ( .i_inner_input(w_inputForInnerModule), .o_inner_output(w_outputFromInnerModule) ); endmodule
module InnerModule ( input i_inner_input, output o_inner_output ); assign o_inner_output = i_inner_input; endmodule
The InnerModule simply connects its input to the output and the top level module has two internal wires that connect to InnerModule's input and output ports but that is all. The wire values are indeterminate, and the design is of little practical use. But it does demonstrate how wires can be connected between modules.
However, we need more than wires. We need reg variables for our logic and processing so that we can eventually pass this information to wires.
More rules for wire data types:
assign
statement. They are continuously connected.always
block.More rules for reg data types:
always
block.assign
statement.assign
.That's a lot to take in. Let's work through them:
Let's try the case where we have a reg in the outer module that is initialised to 1 and is connected to the input of the inner module.
`include "innermodule.v" module top; reg r_inputForInnerModule = 1'b1; wire w_outputFromInnerModule; InnerModule innermodule ( .i_inner_input(r_inputForInnerModule), .o_inner_output(w_outputFromInnerModule) ); endmodule
module InnerModule ( input i_inner_input, output o_inner_output ); assign o_inner_output = i_inner_input; endmodule
And I guess I should supply a small testbench to prove that the output from the inner module was collected from the reg in the outer module:
`timescale 1ns/1ns `include "top.v" module top_tb; top top_test (); initial begin $dumpfile("top_tb.lxt"); $dumpvars(0,top_tb); end initial begin #20 $finish; end endmodule
See FPGA Verilog simulation using GTKWave if you need help setting up testbenches for use in GTKWave simulations.
You can see above that the reg that contained the value of 1'b1 has set the wire w_outputFromInnerModule
to HIGH. Nice.
It is quite possible to pass back an output reg from a module. But it has to connect to a wire. So let's begin with some code attempting to do the wrong thing with the inner module. We can't just use:
//bad InnerModule module InnerModule ( input i_inner_input, output reg o_inner_output = 1'b0 ); assign o_inner_output = i_inner_input; endmodule
This will give us an error of: reg o_inner_output; cannot be driven by primitives or continuous assignment.
We cannot use the assign
statement to wire two regs together. But we can change the value of the output reg whenever i_inner_input
changes using the always
block:
module InnerModule ( input i_inner_input, output reg o_inner_output = 1'b0 ); always @(i_inner_input) begin o_inner_output <= i_inner_input; end endmodule
Let's come up with an outer module that tries to connect a reg to the output reg of the inner module. Can we do it?:
//bad top module `include "innermodule.v" module top; reg r_inputForInnerModule = 1'b1; reg r_outputFromInnerModule = 1'b0; InnerModule innermodule ( .i_inner_input(r_inputForInnerModule), .o_inner_output(r_outputFromInnerModule) ); endmodule
We get an error from iverilog stating: reg r_outputFromInnerModule; cannot be driven by primitives or continuous assignment.
Same deal.
So going back to the original rule we wanted to test: no we can't connect the reg to the output reg of an inner module. We must connect to a wire in the outer module. Therefore, the correct way is to go with this instead:
`include "innermodule.v" module top; reg r_inputForInnerModule = 1'b1; wire w_outputFromInnerModule; InnerModule innermodule ( .i_inner_input(r_inputForInnerModule), .o_inner_output(w_outputFromInnerModule) ); endmodule
And this will be fine. Again, let's test it using the testbench from before:
It actually ends up being the same simulation result. Interesting right?
You can see the reg was initialised to 1 which made the output equal to 1. This output set w_outputFromInnerModule
to HIGH. Fantastic stuff.
If you ever find yourself unsure, always refer to the illustration at the start for a reminder of who can go where.
I would love to hear if this helps you out. Feel free to use the contact link at the top to say hi.