Skip to content
VLSI Mentor

Verilog · Chapter 4 · Foundations

Lexical Conventions

Chapter 3 taught you to write RTL. This chapter makes the source text itself stop looking mysterious. Verilog reads your file as a sequence of small pieces — keywords, names you invented, numbers, operators and punctuation — and once you can see those pieces, a line of RTL turns from a strange programming sentence into a readable description of hardware. You will learn what a token is, what whitespace and comments do, how names work and why capitalisation matters, how a number carries its width and base, and which punctuation marks actually change meaning. The goal is not to memorise grammar; it is to read Verilog without guessing.

Foundation26 min readVerilogSyntaxIdentifiersLiteralsReading Code

Chapter 4 · Page 1.4 · Foundations

1. How Verilog Reads Your Code

Here is a line you already understand from Chapter 3:

Azvya Education Pvt. Ltd.VLSI Mentor
one line of RTL
assign y = sel ? b : a;

You read that as a multiplexer. Verilog does not — not at first. Before any of it means hardware, the tool has to break the text into pieces:

Azvya Education Pvt. Ltd.VLSI Mentor
the same line, split into pieces
assign    y    =    sel    ?    b    :    a    ;

Nine pieces. Each one is a token — a chunk of source text the language recognises as a single meaningful unit. assign is one token, not six letters. sel is one token. So is the lone ;.

That is the whole idea of this chapter:

Verilog first reads your file as a sequence of tokens. Only then does it work out what hardware you described.

Once you can see the tokens, the line stops being a wall of symbols and becomes:

  • a keyword the language owns — assign
  • names you invented — y, sel, b, a
  • operators and punctuation — =, ? :, ;

And that reads as: continuously drive y from a choice between b and a. A mux.

2. The Pieces Verilog Reads

Verilog recognises a small number of token kinds. You have already met most of them without naming them.

KindWhat it isExample
KeywordA word the language reserves and gives meaning tomodule, assign, always
IdentifierA name you chose for somethingclk, data_in, count_q
NumberA literal value, usually with a width and a base8'hA5, 1'b0, 42
OperatorCombines or compares values&, |, +, ? :
PunctuationStructural marks — they hold the code together; , ( ) [ ]
StringCharacters inside double quotes, used in simulation output"count = %0d"

Two more things appear in source files but are not part of the hardware description:

  • Whitespace — spaces, tabs and newlines, which separate tokens.
  • Comments — notes for humans, which the tools ignore.

And two families carry a marker character that tells you immediately what they are:

  • System tasks and functions begin with $ — $display, $finish. These are services the simulator provides.
  • Compiler directives begin with a backtick — `default_nettype, `timescale. These are instructions to the tool.

Everything in the rest of this chapter is one of the above. Here is the Chapter 3 mux again, with every piece labelled:

