Verilog `ifdef: 조건부 컴파일 완벽 가이드
Verilog는 컴파일러에게 코드를 특정 방식으로 처리하도록 지시하는 몇 가지 컴파일러 지시자를 지원합니다. 예를 들어, 코드의 일부가 특정 기능의 구현을 나타내는데, 해당 기능이 사용되지 않으면 코드를 설계에 포함하지 않는 방법이 필요합니다.
이는 조건부 컴파일로 해결할 수 있습니다. 설계자는 코드를 컴파일러 지시자로 감싸서, 주어진 플래그가 설정되었을 때 컴파일러가 코드를 포함하거나 제외하도록 할 수 있습니다.
문법
조건부 컴파일은 Verilog `ifdef와 `ifndef 키워드로 달성할 수 있습니다. 이 키워드들은 설계 어디에나 나타날 수 있으며 서로 중첩될 수 있습니다.
`ifdef 키워드는 주어진 매크로(FLAG)가 `define 지시자로 정의된 경우, 다음 `else 또는 `endif까지의 코드 조각을 포함하도록 컴파일러에게 지시합니다.
// 스타일 #1: 단일 `ifdef
`ifdef <FLAG>
// 문장들
`endif
// 스타일 #2: `else 부분 포함
`ifdef <FLAG>
// 문장들
`else
// 문장들
`endif
// 스타일 #3: 추가 ifdef들
`ifdef <FLAG1>
// 문장들
`elsif <FLAG2>
// 문장들
`elsif <FLAG3>
// 문장들
`else
// 문장들
`endif
`ifndef 키워드는 주어진 매크로(FLAG)가 `define 지시자로 정의되지 않은 경우, 다음 `else 또는 `endif까지의 코드 조각을 포함하도록 컴파일러에게 지시합니다.
`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
테스트벤치
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
기본적으로 rstn은 설계 컴파일에 포함되지 않으므로 포트리스트에 나타나지 않습니다. 그러나 INCLUDE_RSTN 매크로가 컴파일 파일 목록에 포함된 아무 Verilog 파일에서 정의되거나, 컴파일러 명령줄로 전달되면 rstn이 컴파일에 포함되고 설계에 나타납니다.
왼쪽 패인의 'Compile & Run Options'에서 +define+INCLUDE_RSTN을 추가/제거하며 차이를 실험해 보세요.
Verilog `ifdef `elsif 예제
다음 예제는 별도의 `ifdef 범위 안에 두 개의 display 문이 있으며 기본 `else 부분이 없습니다. 따라서 기본적으로 아무것도 표시되지 않습니다. MACRO1 또는 MACRO2 매크로가 정의되면 해당 display 메시지가 포함되어 시뮬레이션 중에 표시됩니다.
module tb;
initial begin
`ifdef MACRO1
$display ("This is MACRO1");
`elsif MACRO2
$display ("This is MACRO2");
`endif
end
endmodule
시뮬레이션 로그
# 매크로 정의 없음
ncsim> run
ncsim: *W,RNQUIE: Simulation is complete.
# +define+MACRO1
ncsim> run
This is MACRO1
ncsim: *W,RNQUIE: Simulation is complete.
# +define+MACRO2
ncsim> run
This is MACRO2
ncsim: *W,RNQUIE: Simulation is complete.
Verilog `ifndef `elsif 예제
같은 코드를 `ifndef로 작성하면 결과가 정반대가 됩니다.
module tb;
initial begin
`ifndef MACRO1
$display ("This is MACRO1");
`elsif MACRO2
$display ("This is MACRO2");
`endif
end
endmodule
시뮬레이션 로그
# 매크로 정의 없음
ncsim> run
This is MACRO1
ncsim: *W,RNQUIE: Simulation is complete.
# +define+MACRO1
ncsim> run
ncsim: *W,RNQUIE: Simulation is complete.
# +define+MACRO2
ncsim> run
This is MACRO1
ncsim: *W,RNQUIE: Simulation is complete.
# +define+MACRO1 +define+MACRO2
ncsim> run
This is MACRO2
ncsim: *W,RNQUIE: Simulation is complete.
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
시뮬레이션 로그
# 매크로 정의 없음
ncsim> run
FLAG is not defined
ncsim: *W,RNQUIE: Simulation is complete.
# +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.
# +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.
# +define+FLAG
ncsim> run
FLAG is defined
Only FLAG is defined
ncsim: *W,RNQUIE: Simulation is complete.
# +define+WHITE
ncsim> run
FLAG is not defined
ncsim: *W,RNQUIE: Simulation is complete.
# +define+NEST1_A
ncsim> run
FLAG is not defined
ncsim: *W,RNQUIE: Simulation is complete.
부모 매크로가 정의되지 않는 한, 그 안에 중첩된 다른 매크로의 정의는 컴파일되지 않습니다. 예를 들어, FLAG 없이 NEST1_A나 WHITE 매크로 정의만으로는 컴파일러가 중첩된 코드를 선택하지 않습니다.