Loading header...

Block RAM, ROM, and FIFOs

FPGAs contain dedicated memory blocks. Use them. Building every memory from flip-flops or LUTs is wasteful and often slower.

Learning Objectives

You will learn to:

  • distinguish distributed RAM, block RAM, ROM, and FIFOs;
  • infer a small ROM or RAM in HDL;
  • understand synchronous read behavior;
  • choose FIFO structures for buffering and CDC.

Memory Types

Type Built from Best for
Registers flip-flops tiny state, control flags
Distributed RAM LUT fabric small tables, shallow buffers
Block RAM dedicated memory blocks buffers, FIFOs, frame data, lookup tables
ROM RAM initialized with fixed content constants, fonts, sine tables
FIFO RAM plus read/write pointers streaming queues and rate matching

Synchronous RAM Model

Many FPGA memories read synchronously: address is sampled on a clock edge and data appears after that edge.

module simple_ram #(
    parameter AW = 8,
    parameter DW = 8
) (
    input  wire             clk,
    input  wire             we,
    input  wire [AW-1:0]    addr,
    input  wire [DW-1:0]    din,
    output reg  [DW-1:0]    dout
);
    reg [DW-1:0] mem [0:(1<<AW)-1];

    always @(posedge clk) begin
        if (we)
            mem[addr] <= din;
        dout <= mem[addr];
    end
endmodule

ROM Example

always @* begin
    case (addr)
        4'd0: data = 8'h3f;
        4'd1: data = 8'h06;
        4'd2: data = 8'h5b;
        4'd3: data = 8'h4f;
        default: data = 8'h00;
    endcase
end

Small ROMs may map to LUTs. Larger ROMs are often initialized block RAM.

FIFO Concept

flowchart LR A["Write side\nwr_en, wr_data"] --> B["Memory array"] B --> C["Read side\nrd_en, rd_data"] D["Write pointer"] --> B E["Read pointer"] --> B D --> F["Full/empty logic"] E --> F

A FIFO stores data in order. Write pushes data in. Read pops data out. Full and empty flags protect against overflow and underflow.

Asynchronous FIFOs

When write and read sides use different clocks, the FIFO must handle CDC. A safe asynchronous FIFO typically uses:

  • separate write and read pointers;
  • gray-coded pointer synchronization;
  • two-flop synchronizers for pointer crossing;
  • full and empty calculations in the correct clock domains.

Do not invent an async FIFO casually. Use a proven design or vendor IP until you have studied the details.

Worked Example: UART Receive Buffer

A UART receiver may produce one byte at irregular intervals. Firmware or another FPGA block may read bytes later. A FIFO decouples those rates:

  • UART side writes when a byte is valid.
  • Consumer side reads when ready.
  • Empty prevents reading invalid data.
  • Full warns that the consumer is too slow.

Common Mistakes

  • Expecting block RAM reads to be combinational.
  • Forgetting one-cycle memory latency.
  • Ignoring full/empty flags.
  • Crossing FIFO status flags without CDC discipline.
  • Using thousands of flip-flops for a buffer that should be BRAM.

Summary

FPGA memories are architectural resources. Use registers for tiny state, LUT RAM for small structures, block RAM for real buffers and tables, ROMs for fixed data, and FIFOs for ordered queues. Respect memory latency and CDC rules.

Next: Building Peripherals.

Further Reading

  • Vendor block RAM user guides
  • FIFO generator documentation from FPGA vendors
  • Clifford Cummings: Simulation and Synthesis Techniques for Asynchronous FIFO Design

Mind Map

mindmap root((BRAM ROM FIFO)) Core concept BRAM stores arrays ROM holds constants FIFO crosses rates Depth in words Applications Width in bits Applications Buffers Design checks Lookup tables Queues Checks Read latency Common mistakes Full empty flags Common mistakes Assuming async read Ignoring overflow