Block RAM (BRAM) is a dedicated, hard-instantiated on-chip memory resource found in a wide range of FPGAs, distinct from logic fabric (LUTs/flip-flops). Each BRAM tile provides a fixed block of synchronous RAM, typically ranging from 1 Kb to 36 Kb per tile depending on the device family (exact capacities and configurations, including parity and mixed-width modes, vary by vendor), and can usually be configured as simple dual-port, true dual-port, or single-port memory.
In practice
BRAMs are used to implement FIFOs, lookup tables, frame buffers, coefficient stores for DSP pipelines, instruction memory for soft-core processors, and any other on-chip storage need that would be wasteful or impractical to build from distributed LUT-RAM. Inferring a BRAM from HDL is typically done by writing synchronous read/write logic that the synthesis tool recognizes as a RAM pattern; many tools also allow direct instantiation of vendor primitives such as Xilinx RAMB18E2/RAMB36E2 or Intel (Altera) M10K/M20K blocks for precise control.
True dual-port mode allows two independent read/write ports with separate clocks, which can be useful for crossing clock domains, though proper CDC design still requires care because same-address access behavior and timing assumptions remain device- and implementation-specific. Simultaneous writes to the same address from both ports produce device-specific behavior; the Xilinx 7-series and UltraScale datasheets, for example, define several collision modes (READ_FIRST, WRITE_FIRST, NO_CHANGE) that affect what data appears on the read port during a write. Choosing the wrong mode can produce subtle simulation-versus-hardware mismatches.
Depth and width are configurable within the limits of a tile. On Xilinx 7-series devices, a single 36 Kb tile can be configured as 16K x 2, 8K x 4, 4K x 9, 2K x 18, or 1K x 36 (among other modes), and two 36 Kb tiles can be cascaded by the tool for deeper memories. Intel Cyclone and Arria devices offer similar reconfigurability on their M10K (10 Kb) and M20K (20 Kb) blocks.
In soft-core CPU designs, BRAM is often the only practical place to store program and data memory at useful sizes without going off-chip. The blog posts "Homebrew CPUs: Messing around with a J1" and "PicoBlaze - Program RAM Access for an Interactive Monitor" both demonstrate this pattern, showing how dual-port BRAM enables instruction fetch and data access to coexist or how program memory can be made writable at runtime. Because BRAM is a finite per-device resource, running out of it forces a redesign or moves memory off-chip to SRAM/SDRAM, which complicates timing closure.
Frequently asked
How does BRAM differ from distributed RAM?
Distributed RAM is built from the
LUT cells in the logic fabric and is better suited for small, shallow memories (tens to a few hundred bits). BRAM is a dedicated hard tile optimized for larger, deeper memories. Using distributed RAM for a 4 KB buffer wastes a large fraction of the LUT budget; using BRAM for a 16-bit lookup table wastes an entire tile.
Synthesis tools usually choose automatically, but the choice can be forced with attributes.
Can BRAM be used as ROM?
Yes. Most
FPGA synthesis flows let you initialize BRAM contents at configuration time via
HDL initial blocks or memory initialization files (e.g., .mif for Intel tools, .coe for Xilinx). A BRAM with no write port driven is functionally a ROM. Some tools will warn if write logic is generated unnecessarily.
What is the read latency of a BRAM?
On most
FPGA families, BRAM has a synchronous read port, so data appears one clock cycle after the read address is registered. Some families offer an optional output register that adds a second cycle of latency but improves the achievable clock frequency. Asynchronous (combinational) read behavior is not a standard mode on most vendor block RAMs and is generally unavailable or unsupported for timing-sensitive designs; where it does appear, it is typically on simpler or older device families and is best avoided.
Why might my design simulate correctly but fail on hardware when using BRAM?
Common causes include read-during-write collision behavior that differs between the
simulation model and the synthesized primitive (READ_FIRST vs. WRITE_FIRST vs. NO_CHANGE modes), uninitialized BRAM contents that the simulator defaults to zero while hardware defaults to the configured init value, or inferring logic that the tool does not map to BRAM and instead builds from
LUTs with different timing characteristics. Always check the
synthesis and implementation reports to confirm BRAM inference.
How many BRAMs does a typical mid-range FPGA provide?
This varies widely. A Xilinx Artix-7 XC7A35T has approximately 50 x 36 Kb BRAM tiles (consult the device datasheet for exact figures, as counts can vary by package variant). A Xilinx Kintex-7 XC7K325T has 445 x 36 Kb tiles. Intel Cyclone V devices range from roughly 200 Kb to 4 Mb of M10K block memory depending on density. Checking the device datasheet and the utilization report after
synthesis is the only reliable way to know if a design fits.
Differentiators vs similar concepts
BRAM is sometimes confused with
distributed RAM (also called
LUT-RAM or LUTRAM), which is built from the same LUT primitives used for logic. Distributed RAM is flexible and low-latency for small memories but consumes routing and LUT resources that would otherwise implement logic. BRAM is a separate hard resource and does not compete with the LUT budget. A related but distinct resource on newer Xilinx/AMD devices is UltraRAM (URAM), which provides larger 288 Kb tiles with a fixed 72-bit width and is targeted at very deep memories; URAM has more pipeline stages and less configuration flexibility than BRAM.