Skip to content
VLSI Mentor

Verilog · Chapter 4.2 · Lexical Conventions

Comment Implementation in Verilog

Verilog supports two comment forms, a line comment and a block comment, and the syntax matches C exactly. The rules themselves are simple, but the discipline around them is what separates clean RTL from messy code. This lesson covers the precise lexical rules for each form, the block-comment nesting trap that bites almost every beginner at least once, and the comment-hygiene habits that working teams enforce so code stays readable and searchable. It also explains pragmas, the specially formatted comments that lint, synthesis, and coverage tools read as instructions, such as lint waivers, synthesis directives, and coverage controls. By the end you will know not just how to write comments, but how professional RTL teams use them to communicate intent and guide their tools.

Foundation14 min readVerilogSyntaxStyleComments

Chapter 4 · Page 4.2 · Lexical Conventions

The Two Comment Forms

Verilog inherits C's comment syntax exactly. Two forms; nothing more.

Azvya Education Pvt. Ltd.VLSI Mentor
comments-basics.v — the two forms
// Line comment — runs from `//` to the end of the line.
assign y = a & b;   // can also be at the end of a code line.

/* Block comment — runs from /* to the next */
   and can span multiple lines. */

/*
 * Conventional multi-line block: padded leading-`*` on every line,
 * used at the top of every file for copyright, author, change log.
 */

Both forms are removed before the parser sees the source, so a comment never becomes hardware and never changes what your design does. Use them generously. (One qualification, covered later on this page: some tools look for specially formatted pragmas inside comment text — so "ignored by the language" is not quite the same as "unread by every tool".)

Lexical Rules

The exact rules every comment obeys.

Line comments

  • Begin with //.
  • End at the next newline (\n, \r, or \r\n).
  • The newline itself is not part of the comment — it's preserved as a whitespace token.
  • A line comment can appear anywhere a token can appear.
Azvya Education Pvt. Ltd.VLSI Mentor
line-comments-anywhere.v — placements that all work
// Top of file
module my_block ( // after the module name
    input  wire clk,    // after a port declaration
    input  wire rst_n,  // ...
    output reg  data_q
); // after the port list

    // Standalone block — separates sections of code

    always @(posedge clk) begin
        data_q <= 1'b0;  // after a statement
    end // after `end`

endmodule  // after `endmodule`

Block comments

  • Begin with /*.
  • End at the first */ (greedy from left).
  • Everything in between — including newlines — is part of the comment.
  • A block comment can appear anywhere whitespace can appear.
Azvya Education Pvt. Ltd.VLSI Mentor
block-comments-mid-expression.v — block comments inline
// Block comments can split an expression — used for inline documentation
assign sum = a /* operand A */ + b /* operand B */ ;

// Or wrap a parameter
my_block #(
    .WIDTH (/* parameterised */ 8),
    .DEPTH (/* memory depth */ 1024)
) u_dut ( ... );

In practice, inline block comments in expressions are rare — they hurt readability. Use them at the file and block level, not inside a single statement.

The Nesting Trap

This is the one beginner trap every Verilog engineer hits once. Block comments do not nest.

Azvya Education Pvt. Ltd.VLSI Mentor
nesting-trap.v — the canonical bug
// ❌ BUG — looks like a nested comment, isn't
/* outer comment
   /* inner comment */     // this `*/` ends the OUTER block comment
   still part of the outer */  // this text is now CODE (and is a syntax error)

// Compiler error: "syntax error near 'still'"
// Reason: the first `*/` closed the only block comment that was open.

The simulator's tokeniser scans left-to-right. The opening /* opens one comment. The first */ it encounters closes that comment. The text after the intended closing */ is then parsed as code, producing a confusing error message that doesn't point at the actual problem.

Two safe alternatives

Azvya Education Pvt. Ltd.VLSI Mentor
nesting-fix.v — patterns that work
// ✅ Pattern 1 — use line comments for the inner annotation
/* outer comment block
   // inner comment that doesn't close the outer
   still part of the outer */

// ✅ Pattern 2 — temporarily comment-out a block of code with `ifdef
`ifdef NEVER_DEFINED
    // ... any code here, including `/* */` blocks ...
    /* this block stays inside the ifdef */
`endif

