# Verilog 条件编译

Verilog 支持一些编译器指令,这些指令可以指导编译器以某种方式处理代码。例如,代码的一部分可能代表某个功能的实现,如果不使用该功能,则应该有某种方式不将代码包含在设计中。

这可以通过条件编译来解决,其中设计人员可以将代码包装在编译器指令中,这些指令告诉编译器在设置给定的命名标志处包含或排除要编译的代码。

# 语法

条件编译可以通过 Verilog 的 ifdefifndef 关键字来实现。这些关键字可以出现在设计中的任何位置,并且可以嵌套在另一个内部。

// 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

关键字 ifdef 只是告诉编译器,直到下一个 elseendif ,如果给定的名为 FLAG 的宏是使用 define 指令定义的,则包含这段代码,

注:这里的关键字之前需要加一个反引号,因为这是markdown的保留符号,我没办法在正文里面写出这个符号。

# 带有条件编译的设计示例

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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 测试台

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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

请注意,默认情况下,rstn 在设计编译期间不会包含在内,因此它不会出现在端口列表中。但是,如果一个名为 INCLUDE_RSTN 的宏在作为文件编译列表一部分的任何 Verilog 文件中定义或通过命令行传递给编译器,则 rstn 将包含在编译中,并且设计模块将拥有这个端口。

# Verilog ifdef elsif 示例

以下示例在单独的 ifdef 范围内有两个显示语句,它们没有默认的 else 部分。所以这意味着默认情况下不会显示任何内容。如果定义了 MACRO1 或者 MACRO2 ,则包含相应的显示消息,并将在模拟过程中显示。

module tb;
    initial begin

`ifdef MACRO1
        $display ("This is MACRO1");

`elsif MACRO2
        $display ("This is MACRO2");

`endif
    end
endmodule
1
2
3
4
5
6
7
8
9
10
11
12

仿真日志:

# With no macros defined

# With +define+MACRO1
This is MACRO1

# With +define+MACRO2
This is MACRO2
1
2
3
4
5
6
7

# Verilog ifndef elsif 示例

可以使用 ifndef 编写相同的代码,结果正好相反。

module tb;
    initial begin

`ifndef MACRO1
        $display ("This is MACRO1");

`elsif MACRO2
        $display ("This is MACRO2");

`endif
    end
endmodule
1
2
3
4
5
6
7
8
9
10
11
12

仿真日志:

# With no macros defined
This is MACRO1

# With +define+MACRO1

# With +define+MACRO2
This is MACRO1

# With +define+MACRO1 +define+MACRO2
This is MACRO2
1
2
3
4
5
6
7
8
9
10

# Verilog 嵌套 ifdef 示例

ifdef 可以嵌套在另一个中,以使用已定义的宏创建复杂的代码包含和排除逻辑。

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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

仿真日志:

FLAG is not defined

# With +define+FLAG +define+NEST1_B
FLAG is defined
FLAG and NEST1_B are defined
FLAG and NEST1_B are defined, but WHITE is not

# With +define+FLAG +define+NEST1_B +define+WHITE
FLAG is defined
FLAG and NEST1_B are defined
FLAG, NEST1_B and WHITE are defined

# With +define+FLAG
FLAG is defined
Only FLAG is defined

# With +define+WHITE
FLAG is not defined

# With +define+NEST1_A
FLAG is not defined
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

注意,只要未定义父宏,就不会编译其中任何其他嵌套宏的定义。例如,没有 FLAGNEST1_AWHITE 宏定义不会使编译器拾取嵌套代码。

最后更新: 2022/10/6 01:12:51