FPGARelated.com

Distributed RAM

Category: Logic-resources

Distributed RAM is a feature of many SRAM-based FPGAs that allows the look-up tables (LUTs) normally used for logic to be reconfigured as small, fast RAM cells. Rather than consuming dedicated block RAM resources, storage is spread across the fabric's LUT array, hence the name.

In practice

In Xilinx 7-series and UltraScale devices, a single 6-input LUT (LUT6) can typically be configured as a 64x1-bit single-port RAM, and four adjacent LUTs sharing write logic can form a 64x4-bit or 32x6-bit structure, though exact packing and port configurations are device- and mode-specific. Intel (Altera) FPGAs implement a similar concept through MLAB (Memory Logic Array Block) cells, which are dedicated small-memory resources built into the fabric alongside their ALM-based logic. The exact sizes, port configurations, and inferred depth-versus-width trade-offs differ between vendors and device families, so always consult the device data sheet.

Distributed RAM is well-suited to small, low-latency storage needs: shift registers used as delay lines, small FIFOs, register files for soft-core CPUs, and LUT-RAM-based scratchpads. Because the read path is typically asynchronous (single-cycle, combinational) in single-port mode on most devices, distributed RAM can return data in the same clock cycle it is addressed, whereas block RAM usually adds at least one pipeline register stage. The blog post "PicoBlaze - Program RAM Access for an Interactive Monitor" illustrates how distributed RAM can be exploited inside a soft-core design for dynamic program access.

A key pitfall is resource budget awareness. Distributed RAM consumes LUTs that would otherwise implement logic, so heavy use in a congested design can force the placer into longer routing paths and hurt timing. Tools will usually infer distributed RAM automatically from HDL array descriptions, but synthesis attributes (e.g., Xilinx's `ram_style = "distributed"` or Intel's `ramstyle = "MLAB"`) let designers override the inference when the tool chooses block RAM instead, or vice versa.

Write operations to distributed RAM are synchronous (clocked), while reads are typically asynchronous in single-port mode. This asymmetry can introduce subtle bugs: a read immediately after a write in the same cycle will return the old value unless the design explicitly accounts for read-during-write behavior or uses the synchronous read option. Simulation and synthesis may disagree on read-during-write semantics if the HDL model is not written carefully.

 Learn this in FPGA Fundamentals

Discussed on FPGARelated

Frequently asked

When should I choose distributed RAM over block RAM?
Distributed RAM is generally preferable for small memories (a few dozen to a few hundred bits), when combinational (zero-latency) read access is required, or when all block RAM resources are already committed. Block RAM is the better choice for larger buffers, dual-port needs at scale, or when freeing up LUTs for logic is a priority.
Does using distributed RAM cost me any logic LUTs?
Yes. Each LUT configured as RAM is unavailable for combinational or registered logic. On congested designs this can increase routing pressure and degrade timing. Monitor LUT utilization reports and consider switching large inferred RAMs to block RAM if place-and-route struggles.
How do I control whether the synthesizer infers distributed RAM or block RAM?
Most toolchains respond to synthesis attributes attached to the HDL signal or array. In Xilinx Vivado, use `(* ram_style = "distributed" *)` or `(* ram_style = "block" *)` on the signal declaration. In Intel Quartus, use `(* ramstyle = "MLAB" *)` or `(* ramstyle = "M20K" *)`. Without attributes the tool picks based on size heuristics, which may not match your intent.
Is the read port of distributed RAM truly asynchronous?
In single-port and simple-dual-port modes on most Xilinx and Intel devices, the read output is typically a combinational function of the address, with no clock required for the read. However, this is not universal across all families and configurations: some device families also offer a synchronous read option (output registered), trading the latency advantage for better timing closure, and behavior can vary by mode. Check the primitive documentation for the specific device.
Can distributed RAM be used to build shift registers efficiently?
Yes. Xilinx FPGAs include a dedicated SRL (Shift Register LUT) primitive that implements a shift register of up to 32 or 64 bits in a single LUT, with a configurable tap address. This is one of the most area-efficient uses of distributed RAM and is commonly inferred automatically by synthesis tools from HDL shift-register patterns.

Differentiators vs similar concepts

Distributed RAM vs. Block RAM: Block RAM is dedicated, hardened memory arranged in large fixed-size tiles (e.g., 18 Kb or 36 Kb on Xilinx 7-series, 20 Kb on Intel M20K). It does not consume LUT resources but typically adds read latency due to its synchronous (registered) output; the exact number of cycles depends on the mode and device configuration, and pipelined paths may add more than one cycle. Distributed RAM repurposes LUTs and offers combinational reads at the cost of logic area. The two are not interchangeable without timing and resource trade-off analysis. Distributed RAM vs. registers: A plain HDL array inferred as flip-flops uses one DFF per bit and is always synchronously read; distributed RAM uses LUTs and can be read asynchronously, making it far more area-efficient for addressable storage beyond a handful of words.