Un flip-flop es un elemento de memoria capaz de almacenar un solo bit y actualizarlo en un flanco de reloj.
En el artículo anterior conocimos al reloj, ese director de orquesta que marca el ritmo. Ahora necesitamos un elemento que recuerde qué valor debe conservar entre dos flancos.
Es la unidad mínima de memoria en electrónica digital. Con muchos flip-flops juntos podemos construir registros, contadores, máquinas de estados y, en general, cualquier circuito secuencial.
Si las LUTs eran el cerebro (calculaban) y el Reloj era el corazón (daba el ritmo), los Flip-Flops son las neuronas donde se guardan los recuerdos momentáneos.
El flip-flop tipo D
Existen varios tipos de flip-flops (JK, T, SR…), pero en las FPGAs el más habitual es el flip-flop tipo D (Data). Es tan fundamental que estos dispositivos incluyen una gran cantidad de ellos junto a sus bloques lógicos.
Su funcionamiento es extremadamente simple, pero potente:
“Copia lo que hay en la entrada D a la salida Q, pero SOLO cuando el reloj pega un subidón (flanco de subida).”
Comportamiento temporal
Antes del flanco: Puedes cambiar la entrada D tantas veces como quieras (0, 1, 0, 1…). A la salida Q no le importa, sigue mostrando el valor antiguo guardado.
Flanco de subida (posedge clk): El Flip-Flop abre su puerta un instante, hace una “foto” a la entrada D, y cierra la puerta.
Después del flanco: La salida Q ahora muestra el nuevo valor copiado. Y se quedará así, fijo y estable, hasta que llegue el siguiente flanco, pase lo que pase en la entrada.
Esta propiedad es la que nos permite sincronizar señales. El Flip-Flop actúa como una barrera que solo deja pasar datos limpios al ritmo del reloj.
Inferencia en Verilog
¿Cómo le decimos a la FPGA “quiero un Flip-Flop”? No hay un comando create_flipflop. Lo inferimos mediante el comportamiento.
Siempre que asignemos valor a un reg dentro de un bloque sincronizado por reloj, estamos creando un Flip-Flop.
module memoria_un_bit (
input wire clk,
input wire d,
output reg q
);
// Esto genera un D Flip-Flop físico
always @(posedge clk) begin
q <= d; // Asignación no bloqueante (la habitual en secuencial)
end
endmoduleRegistros
Un Flip-Flop guarda 1 bit. Pero nosotros solemos trabajar con números (8 bits, 16 bits, 32 bits). Cuando ponemos varios Flip-Flops en paralelo para guardar un dato completo, lo llamamos Registro.
En Verilog es tan sencillo como definir un vector:
reg [7:0] mi_registro; // Esto crea 8 Flip-Flops conectados al mismo reloj
always @(posedge clk) begin
mi_registro <= entrada_datos;
endEl concepto de estado
Aquí es donde cambia nuestra mentalidad de programador. En software, una variable es un lugar en la RAM. En hardware, un registro es un componente físico que mantiene el Estado de nuestro sistema.
Si apagamos el reloj, el registro mantiene su valor eternamente (mientras haya energía). Es nuestra “memoria a corto plazo”.
La importancia del reset
Si encendemos una FPGA, ¿qué valor tienen los flip-flops? La respuesta depende del dispositivo y de cómo se haya implementado el diseño. Muchas familias permiten valores de inicialización, pero no conviene asumirlos sin consultar la documentación.
Cuando un circuito necesita arrancar en un estado conocido, utilizamos inicialización o una señal de reset. No todos los registros necesitan resetearse; añadir reset a todo también puede consumir routing y limitar la inferencia de ciertos recursos.
Existen dos filosofías para resetear:
Reset asíncrono
En cuanto pulsas el botón de Reset, el Flip-Flop se va a 0, sin esperar al reloj. Es como un “freno de emergencia”.
// Sensible al reloj O al reset
always @(posedge clk or posedge rst) begin
if (rst) begin
q <= 0; // Reset manda
end else begin
q <= d; // Comportamiento normal
end
endReset síncrono
Si activas el reset, el flip-flop espera al siguiente flanco de reloj para ponerse a 0. Suele integrarse bien en la lógica síncrona, aunque la mejor opción depende de la arquitectura de la FPGA y de los requisitos del diseño.
// Solo sensible al reloj
always @(posedge clk) begin
if (rst) begin
q <= 0; // Se aplicará en el flanco
end else begin
q <= d;
end
endEnable o habilitación de carga
A veces no queremos guardar datos en cada ciclo de reloj. Queremos guardar datos solo “cuando yo te diga”. Para eso usamos una señal de Enable (ce).
Físicamente, esto se implementa con un Multiplexor antes del Flip-Flop que elige entre “dato nuevo” o “dato viejo”.
always @(posedge clk) begin
if (enable) begin
q <= d; // Cargar nuevo valor
end
// Si no hay enable, no ponemos 'else'.
// Verilog infiere que debe mantener el valor (q <= q).
end