Escopo de Referência Hierárquica Verilog
A maioria das linguagens de programação tem um recurso característico chamado escopo que define a visibilidade de certas seções de código para variáveis e métodos. O escopo define um namespace para evitar a colisão entre diferentes nomes de objetos dentro do mesmo namespace.
Verilog define um novo escopo para módulos, funções, tarefas, blocos nomeados e blocos de geração.
module tb;
reg signal;
// Another variable cannot be declared with
// an already existing name in the same scope
reg signal;
// However, the name 'signal' can be reused inside
// a task because it belongs to a different scope.
task display();
reg signal = 1;
$display("signal = %0b", signal);
endtask
endmodule
Um identificador, como um nome de sinal, pode ser usado para declarar apenas um tipo de item em um determinado escopo. Isso significa que duas variáveis de tipos de dados diferentes ou iguais não podem ter o mesmo nome, ou uma tarefa e uma variável com o mesmo nome, ou mesmo uma instância de rede e gate com o mesmo nome no mesmo escopo.
Cada identificador em Verilog tem um nome de caminho hierárquico único, onde cada instância de módulo, tarefa, função ou nome
begin end
ou fork join
bloco define um novo nível ou escopo. Exemplo de referência hierárquica
module tb;
// Create two instances of different modules
A uA();
B uB();
// Create a named block that declares a signal and
// prints the value at 10ns from simulation start
initial begin : TB_INITIAL
reg signal;
#10 $display("signal=%0d", signal);
end
// We'll try to access other scopes using hierarchical
// references from this initial block
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("Hello, this is 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
Registro de simulação xcelium> run Hello, this is A TB signal=0 signal_1=1 signal_2=0 xmsim: *W,RNQUIE: Simulation is complete.
Referência de nome ascendente
Um módulo de nível inferior pode fazer referência a itens em um módulo acima dele na hierarquia. Por exemplo, o sinal no bloco TB_INITIAL seria visível da tarefa de exibição em A.
module A;
task display();
$display("Hello, this is A");
// Upward referencing, TB_INITIAL is visible in this module
#5 TB_INITIAL.signal = 1;
endtask
endmodule
Observe que o sinal TB agora é 1 em vez de 0, devido à mudança de referência ascendente feita no sinal pelo módulo A.
Registro de simulação
xcelium> run Hello, this is A TB signal=1 signal_1=1 signal_2=0 xmsim: *W,RNQUIE: Simulation is complete.
Aqui está outro exemplo com vários módulos aninhados e o nó folha pode acessar diretamente os membros dos nós acima por meio de referência hierárquica ascendente.
module tb;
A a();
function display();
$display("Hello, this is TB");
endfunction
endmodule
module A;
B b();
function display();
$display("Hello, this is A");
endfunction
endmodule
module B;
C c();
function display();
$display("Hello, this is B");
endfunction
endmodule
module C;
D d();
function display();
$display("Hello, this is C");
endfunction
endmodule
module D;
initial begin
a.display(); // or A.display()
b.display(); // or B.display()
c.display(); // or C.display()
a.b.c.display();
end
endmodule
Registro de simulação xcelium> run Hello, this is A Hello, this is B Hello, this is C Hello, this is C xmsim: *W,RNQUIE: Simulation is complete.
Quando o compilador encontra b.display(),
- Procura no escopo atual dentro do módulo D para ver se b está definido. Se ele não existir, ele procurará o nome no escopo delimitador e se moverá para cima até que o escopo do módulo seja alcançado. Se o nome ainda não for encontrado, ele vai para a próxima etapa.
- Ele procura no escopo mais externo do módulo pai e, se não for encontrado, continua subindo na hierarquia.
Verilog