Verilog Syntax Fundamentals
Verilog syntax shares similarities with C, operating on a flow of lexical tokens. Each token, composed of one or more characters, may be a comment, keyword, number, string, or whitespace. All statements must terminate with a semicolon, and the language is case-sensitive.
Comments:
Two styles are available: // for single-line comments and /* */ for multi-line comments. The multi-line format cannot be nested, though single-line comments may appear within a multi-line block.
Whitespace:
This includes characters for spaces, tabs, newlines, and form feeds.
Operators:
Verilog includes unary, binary, and ternary (conditional) operators.
Number Representation:
Numbers can be expressed in decimal, binary, octal, or hexadecimal bases. The default interpretation is decimal.
[bit_width]'[radix][value]
The bit_width is a decimal number specifying the total bit count. The radix can be d, b, o, or h for decimal, binary, octal, and hexadecimal, respectively. The value comprises digits valid for the chosen radix (e.g., 0-9, a-f for hex). Omitting the radix implies decimal. Omitting the bit_width results in a simulator-dependent default size. A negative number is endicated by a minus sign before the bit_width; placing it between the radix and value is erroneous.
Strings:
Characters enclosed in double quotes form a string. Each character consumes one byte of storage.
Identifiers:
An identifier names a variable and can include alphabetic characters, digits, underscores, and dollar signs. It is case-sensitive and cannot start with a digit or $.
Keywords:
Keywords are reserved, lowercase identifiers that define language constructs.
Core Data Types in Verilog
Data types model the storage and connection of digital data. Most types can hold one of four basic values: 0, 1, X (unknown), or Z (high-impedance). The exceptions are real and event types. In simulation waveforms, X is often shown in red and Z in an intermediate color like orange.
Nets vs. Variables:
These two primary categories represent different hardware structures with distinct assignment and value retention behaviors.
- Nets: Model physical connections between hardware elements like gates and do not store values. The
wiretype is the most common net, used for connecting components and nets driven by a single gate or continuous assignment. Multiple wires can be grouped into a vector.wire [3:0] bus_line; // A 4-bit vector wire. - Variables: Abstract data storage elements. The
regtype can model storage elements (e.g., flip-flops) or represent combinational logic.
Additional Data Types:
- Integer: A 32-bit wide variable declared as
integer. - Time: A 64-bit unsigned variable declared as
time.realtimestores time as a floating-point number. - Real: A variable declared as
realfor storing floating-point numbers, assignable similarly tointegerandreg. - Strings: Stored in
regvariables. The string is assigned starting from the least significant bit (right side). If the register is wider than the string, the most significant bits are filled with zeros.
Scalar and Vector Representations
A net or reg declared without a range is a scalar. A declaration with a range specifies a vector.
wire enable; // Scalar
wire [15:0] data_bus; // 16-bit vector
reg flag;
reg [7:0] counter;
The leftmost index in a vector range denotes the most significant bit (MSB), and the rightmost denotes the least significant bit (LSB). The syntax is [msb:lsb]. Both msb and lsb must be constant expressions, not variables. The lsb can be greater than, equal to, or less than the msb.
Bit-Select:
Individual bits within a vector can be accessed and assigned. If the selected index is out of bounds or evaluates to X or Z, the result is X.
Part-Select:
This operation selects a contiguous range of bits. There are two forms: constant part-select and indexed part-select.
[base_index +: width] // Selects *width* bits upward from base_index.
[base_index -: width] // Selects *width* bits downward from base_index.
For example:
reg [31:0] packet;
packet = 32'hFACE_CAFE;
$display("packet[0+:8] = 0x%0h", packet[0+:8]); // Displays 0xFE
Arrays and Memory Models
Verilog Arrays:
Arrays of nets or variables can be declared for scalar or vector types. Multiple dimensions are created by specifying address ranges after the idantifier.
reg sensor[0:11]; // Array of 12 scalar regs.
wire [7:0] port[0:3]; // Array of 4, each an 8-bit vector.
reg [3:0] matrix[0:1][0:3]; // Two-dimensional array (2x4) of 4-bit vectors.
An array of n scalar 1-bit reg elements is distinct from a single n-bit vector reg.
Memory Modeling:
Memories are modeled as one-dimensional arrays of reg type, where each element represents a memory word addressable by a single index.
reg [15:0] system_ram[0:1023]; // Memory with 1024 words, each 16 bits wide.