Условная компиляция в Verilog: `ifdef, `ifndef, `elsif
Verilog поддерживает директивы компилятора, указывающие, как обрабатывать код. Например, часть кода может реализовывать определенную функцию, и нужен способ исключить её из дизайна, если функция не используется.
Это решается условной компиляцией: код оборачивается в директивы, которые говорят компилятору включать или исключать код, если заданный именованный флаг установлен.
Синтаксис
Условная компиляция достигается через `ifdef и `ifndef. Эти ключевые слова могут появляться где угодно в дизайне и могут вкладываться друг в друга.
`ifdef включает код до следующего `else или `endif, если макрос FLAG определен через `define.
// Стиль 1: только `ifdef
`ifdef <FLAG>
// Statements
`endif
// Стиль 2: `ifdef с `else
`ifdef <FLAG>
// Statements
`else
// Statements
`endif
// Стиль 3: `ifdef с дополнительными ifdef
`ifdef <FLAG1>
// Statements
`elsif <FLAG2>
// Statements
`elsif <FLAG3>
// Statements
`else
// Statements
`endif
`ifndef включает код до `else или `endif, если макрос FLAG не определен через `define.
Пример дизайна с `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 включается в компиляцию и дизайн его получает.
Экспериментируйте: добавляйте и убирайте +define+INCLUDE_RSTN в 'Compile & Run Options' слева, чтобы увидеть разницу.
Пример `ifdef `elsif
Два $display в отдельных областях `ifdef без дефолтного `else. По умолчанию ничего не печатается. Если определен MACRO1 или MACRO2, соответствующее сообщение включается и печатается.
module tb;
initial begin
`ifdef MACRO1
$display ("This is MACRO1");
`elsif MACRO2
$display ("This is MACRO2");
`endif
end
endmodule
Simulation Log
# Без макросов 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.
Пример `ifndef `elsif
Тот же код с `ifndef — результаты противоположные.
module tb;
initial begin
`ifndef MACRO1
$display ("This is MACRO1");
`elsif MACRO2
$display ("This is MACRO2");
`endif
end
endmodule
Simulation Log
# Без макросов 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.
Вложенный `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
Simulation Log
# Без макросов 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.
Обратите внимание: пока родительский макрос не определен, определение любого вложенного макроса внутри него не заставляет компилятор подхватывать вложенный код. Например, NEST1_A или WHITE без FLAG не включают вложенный код.
Verilog
- Освоение Verilog: полное руководство по проектированию цифровых схем
- Освоение конкатенации в Verilog: практическое руководство
- Понимание назначений в Verilog: типы, синтаксис и лучшие практики
- Блокирующие и неблокирующие назначения в Verilog: ключевые различия
- Мастерство функций в Verilog для эффективного RTL дизайна
- Понимание задач (Tasks) в Verilog: отличия от функций, синтаксис и применение
- Генератор тактового сигнала в Verilog: проектирование и реализация
- Мастерство задач отображения в Verilog: эффективная отладка и логирование
- Мастерство математических функций Verilog для эффективного аппаратного дизайна
- Мастерство $timeformat в Verilog: точность и контроль отображения времени