Programmable Logic/Verilog Module Structure
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 defined using the module keyword, and are ended with the endmodule keyword.
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 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
In Verilog, all inputs and outputs are passed through the parameter list. 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.
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.