In Verilog, a `define macro is a powerful feature that allows for global text substitution in your code. It is a compiler directive that enables developers to define reusable code snippets or constants that can be easily referenced throughout the design.


`define  WIDTH       16        // Define macro WIDTH, substitute 16 
`define  EN_ADDR               // Define macro EN_ADDR, substitute nothing

wire   [`WIDTH-1:0]   addr;    // Declares a 16-bit wire

`ifdef EN_ADDR                 // Instantiate an adder if EN_ADDR macro is defined
  genvar i;
  generate 
    // Code to instantiate an adder
  endgenerate
`endif

Read more on Verilog `define Macros !

`define without default arguments

When using formal arguments in a macro, enclose the list of argument names in parentheses directly after the macro name. Each argument name should be a simple identifier, separated by commas and optional whitespace. White space is allowed between the text macro name and the left parenthesis in the macro usage.


`define   ADD(name, a, b)    $display("%s a=%0d b=%0d sum=%0d", name, a, b, a + b);

module tb;
  
  bit [3:0]   a;
  bit [3:0]   b;
  
  initial begin
    std::randomize(a, b);    
    
    // The macro below will be replaced by the display statement
    // Remember ! `define is not a function, it is text substitution
    // before compilation
    `ADD("", a, b)
        
    // ERROR ! Hierarchical name component lookup failed for 'ADDR' at 'tb'
    // First argument in the display statement requires it to be a string
    // `ADD(ADDR, a, b)
    
    // Text substitute a with 3 and b with 4
    `ADD("ADDER", 3, 4)
    
    // Notice the extra space in the first argument
    `ADD(" INST ", 3, 4)
    
    // ERROR ! Macro is missing trailing arguments that have no default values
    // 'b' does not have a default argument and none is passed during macro call
    //`ADD(3, )
    
    // ERROR ! Macro is missing trailing arguments that have no default values (1 instead of 3)
    // `ADD(5)
    
    // ERROR ! Too many actual macro arguments (4 instead of 3)
    //`ADD("STH", 4, 5, 6)    
    
    // Whitespace between `ADD and (
    `ADD ("SPACE", 1, 1)
  end  
endmodule
 Simulation Log
xcelium> run
  a=6 b=7 sum=13
ADDER a=3 b=4 sum=7
 INST  a=3 b=4 sum=7
SPACE a=1 b=1 sum=2
xmsim: *W,RNQUIE: Simulation is complete.

`define with default arguments

If fewer actual arguments are provided than the number of formal arguments, and all remaining formal arguments have default values, those defaults will be used in place of the missing arguments.


`define   ADD(name="INST", a=5, b)    $display("%s a=%0d b=%0d sum=%0d", name, a, b, a + b);

module tb;  
  initial begin            
    // Text substitute a with 3 and b with 4
    `ADD("ADDER", 3, 4)    
    
    // 'b' does not have a default argument and none is passed during macro call
    `ADD( , 3, 1)
    
    // First argument
    `ADD(, , 5)
    
    // Whitespace between `ADD and (
    `ADD ("SPACE", 1, 2)
  end  
endmodule
 Simulation Log
xcelium> run
ADDER a=3 b=4 sum=7
INST a=3 b=1 sum=4
INST a=5 b=5 sum=10
SPACE a=1 b=2 sum=3
xmsim: *W,RNQUIE: Simulation is complete.

SystemVerilog enhances Verilog’s `define text substitution macro by permitting the inclusion of certain special characters in the macro text.

In Verilog, quotation marks (") can be used in a define macro, but the text within the quotation marks is treated as a literal string.


`define show_txn(addr, data) \
   $display("addr=0x%0h data=0x%0h", addr, data);

module tb;
  initial begin
    `show_txn(8'hf0, 8'h1d)
  end
endmodule

Note that addr and data within the string did not get replaced.

 Simulation Log
xcelium> run
addr=0xf0 data=0x1d
xmsim: *W,RNQUIE: Simulation is complete.

SystemVerilog `define

In SystemVerilog, you can enable argument substitution within a macro text string by placing a grave accent ( ` ) before the quotation marks that define the string.


// Note (`) before (")
`define show_txn(addr, data) \
$display(`"addr=0x%0h data=0x%0h`", addr, data);

module tb;
  initial begin
    `show_txn(8'hf0, 8'h1d)
  end
endmodule

Now, addr and data within the string are also replaced.

 Simulation Log
xcelium> run
8'hf0=0xf0 8'h1d=0x1d
xmsim: *W,RNQUIE: Simulation is complete.

Quotation marks embedded within a string should be escaped with \ , and extending the previous example to replace something within quotations inside a string, a grave accent should precede both \ and " .


`define show_txn(addr, data) \
$display("addr=0x%0h \"data\"=0x%0h", addr, data);

module tb;
  initial begin
    `show_txn(8'hf0, 8'h1d)
  end
endmodule

Note that data itself is within quotes because of the preceding escape character \ .

 Simulation Log
xcelium> run
addr=0xf0 "data"=0x1d
xmsim: *W,RNQUIE: Simulation is complete.

Lets look at how to substitute addr and data like we did in the previous example, by adding a grave accent ` before the quotes as well as the escape character.


`define show_txn(addr, data) \
$display(`"addr=0x%0h `\`"data`\`"=0x%0h`", addr, data);

module tb;
  initial begin
    `show_txn(8'hf0, 8'h1d)
  end
endmodule

Note that both addr and data have been replaced.

 Simulation Log
xcelium> run
8'hf0=0xf0 "8'h1d"=0x1d
xmsim: *W,RNQUIE: Simulation is complete.

Concatenate Macros

Verilog does not allow the construction of an identifier by concatenating two or more text macros togther because there will always be a white space in the constructed identifier name.

In SystemVerilog, a double accent grave `` is used to concatenate two text macros.


`define MODULE 	tb
`define SIGNAL 	a

`define CONCAT(mod, sig)     assign ``mod.``sig = 1;

module tb;
  
  wire a;
  
  `CONCAT(`MODULE, `SIGNAL)
    
  initial begin
    $strobe("a=0x%0h", a);
  end
endmodule
 Simulation Log
xcelium> run
a=0x1
xmsim: *W,RNQUIE: Simulation is complete.

Keywords can be used as arguments in a macro definition.


// Both arguments to the text macro are real Verilog keywords
`define   PATH(module, wire)       ``module.``wire