fpga-flip-flops-registros-memoria

Flip-flops y registros: memoria básica en FPGA

  • 4 min

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

endmodule
Copied!

Registros

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;
end
Copied!

El 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
end
Copied!

Reset 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
end
Copied!

Enable 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
Copied!