8 de marzo de 2026
En el siguiente tema veremos las mejoras de always_comb , always_ff y always_latch introducidas en SystemVerilog frente al bloque always tradicional de Verilog.
Estos nuevos bloques de procedimiento expresan claramente la intención del diseñador de modelar un tipo concreto de hardware (combinacional, flip-flops) imponiendo una serie de reglas de diseño que las herramientas de software verifican en tiempo de síntesis y en caso de no coincidir pueden emitir mensajes de error o advertencia.
La palabra clave always_comb indica que se va a describir una sección de circuitos lógicos combinacionales. Sustituye al uso de always @(*) con varias mejoras técnicas:
Sensibilidad completa: No es necesario describir una lista de sensibilidades completa; se crea automáticamente en función de las variables contenidas dentro de las funciones llamadas por el bloque, algo que always @(*) no siempre garantiza.
Restricción de asignación única: Las variables asignadas dentro de un bloque always_comb no pueden ser asignadas por ningún otro bloque, lo que evita conflictos de controladores (drivers).
Detección de latches: Si el código describe accidentalmente un latch (por ejemplo, un if sin else), las herramientas de síntesis emitirán una advertencia específica, ya que la intención declarada es puramente combinacional.
Activación automática en tiempo 0: A diferencia de always @(*), always_comb se ejecuta automáticamente al inicio de la simulación (tiempo 0), asegurando que las salidas reflejen el estado inicial de las entradas incluso si no hay cambios inmediatos.
Ejemplo de un Multiplexor 4-1 descrito con la declaración always_comb
module mux4_1 (
input logic [1:0] sel,
input logic in0, in1, in2, in3,
output logic out);
always_comb begin
case (sel)
2'b00: out = in0;
2'b01: out = in1;
2'b10: out = in2;
2'b11: out = in3;
default: out = 1'b0;
endcase
end
endmodule
Sustituye a always @(posedge clk) proporcionando un mayor control sobre el hardware resultante:
Se utiliza para describir registros y lógica secuencial (flip-flops).
Verificación de síntesis: Impone reglas que el compilador verifica como tener un único evento de control obligando a que el bloque de procedimiento contenga una única señal de reloj (ej. posedge clk) y opcionalmente un reset. El procedimiento always_ff ejecutará la declaración if-else en cada flanco positivo del reloj.
No permite múltiples drivers. Una variable asignada en un always_ff no puede asignarse en otro bloque.
Restricción de asignaciones bloqueantes: Solo permite el uso de asignaciones non-bloking (<=). En caso de utilizar asignaciones bloking (=), las herramientas de simulación o síntesis generarán un error.
El siguiente ejemplo muestra un contador de 4 bits descrito en Systemverilog mediante bloque always_ff . Se añade un reloj lento para ver el funcionamiento del contador en los ledes de la BASYS 3.
module contador_4_bits(
input logic clk,
input logic rst, // reset síncrono
input logic en, // enable
output logic [3:0] q
);
always_ff @(posedge clk) begin
if (rst)
q <= 4'd0;
else if (en)
q <= q + 1;
end
endmodule
module contador_top(
input logic clk,
input logic reset, enable,
output logic led_hb, // heartbeat
output logic [3:0] led);
wire w_clk;
assign led_hb = w_clk;
custom_clk_top C_CLK (
.clk(clk), .led(w_clk));
contador_4_bits CNT(
.clk(w_clk), .rst(reset), .en(enable), .q(led));
endmodule
En SystemVerilog, always_latch es un bloque de procedimiento especializado que se utiliza para describir latches (biestables sensibles a nivel). Cuando el diseñador utiliza un bloque de procedimiento always_latch está indicando su propósito explícito de describir lógica con biestables.
Un latch es un elemento de almacenamiento sensible al nivel (no al flanco), es decir, cuando la señal de control está activa (por ejemplo un enable) la salida sigue a la entrada y cuando la señal de control está inactiva → mantiene el último valor. Es distinto de un flip-flop, que es sensible a flanco del reloj (posedge / negedge).
Las características de always_latch son:
Describir latches de forma explícita; hace que el compilador verifique que realmente se está creando un latch.
Mejorar legibilidad e intención del diseño.
No necesita lista de sensibilidad, el compilador la infiere automáticamente (como en always_comb).
Prohíbe múltiples drivers, al igual que always_ff y always_comb, la misma señal no puede ser escrita en varios bloques.
Normalmente usa asignaciones non-bloking (<=); como regla general si la lógica almacena estado se usa <=.
En siguiente código, muestra un ejemplo del bloque de procedimiento always_latch
module latch_example (
input logic en,
input logic d,
output logic q
);
// This block infers a transparent latch
always_latch begin
if (en)
q <= d; // When enable is high, q updates
// No 'else' → q must retain its previous value
// → latch is inferred
end
endmodule
Nota: aunque always_latch esta descrito en el estándar Systemverilog y Vivado ofrece soporte a este tipo de bloque always, no he conseguido que funcione en la BASYS 3 seleccionando uno de los switches como entrada enable; Vivano no soporta switches físicos en la lista de sensibilidad del bloque de procedimiento always_latch. Para que funcione supuestamente la señal enable debe venir de un pin CCIO (Clock‑Capable I/O) del que la BASYS 3 parece que carece.
ECE 4305 - Advanced Digital Design Using SystemVerilog HDL
Ver bloque M1-4 - always block
Many thanks to Mr Anas Salah Eddin for sharing
Descarga los ejemplos empleados en este tema aquí abajo: