Dominar el alcance de referencia jerárquica en Verilog: Evitar colisiones de nombres en módulos y bloques
La mayoría de los lenguajes de programación tienen una característica llamada alcance (scope) que define la visibilidad de ciertas secciones de código a variables y métodos. El alcance define un espacio de nombres para evitar colisiones entre diferentes nombres de objetos dentro del mismo espacio de nombres.
Verilog define un nuevo alcance para módulos, funciones, tasks, bloques nombrados y bloques generate.
module tb;
reg signal;
// Otra variable no puede declararse con
// un nombre ya existente en el mismo alcance
reg signal;
// Sin embargo, el nombre 'signal' puede reutilizarse dentro
// de una task porque pertenece a un alcance diferente.
task display();
reg signal = 1;
$display("signal = %0b", signal);
endtask
endmodule
Un identificador, como un nombre de señal, puede usarse para declarar solo un tipo de elemento en un alcance dado. Esto significa que dos variables de diferentes o mismos tipos de datos no pueden tener el mismo nombre, o una task y una variable del mismo nombre, o incluso una red e instancia de puerta con el mismo nombre en el mismo alcance.
Cada identificador en Verilog tiene un nombre de ruta jerárquica único, donde cada instancia de módulo, task, function o bloque nombrado begin end o fork join define un nuevo nivel o alcance.
Ejemplo de referencia jerárquica
module tb;
// Crear dos instancias de diferentes módulos A y B
A uA();
B uB();
// Crear un bloque nombrado que declara una señal e
// imprime el valor a 10ns desde inicio de simulación
initial begin : TB_INITIAL
reg signal;
#10 $display("signal=%0d", signal);
end
// Intentaremos acceder a otros alcances usando referencias
// jerárquicas desde este bloque initial
initial begin
TB_INITIAL.signal = 0;
uA.display();
uB.B_INITIAL.B_INITIAL_BLOCK1.b_signal_1 = 1;
uB.B_INITIAL.B_INITIAL_BLOCK2.b_signal_2 = 0;
end
endmodule
module A;
task display();
$display("Hola, esto es A");
endtask
endmodule
module B;
initial begin : B_INITIAL
#50;
begin : B_INITIAL_BLOCK1
reg b_signal_1;
#10 $display("signal_1=%0d", b_signal_1);
end
#50;
begin : B_INITIAL_BLOCK2
reg b_signal_2;
#10 $display("signal_2=%0d", b_signal_2);
end
end
endmodule
xcelium> run Hola, esto es A TB signal=0 signal_1=1 signal_2=0 xmsim: *W,RNQUIE: Simulation is complete.
Referencia de nombre hacia arriba
Un módulo de nivel inferior puede referenciar elementos en un módulo por encima de él en la jerarquía. Por ejemplo, signal en el bloque TB_INITIAL sería visible desde la task display en A.
module A;
task display();
$display("Hola, esto es A");
// Referencia hacia arriba, TB_INITIAL es visible en este módulo
#5 TB_INITIAL.signal = 1;
endtask
endmodule
Tenga en cuenta que TB signal ahora es 1 en lugar de 0, debido al cambio de referencia hacia arriba hecho a la signal por el módulo A.
xcelium> run Hola, esto es A TB signal=1 signal_1=1 signal_2=0 xmsim: *W,RNQUIE: Simulation is complete.
Aquí hay otro ejemplo con múltiples módulos anidados y el nodo hoja puede acceder directamente a miembros de nodos superiores a través de referencia jerárquica hacia arriba.
module tb;
A a();
function display();
$display("Hola, esto es TB");
endfunction
endmodule
module A;
B b();
function display();
$display("Hola, esto es A");
endfunction
endmodule
module B;
C c();
function display();
$display("Hola, esto es B");
endfunction
endmodule
module C;
D d();
function display();
$display("Hola, esto es C");
endfunction
endmodule
module D;
initial begin
a.display(); // o A.display()
b.display(); // o B.display()
c.display(); // o C.display()
a.b.c.display();
end
endmodule
xcelium> run Hola, esto es A Hola, esto es B Hola, esto es C Hola, esto es C xmsim: *W,RNQUIE: Simulation is complete.
Cuando el compilador encuentra b.display(),
- Busca en el alcance actual dentro del módulo D para ver si b está definido. Si no existe, busca el nombre en el alcance envolvente y sube hasta alcanzar el alcance del módulo. Si el nombre aún no se encuentra, pasa al siguiente paso.
- Busca en el alcance más externo del módulo padre y si no se encuentra, sigue subiendo en la jerarquía.
Verilog
- Dominar Verilog: Tutorial completo para diseño de circuitos digitales
- Dominar la concatenación en Verilog: Guía práctica
- Verilog Esencial: Resumen conciso
- 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
- Dominar el alcance de referencia jerárquica en Verilog: Evitar colisiones de nombres en módulos y bloques
- 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