Introduction
Every language, whether spoken or for programming, has a fundamental set of rules and building blocks. Verilog is no different. Before we can design complex digital circuits, we must first master the basic syntax and components that form the foundation of the language. This chapter introduces the essential elements of Verilog, from the primary design unit—the module—to the data types that hold values and the operators that manipulate them. Understanding these core concepts is the first and most critical step toward becoming proficient in hardware description with Verilog.
Module Declaration and Instantiation
The module is the basic building block of any Verilog design. It is a self-contained unit that describes a component of a digital circuit. Think of a module as a black box with inputs and outputs, which encapsulates a specific function. A complex design is built by connecting these modules together in a hierarchy.
Module Declaration
A module is defined using the `module` and `endmodule` keywords. The declaration includes the module name and a list of its ports. There are two common styles for declaring ports:
Style 1: Non-ANSI (Verilog-1995)
In this older style, the port names are listed in the module definition, and their directions are declared separately within the module body.
module and_gate_non_ansi (y, a, b);
output y;
input a;
input b;
assign y = a & b;
endmodule
Style 2: ANSI (Verilog-2001)
This modern, more concise style allows the port direction and data type to be declared directly within the port list. This is the recommended style for new designs.
module and_gate_ansi (
output wire y,
input wire a,
input wire b
);
assign y = a & b;
endmodule
Module Instantiation
Once a module is defined, you can use it within another module. This process is called instantiation. It creates a unique copy of the module and allows you to connect its ports to signals in the higher-level module. There are two ways to connect the ports:
Connection by Position vs. Connection by Name
module top_module ( ... );
...
// Method 1: Connection by Position (Order Matters!)
// Prone to errors if the module definition changes.
and_gate_ansi u1 (out, in1, in2);
// Method 2: Connection by Name (Recommended)
// Explicitly connects ports, making code robust and readable.
and_gate_ansi u2 (
.y(out), // Connects port 'y' of the and_gate to the 'out' wire
.a(in1), // Connects port 'a' to 'in1'
.b(in2) // Connects port 'b' to 'in2'
);
endmodule
Data Types
Verilog uses a 4-state logic system. Every bit can have one of four values:
0
: Logic zero, or a false condition.1
: Logic one, or a true condition.X
: An unknown logic value. This can represent an uninitialized value or a conflict (e.g., two drivers driving a wire with different values).Z
: High-impedance state. This represents a disconnected or floating wire. It is crucial for modeling buses where multiple devices can drive the same line.
Nets vs. Variables
Verilog has two main groups of data types: **nets** and **variables**.
- Nets (e.g.,
wire
,tri
): Represent physical connections between hardware elements. They do not store values themselves but must be continuously driven by something, like the output of a gate or an `assign` statement. If nothing is driving a wire, its value is `Z`. - Variables (e.g.,
reg
,integer
): Represent storage elements. They hold a value until a new value is assigned to them within a procedural block (like `always` or `initial`). If a `reg` is not assigned, it holds its previous value.
reg
does not always mean a hardware register (flip-flop). It simply means it is a variable that can store a value. Synthesis tools will infer a flip-flop only if the `reg` is assigned a value based on a clock edge within an `always` block.Vectors and Parameters
Signals can be single-bit (scalar) or multi-bit (vector).
// Scalar (single-bit) signals
wire enable;
reg error_flag;
// Vector (multi-bit) signals
wire [7:0] data_bus; // An 8-bit wire from bit 7 down to bit 0
reg [0:31] address; // A 32-bit register from bit 0 up to bit 31
// Parameters define constants to make code reusable
parameter DATA_WIDTH = 16;
wire [DATA_WIDTH-1:0] wide_bus; // A 16-bit wire
Operators
Verilog provides a rich set of operators to manipulate data.
Category | Operators | Description |
---|---|---|
Arithmetic | + - * / % |
Addition, Subtraction, Multiplication, Division, Modulus. |
Logical | && || ! |
Logical AND, OR, NOT. Returns a single bit (1 or 0). |
Bitwise | & | ~ ^ ~^ |
Bitwise AND, OR, NOT, XOR, XNOR. Operates on each bit of the operands. |
Relational | > < >= <= == != |
Comparison operators. |
Shift | >> << >>> <<< |
Logical and Arithmetic shift operators. |
Concatenation | { } |
Joins bits of two or more signals together. {a, b} |
Lexical Conventions and Comments
Verilog follows specific rules for naming and commenting.
- Identifiers: Names for modules, variables, etc., must start with a letter or underscore and can contain letters, numbers, underscores, and dollar signs ($). Verilog is case-sensitive.
- Comments: Use comments to make your code readable.
- Single-line comments start with
//
. - Multi-line comments are enclosed in
/* ... */
.
- Single-line comments start with
- Number Literals: You can specify the size and base of a number. The format is
<size>'<base><value>
.8'b1010_1111
// 8-bit binary number (underscores are ignored)12'hA2F
// 12-bit hexadecimal number32'd255
// 32-bit decimal number