Verilog \`ifdef: Conditionele compilatie uitgelegd
Verilog ondersteunt een paar compiler-directives die de compiler essentieel vertellen de code op een bepaalde manier te behandelen. Een deel van de code kan bijvoorbeeld een implementatie van een bepaalde feature vertegenwoordigen en er moet een manier zijn om de code niet in het ontwerp op te nemen als de feature niet gebruikt wordt.
Dit kan opgelost worden met conditionele compilatie waarbij de ontwerper de code kan omhullen met compiler-directives die de compiler vertellen om de code wel of niet voor compilatie op te nemen wanneer de gegeven vlag gezet is.
Syntax
Conditionele compilatie kan bereikt worden met Verilog \`ifdef en \`ifndef trefwoorden. Deze trefwoorden kunnen overal in het ontwerp voorkomen en kunnen genest worden.
Het trefwoord \`ifdef vertelt de compiler simpelweg om het stuk code op te nemen tot de volgende \`else of \`endif als de gegeven macro FLAG gedefinieerd is met een \`define-directive.
// Stijl #1: Alleen enkele \`ifdef
\`ifdef <FLAG>
// Statements
\`endif
// Stijl #2: \`ifdef met \`else deel
\`ifdef <FLAG>
// Statements
\`else
// Statements
\`endif
// Stijl #3: \`ifdef met additionele ifdefs
\`ifdef <FLAG1>
// Statements
\`elsif <FLAG2>
// Statements
\`elsif <FLAG3>
// Statements
\`else
// Statements
\`endif
Het trefwoord \`ifndef vertelt de compiler om het stuk code op te nemen tot de volgende \`else of \`endif als de gegeven macro FLAG niet gedefinieerd is met een \`define-directive.
Ontwerpvoorbeeld met \`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
Let op dat standaard rstn niet meegenomen wordt tijdens compilatie van het ontwerp en dus niet in de poortlijst verschijnt. Als echter een macro INCLUDE_RSTN gedefinieerd is in een Verilog-bestand dat deel uitmaakt van de compilatielijst of via de commandoregel aan de compiler doorgegeven, wordt rstn meegenomen in de compilatie en heeft het ontwerp het.
Experimenteer door +define+INCLUDE_RSTN toe te voegen of te verwijderen uit 'Compile & Run Options' in het linkerdeelvenster om het verschil te zien.
Verilog \`ifdef \`elsif Voorbeeld
Het volgende voorbeeld heeft twee display-statements binnen afzonderlijke \`ifdef-scopes zonder een standaard \`else-deel. Dit betekent dat standaard niets getoond wordt. Als de macro MACRO1 of MACRO2 gedefinieerd is, wordt het bijbehorende display-bericht meegenomen en getoond tijdens simulatie.
module tb;
initial begin
\`ifdef MACRO1
$display ("Dit is MACRO1");
\`elsif MACRO2
$display ("Dit is MACRO2");
\`endif
end
endmodule
Simulatie-log
# Zonder macro's gedefinieerd ncsim> run ncsim: *W,RNQUIE: Simulation is complete. # Met +define+MACRO1 ncsim> run This is MACRO1 ncsim: *W,RNQUIE: Simulation is complete. # Met +define+MACRO2 ncsim> run This is MACRO2 ncsim: *W,RNQUIE: Simulation is complete.
Verilog \`ifndef \`elsif Voorbeeld
Deze code kan ook geschreven worden met \`ifndef en de resultaten zijn precies het tegenovergestelde.
module tb;
initial begin
\`ifndef MACRO1
$display ("Dit is MACRO1");
\`elsif MACRO2
$display ("Dit is MACRO2");
\`endif
end
endmodule
Simulatie-log
# Zonder macro's gedefinieerd ncsim> run This is MACRO1 ncsim: *W,RNQUIE: Simulation is complete. # Met +define+MACRO1 ncsim> run ncsim: *W,RNQUIE: Simulation is complete. # Met +define+MACRO2 ncsim> run This is MACRO1 ncsim: *W,RNQUIE: Simulation is complete. # Met +define+MACRO1 +define+MACRO2 ncsim> run This is MACRO2 ncsim: *W,RNQUIE: Simulation is complete.
Verilog Geneste \`ifdef Voorbeeld
\`ifdef en varianten kunnen genest worden om complexe manieren van code-inclusie en -exclusie te creëren met gedefinieerde macro's.
module tb;
initial begin
\`ifdef FLAG
$display ("FLAG is gedefinieerd");
\`ifdef NEST1_A
$display ("FLAG en NEST1_A zijn gedefinieerd");
\`ifdef NEST2
$display ("FLAG, NEST1_A en NEST2 zijn gedefinieerd");
\`endif
\`elsif NEST1_B
$display ("FLAG en NEST1_B zijn gedefinieerd");
\`ifndef WHITE
$display ("FLAG en NEST1_B zijn gedefinieerd, maar WHITE niet");
\`else
$display ("FLAG, NEST1_B en WHITE zijn gedefinieerd");
\`endif
\`else
$display ("Alleen FLAG is gedefinieerd");
\`endif
\`else
$display ("FLAG is niet gedefinieerd");
\`endif
end
endmodule
Simulatie-log
# Zonder macro's definiëren ncsim> run FLAG is niet gedefinieerd ncsim: *W,RNQUIE: Simulation is complete. # Met +define+FLAG +define+NEST1_B ncsim> run FLAG is gedefinieerd FLAG en NEST1_B zijn gedefinieerd FLAG en NEST1_B zijn gedefinieerd, maar WHITE is niet ncsim: *W,RNQUIE: Simulation is complete. # Met +define+FLAG +define+NEST1_B +define+WHITE ncsim> run FLAG is gedefinieerd FLAG en NEST1_B zijn gedefinieerd FLAG, NEST1_B en WHITE zijn gedefinieerd ncsim: *W,RNQUIE: Simulation is complete. # Met +define+FLAG ncsim> run FLAG is gedefinieerd Alleen FLAG is gedefinieerd ncsim: *W,RNQUIE: Simulation is complete. # Met +define+WHITE ncsim> run FLAG is niet gedefinieerd ncsim: *W,RNQUIE: Simulation is complete. # Met +define+NEST1_A ncsim> run FLAG is niet gedefinieerd ncsim: *W,RNQUIE: Simulation is complete.
Let op: zolang de parent-macro niet gedefinieerd is, wordt de definitie van geneste macro's binnenin niet gecompileerd. Bijvoorbeeld, NEST1_A of WHITE macro-definities zonder FLAG laten de compiler de geneste code niet oppikken.
Verilog
- Verilog beheersen: Complete tutorial voor digitale schakelingontwerp
- Verilog concatenatie beheersen: Een praktische gids
- Verilog-toewijzingen begrijpen: types, syntax en best practices
- Verilog Blocking vs. Non-Blocking: belangrijkste verschillen uitgelegd
- Verilog-functies beheersen voor efficiënt RTL-ontwerp
- Verilog Tasks begrijpen: Functions vs Tasks, Syntax en Gebruik
- Verilog Clock Generator: Ontwerp & Implementatie Gids
- Verilog Display Tasks beheersen: Efficiënt Debuggen & Loggen
- Verilog Math Functions beheersen voor efficiënt Hardware-ontwerp
- Verilog $timeformat beheersen: Precisie en Weergave-controle
- Verilog Timescales begrijpen en printen in elke Scope