Controle de atraso Verilog
Existem dois tipos de controles de tempo no Verilog - atraso e evento expressões. O atraso O controle é apenas uma maneira de adicionar um atraso entre o momento em que o simulador encontra a instrução e quando ele realmente a executa. A expressão de evento permite que a instrução seja atrasada até a ocorrência de algum evento de simulação que pode ser uma mudança de valor em uma rede ou variável (evento implícito ) ou um evento explicitamente nomeado que é acionado em outro procedimento.
O tempo de simulação pode ser avançado por um dos seguintes métodos.
Portões e redes que foram modelados para ter atrasos internos também avançam o tempo de simulação.
Controle de atraso
Se a expressão de atraso for avaliada como um valor desconhecido ou de alta impedância, ela será interpretada como atraso zero. Se for avaliado como um valor negativo, será interpretado como um inteiro sem sinal de complemento de 2 do mesmo tamanho de uma variável de tempo.
`timescale 1ns/1ps
module tb;
reg [3:0] a, b;
initial begin
{a, b} <= 0;
$display ("T=%0t a=%0d b=%0d", $realtime, a, b);
#10;
a <= $random;
$display ("T=%0t a=%0d b=%0d", $realtime, a, b);
#10 b <= $random;
$display ("T=%0t a=%0d b=%0d", $realtime, a, b);
#(a) $display ("T=%0t After a delay of a=%0d units", $realtime, a);
#(a+b) $display ("T=%0t After a delay of a=%0d + b=%0d = %0d units", $realtime, a, b, a+b);
#((a+b)*10ps) $display ("T=%0t After a delay of %0d * 10ps", $realtime, a+b);
#(b-a) $display ("T=%0t Expr evaluates to a negative delay", $realtime);
#('h10) $display ("T=%0t Delay in hex", $realtime);
a = 'hX;
#(a) $display ("T=%0t Delay is unknown, taken as zero a=%h", $realtime, a);
a = 'hZ;
#(a) $display ("T=%0t Delay is in high impedance, taken as zero a=%h", $realtime, a);
#1ps $display ("T=%0t Delay of 10ps", $realtime);
end
endmodule
Observe que a precisão da escala de tempo está em 1ps e, portanto,
$realtime
é necessário para exibir o valor de precisão para a instrução com uma expressão de atraso (a+b)*10ps. Registro de simulação
xcelium> run T=0 a=x b=x T=10000 a=0 b=0 T=20000 a=4 b=0 T=24000 After a delay of a=4 units T=29000 After a delay of a=4 + b=1 = 5 units T=29050 After a delay of 5 * 10ps T=42050 Expr evaluates to a negative delay T=58050 Delay in hex T=58050 Delay is unknown, taken as zero a=x T=58050 Delay is in high impedance, taken as zero a=z T=58051 Delay of 10ps xmsim: *W,RNQUIE: Simulation is complete.
Controle de eventos
Mudanças de valor em redes e variáveis podem ser usadas como um evento de sincronização para acionar a execução de outras instruções processuais e é um implícito evento. O evento também pode ser baseado na direção da mudança, como em direção a 0, o que o torna um
negedge
e uma mudança para 1 torna um posedge
. - Um
negedge
é quando há uma transição de 1 para X, Z ou 0 e de X ou Z para 0 - Um
posedge
é quando há uma transição de 0 para X, Z ou 1 e de X ou Z para 1
Uma transição do mesmo estado para o mesmo estado não é considerada uma aresta. Um evento de borda como posedge ou negedge pode ser detectado apenas no LSB de um sinal vetorial ou variável. Se uma expressão for avaliada com o mesmo resultado, ela não poderá ser considerada um evento.
module tb;
reg a, b;
initial begin
a <= 0;
#10 a <= 1;
#10 b <= 1;
#10 a <= 0;
#15 a <= 1;
end
// Start another procedural block that waits for an update to
// signals made in the above procedural block
initial begin
@(posedge a);
$display ("T=%0t Posedge of a detected for 0->1", $time);
@(posedge b);
$display ("T=%0t Posedge of b detected for X->1", $time);
end
initial begin
@(posedge (a + b)) $display ("T=%0t Posedge of a+b", $time);
@(a) $display ("T=%0t Change in a found", $time);
end
endmodule
Registro de simulação ncsim> run T=10 Posedge of a detected for 0->1 T=20 Posedge of b detected for X->1 T=30 Posedge of a+b T=45 Change in a found ncsim: *W,RNQUIE: Simulation is complete.
Eventos nomeados
A palavra-chave
event
pode ser usado para declarar um named evento que pode ser acionado explicitamente. Um event
não pode conter nenhum dado, não tem duração de tempo e pode ocorrer em qualquer momento específico. Um evento nomeado é acionado pelo ->
operador prefixando-o antes do identificador de evento nomeado. Um evento nomeado pode ser esperado usando o @
operador descrito acima.
module tb;
event a_event;
event b_event[5];
initial begin
#20 -> a_event;
#30;
->a_event;
#50 ->a_event;
#10 ->b_event[3];
end
always @ (a_event) $display ("T=%0t [always] a_event is triggered", $time);
initial begin
#25;
@(a_event) $display ("T=%0t [initial] a_event is triggered", $time);
#10 @(b_event[3]) $display ("T=%0t [initial] b_event is triggered", $time);
end
endmodule
Os eventos nomeados podem ser usados para sincronizar dois ou mais processos em execução simultânea. Por exemplo, o
always
bloco e o segundo initial
bloco são sincronizados por a_event. Os eventos podem ser declarados como arrays, como no caso de b_event, que é um array de tamanho 5 e o índice 3 é usado para fins de disparo e espera. Registro de simulação
ncsim> run T=20 [always] a_event is triggered T=50 [always] a_event is triggered T=50 [initial] a_event is triggered T=100 [always] a_event is triggered T=110 [initial] b_event is triggered ncsim: *W,RNQUIE: Simulation is complete.
Evento ou operador
O
or
O operador pode ser usado para aguardar até que qualquer um dos eventos listados seja acionado em uma expressão. A vírgula ,
também pode ser usado em vez do or
operador.
module tb;
reg a, b;
initial begin
$monitor ("T=%0t a=%0d b=%0d", $time, a, b);
{a, b} <= 0;
#10 a <= 1;
#5 b <= 1;
#5 b <= 0;
end
// Use "or" between events
always @ (posedge a or posedge b)
$display ("T=%0t posedge of a or b found", $time);
// Use a comma between
always @ (posedge a, negedge b)
$display ("T=%0t posedge of a or negedge of b found", $time);
always @ (a, b)
$display ("T=%0t Any change on a or b", $time);
endmodule
Registro de simulação ncsim> run T=0 posedge of a or negedge of b found T=0 Any change on a or b T=0 a=0 b=0 T=10 posedge of a or b found T=10 posedge of a or negedge of b found T=10 Any change on a or b T=10 a=1 b=0 T=15 posedge of a or b found T=15 Any change on a or b T=15 a=1 b=1 T=20 posedge of a or negedge of b found T=20 Any change on a or b T=20 a=1 b=0 ncsim: *W,RNQUIE: Simulation is complete.
Lista de expressões de eventos implícitos
A lista de sensibilidade ou a lista de expressão de evento geralmente é uma causa comum para muitos erros funcionais no RTL. Isso ocorre porque o usuário pode esquecer de atualizar a lista de sensibilidade após a introdução de um novo sinal no bloco procedural.
module tb;
reg a, b, c, d;
reg x, y;
// Event expr/sensitivity list is formed by all the
// signals inside () after @ operator and in this case
// it is a, b, c or d
always @ (a, b, c, d) begin
x = a | b;
y = c ^ d;
end
initial begin
$monitor ("T=%0t a=%0b b=%0b c=%0b d=%0b x=%0b y=%0b", $time, a, b, c, d, x, y);
{a, b, c, d} <= 0;
#10 {a, b, c, d} <= $random;
#10 {a, b, c, d} <= $random;
#10 {a, b, c, d} <= $random;
end
endmodule
Registro de simulação ncsim> run T=0 a=0 b=0 c=0 d=0 x=0 y=0 T=10 a=0 b=1 c=0 d=0 x=1 y=0 T=20 a=0 b=0 c=0 d=1 x=0 y=1 T=30 a=1 b=0 c=0 d=1 x=1 y=1 ncsim: *W,RNQUIE: Simulation is complete.
Se o usuário decidir adicionar um novo sinal e e capturar o inverso em z, deve-se ter cuidado especial para adicionar e também na lista de sensibilidade.
module tb;
reg a, b, c, d, e;
reg x, y, z;
// Add "e" also into sensitivity list
always @ (a, b, c, d, e) begin
x = a | b;
y = c ^ d;
z = ~e;
end
initial begin
$monitor ("T=%0t a=%0b b=%0b c=%0b d=%0b e=%0b x=%0b y=%0b z=%0b",
$time, a, b, c, d, e, x, y, z);
{a, b, c, d, e} <= 0;
#10 {a, b, c, d, e} <= $random;
#10 {a, b, c, d, e} <= $random;
#10 {a, b, c, d, e} <= $random;
end
endmodule
Registro de simulação ncsim> run T=0 a=0 b=0 c=0 d=0 e=0 x=0 y=0 z=1 T=10 a=0 b=0 c=1 d=0 e=0 x=0 y=1 z=1 T=20 a=0 b=0 c=0 d=0 e=1 x=0 y=0 z=0 T=30 a=0 b=1 c=0 d=0 e=1 x=1 y=0 z=0 ncsim: *W,RNQUIE: Simulation is complete.
Verilog agora permite que a lista de sensibilidade seja substituída por
*
que é uma abreviação conveniente que elimina esses problemas adicionando todas as redes e variáveis que são lidas pelo comando como mostrado abaixo.
module tb;
reg a, b, c, d, e;
reg x, y, z;
// Use @* or @(*)
always @ * begin
x = a | b;
y = c ^ d;
z = ~e;
end
initial begin
$monitor ("T=%0t a=%0b b=%0b c=%0b d=%0b e=%0b x=%0b y=%0b z=%0b",
$time, a, b, c, d, e, x, y, z);
{a, b, c, d, e} <= 0;
#10 {a, b, c, d, e} <= $random;
#10 {a, b, c, d, e} <= $random;
#10 {a, b, c, d, e} <= $random;
end
endmodule
Registro de simulação ncsim> run T=0 a=0 b=0 c=0 d=0 e=0 x=0 y=0 z=1 T=10 a=0 b=0 c=1 d=0 e=0 x=0 y=1 z=1 T=20 a=0 b=0 c=0 d=0 e=1 x=0 y=0 z=0 T=30 a=0 b=1 c=0 d=0 e=1 x=1 y=0 z=0 ncsim: *W,RNQUIE: Simulation is complete.
Controle de evento sensível a nível
A execução de uma instrução procedural também pode ser atrasada até que uma condição se torne verdadeira e pode ser realizada com o
wait
palavra-chave e é um controle sensível ao nível. A instrução de espera deve avaliar uma condição e, se for falsa, as instruções de procedimento seguintes permanecerão bloqueadas até que a condição se torne verdadeira.
module tb;
reg [3:0] ctr;
reg clk;
initial begin
{ctr, clk} <= 0;
wait (ctr);
$display ("T=%0t Counter reached non-zero value 0x%0h", $time, ctr);
wait (ctr == 4) $display ("T=%0t Counter reached 0x%0h", $time, ctr);
$finish;
end
always #10 clk = ~clk;
always @ (posedge clk)
ctr <= ctr + 1;
endmodule
Registro de simulação ncsim> run T=10 Counter reached non-zero value 0x1 T=70 Counter reached 0x4 T=90 Counter reached 0x5 T=170 Counter reached 0x9 Simulation complete via $finish(1) at time 170 NS + 1
Verilog