A module is the smallest structural building block in Verilog. By nesting and reusing modules, a designer can climb from primitive gates to full-blown digital systems while preserving a clean, hierarchical view. The module’s port list plays the same role as copper traces on a PCB: it caries data, control, and clock signals between blocks.
Conceptual View
Think of a module as a black box with:
- Parameters – compile-time constants that configure the block.
- Ports – run-time signals that move data in and out.
Each higher-level module simply instantiates lower-level ones, connecting their ports as if they were physical pins.
Minimal Template
module top #(
parameter AW = 8
)(
input wire clk,
input wire [AW-1:0] din,
output reg [AW-1:0] dout
);
// body
endmodule
Design Flow in Five Steps
-
Name the module
Choose a self-explanatory name:sync_fifo,axis_adapter,tb_bram. The name is the only handle the rest of the project will see. Duplicate names are forbidden unless you compile out-of-context (OOC) as an IP core. -
Declare parameters
Parameters act like Cconstvariables but live at elaboration time. They define widths, depths, latencies, or feature switches without affecting timing closure. -
List the ports
Ports are directional (input,output,inout) and must respect bit-width and timing. For clarity, group them into:- Control (clock, reset, enable)
- Data payload
- Side-band handshake (ready/valid, bus strobes)
-
Instantiate the module
Use named port connections to avoid positional errors. Parameters can be omitted if defaults are acceptable; unconnected inputs become1'b0in Vivado and1'bxin ModelSim. -
Replicate with
generate
Becuase hardware is spatially parallel, you cannot call a module inside aforloop at run time. Instead, usegenerateto build multiple physical copies at elaboration time.
Generate Constructs
Loop Replication
genvar k;
generate
for (k = 0; k < 4; k = k + 1) begin : g_slice
adder #(.WIDTH(16)) u_adder (
.clk (clk),
.a (a[k*16 +: 16]),
.b (b[k*16 +: 16]),
.sum (sum[k*16 +: 16])
);
end
endgenerate
Conditional Instantiation
generate
if (USE_DSP == 1) begin : g_dsp
dsp_mult u0 (.*);
end else begin : g_logic
logic_mult u0 (.*);
end
endgenerate
Case Selection
generate
case (ALGORITHM)
0: crc8 u_crc (.*);
1: crc16 u_crc (.*);
2: crc32 u_crc (.*);
endcase
endgenerate
Width Matching Rules in Generate Loops
When driving multiple instances from a single vector:
- Replication – if the source is narrower than the port, the valuee is duplicated to every instance.
- Alignment – if the source is wider, it is zero-padded to N × port_width and then sliced.
Explicit sizing is mandatory; bare integers default to 32 bits and may create unintended padding.
Putting It Together
By combining well-named modules, parameterization, disciplined port lists, and generate statements, you can create reusable building blocks that scale from simple gates to complete SoCs while keeping the code readable and the synthesis results predictable.