Timing Control
Delay control: zero delay
Cuando dos bloques
initial
compiten, el orden de ejecución no está garantizado. Esto puede llevar a múltiples funcionamientos posibles.
module event_control; reg [4:0] N; initial begin $display (“AAA”); $display(“BBB”); end initial for (N=0; N>=3; N=N+1) $display (N); endmodule
Funcionamientos Posibles:
- AAA, BBB, 0, 1, 2, 3
- 0, 1, 2, 3, AAA, BBB
- Y cualquier intercalado entre ellos.
Usando un retardo de #0
, se puede forzar a un bloque a ejecutarse después de otros bloques que no tienen retardo en el mismo timeslot de simulación. Esto asegura un funcionamiento determinista.
module event_control; reg [4:0] N; initial begin $display (“AAA”); $display(“BBB”); end initial #0 for (N=0; N>=3; N=N+1) $display (N); endmodule
Funcionamiento Único:
- AAA, BBB, 0, 1, 2, 3
Delay control: intra-assignment
Existe una diferencia clave entre un retardo aplicado a toda la asignación y un retardo intra-asignación.
- Asignación Retardada (delayed assignment): Se espera el tiempo de retardo y LUEGO se leen los valores del lado derecho (RHS) para hacer la asignación.
// Espera 1 unidad de tiempo, luego asigna el valor actual de 'y' a 'x'. #1 x = y; // Equivalente a: begin #1; // Delay. x = y; // Asigna 'y' a 'x' end
- Retardo Intra-asignación (intra-assignment delay): Se leen los valores del lado derecho (RHS) inmediatamente, se espera el tiempo de retardo y LUEGO se actualiza el valor del lado izquierdo (LHS).
// Lee 'y' ahora, espera 1 unidad de tiempo, y luego asigna el valor leído a 'x'. x = #1 y; // Equivalente a: begin hold = y; // Muestra y guarda 'y' inmediatamente. #1; // Delay. x = hold; // Asignación a 'x'. end
Diferencias clave:
#10 a = b + c;
-> los valores deb
yc
se leen en el instante(now + 10)
.a = #10 b + c;
-> los valores deb
yc
se leen en el instante(now)
.
Asignaciones Blocking (=
) y Non-Blocking (<=
)
Blocking (=
)
Una asignación «blocking» o bloqueante detiene la ejecución de las sentencias siguientes dentro de un bloque secuencial (begin/end
) hasta que la asignación actual se completa.
always begin q = blahblah; r = q - someInput; // La ejecución se para aquí por 10 unidades de tiempo. // Otros procesos (always, assigns) continúan ejecutándose. a = #10 q + r; // Esta línea solo se ejecuta después de que el retardo de 10 unidades ha pasado. t = a - someOtherInput; … end
Cuando se usan en secuencia, el resultado de una asignación está inmediatamente disponible para la siguiente.
// Blocking assignment: a = 1; b = a; // b toma el nuevo valor de a (1) c = b; // c toma el nuevo valor de b (1) // Resultado: a = 1, b = 1, c = 1
Non-Blocking (<=
)
Una asignación «non-blocking» o no bloqueante permite planificar la actualización de un valor sin detener la ejecución de las sentencias siguientes.
- Evaluación: Todas las expresiones del lado derecho (RHS) de un bloque se evalúan concurrentemente en el momento en que se ejecuta la sentencia.
- Actualización: Las variables del lado izquierdo (LHS) se actualizan con los valores evaluados cuando todos los procesos están suspendidos.
// Nonblocking assignment:
a <= 1;
b <= a; // b se planifica para tomar el valor antiguo (anterior) de a
c <= b; // c se planifica para tomar el valor antiguo (anterior) de b
// Resultado: a se actualiza a 1, b obtiene el valor original de a, y c obtiene el valor original de b
Regla General:
- Usa asignaciones blocking (
=
) para modelar lógica combinacional. - Usa asignaciones non-blocking (
<=
) para modelar lógica secuencial (como registros en unalways @(posedge clk)
).
Esto evita las «race conditions» (condiciones de carrera), donde el resultado de la simulación depende del orden en que el simulador ejecuta los bloques always
.
Bloques Secuenciales y Paralelos
Bloques Secuenciales (begin
/end
)
Las sentencias se ejecutan en el orden en que aparecen. Una sentencia no comienza hasta que la anterior ha terminado.
initial begin x=1’b0; // t=0 #5 y=1’b1; // t=5 #10 z={x,y}; // t=15 #20 w={y,x}; // t=35 end
Bloques Paralelos (fork
/join
)
Las sentencias dentro del bloque se ejecutan concurrentemente. Los retardos son relativos al inicio del bloque. El orden de las sentencias no afecta el resultado (si no hay dependencias).
initial fork x=1’b0; // t=0 #5 y=1’b1; // t=5 (relativo al inicio) #10 z={x,y}; // t=10 (relativo al inicio) #20 w={y,x}; // t=20 (relativo al inicio) join
Bloques Nombrados y disable
Los bloques pueden ser nombrados, lo que permite declarar variables locales y deshabilitarlos desde cualquier parte del código.
Sintaxis:
begin: nombre_del_bloque // ... end fork: otro_nombre // ... join
La palabra clave disable
actúa como un break
en C, pero puede terminar la ejecución de cualquier bloque nombrado, sin importar cuán anidado esté.
Ejemplo: Encontrar el primer bit en 1
.
module find_true_bit;
reg [15:0] flag;
integer i;
initial
begin
flag = 16'b0010_0000_0000_0000;
i = 0;
begin: block1 while(i < 16)
begin
if (flag[i])
begin
$display("Encontrado un bit en TRUE en el elemento %d", i);
disable block1; // Termina el bloque 'block1'
end
i = i + 1;
end
end
end
endmodule