Verilog · Chapter 7.2 · Compiler Directives
`define in Verilog — Text-Substitution Macros
The define directive is Verilog's mechanism for text-substitution macros, which are name-to-expression mappings the preprocessor expands inline at every use site. Every included header carries them, every project-wide constant rides on top of them, and reusable RTL depends on them. The mechanism is borrowed from C, with the same affordances such as multi-line continuation, argument-style macros, and nested definitions, and the same hazards such as multiple evaluation of arguments with side effects, scope pollution, and name collisions. This page is the deep drill: the declaration syntax, argument-form macros, the multi-line backslash trick, nested expansion, undef semantics, the decision rule that separates define from parameter and localparam, and the failure modes every macro author hits at least once.
Foundation18 min readVerilogdefineMacrosPreprocessor
Chapter 7 · Section 7.2 · Compiler Directives
1. The Engineering Problem
A junior engineer is asked to drop a one-cycle pipeline stage between two modules. The change is mechanical — wrap the inter-module signal in a flop, add clk to the receiving module's sensitivity list. The engineer writes:
module wrapper (input wire clk, ...);
reg [31:0] data_stage1;
always @(posedge clk) data_stage1 <= data_in;
// ...
endmoduleThe team's senior engineer reviews and asks for a cleaner version. The data path is 32-bit across the project, and a future-proof design shouldn't hard-code the width in three files. The senior writes:
// In common_defines.vh
`define DATA_WIDTH 32
// In wrapper.v
`include "common_defines.vh"
module wrapper (input wire clk, ...);
reg [`DATA_WIDTH-1:0] data_stage1;
always @(posedge clk) data_stage1 <= data_in;
endmoduleThe macro `DATA_WIDTH is text-substituted at preprocessing — every `DATA_WIDTH in any file that `include-s common_defines.vh becomes the literal text 32. The synthesis tool sees reg [32-1:0], exactly as if the engineer had written reg [31:0] directly. Future migration to 64-bit is a one-line change in the header; every consuming file picks it up.
This is the canonical role of `define: share constants across files. The 6.1 parameter page covered module-scoped configuration knobs; the 7.1 `include page covered file inclusion; this page covers the substitution primitive that ties them together. The mechanism has narrow but real edge cases — argument forms, multi-line definitions, nested expansion, multiple-evaluation hazards — that every working engineer needs to know.
2. Anatomy of `define
The full syntax has two forms.
2.1 Simple form — name → text
// `define MACRO_NAME <substitution-text>
`define DATA_WIDTH 32
`define ADDR_WIDTH 16
`define CLK_HZ 100_000_000
`define PROJECT_NAME "my_soc"
`define ENABLE_LOW 1'b0
`define DEFAULT_MASK 8'hFF
`define ALL_ZEROS 32'h0000_0000Each declaration names a macro and provides the substitution text. The text can be any sequence of characters — numbers, strings, bit patterns, complex expressions. The preprocessor literally substitutes the text wherever the macro is referenced (with a backtick prefix).
2.2 Argument form — name(args) → expression
// `define MACRO_NAME(arg1, arg2, ...) <substitution-expression>
`define MAX(a, b) ((a) > (b) ? (a) : (b))
`define MIN(a, b) ((a) < (b) ? (a) : (b))
`define ABS(x) ((x) >= 0 ? (x) : -(x))
`define BIT(name, idx) name[idx]
`define MASK(width) ((1 << (width)) - 1)The macro takes one or more arguments; the substitution text references the arguments by name. At every use site, the preprocessor substitutes the arguments verbatim into the substitution expression. Two important rules emerge from this:
- Always parenthesise arguments. Without parens, the substituted text picks up operator precedence from its context.
`define DBL(x) x * 2plus`DBL(a + b)expands toa + b * 2(=a + 2b), not the intended(a + b) * 2. - Always parenthesise the whole expression. Without outer parens, the macro's result picks up its surrounding context's precedence the same way.
The canonical safe form is ((arg1) <op> (arg2)) — every argument parenthesised AND the whole expression wrapped.
3. Mental Model
4. Multi-Line Definitions
Long macros span multiple lines using a backslash-newline continuation:
`define ASSERT_RESET(rst_n) \
if (!rst_n) begin \
$display("RESET ASSERTED at %0t", $time); \
// ... reset assertion logic ... \
end
// Use:
always @(posedge clk or negedge rst_n) begin
`ASSERT_RESET(rst_n)
// ... rest of logic ...
endThe backslash at end of each line tells the preprocessor "the macro continues on the next line." The newlines DON'T appear in the substituted text — the entire multi-line definition becomes one continuous expression at expansion time.
Three rules for multi-line macros:
- No trailing whitespace after the backslash. A space between
\and the newline is a syntax error in some tools. - No comments at end of continuation lines. The
// ...syntax may swallow the backslash. If you need to comment, put the comment on its own line above the macro or use/* ... */block-style. - Closing brace /
endon the last line should NOT have a trailing backslash. The last line of the macro doesn't continue.
5. Nested Macros
A macro's substitution text can reference other macros:
`define DATA_WIDTH 32
`define DATA_MASK ((1 << `DATA_WIDTH) - 1)
`define HALF_WIDTH (`DATA_WIDTH / 2)
reg [`DATA_WIDTH-1:0] data;
reg [`HALF_WIDTH-1:0] half_data;
assign masked = data & `DATA_MASK;When the preprocessor encounters `DATA_MASK, it substitutes ((1 << \`DATA_WIDTH) - 1), then recursively expands the inner `DATA_WIDTH to 32, producing ((1 << 32) - 1). Each level of nesting expands once.
The order of declaration matters: the inner macro must be defined before any reference (even via another macro). Forward-referencing an undefined macro produces a compile error or — worse — emits the literal backtick-name as text and produces silent garbage.
6. The Multiple-Evaluation Pitfall
The single biggest pitfall in argument-form macros. Because the preprocessor substitutes the literal argument text into every appearance of the parameter in the macro body, an argument that has side effects (or is expensive to compute) executes multiple times.
`define MAX(a, b) ((a) > (b) ? (a) : (b))
reg [31:0] counter;
reg [31:0] result;
// Buggy use — `f()` is called twice
result = `MAX(f(counter), 10);
// After preprocessing:
result = ((f(counter)) > (10) ? (f(counter)) : (10));
// ^^^^^^^^^^^^ ^^^^^^^^^^^^
// first call second call (when first > 10)If f() has side effects (e.g., f increments counter, writes to a log, allocates memory in a testbench), the macro evaluates them twice. If f() is expensive (a deep arithmetic chain), the work runs twice.
The same pitfall appears with simpler expressions:
`define DBL(x) ((x) * (x))
// Looks safe…
result = `DBL(counter++);
// After preprocessing:
result = ((counter++) * (counter++));
// counter is incremented TWICE before the multiplyVerilog's ++ is technically not standard Verilog (it's SystemVerilog), but the underlying issue — arguments expanded literally — applies to any expression with side effects.
The fix: avoid side effects in macro arguments. Either compute the value once outside the macro and pass a simple identifier in, or use a function (Chapter 15) instead of a macro for non-trivial logic.
// Right way: compute once, pass the result
reg [31:0] tmp = f(counter);
result = `MAX(tmp, 10);7. `undef — Removing a Macro
`define DATA_WIDTH 32
reg [`DATA_WIDTH-1:0] x; // x is reg [31:0]
`undef DATA_WIDTH
// Subsequent references to `DATA_WIDTH produce an undefined-macro error.
// reg [`DATA_WIDTH-1:0] y; // ERROR: macro DATA_WIDTH not defined`undef removes a macro from the preprocessor's symbol table. After the directive, the macro name is undefined; subsequent references error out (or in some tools silently emit the literal backtick-name as text).
Use cases for `undef:
- Localised macro re-definition. A header may temporarily redefine a macro for a specific section, then undef it to restore the prior definition (rare in practice).
- Clean-up at end of file. A "library" file may undef all its macros at the bottom to avoid polluting the consuming file's namespace (rare; usually solved with macro-name prefixing instead).
`undef is rarely used in modern code. Include guards plus disciplined macro naming (project-wide prefixes like MYPROJ_) handle the namespace concerns more cleanly.
8. Visual Explanation
Three figures cover the substitution model.
8.1 Visual A — substitution flow
The conceptual picture: `define registers a name → text mapping; `-prefixed references trigger expansion at preprocessing time.
`define and expansion at preprocessing time
data flow8.2 Visual B — argument-form expansion
A function-like macro and how its arguments expand.
8.3 Visual C — `define vs parameter
Same value, two mechanisms. The right choice depends on scope: project-wide → `define; module-scoped → parameter.
9. The `define vs parameter Decision Rule
When you need a constant, the question is: who needs to change this value, and how often?
| Aspect | `define | parameter |
|---|---|---|
| Scope | File / project (via `include) | Module-scoped |
| Override at instantiation | No | Yes (via #(.PARAM(value))) |
| Layer | Preprocessor (text substitution) | Language (compile-time elaboration) |
| Type information | None — pure text | Typed (width / signedness) |
| Side effects on consumers | Affects every subsequent file | Affects only this instance |
| Typical use | Project-wide widths, version numbers, paths | Per-module width, depth, mode |
| Failure mode | Name collision across libraries | None |
The working rule:
`definewhen the value needs to be shared across multiple files and should change in lockstep across all of them. Examples:`DATA_WIDTH,`CLK_HZ,`PROJECT_VERSION,`REG_BASE_ADDR.parameterwhen the value is a per-instance configuration knob. Examples: a FIFO'sDEPTH, an arbiter'sNUM_REQUESTERS, a counter'sWIDTH.localparamwhen the value is module-internal and should not be overridden. Examples: state-encoding values (localparam IDLE = 2'b00;), derived values (localparam ADDR_W = $clog2(DEPTH);).
A common mistake: using `define for what should be a parameter. Symptom — the FIFO can't be instantiated at two different depths because both reference the same `define value. Fix: convert to parameter.
The opposite mistake: using parameter for what should be a `define. Symptom — every module declares the same parameter DATA_WIDTH = 32; and the team has to update each one in sync. Fix: move to a common_defines.vh header.
10. Industry Use Cases
Three patterns where `define shows up in production RTL.
10.1 Project-wide constants
Every modern Verilog project has a common_defines.vh (or similar) containing version numbers, data widths, address constants, protocol IDs. Every source file `include-s it. Changing a constant updates every file atomically. The 7.1 include-directive page covers this pattern; this page provides the `defines that live inside it.
10.2 Argument-form math macros
Lightweight reusable expressions — `MAX, `MIN, `ABS, `LOG2, `BIT_MASK. Function-style but with zero runtime overhead (they expand at compile time). Use when the equivalent function would be unwieldy and when the macro can stay simple enough to avoid the multiple-evaluation trap.
10.3 Protocol-specific naming
Configurable register names, signal name generation, or bit-field positioning macros — especially common in register-map headers shared between RTL and verification. Example:
`define REG_CTRL_OFFSET 12'h000
`define REG_STATUS_OFFSET 12'h004
`define BIT_EN 0
`define BIT_RST 1Both RTL and testbench `include the header. The same constants drive the decoder logic and the stimulus generator — no risk of divergence between sides.
11. Common Mistakes
Six pitfalls that catch every macro author.
11.1 Forgetting parentheses
`define DBL(x) x * 2
// Buggy use
result = `DBL(a + b);
// Expands to: a + b * 2 = a + 2b (operator precedence picks up *)Fix: parenthesise everything — `define DBL(x) ((x) * 2).
11.2 Multiple evaluation of side-effecting arguments
`define MAX(a, b) ((a) > (b) ? (a) : (b))
result = `MAX(f(counter), 10); // f() called twice if first > 10Fix: pass simple identifiers. Compute side-effecting expressions once outside the macro.
11.3 Using `define for per-instance configuration
`define FIFO_DEPTH 16 // Whole project sees 16; can't have two depthsFix: use parameter FIFO_DEPTH = 16; inside the module so each instantiation can override.
11.4 Macro name collision
Two libraries both define `MAX(a, b). Whichever is `include-d last wins; the other is silently overridden. Lint warns about redefinition, but the build proceeds.
Fix: prefix macro names by library (e.g., `MYLIB_MAX) or by project (`MYPROJ_MAX). Universal industry convention for large codebases.
11.5 Forgetting include guards on the host header
A `define outside an include guard fires every time the header is included. With multiple include paths, the same macro is registered twice and lint warns about redefinition.
Fix: every header file uses include guards (the 7.1 include-directive page covers this).
11.6 Mid-token concatenation
Verilog-2001 doesn't support C's ## token-pasting macro operator. SystemVerilog adds \`` (backtick-backtick) for this purpose:
// SystemVerilog (not pure Verilog-2001):
`define REG(name) reg_``name``_q
// Pure Verilog-2001: no equivalent. Either spell out the name, or use a
// runtime mechanism (a function returning a string for $display).Fix: in pure Verilog-2001 codebases, spell out the full identifier in each macro. Migrate to SystemVerilog if you need programmatic signal-name construction.
12. Debugging Lab
Three define-directive debug post-mortems
13. Coding Guidelines
- Use ALL_CAPS for macro names.
`DATA_WIDTH,`MAX_BURST,`REG_BASE_ADDR. Visually distinguishes macros from variables and parameters. - Always parenthesise arguments and the whole expression.
`define MAX(a, b) ((a) > (b) ? (a) : (b))— everya/bwrapped, outer parens wrap the whole. - Avoid side effects in macro arguments. Compute side-effecting expressions once outside the macro.
- Prefix macros by project / library.
`MYPROJ_LOG_LEVEL, not`LOG_LEVEL. Prevents collisions across libraries. - Use multi-line backslash continuation for long macros. Keep the macro body readable; one statement per line.
- Document non-obvious macros. A
/* what it does */comment above complex macros prevents future engineers from re-deriving the semantics. - Reach for
localparambefore`definefor module-internal constants. Macros are for cross-file sharing;localparamis for in-module use. - Don't use
`definefor module-instantiable configuration. Width / depth / mode should beparameters so each instance can override.
14. Interview Q&A
15. Exercises
Three exercises that turn macro usage into reflex.
Exercise 1 — Spot the bug
Each of the following macros has at least one bug. Identify and fix.
`define SQR(x) x * x
`define MAX3(a, b, c) ((a) > (b) ? (a) : (b)) > (c) ? ((a) > (b) ? (a) : (b)) : (c)
`define LOG2_4(x) x >> 4Hints. Look for missing parens, missing outer wrap, multiple-evaluation of complex arguments, and operator-precedence pitfalls.
Exercise 2 — Convert to safe forms
The following macros work for simple use cases but break with complex arguments. Rewrite each in the canonical safe pattern (((arg1) <op> (arg2))).
`define ABS(x) x >= 0 ? x : -x
`define MUL(a, b) a * b
`define EVEN(x) x % 2 == 0
`define CLIP(x, max) x > max ? max : xWhat to produce. For each, write the canonical safe form with full parenthesisation.
Exercise 3 — Macro vs parameter
For each scenario, recommend `define, parameter, or localparam.
| # | Scenario |
|---|---|
| 1 | A 32-bit data path shared across 12 source files |
| 2 | A FIFO's depth (different instances can have different depths) |
| 3 | A counter's state-encoding values (IDLE=0, BUSY=1, DONE=2) |
| 4 | The system clock frequency (100 MHz) referenced in baud-rate calculations |
| 5 | An arbiter's number of requesters |
| 6 | The project version string |
Hints. Cross-file shared → `define. Per-instance configurable → parameter. Module-internal fixed → localparam.
16. Summary
`define declares a text-substitution macro — a name-to-text mapping the preprocessor expands inline at every reference. The mechanism is borrowed from C and works the same way.
The two forms:
- Simple:
`define MACRO_NAME substitution-text— bare name → text mapping. - Argument:
`define MACRO_NAME(arg1, arg2) expression— function-like macro with parameters.
The canonical safe pattern:
- ALL_CAPS naming to visually distinguish macros from variables.
- Parenthesise every argument in the macro body:
((a) > (b) ? (a) : (b)). - Wrap the whole expression so surrounding context can't pick up unintended precedence.
- Avoid side-effecting arguments — macro args may evaluate multiple times.
- Prefix by project / library (
`MYPROJ_MAX) to prevent collisions.
The decision rule vs parameter:
`definefor project-wide constants shared across files.parameterfor per-instance module configuration.localparamfor module-internal derived / fixed values.
The day-to-day discipline:
- Every header gets include guards (the 7.1 include-directive page).
- Macros declared in shared headers, not in module bodies.
- Multi-line macros use backslash continuation; no trailing whitespace.
`undefis rarely needed; rely on naming discipline.- For non-trivial logic, use a
function, not a macro. Function args evaluate once.
The next two sub-pages drill into the rest of the directive family: 7.3 `timescale sets the simulation time unit and precision, 7.4 Conditional Compilation covers `ifdef / `ifndef / `elsif / `endif for build-target gating.
After Chapter 7 closes, Chapter 8 picks up with system tasks & functions — $display, $monitor, $random, $readmemh — the simulation-infrastructure layer.
Related Tutorials
- [
include](/verilog/include-directive) — Chapter 7.1; the file-inclusion mechanism that shipsdefine-d macros across files. - Compiler Directives — Chapter 7; the parent overview of the directive family.
- parameter — Chapter 6.1; per-instance configuration knob (the language-layer counterpart).
- localparam — Chapter 6.2; module-internal compile-time constants.
- Number Representation — Chapter 4.4; literal syntax for macro-defined constants.