Language Constructs & Conventions
The building blocks of every Verilog source file โ tokens, keywords, identifiers, white space, and comments explained clearly with examples.
๐ Introduction โ What are Tokens?
A Verilog source file is read by the compiler character by character. The compiler groups those characters into meaningful units called lexical tokens โ the smallest building blocks of the language, just as words are the smallest meaningful units in a sentence.
Understanding tokens is important because the Verilog compiler’s first job is lexical analysis โ breaking your source file into a stream of tokens before it attempts to understand the grammar of the design.
๐งฉ The 7 Token Types
Every character in a Verilog source file belongs to one of seven token categories:
assign y = a & b; โโโโโโ โ โ โ โ โ keyword id op id op id
๐ Keywords
Keywords are reserved words that have a fixed, predefined meaning in the Verilog language. They form the vocabulary of the language itself โ the compiler assigns special significance to each one.
MODULE and Module are not keywords โ they would be treated as identifiers (though using them is confusing and discouraged).๐ Keyword Categories
Verilog keywords can be grouped by purpose. Here is the complete set organized into four categories:
Module & Port Declarations blue
Control Flow purple
Procedural Blocks green
Gate Primitives orange
module counter ( // โ declaration keyword input clk, rst, // โ port keyword output reg [3:0] count // โ declaration keywords ); always @(posedge clk) begin // โ procedural keywords if (rst) // โ control flow keyword count <= 4'd0; else // โ control flow keyword count <= count + 1; end // โ control flow keyword endmodule // โ declaration keyword
wire wire; or reg module; will cause a compile error. If you accidentally name a signal after a keyword, rename it (e.g., wire_data, mod_ctrl).
๐ท Identifiers
Identifiers are user-defined names given to modules, ports, signals, instances, tasks, functions, and parameters. They let you refer to design elements by meaningful names rather than anonymous positions.
A good identifier is descriptive, consistent, and unambiguous. Poor naming is one of the most common causes of bugs that are hard to find.
module uart_tx ( // โ module name (identifier) input clk, // โ port name (identifier) input tx_data, // โ port name (identifier) output reg tx_out // โ port name (identifier) ); parameter BAUD_DIV = 868; // โ parameter name (identifier) reg [9:0] shift_reg; // โ signal name (identifier) integer bit_count; // โ variable name (identifier) baud_gen u_baud (...); // โ module & instance name (identifiers) endmodule
๐ Identifier Rules
Verilog identifiers must follow strict syntactic rules:
Digits (0โ9) and dollar sign ($) are not allowed as the first character.
No spaces, hyphens, or special characters allowed.
clk, CLK, and Clk are three completely different identifiers. See the case sensitivity section below.
wire, module, always, etc. as an identifier.
\) and followed by white space. Example: \add+1 . Rarely used in practice.
Naming Conventions (Best Practices)
// Modules โ lowercase with underscores (snake_case) module uart_tx fifo_ctrl axi_master // Parameters โ UPPER_CASE (screaming snake case) parameter DATA_WIDTH = 32; parameter FIFO_DEPTH = 16; // Clocks โ clk prefix/suffix clk clk_50m sys_clk axi_clk // Active-low resets โ _n suffix rst_n reset_n arst_n // Active signals โ descriptive, lowercase tx_valid rx_ready data_in addr_out // Instance names โ u_ prefix is common industry convention u_fifo u_alu u_uart u0 u1
โ Valid vs Invalid Identifiers
| Identifier | Status | Reason |
|---|---|---|
| clock | VALID | Starts with a letter, only letters |
| _reset | VALID | Starts with underscore โ allowed |
| data_32b | VALID | Letters, digits, underscores โ all fine |
| tx$valid | VALID | $ is allowed after the first character |
| A1_out | VALID | Starts with letter, alphanumeric rest |
| 1_name | INVALID | Starts with a digit โ not allowed |
| $signal | INVALID | $ cannot be the first character |
| data out | INVALID | Space splits this into two separate tokens |
| data-bus | INVALID | Hyphen is not a valid identifier character |
| wire | INVALID | Reserved keyword โ cannot be used as an identifier |
| MODULE | VALID | Technically valid (not a keyword โ keywords are lowercase), but very confusing. Avoid. |
๐ก Case Sensitivity
Verilog is fully case-sensitive, exactly like C. This means the same sequence of letters in different cases are treated as completely independent identifiers by the compiler.
These are three entirely different signals as far as Verilog is concerned. If you declare wire clk and then reference CLK, the compiler will report an undeclared identifier error.
wire clk; // declares a signal named "clk" wire CLK; // declares a DIFFERENT signal named "CLK" wire Clk; // yet another different signal named "Clk" assign CLK = clk; // legal โ connecting two distinct signals
input clk and later writing always @(posedge CLK) โ the CLK is undeclared, so the block never triggers. Always use consistent casing. Most teams adopt an all-lowercase-with-underscores convention to avoid this entirely.
Keywords are lowercase only
Since all Verilog keywords are defined in lowercase, writing MODULE, WIRE, or ALWAYS will not be treated as keywords โ they will be parsed as identifiers. This is technically valid but extremely confusing and should never be done.
module my_block (...); // โ correct keyword MODULE my_block (...); // โ MODULE is an identifier, not a keyword โ compile error
โฃ White Space Characters
White space in Verilog refers to any character that produces blank space in a file but carries no semantic meaning of its own. The Verilog compiler uses white space to separate tokens โ once the tokens are identified, all white space is discarded.
// Compact โ tokens separated by single spaces assign y = a & b; // Spread across lines โ still the same statement assign y = a & b; // Extra spaces โ still valid assign y = a & b ;
4'b 1010 is a syntax error โ the space inside the number literal breaks the token. mo dule is two tokens, not the keyword module.
White Space and Readability
While white space is semantically meaningless to the compiler, it is critically important to human readers. Well-spaced, consistently indented code is easier to read, review, and debug. Most teams enforce a style guide (e.g., 2-space or 4-space indentation, spaces around operators).
// โ Hard to read โ no spacing or indentation always@(posedge clk)begin if(rst) q<=0; else q<=d; end // โ Readable โ proper spacing and indentation always @(posedge clk) begin if (rst) q <= 1'b0; else q <= d; end

๐ฌ Comments
Comments are text in the source file that is completely ignored by the compiler. They exist purely for human readers โ to explain intent, document assumptions, mark TODOs, or disable code temporarily.
Verilog supports two comment styles:
// Single-Line Comment
///* Multi-Line Comment */
/*and ends with*//* */Cannot Nest Multi-Line Comments
/* */comments. The first*/encountered always ends the comment โ even if it was meant to close an inner comment. If you need to comment out a block that already contains/* */comments, use//on each line instead, or use the`ifdef NEVER ... `endiftrick shown above.Comments vs Compiler Directives
Comments are not the same as compiler directives (sometimes called preprocessor directives). Directives like
`timescale,`include,`define, and`ifdefare active instructions to the compiler โ they are not ignored. They begin with a backtick (`), not//or/*.// increment counteradds nothing. A comment like// saturate at max value to prevent wrap-aroundexplains intent that isn’t obvious from the code.