Azvya Education Pvt. Ltd.VLSI Mentor
mux2.v — the same module, read as tokens
`default_nettype none          // compiler directive

module mux2 (                  // keyword, identifier, punctuation
    input  wire sel,           // keywords, identifier, punctuation
    input  wire a,
    input  wire b,
    output wire y
);

    assign y = sel ? b : a;    // keyword, identifiers, operators, punctuation

endmodule                      // keyword

Nothing new has been added to the module. You are simply reading it a second way.

3. Whitespace

Spaces, tabs and newlines separate one token from the next. Beyond that separation, Verilog does not care how much of it you use.

Azvya Education Pvt. Ltd.VLSI Mentor
these describe exactly the same hardware
assign y=a&b;

assign y = a & b;

assign y =
    a & b;

All three produce the same tokens, so all three describe the same AND gate. Whitespace is not hardware.

But whitespace is needed where two tokens would otherwise run together. a&b is fine because & cannot be part of a name, so the tool can see three tokens. Remove the space in input wire a and you get inputwire, which is a single identifier and not what you meant.

The practical conclusion is not "formatting is optional." It is:

The tool needs whitespace only to separate tokens. You need it to be able to read your own design six months later.

Write the spaced version. Deep dive: 4.1 White Space Requirements.

4. Comments

Comments are notes to humans. The tools skip over them, so they never become hardware.

Azvya Education Pvt. Ltd.VLSI Mentor
comment-forms.v
// A single-line comment runs to the end of the line.

assign y = a & b;   // it can also sit after code

/* A block comment can
   run across several lines. */

A block comment starts at /* and ends at the first */ it finds. That is worth knowing because it means block comments do not nest — if you wrap a region that already contains */, the comment ends earlier than you expected and the rest becomes code again.

Because comments are free, use them for what the code cannot say — why, not what:

Azvya Education Pvt. Ltd.VLSI Mentor
a comment that earns its place
// Wraps at 15 by design; the downstream block expects modulo-16 timing.
count_q <= count_q + 4'b0001;

Compare that with // increment count, which tells the reader something they could already see.

Deep dive: 4.2 Comment Implementation.

5. Identifiers — the Names You Choose

An identifier is a name you invent: a signal, a port, a module, an instance.

Azvya Education Pvt. Ltd.VLSI Mentor
identifiers from designs you have already seen
wire clk;          // a clock signal
wire rst_n;        // an active-low reset
wire [7:0] data_in;
reg  [3:0] count_q;

clk, rst_n, data_in and count_q are all identifiers. So is mux2, the module name. Verilog attaches no meaning to the name itself — rst_n is reset because of what the code does with it, not because of what it is called. Naming conventions are for humans.

What each of these names is — a net, a variable, a vector — is Variables & Data Types (Chapter 5). Here we only care about how the name is spelled.

  • It must start with a letter or an underscore (_).
  • After that it may contain letters, digits, underscores and $.
  • It may not start with a digit, and it may not start with $ — that first-character $ belongs to the system-task namespace ($display).
  • It may not be a keyword.
  • The standard requires tools to support names of at least 1024 characters, so length is never your practical problem.
Azvya Education Pvt. Ltd.VLSI Mentor
legal and illegal names
wire data_in;      // legal
wire _internal;    // legal — underscore start
wire bus32;        // legal — digits after the first character
wire count_q;      // legal

// wire 2bus;      // illegal — starts with a digit
// wire wire;      // illegal — `wire` is a keyword

Deep dive: 4.6 Identifier Declaration.

6. Verilog Is Case-Sensitive

This one catches almost everyone once, so it gets its own section.

Azvya Education Pvt. Ltd.VLSI Mentor
three different names
data
Data
DATA

Those are three separate identifiers. Not three spellings of one name — three names.

Here is how that becomes a real bug:

Azvya Education Pvt. Ltd.VLSI Mentor
case-bug.v — looks right, is not
wire data_ready;

assign valid = Data_Ready;   // ❌ different name entirely

data_ready and Data_Ready have nothing to do with each other. Depending on how the file is set up, this either fails to compile or quietly creates a second signal that nobody drives — and valid never behaves as intended.

This is exactly why Chapter 3 put `default_nettype none at the top of every design file: with it, an undeclared name like Data_Ready becomes an error you see immediately instead of a silently invented one-bit wire.

Capitalisation is not cosmetic. It changes which name the tool sees.

Pick one convention — lowercase with underscores is the common one for signals — and stay inside it.

7. Escaped Identifiers

Occasionally you will open a machine-generated file and meet a name like this:

Azvya Education Pvt. Ltd.VLSI Mentor
an escaped identifier
wire \data[7] ;

That is an escaped identifier. It starts with a backslash and ends at the next whitespace. Everything between them is the name — here, literally data[7], square brackets included.

The point of the form is that it can contain characters an ordinary name cannot. You will see it in synthesised netlists and other tool output, where a vector has been split into individual bits and the tool needs a legal name for each one.

Two things to notice: the terminating space really is required, and the backslash and that space are not part of the name. You will rarely write these by hand — recognising them is enough.

