Programmable Logic/Verilog Module Structure

From Wikibooks, open books for an open world
Jump to navigation Jump to search

Verilog Modules[edit | edit source]

Modules are the fundamental descriptive units in Verilog HDL. Verilog modules, like functions in other programming languages, are pieces of code that can be used and reused within a single program. Verilog modules are declared using the module keyword, and are ended with the endmodule keyword.

Module Format[edit | edit source]

Basic Modules are laid out as follows:

module MyModule ([parameters]);
     inputs ...
     outputs ...
     internal variables ...
     ...
     Module Code ...
endmodule

The module is declared with a module name (in this case, "MyModule"), followed by a list of parameters. Parameters in this case are a list of input and output signals (also called the 'port list') that the module can interact with. If we synthesize our Verilog code, the parameters will signify the physical wire connections that connect our module to the rest of the microchip. Note that in the parameter list, we do not need to specify what the type of the connection is, or whether it is an input or an output. We do that in the next few lines. Here is an example module declaration with some parameters:

module MyModule(a, b, c, clock);

Inputs and Outputs[edit | edit source]

In Verilog, all inputs and outputs are passed through the parameter list. A module requires this list of input and output ports to interact with the environment.

Modules do not return a value in the same way that a C function or a Java function can return a value. Therefore, we use the input and output keywords to specify which parameters are going which direction:

module MyModule(a, b, c, clock);
   input a, b, clock;
   output c;
   ...
endmodule

output connections are generally not initialized, so it is bad practice to attempt to read from a connection specified as an output.

Instance Identifiers[edit | edit source]

When calling a Verilog module from a higher-level module, we need to include an instance identifier. This is done because when we synthesize our code onto a physical chip, functions that need to be called multiple times in parallel are actually created multiple times! This means that if we want the same module to execute with itself in parallel, we need to instruct the synthesizer program to create multiple physical copies of the module. Furthermore, using instance identifiers allows oneself to "wire" multiple modules together (i.e. if we wanted the output of one module to be the input of another module). For the first definition exemplified, let's say we have a module AND that's defined as such:

module AND(a, b, c);
   input a, b;
   output c;
   assign c = a & b;
endmodule

If we want to use AND in another module, we need to call it as follows:

wire w, x, y, z;
...
AND A1(w, x, y);
AND A2(w, y, z);
AND A3(z, x, w);

Notice how we place an identifier in between the module name "AND" and the parameter list? This is an instance identifier. Note that we are defining 3 separate instances of the module AND.

An identifier can be composed of Alphanumeric characters and underscore(_), and it cannot begin with a number.