Table of Contents

Simple guide to Verilog Wire and Reg types

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:

  1. A wire from an outer module can be connected to the input or output of an inner module.

The simple reg rules are:

  1. A reg can be used as input to an inner module.
  2. In an inner module, a reg can be used as an output, but not as an input.
  3. A reg in an outer module cannot be connected to the output reg of an inner module. This rule can seem confusing.

This illustration will help show what connections are possible:

Testing simple wires between modules

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 a wire and reg data types

More rules for wire data types:

  1. Only wires can be assigned to using the assign statement. They are continuously connected.
  2. Wires can't store information. They have no state.
  3. Wires cannot be assigned a value in an always block.

More rules for reg data types:

  1. A reg can store information.
  2. Only a reg can be assigned a value in an always block.
  3. A reg cannot be continually assigned to using the assign statement.
  4. A reg can continually pass to a wire using assign.
  5. Reg can be used to create both combination and sequential logic.

That's a lot to take in. Let's work through them:

Reg In / Wire Out

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.

A module's output reg cannot connect to a reg in the outer module

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.

Additional references

https://www.youtube.com/watch?v=zWEgSHZ5ex4