Deep dive: 4.6 Identifier Declaration.

8. Numbers — Width, Base, Value

This is the highest-value section in the chapter. Hardware is built from fixed-width signals, so Verilog numbers carry more information than an ordinary integer does.

The full form has three parts:

Azvya Education Pvt. Ltd.VLSI Mentor
the shape of a Verilog literal
8'hA5
│ ││
│ │└── value — the digits, in the chosen base
│ └─── base  — b, o, d or h
└───── size  — how many bits wide

Read 8'hA5 as: eight bits wide, written in hexadecimal, value A5. The apostrophe separates the width from the base.

The four bases:

BaseLetterExampleMeaning
Binaryb4'b10104 bits: 1010
Octalo6'o526 bits: 101010
Decimald8'd428 bits: 00101010
Hexadecimalh8'hA58 bits: 10100101

Why width matters is a hardware question, not a syntax one:

Azvya Education Pvt. Ltd.VLSI Mentor
width is part of the design
reg [3:0] count_q;

count_q <= 4'b0000;        // four bits of zero — matches the register

Writing 4'b0000 says plainly "this is a four-bit value." That intent survives code review and refactoring in a way a bare 0 does not.

8.1 Underscores are free

Long literals are hard to read, so Verilog lets you drop underscores between digits purely as visual separators:

Azvya Education Pvt. Ltd.VLSI Mentor
same value, easier to read
32'b1010_1100_0011_0101

The underscores add nothing to the value and change no bits. They just group the digits.

8.2 Leaving the size off

You can write a number without a size:

Azvya Education Pvt. Ltd.VLSI Mentor
sized versus unsized — two ways to write the same intent
assign count_d = 4'd1;   // explicitly four bits — say this
// assign count_d = 1;   // unsized — the tool decides the width for you

Unsized literals default to 32 bits. When such a value meets a narrower signal the extra bits are dropped, which is a quiet way to lose a value you thought you had written. Expression sizing has real rules and they matter — 4.4 Number Representation covers them properly.

For now, one habit avoids the whole category of problem:

Give every literal in your RTL an explicit width. Write 8'd0, not 0.

8.3 x and z

Two more values can appear in a literal:

Azvya Education Pvt. Ltd.VLSI Mentor
x and z
8'hxx      // eight bits, all unknown
1'bz       // one bit, high-impedance
  • x means unknown — the value is not known in the model. It shows up when a signal has not been driven or reset yet, and it is enormously useful in simulation because it makes "I never set this" visible instead of silently reading as 0.
  • z means high-impedance — nothing is actively driving the signal, as when a tri-state driver is released.

Be careful with what these are. They are values in Verilog's logic model, used to describe uncertainty and undriven lines. x is not a third voltage sitting between 0 and 1 on real silicon; it is the model's way of saying this is not determined. The full four-value picture belongs to Variables & Data Types (Chapter 5).

Deep dive: 4.4 Number Representation.

9. Strings

A string is characters between double quotes. In this course you will meet them almost entirely in simulation output:

Azvya Education Pvt. Ltd.VLSI Mentor
a string in a testbench
$display("count = %0d", count_q);

"count = %0d" is a string. $display is a system task — the simulator prints the line for you.

Chapter 3's distinction applies here too. All of that line is Verilog. None of it means your chip contains text:

The string is a message for the person watching the simulation, not data stored in hardware.

String literals do appear elsewhere — as parameter values, or naming a file for a memory-initialisation task, for instance — so "strings are testbench-only" would be too strong a rule. But for now, when you see a quoted string, ask what it is for, and the answer is usually simulation output.

Formatting codes like %0d and %h belong to System Tasks & Functions (Chapter 8). Deep dive: 4.5 String Handling.

10. Punctuation You Are Already Using

Hardware-first learners often understand the circuit long before the punctuation. Every mark below has already appeared in code you have read.

