Control de retardo de Verilog
Hay dos tipos de controles de tiempo en Verilog:delay y evento expresiones El retraso El control es solo una forma de agregar un retraso entre el momento en que el simulador encuentra la declaración y cuando realmente la ejecuta. La expresión de evento permite retrasar la declaración hasta que ocurra algún evento de simulación que puede ser un cambio de valor en una red o variable (evento implícito ) o un evento con nombre explícito que se activa en otro procedimiento.
El tiempo de simulación se puede adelantar mediante uno de los siguientes métodos.
Las puertas y redes que se han modelado para tener retrasos internos también aumentan el tiempo de simulación.
Control de retraso
Si la expresión de retraso se evalúa como un valor desconocido o de alta impedancia, se interpretará como retraso cero. Si se evalúa como un valor negativo, se interpretará como un entero sin signo en complemento a 2 del mismo tamaño que una variable de tiempo.
`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
Tenga en cuenta que la precisión de la escala de tiempo está en 1ps y, por lo tanto, $realtime
es necesario para mostrar el valor de precisión de la instrucción con una expresión de retraso (a+b)*10ps.
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.
Control de eventos
Los cambios de valor en redes y variables se pueden usar como un evento de sincronización para desencadenar la ejecución de otras declaraciones de procedimiento y es un implícito evento. El evento también se puede basar en la dirección del cambio, como hacia 0, lo que lo convierte en un negedge
y un cambio hacia 1 lo convierte en un posedge
.
- A
negedge
es cuando hay una transición de 1 a X, Z o 0 y de X o Z a 0 - A
posedge
es cuando hay una transición de 0 a X, Z o 1 y de X o Z a 1
Una transición del mismo estado al mismo estado no se considera un borde. Un evento de borde como posedge o negedge solo se puede detectar en el LSB de una señal vectorial o variable. Si una expresión se evalúa con el mismo resultado, no se puede considerar como un 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 simulación 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 con nombre
La palabra clave event
se puede utilizar para declarar un named evento que se puede desencadenar explícitamente. Un event
no puede contener ningún dato, no tiene duración de tiempo y se puede hacer que ocurra en cualquier momento en particular. Un evento con nombre es activado por el ->
operador prefijándolo antes del identificador de evento nombrado. Se puede esperar un evento con nombre usando el @
operador descrito anteriormente.
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
Los eventos con nombre se pueden usar para sincronizar dos o más procesos que se ejecutan simultáneamente. Por ejemplo, el always
bloque y el segundo initial
bloque están sincronizados por a_event. Los eventos se pueden declarar como matrices, como en el caso de b_event, que es una matriz de tamaño 5 y el índice 3 se usa para desencadenar y esperar.
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 u operador
El or
El operador se puede usar para esperar hasta que cualquiera de los eventos enumerados se active en una expresión. La coma ,
también se puede usar en lugar del 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 simulación 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 expresiones de eventos implícitos
La lista de sensibilidad o la lista de expresiones de eventos suele ser una causa común de muchos errores funcionales en el RTL. Esto se debe a que el usuario puede olvidarse de actualizar la lista de sensibilidad después de introducir una nueva señal en el bloque de procedimiento.
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 simulación 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.
Si el usuario decide agregar una nueva señal e y capturar la inversa en z, se debe tener especial cuidado para agregar e también a la lista de sensibilidad.
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 simulación 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 ahora permite que la lista de sensibilidad sea reemplazada por *
que es una forma abreviada conveniente que elimina estos problemas al agregar todas las redes y variables que son leídas por la instrucción como se muestra a continuación.
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 simulación 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.
Control de eventos sensibles al nivel
La ejecución de una declaración de procedimiento también se puede retrasar hasta que una condición se vuelve verdadera y se puede lograr con el wait
palabra clave y es un control sensible al nivel.
La sentencia de espera evaluará una condición y, si es falsa, las sentencias de procedimiento que le sigan permanecerán bloqueadas hasta que la condición se vuelva verdadera.
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 simulación 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