Pattern 2 is what every working RTL engineer reaches for when "commenting out" a region of code that itself contains block comments. The `ifdef NEVER_DEFINED is conventional — readers recognise it as a "disabled block" marker.

Comment Hygiene — The Working Discipline

The lexical rules are the easy part. The discipline of what to write in a comment is what separates good RTL from textbook RTL.

Comments explain why, not what

The code already says what it does. A comment that restates the code is noise.

Azvya Education Pvt. Ltd.VLSI Mentor
hygiene-1.v — bad vs good comments
// ❌ Bad — restates the code
assign y = a & b;          // assigns a AND b to y

// ❌ Bad — adds nothing
count_q <= count_q + 1;    // increment count_q

// ✅ Good — explains the engineering decision
// Increment only on the leading edge of `valid` to avoid double-counting
// retried transactions that re-assert mid-burst.
count_q <= count_q + 1;

Comments document intent, not history

The Git log carries history. Comments carry intent.

Azvya Education Pvt. Ltd.VLSI Mentor
hygiene-2.v — keep intent, drop history
// ❌ Bad — historical commentary in source
assign mask = 8'hAA;       // changed from 0xFF on 2024-03-15 per Alice's review

// ✅ Good — the intent, not the timeline
assign mask = 8'hAA;       // even-bit positions only — odd positions are reserved
                            // for vendor extensions (see spec §3.4.2).

Comments cite specs

When the RTL implements a specific clause of a public spec, cite it.

Azvya Education Pvt. Ltd.VLSI Mentor
hygiene-3.v — cite the spec
// ✅ Good — anchored to the spec
// AXI4 §A3.3.1 — WLAST asserts on the last beat of a write burst.
// The counter loads AWLEN+1, decrements on each accepted beat, and
// asserts WLAST when it reaches 1.
assign w_last = (beats_remaining_q == 5'd1);

The cited spec section makes the comment auditable — a reviewer can verify the implementation against the named clause.

File-level header comments

Every working RTL file starts with a header. The format every team converges on:

Azvya Education Pvt. Ltd.VLSI Mentor
hygiene-4.v — file header convention
/* ───────────────────────────────────────────────────────────────────
 * Module       : counter_4b
 * Description  : 4-bit synchronous up-counter with async-low reset.
 * Author       : VLSI Mentor (rtl@vlsimentor.com)
 * Created      : 2026-04-15
 *
 * Interfaces   : clk / rst_n / en input · q[3:0] output
 * Clock domain : single (clk)
 * Reset        : async-low (rst_n)
 *
 * Spec ref     : project-spec §2.3.1
 * Lint waivers : (none)
 * ─────────────────────────────────────────────────────────────────── */

`timescale 1ns/1ps
`default_nettype none

module counter_4b ( ... );
    ...
endmodule

Some teams add a copyright notice. Some add a change log (despite the "don't put history in comments" rule — the change log is the exception every team accepts). Some add a tool-version stamp. The exact fields vary; the existence of a structured header doesn't.

Tool Pragmas Hidden Inside Comments

This is the part of comments most beginners don't realise exists. Several EDA tools encode pragmas — directives the tool reads — inside specially-formatted comments. The Verilog parser sees them as comments; the tool sees them as instructions.

Lint waivers

A lint waiver tells the lint tool "I know this rule fires here; suppress it." Most lint tools (SpyGlass, Conformal, Meridian) use a comment pragma.

Azvya Education Pvt. Ltd.VLSI Mentor
pragmas-1.v — SpyGlass waiver syntax
// spyglass disable_block W116
// W116 fires on combinational `for` loops, but we know the unroll is safe here.
for (i = 0; i < 8; i = i + 1) begin
    masked[i] = data[i] & enable_mask[i];
end
// spyglass enable_block W116

Without the waiver, the lint tool would flag every run. With the waiver, it stays silent for just that block. Waivers must include a justification comment — un-justified waivers are a code-review block at every modern team.

Synthesis pragmas

Synthesis tools accept pragmas that fine-tune the synthesised hardware.

Azvya Education Pvt. Ltd.VLSI Mentor
pragmas-2.v — Synopsys DC synthesis pragmas
// synopsys translate_off
// This block runs in simulation but is invisible to synthesis.
initial $display("debug build");
// synopsys translate_on

reg [3:0] data_q;
// synopsys keep_signal_name "data_q"
// Tells DC not to rename `data_q` during optimisation — useful when
// the signal name shows up in waveforms and post-silicon debug.

// synopsys async_set_reset rst_n
// Marks rst_n as the async reset, even when sensitivity-list rules
// would otherwise produce a different inference.

Other tools use different syntax (// genus, // dc, etc.). The pragma is not portable between tools — every tool reads only its own pragmas and ignores comments it doesn't recognise.

Coverage directives

Coverage tools use pragmas to exclude regions from coverage analysis.

Azvya Education Pvt. Ltd.VLSI Mentor
pragmas-3.v — coverage directives
// VCS coverage off
// This assertion is only used in debug builds — don't count it in coverage.
assert property (@(posedge clk) !overflow_q);
// VCS coverage on

Why pragmas are inside comments

Two reasons:

  1. Lexical compatibility. Pragmas inside comments mean the file remains parseable by any simulator or synthesiser, even ones that don't recognise the pragma. The unrecognising tool just ignores the comment.
  2. Cross-tool portability. A file with // spyglass disable_block W116 lints clean in SpyGlass and is invisible to every other tool. No #ifdef gymnastics needed.

Comments in Generated Files

When tools generate Verilog (synthesis output, IP-generator output, behavioural-model exports), the generated file usually has a header comment identifying the source.

Azvya Education Pvt. Ltd.VLSI Mentor
generated.v — typical machine-generated header
//-----------------------------------------------------------------------------
// Generated by: Synopsys Design Compiler X-2024.06
// Generation time: 2026-04-15 14:32:51 PDT
// Source: rtl/counter_4b.v
// SDC constraints: constraints/counter_4b.sdc
// Library: tsmc5_svt.db
//
// DO NOT EDIT THIS FILE BY HAND — re-run synthesis instead.
//-----------------------------------------------------------------------------

module counter_4b ( ... );
    DFFRX1 \count_q_reg[0] ( .D(...), .CK(clk), .RN(rst_n), .Q(...) );
    ...
endmodule

The "do not edit by hand" warning is non-negotiable — the file gets regenerated on every synthesis run, so any hand edit gets blown away. Treat generated files as build artifacts, not as source.

Common Mistakes

Six failure modes every Verilog engineer encounters.

  1. Unclosed block comments. /* ... without a */ swallows the rest of the file. Every editor highlights this; pay attention to the highlighting.
  2. Nested block comments. Covered above — the inner */ closes the outer.
  3. Restating-the-code comments. Noise in the source. Removed on every review.
  4. Comment drift. The code changes, the comment doesn't. The comment now lies. Lies are worse than no comment at all — they actively mislead. Every code review should ask "does the comment still match the code?"
  5. Un-justified lint waivers. A // spyglass disable_block W116 with no explanation is a maintenance hazard. The reviewer (or the future you) has to re-derive why the waiver is safe. Always include a justification.
  6. History in comments. "Changed by Alice on 2024-03-15" belongs in git log, not in the source. Comments are read by every reader; history is read by the engineer specifically auditing changes.

Interview Insights

Summary

Verilog has exactly two comment forms — line (//) and block (/* */) — both inherited unchanged from C. The lexical rules are simple; the discipline is the harder part: comments explain why not what, document intent not history, cite specs when implementing them, and follow the team's file-header convention. The non-obvious layer is that EDA tools encode pragmas inside specially-formatted comments — lint waivers, synthesis pragmas, coverage directives — every working RTL engineer learns to read alongside the language itself. The next sub-topic covers identifiers — naming rules, the case-sensitivity gotcha, and the rare-but-real escaped-identifier form.

Beat coverage notes: all required beats present. ⏱ Timing Observation, 🧠 Simulator Scheduling Insight callouts omitted — comments are pure-text-rules; no timing or scheduling angle. The 🚀 RTL Design Insight callout is folded into the comment-hygiene section's "intent vs history" framing.

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.