Concurrencia en Verilog



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 de b y c se leen en el instante (now + 10).
  • a = #10 b + c; -> los valores de b y c 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.

  1. 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.
  2. 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 un always @(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