fpga-flip-flops-registros-memoria

Flip-flops and registers: basic memory in FPGA

  • 4 min

A flip-flop is a memory element capable of storing a single bit and updating it on a clock edge.

In the previous article, we met the clock, that conductor who sets the beat. Now we need an element that remembers what value to keep between two edges.

It is the minimum memory unit in digital electronics. With many flip-flops together, we can build registers, counters, state machines, and, in general, any sequential circuit.

If LUTs were the brain (they computed) and the Clock was the heart (it gave the beat), Flip-Flops are the neurons where momentary memories are stored.

The D flip-flop

There are several types of flip-flops (JK, T, SR…), but in FPGAs the most common is the D flip-flop (Data). It is so fundamental that these devices include a large number of them alongside their logic blocks.

Its operation is extremely simple, yet powerful:

“Copy what is at the input D to the output Q, but ONLY when the clock has a rising edge.”

Temporal behavior

Before the edge: You can change the input D as many times as you like (0, 1, 0, 1…). The output Q doesn’t care; it keeps showing the old stored value.

Rising edge (posedge clk): The Flip-Flop opens its gate for an instant, takes a “snapshot” of the input D, and closes the gate.

After the edge: The output Q now shows the new copied value. And it will stay that way, fixed and stable, until the next edge arrives, no matter what happens at the input.

This property is what allows us to synchronize signals. The Flip-Flop acts as a barrier that only lets clean data pass through at the clock’s rhythm.

Inference in Verilog

How do we tell the FPGA “I want a Flip-Flop”? There is no create_flipflop command. We infer it through behavior.

Whenever we assign a value to a reg inside a clock-synchronized block, we are creating a Flip-Flop.

module one_bit_memory (
    input wire clk,
    input wire d,
    output reg q
);

    // This generates a physical D Flip-Flop
    always @(posedge clk) begin
        q <= d; // Non-blocking assignment (typical for sequential logic)
    end

endmodule
Copied!

Registers

A Flip-Flop stores 1 bit. But we usually work with numbers (8 bits, 16 bits, 32 bits). When we put several Flip-Flops in parallel to store a complete data word, we call it a Register.

In Verilog, it is as simple as defining a vector:

reg [7:0] my_register; // This creates 8 Flip-Flops connected to the same clock

always @(posedge clk) begin
    my_register <= data_input;
end
Copied!

The concept of state

Here is where our programmer’s mindset changes. In software, a variable is a location in RAM. In hardware, a register is a physical component that maintains the State of our system.

If we stop the clock, the register keeps its value forever (as long as power is present). It is our “short-term memory”.

The importance of reset

If we power up an FPGA, what value do the flip-flops have? The answer depends on the device and how the design has been implemented. Many families allow initialization values, but it is not advisable to assume them without consulting the documentation.

When a circuit needs to start in a known state, we use initialization or a reset signal. Not all registers need to be reset; adding reset to everything can also consume routing and limit the inference of certain resources.

There are two philosophies for resetting:

Asynchronous Reset

As soon as you press the Reset button, the Flip-Flop goes to 0, without waiting for the clock. It is like an “emergency brake”.

// Sensitive to clock OR reset
always @(posedge clk or posedge rst) begin
    if (rst) begin
        q <= 0; // Reset takes precedence
    end else begin
        q <= d; // Normal behavior
    end
end
Copied!

Synchronous Reset

If you activate the reset, the flip-flop waits for the next clock edge to go to 0. It usually integrates well into synchronous logic, although the best option depends on the FPGA architecture and the design requirements.

// Only sensitive to clock
always @(posedge clk) begin
    if (rst) begin
        q <= 0; // Will be applied on the edge
    end else begin
        q <= d;
    end
end
Copied!

Enable or load enable

Sometimes we don’t want to store data on every clock cycle. We want to store data only “when I tell you to”. For this, we use an Enable signal (ce).

Physically, this is implemented with a Multiplexer before the Flip-Flop that selects between “new data” or “old data”.

always @(posedge clk) begin
    if (enable) begin
        q <= d; // Load new value
    end
    // If there is no enable, we do not put 'else'. 
    // Verilog infers that it should keep the value (q <= q).
end
Copied!