Compilación condicional en Verilog: `ifdef explicado
Verilog soporta algunas directivas de compilador que esencialmente dirigen al compilador a tratar el código de cierta manera. Por ejemplo, una porción del código puede representar una implementación de cierta característica y debería haber alguna forma de no incluir el código en el diseño si la característica no se usa.
Esto se puede resolver con compilación condicional donde el diseñador puede envolver el código dentro de directivas de compilador que le dicen al compilador si incluir o excluir el código para compilación cuando la bandera nombrada dada está establecida.
Sintaxis
La compilación condicional se puede lograr con las palabras clave `ifdef y `ifndef de Verilog. Estas palabras clave pueden aparecer en cualquier lugar en el diseño y pueden anidarse una dentro de la otra.
La palabra clave `ifdef simplemente le dice al compilador que incluya la pieza de código hasta el siguiente `else o `endif si el macro dado llamado FLAG está definido usando una directiva `define.
// Estilo #1: Solo `ifdef simple
`ifdef <FLAG>
// Declaraciones
`endif
// Estilo #2: `ifdef con parte `else
`ifdef <FLAG>
// Declaraciones
`else
// Declaraciones
`endif
// Estilo #3: `ifdef con ifdefs adicionales
`ifdef <FLAG1>
// Declaraciones
`elsif <FLAG2>
// Declaraciones
`elsif <FLAG3>
// Declaraciones
`else
// Declaraciones
`endif
La palabra clave `ifndef simplemente le dice al compilador que incluya la pieza de código hasta el siguiente `else o `endif si el macro dado llamado FLAG no está definido usando una directiva `define.
Ejemplo de diseño con `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
Tenga en cuenta que por defecto, rstn no se incluirá durante la compilación del diseño y por tanto no aparecerá en la lista de puertos. Sin embargo, si un macro llamado INCLUDE_RSTN se define en cualquier archivo Verilog que sea parte de la lista de compilación de archivos o se pasa por línea de comandos al compilador, rstn se incluirá en la compilación y el diseño lo tendrá.
Experimente agregando y quitando +define+INCLUDE_RSTN de 'Compile & Run Options' en el panel izquierdo para conocer la diferencia.
Ejemplo de Verilog `ifdef `elsif
El siguiente ejemplo tiene dos declaraciones display dentro de ámbitos `ifdef separados que no tienen una parte `else por defecto. Así que esto significa que por defecto nada se mostrará. Si se define el macro MACRO1 o MACRO2, el mensaje display correspondiente se incluye y se mostrará durante la simulación.
module tb;
initial begin
`ifdef MACRO1
$display ("Esto es MACRO1");
`elsif MACRO2
$display ("Esto es MACRO2");
`endif
end
endmodule
# Sin macros definidos ncsim> run ncsim: *W,RNQUIE: Simulation is complete. # Con +define+MACRO1 ncsim> run Esto es MACRO1 ncsim: *W,RNQUIE: Simulation is complete. # Con +define+MACRO2 ncsim> run Esto es MACRO2 ncsim: *W,RNQUIE: Simulation is complete.
Ejemplo de Verilog `ifndef `elsif
El mismo código se puede escribir con `ifndef y los resultados serán justo lo opuesto.
module tb;
initial begin
`ifndef MACRO1
$display ("Esto es MACRO1");
`elsif MACRO2
$display ("Esto es MACRO2");
`endif
end
endmodule
# Sin macros definidos ncsim> run Esto es MACRO1 ncsim: *W,RNQUIE: Simulation is complete. # Con +define+MACRO1 ncsim> run ncsim: *W,RNQUIE: Simulation is complete. # Con +define+MACRO2 ncsim> run Esto es MACRO1 ncsim: *W,RNQUIE: Simulation is complete. # Con +define+MACRO1 +define+MACRO2 ncsim> run Esto es MACRO2 ncsim: *W,RNQUIE: Simulation is complete.
Ejemplo de Verilog `ifdef anidado
`ifdef y sus variantes pueden anidarse una dentro de la otra para crear formas complejas de inclusión y exclusión de código con macros definidas.
module tb;
initial begin
`ifdef FLAG
$display ("FLAG está definido");
`ifdef NEST1_A
$display ("FLAG y NEST1_A están definidos");
`ifdef NEST2
$display ("FLAG, NEST1_A y NEST2 están definidos");
`endif
`elsif NEST1_B
$display ("FLAG y NEST1_B están definidos");
`ifndef WHITE
$display ("FLAG y NEST1_B están definidos, pero WHITE no");
`else
$display ("FLAG, NEST1_B y WHITE están definidos");
`endif
`else
$display ("Solo FLAG está definido");
`endif
`else
$display ("FLAG no está definido");
`endif
end
endmodule
# Sin definir ningún macro ncsim> run FLAG no está definido ncsim: *W,RNQUIE: Simulation is complete. # Con +define+FLAG +define+NEST1_B ncsim> run FLAG está definido FLAG y NEST1_B están definidos FLAG y NEST1_B están definidos, pero WHITE no ncsim: *W,RNQUIE: Simulation is complete. # Con +define+FLAG +define+NEST1_B +define+WHITE ncsim> run FLAG está definido FLAG y NEST1_B están definidos FLAG, NEST1_B y WHITE están definidos ncsim: *W,RNQUIE: Simulation is complete. # Con +define+FLAG ncsim> run FLAG está definido Solo FLAG está definido ncsim: *W,RNQUIE: Simulation is complete. # Con +define+WHITE ncsim> run FLAG no está definido ncsim: *W,RNQUIE: Simulation is complete. # Con +define+NEST1_A ncsim> run FLAG no está definido ncsim: *W,RNQUIE: Simulation is complete.
Tenga en cuenta que mientras el macro padre no esté definido, la definición de cualquier otro macro anidado dentro de él no se compila. Por ejemplo, definiciones de NEST1_A o WHITE sin FLAG no hacen que el compilador recoja el código anidado.
Verilog
- Dominar Verilog: Tutorial completo para diseño de circuitos digitales
- Dominar la concatenación en Verilog: Guía práctica
- Comprender las asignaciones en Verilog: tipos, sintaxis y mejores prácticas
- Bloqueante vs. No bloqueante en Verilog: Diferencias clave explicadas
- Dominar las funciones en Verilog para diseño RTL eficiente
- Comprender las Tasks en Verilog: Funciones vs Tasks, sintaxis y uso
- Generador de reloj en Verilog: Guía de diseño e implementación
- Dominar las tareas de visualización en Verilog: Depuración y registro eficientes
- Dominar las funciones matemáticas en Verilog para diseño de hardware eficiente
- Dominar $timeformat en Verilog: Control de precisión y visualización
- Comprender e imprimir timescales de Verilog en cualquier alcance