MarkWhat it doesWhere you saw it
;Ends a statement or declarationassign y = a & b;
,Separates items in a listbetween ports in a port list
( )Groups — port lists, expressions, event controlsmodule mux2 ( ... ), @(posedge clk)
[ ]Vector ranges and bit selectswire [7:0] data_in;
{ }Concatenation and replication{4{1'b0}}
:The range separator, and the middle of ? :[7:0], sel ? b : a
.Named port connection, and hierarchy.clk(clk)
@Introduces an event controlalways @(posedge clk)
#Delay in simulation code#10
'Separates a literal's width from its base8'hA5
`Begins a compiler directive`default_nettype none

Two of these are worth separating carefully, because they look similar and mean nothing alike:

  • The apostrophe ' is part of a number: 8'hA5.
  • The backtick ` starts a directive: `timescale.

Note also that { } is not a block delimiter in Verilog. A group of statements is wrapped in begin and end, as you saw in Chapter 3's always blocks. Braces mean concatenation.

Operators get their own treatment in 4.3 Operator Usage and, in depth, in Verilog Operators and Operands (Chapter 10).

11. Keywords

Some words belong to the language itself. You cannot use them as names, because the tool already knows what they mean.

Azvya Education Pvt. Ltd.VLSI Mentor
keywords from code you have already written
module   endmodule
input    output    inout
wire     reg
assign
always   initial
begin    end
if       else      case      endcase

These are not names anyone invented for a particular design — module means module in every Verilog file ever written. Trying to use one as a name fails immediately:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// wire wire;    // illegal — `wire` is a keyword

You do not need to memorise the list. Two things are enough at this stage: recognise keywords when you read them, and give your own signals descriptive names (data_valid, count_q) that are never going to collide with one.

Deep dive: 4.7 Keyword Usage.

12. Compiler Directives

A word beginning with a backtick is a compiler directive — an instruction about how the source should be processed, not a description of hardware.

Azvya Education Pvt. Ltd.VLSI Mentor
the directive you already use
`default_nettype none

You met this in Chapter 3. It switches off the rule that would otherwise invent a one-bit wire for any undeclared name, which is what turns a typo into an error you can see.

Others you will meet include `timescale (which sets the time unit that makes #10 mean something) and `define (which gives a name to a piece of text). They are the subject of Compiler Directives (Chapter 7); here, only the shape matters.

The thing to carry forward is the category:

A directive tells the tool how to read your file. It is not a gate, a wire or a register.

13. Mistakes That Start in the Text

Four lexical slips that produce real bugs.

13.1 A case mismatch

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
wire data_ready;
assign valid = Data_Ready;   // a different name

Covered in §6. With `default_nettype none this is an error; without it, it can pass quietly.

13.2 A missing apostrophe

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
assign addr = 32d16;    // ❌ not a number — reads as a name
assign addr = 32'd16;   // ✅ the value 16, 32 bits wide

The apostrophe is what makes a literal a literal. Without it the tool sees an identifier that nobody declared.

13.3 The wrong base

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
assign x = 8'd10;   // decimal ten     → 0000_1010
assign y = 8'h10;   // hexadecimal ten → 0001_0000 (sixteen)

Same digits, different values. d and h are one keystroke apart and this is an easy thing to skim past in review.

13.4 A block comment that ends early

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
/* disable this block temporarily
   assign y = a & b;   /* inner comment */
   assign z = c | d;
*/

The comment ends at the first */. So assign z = c | d; is live code again, and the trailing */ is a syntax error. Block comments do not nest.

14. Exercises

Work these out before reading the answers.

Exercise 1 — Name the pieces

For each token in this line, say whether it is a keyword, an identifier, an operator, or punctuation.

Azvya Education Pvt. Ltd.VLSI Mentor
exercise-1.v
assign y = sel ? b : a;

Exercise 2 — Why does this fail?

Azvya Education Pvt. Ltd.VLSI Mentor
exercise-2.v
wire enable_n;
assign gated = Enable_n & data;

What is wrong, and why is it not obvious from reading quickly?

Exercise 3 — Read the literals

For each, state the width, the base, and the value in binary.

Azvya Education Pvt. Ltd.VLSI Mentor
exercise-3.v
4'b1010
8'hA5
8'd42

Exercise 4 — Hardware, or not?

Which of these describe hardware, and which exist only for humans or for the simulator?

Azvya Education Pvt. Ltd.VLSI Mentor
exercise-4.v
// (a)
assign y = a & b;

// (b)
// assign y = a | b;

// (c)
$display("y = %b", y);

// (d)
`default_nettype none

Exercise 5 — Fix the line

Each line has one lexical mistake.

Azvya Education Pvt. Ltd.VLSI Mentor
exercise-5.v
// (a)
assign count = 8d5;

// (b)
wire 4bit_bus;

// (c)
assign y = a & b

Answers

Exercise 1.

TokenKind
assignkeyword
yidentifier
=operator
sel, b, aidentifiers
? and :operator (the two halves of the conditional operator)
;punctuation

Read together they say: continuously drive y from a choice between b and a — a multiplexer.

Exercise 2. enable_n was declared; Enable_n is a different identifier, because Verilog is case-sensitive. It is easy to miss because the two look alike when you are scanning rather than reading. With `default_nettype none at the top of the file the tool reports the undeclared name; without it, Enable_n may be created silently as a one-bit wire that nothing drives.

Exercise 3.

LiteralWidthBaseBinary
4'b10104 bitsbinary1010
8'hA58 bitshexadecimal1010_0101
8'd428 bitsdecimal0010_1010

Each hex digit is exactly four bits, which is why hexadecimal is so convenient for describing wide buses.

Exercise 4.

  • (a) Describes hardware — a continuous assignment, combinational AND logic.
  • (b) Not hardware — it is commented out, so the tools skip it entirely.
  • (c) Not hardware — a system task that prints during simulation.
  • (d) Not hardware — a compiler directive telling the tool how to read the file.

Only (a) becomes part of the design. This is Chapter 3's point again: all four lines are Verilog, but only one of them is describing your circuit.

Exercise 5.

  • (a) 8d5 is missing the apostrophe, so it reads as a name rather than a number → 8'd5.
  • (b) An identifier cannot start with a digit → for example bus_4bit, or four_bit_bus.
  • (c) The statement is missing its terminating semicolon → assign y = a & b;.

15. Summary

You can now read Verilog source as structure rather than as a wall of symbols.

  • Verilog reads your file as tokens — keywords, identifiers, numbers, operators, punctuation and strings.
  • Whitespace separates tokens. It is for your readability; it describes no hardware.
  • Comments are for humans and never become hardware. Use them to say why.
  • Identifiers are the names you choose. They start with a letter or underscore, and they are case-sensitive — data and Data are different names.
  • Numbers carry a width, a base and a value — 8'hA5 is eight bits, hexadecimal, A5. Size your literals explicitly.
  • x means unknown and z means high-impedance in Verilog's logic model — not physical voltage levels.
  • Strings are usually simulation output, not data in your chip.
  • An apostrophe belongs to a number; a backtick starts a directive. They are not interchangeable.

When you next open an unfamiliar Verilog file, read it in this order: find the keywords to see the structure, find the names to see the signals, read the numbers with their widths, notice the punctuation, skip the comments — and then ask the question this whole course keeps coming back to:

What hardware does this describe, and when does it change?

Lexical knowledge is not the goal. It exists so that question becomes easy to answer.

Deep Dives — Chapter 4 Sub-Topics

Each of these takes one category from this chapter to full working depth.

Standards & specifications

Governing standard
IEEE Std 1364 (Verilog)(opens IEEE in a new tab)

Defines the Verilog language and its simulation semantics, including the event scheduling model. Synthesis support is defined by tools, not by this standard.

This page also covers RTL structure, verification approach and debugging technique. Those are engineering practice built on the standard, not requirements the standard itself imposes.

Where this fits

Part of the Verilog HDL curriculum.