Verilog Language Fundamentals

 

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.
Note: The keyword 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 /* ... */.
  • 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 number
    • 32'd255 // 32-bit decimal number

 

Leave a Reply

Your email address will not be published. Required fields are marked *