Verilog supports a few compiler directives that essentially direct the compiler to treat the code in a certain way. For example, a portion of the code may represent an implementation of a certain feature and there should be some way to not include the code in the design if the feature is not used.
This can be solved with conditional compilation where the designer can wrap the code within compiler directives which tell the compiler to either include or exclude the code for compilation when the given named flag is set.
Syntax
Conditional compilation can be achieved with Verilog `ifdef
and `ifndef
keywords. These keywords can appear anywhere in the design and can be nested one inside the other.
The keyword `ifdef
simply tells the compiler to include the piece of code until the next `else
or `endif
if the given macro called FLAG is defined using a `define
directive.
// Style #1: Only single `ifdef
`ifdef <FLAG>
// Statements
`endif
// Style #2: `ifdef with `else part
`ifdef <FLAG>
// Statements
`else
// Statements
`endif
// Style #3: `ifdef with additional ifdefs
`ifdef <FLAG1>
// Statements
`elsif <FLAG2>
// Statements
`elsif <FLAG3>
// Statements
`else
// Statements
`endif
The keyword `ifndef
simply tells the compiler to include the piece of code until the next `else
or `endif
if the given macro called FLAG is not defined using a `define
directive.
Design Example with `ifdef
module my_design (input clk, d,
`ifdef INCLUDE_RSTN
input rstn,
`endif
output reg q);
always @ (posedge clk) begin
`ifdef INCLUDE_RSTN
if (!rstn) begin
q <= 0;
end else
`endif
begin
q <= d;
end
end
endmodule
Testbench
module tb;
reg clk, d, rstn;
wire q;
reg [3:0] delay;
my_design u0 ( .clk(clk), .d(d),
`ifdef INCLUDE_RSTN
.rstn(rstn),
`endif
.q(q));
always #10 clk = ~clk;
initial begin
integer i;
{d, rstn, clk} <= 0;
#20 rstn <= 1;
for (i = 0 ; i < 20; i=i+1) begin
delay = $random;
#(delay) d <= $random;
end
#20 $finish;
end
endmodule
Note that by default, rstn will not be included during compilation of the design and hence it will not appear in the portlist. However if a macro called INCLUDE_RSTN is either defined in any Verilog file that is part of the compilation list of files or passed through the command line to the compiler, rstn will be included in compilation and the design will have it.
Experiment by adding and removing +define+INCLUDE_RSTN from 'Compile & Run Options' on the left pane to know the difference.
Verilog `ifdef `elsif Example
The following example has two display statements inside separate `ifdef
scopes which does not have a default `else
part to it. So this means that by default nothing will be displayed. If the macro either MACRO is defined, the corresponding display message is included and will be displayed during simulation
module tb;
initial begin
`ifdef MACRO1
$display ("This is MACRO1");
`elsif MACRO2
$display ("This is MACRO2");
`endif
end
endmodule
Simulation Log
# With no macros defined
ncsim> run
ncsim: *W,RNQUIE: Simulation is complete.
# With +define+MACRO1
ncsim> run
This is MACRO1
ncsim: *W,RNQUIE: Simulation is complete.
# With +define+MACRO2
ncsim> run
This is MACRO2
ncsim: *W,RNQUIE: Simulation is complete.
Verilog `ifndef `elsif Example
The same code can be written with `ifndef
and results will be just the opposite.
module tb;
initial begin
`ifndef MACRO1
$display ("This is MACRO1");
`elsif MACRO2
$display ("This is MACRO2");
`endif
end
endmodule
Simulation Log
# With no macros defined
ncsim> run
This is MACRO1
ncsim: *W,RNQUIE: Simulation is complete.
# With +define+MACRO1
ncsim> run
ncsim: *W,RNQUIE: Simulation is complete.
# With +define+MACRO2
ncsim> run
This is MACRO1
ncsim: *W,RNQUIE: Simulation is complete.
# With +define+MACRO1 +define+MACRO2
ncsim> run
This is MACRO2
ncsim: *W,RNQUIE: Simulation is complete.
Verilog Nested `ifdef Example
`ifdef
and its flavors can be nested one inside the other to create complex ways of code inclusion and exclusion with defined macros.
module tb;
initial begin
`ifdef FLAG
$display ("FLAG is defined");
`ifdef NEST1_A
$display ("FLAG and NEST1_A are defined");
`ifdef NEST2
$display ("FLAG, NEST1_A and NEST2 are defined");
`endif
`elsif NEST1_B
$display ("FLAG and NEST1_B are defined");
`ifndef WHITE
$display ("FLAG and NEST1_B are defined, but WHITE is not");
`else
$display ("FLAG, NEST1_B and WHITE are defined");
`endif
`else
$display ("Only FLAG is defined");
`endif
`else
$display ("FLAG is not defined");
`endif
end
endmodule
Simulation Log
# Without defining any macro
ncsim> run
FLAG is not defined
ncsim: *W,RNQUIE: Simulation is complete.
# With +define+FLAG +define+NEST1_B
ncsim> run
FLAG is defined
FLAG and NEST1_B are defined
FLAG and NEST1_B are defined, but WHITE is not
ncsim: *W,RNQUIE: Simulation is complete.
# With +define+FLAG +define+NEST1_B +define+WHITE
ncsim> run
FLAG is defined
FLAG and NEST1_B are defined
FLAG, NEST1_B and WHITE are defined
ncsim: *W,RNQUIE: Simulation is complete.
# With +define+FLAG
ncsim> run
FLAG is defined
Only FLAG is defined
ncsim: *W,RNQUIE: Simulation is complete.
# With +define+WHITE
ncsim> run
FLAG is not defined
ncsim: *W,RNQUIE: Simulation is complete.
# With +define+NEST1_A
ncsim> run
FLAG is not defined
ncsim: *W,RNQUIE: Simulation is complete.
Note that as long as the parent macro is not defined, definition of any other nested macro within it does not get compiled. For example, NEST1_A or WHITE macro definitions without FLAG does not make the compiler pick up the nested code.