top of page

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.

include

timescale

© Copyright 2025 VLSI Mentor. All Rights Reserved.©

Connect with us

  • Instagram
  • Facebook
  • Twitter
  • LinkedIn
  • YouTube
bottom of page