7.2 The `define Directive: Global Constants and Macros
What is `define?
The `define directive creates text macros that are substituted throughout the code during preprocessing. It's the Verilog equivalent of C's #define.
`define MACRO_NAME value
`define MACRO_NAME(params) expression
7.2.1. Simple Constant Definitions:
Verilog
// Numeric constants
`define DATA_WIDTH 32
`define ADDR_WIDTH 16
`define FIFO_DEPTH 256
// String constants
`define DEFAULT_MODE "SYNCHRONOUS"
`define VERSION "v2.1.3"
// Bit patterns
`define RESET_VECTOR 32'hFFFF_0000
`define NOP_INSTRUCTION 16'h0000
// Boolean flags
`define ENABLE_DEBUG 1
`define ENABLE_CACHE 0
Usage:
Verilog
module processor (
input wire [`DATA_WIDTH-1:0] data_in,
input wire [`ADDR_WIDTH-1:0] address
);
reg [`DATA_WIDTH-1:0] registers [0:31];
reg [`ADDR_WIDTH-1:0] pc;
initial begin
pc = `RESET_VECTOR;
end
endmodule
7.2.2. Parameterized Macros
​
Example 1: Min/Max Functions
Verilog
// Define reusable macros
`define MAX(a, b) ((a) > (b) ? (a) : (b))
`define MIN(a, b) ((a) < (b) ? (a) : (b))
`define ABS(a) ((a) < 0 ? -(a) : (a))
`define CLAMP(val, min_val, max_val) \
(`MIN(`MAX(val, min_val), max_val))
// Usage
module arithmetic_unit (
input wire signed [15:0] a,
input wire signed [15:0] b,
output reg signed [15:0] max_out,
output reg [15:0] abs_a
);
always @(*) begin
max_out = `MAX(a, b);
abs_a = `ABS(a);
end
endmodule
Example 2: Bit Manipulation Macros
Verilog
// Bit field extraction and manipulation
`define GET_BITS(data, high, low) \
(data[high:low])
`define SET_BIT(data, bit_pos) \
(data | (1 << bit_pos))
`define CLR_BIT(data, bit_pos) \
(data & ~(1 << bit_pos))
`define TOGGLE_BIT(data, bit_pos) \
(data ^ (1 << bit_pos))
`define CHECK_BIT(data, bit_pos) \
((data >> bit_pos) & 1'b1)
// Usage
module bit_operations (
input wire [31:0] data_in,
input wire [4:0] bit_pos,
output reg [31:0] set_result,
output reg [31:0] clr_result,
output reg bit_value
);
always @(*) begin
set_result = `SET_BIT(data_in, bit_pos);
clr_result = `CLR_BIT(data_in, bit_pos);
bit_value = `CHECK_BIT(data_in, bit_pos);
end
endmodule
Example 3: Register Field Macros
Verilog
// Register field manipulation
`define FIELD_EXTRACT(reg_val, field_msb, field_lsb) \
((reg_val >> field_lsb) & ((1 << (field_msb - field_lsb + 1)) - 1))
`define FIELD_INSERT(reg_val, field_val, field_msb, field_lsb) \
((reg_val & ~(((1 << (field_msb - field_lsb + 1)) - 1) << field_lsb)) | \
((field_val & ((1 << (field_msb - field_lsb + 1)) - 1)) << field_lsb))
// Control register bit fields
`define CTRL_REG_ENABLE_BIT 0
`define CTRL_REG_MODE_MSB 3
`define CTRL_REG_MODE_LSB 1
`define CTRL_REG_PRIORITY_MSB 7
`define CTRL_REG_PRIORITY_LSB 4
// Usage
module control_register (
input wire [31:0] ctrl_reg,
output wire enable,
output wire [2:0] mode,
output wire [3:0] priority
);
assign enable = `CHECK_BIT(ctrl_reg, `CTRL_REG_ENABLE_BIT);
assign mode = `FIELD_EXTRACT(ctrl_reg, `CTRL_REG_MODE_MSB, `CTRL_REG_MODE_LSB);
assign priority = `FIELD_EXTRACT(ctrl_reg, `CTRL_REG_PRIORITY_MSB, `CTRL_REG_PRIORITY_LSB);
endmodule
7.2.3. Advanced Macro Techniques
7.2.3.1. Multi-Line Macros
Verilog
// Use backslash for line continuation
`define DISPLAY_TRANSACTION(name, addr, data, valid) \
$display("Transaction: %s", name); \
$display(" Address: 0x%08h", addr); \
$display(" Data: 0x%08h", data); \
$display(" Valid: %b", valid); \
$display(" Time: %0t", $time);
// Usage in testbench
initial begin
`DISPLAY_TRANSACTION("Write", 32'h1000, 32'hDEADBEEF, 1'b1)
end
7.2.3.2. Nested Macros
Verilog
// Base macros
`define LOG2(n) $clog2(n)
`define ADDR_BITS(depth) `LOG2(depth)
`define CREATE_MEMORY(width, depth) \
reg [width-1:0] memory [0:depth-1]; \
reg [`ADDR_BITS(depth)-1:0] addr_reg;
// Usage
module ram_block;
`CREATE_MEMORY(32, 1024) // 32-bit wide, 1024 deep
// Expands to:
// reg [31:0] memory [0:1023];
// reg [9:0] addr_reg;
endmodule
7.2.3.3. String Concatenation Macros
Verilog
`define CONCAT(a, b) a``b
`define MAKE_SIGNAL_NAME(base, suffix) base``_``suffix
// Usage - creates signal names programmatically
`define CREATE_IO_PORTS(name) \
input wire `MAKE_SIGNAL_NAME(name, valid); \
input wire `MAKE_SIGNAL_NAME(name, ready); \
input wire [31:0] `MAKE_SIGNAL_NAME(name, data);
module interface_block (
`CREATE_IO_PORTS(rx)
`CREATE_IO_PORTS(tx)
);
// Expands to:
// input wire rx_valid;
// input wire rx_ready;
// input wire [31:0] rx_data;
// input wire tx_valid;
// input wire tx_ready;
// input wire [31:0] tx_data;
endmodule
7.2.4. Practical Examples:
7.2.4.1. FSM State Definitions
Verilog
`define FSM_IDLE 3'b000
`define FSM_FETCH 3'b001
`define FSM_DECODE 3'b010
`define FSM_EXECUTE 3'b011
`define FSM_WRITEBACK 3'b100
`define FSM_ERROR 3'b111
module cpu_control (
input wire clk,
input wire rst_n,
output reg [2:0] state
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state <= `FSM_IDLE;
end else begin
case (state)
`FSM_IDLE: begin
state <= `FSM_FETCH;
end
`FSM_FETCH: begin
state <= `FSM_DECODE;
end
`FSM_DECODE: begin
state <= `FSM_EXECUTE;
end
`FSM_EXECUTE: begin
state <= `FSM_WRITEBACK;
end
`FSM_WRITEBACK: begin
state <= `FSM_IDLE;
end
`FSM_ERROR: begin
state <= `FSM_IDLE;
end
default: state <= `FSM_ERROR;
endcase
end
end
endmodule
7.2.4.2. Timing Calculation Macros
Verilog
// Clock frequency definitions
`define CLOCK_FREQ_HZ 100_000_000 // 100 MHz
`define NS_PER_SEC 1_000_000_000
// Calculate cycles from time
`define NS_TO_CYCLES(ns) \
(((ns) * `CLOCK_FREQ_HZ + `NS_PER_SEC - 1) / `NS_PER_SEC)
`define US_TO_CYCLES(us) \
`NS_TO_CYCLES((us) * 1000)
`define MS_TO_CYCLES(ms) \
`NS_TO_CYCLES((ms) * 1000000)
// SPI timing requirements (from datasheet)
`define SPI_T_CSS_NS 100 // Chip select setup time
`define SPI_T_CSH_NS 100 // Chip select hold time
`define SPI_T_DS_NS 10 // Data setup time
`define SPI_T_DH_NS 10 // Data hold time
module spi_timing_generator (
input wire clk,
output reg cs_n,
output reg sclk
);
localparam CSS_CYCLES = `NS_TO_CYCLES(`SPI_T_CSS_NS);
localparam CSH_CYCLES = `NS_TO_CYCLES(`SPI_T_CSH_NS);
localparam DS_CYCLES = `NS_TO_CYCLES(`SPI_T_DS_NS);
localparam DH_CYCLES = `NS_TO_CYCLES(`SPI_T_DH_NS);
// Use calculated cycle counts for timing
reg [$clog2(CSS_CYCLES+1)-1:0] counter;
// Implementation...
endmodule
7.2.5. Best Practices for `define
​
7.2.5.1. Use ALL_CAPS for Macro Names
Verilog
// Good
`define BUS_WIDTH 32
`define MAX_TIMEOUT 1000
// Avoid
`define bus_width 32
`define MaxTimeout 1000
7.2.5.2. Always Use Parentheses in Macro Expressions
Verilog
// Bad - operator precedence issues
`define ADD(a, b) a + b
wire [7:0] result = `ADD(3, 4) * 2; // Expands to: 3 + 4 * 2 = 11 (WRONG!)
// Good - protected with parentheses
`define ADD(a, b) ((a) + (b))
wire [7:0] result = `ADD(3, 4) * 2; // Expands to: ((3) + (4)) * 2 = 14 (CORRECT!)
7.2.5.3. Document Complex Macros
Verilog
/**
* FIELD_EXTRACT - Extract a bit field from a register
* @param reg_val: The register value
* @param field_msb: MSB position of the field
* @param field_lsb: LSB position of the field
* @return: Extracted field value, right-aligned
*
* Example: FIELD_EXTRACT(32'hABCD_1234, 15, 8) returns 8'h12
*/
`define FIELD_EXTRACT(reg_val, field_msb, field_lsb) \
((reg_val >> field_lsb) & ((1 << (field_msb - field_lsb + 1)) - 1))
7.2.5.4. Prefer localparam Over `define When Possible
Verilog
// If constant is module-specific, use localparam
module fifo (
// ports
);
localparam DEPTH = 16; // Better than `define for module constants
localparam ADDR_WIDTH = $clog2(DEPTH);
endmodule
// Use `define for truly global, cross-module constants
`define SYSTEM_CLOCK_MHZ 100
7.2.5.5. Avoid Side Effects in Macro Arguments
Verilog
// Dangerous - counter incremented twice!
`define DOUBLE(x) ((x) + (x))
result = `DOUBLE(counter++); // Expands to: ((counter++) + (counter++))
// Better - evaluate once
`define DOUBLE(x) ({temp = (x); temp + temp;})
Recommendations with `define
Case 1: Global Scope Pollution
Verilog
// File 2 (compiled after File 1)
`define WIDTH 64 // Redefines WIDTH - affects subsequent code!
module mod_b (input [`WIDTH-1:0] data); // Now uses 64, not 32!
endmodule
// File 3 (compiled after File 2)
module mod_c (input [`WIDTH-1:0] data); // Also gets 64, unexpectedly!
endmodule
Solution: Use include guards and careful organization.
Verilog
// In header file
`ifndef WIDTH_DEFINED
`define WIDTH_DEFINED
`define WIDTH 32
`endif
Case 2: Macro Name Collisions
Verilog
// Library A defines
`define MAX(a,b) ((a)>(b)?(a):(b))
// Library B also defines
`define MAX(a,b) ((a)>=(b)?(a):(b)) // Slightly different!
// Your code gets confused behavior
Solution: Use prefixed names.
Verilog
`define LIBNAME_MAX(a,b) ((a)>(b)?(a):(b))
Case 3: Unexpected Text Substitution
Verilog
`define WIDTH 32
module test;
integer WIDTH; // ERROR: expands to "integer 32;"
reg [`WIDTH-1:0] data; // This works: "reg [32-1:0] data;"
endmodule
Solution: Choose macro names that won't conflict with variable names.
