Day 82: Memory inference: BRAM patterns the tools recognize
Memory inference: BRAM patterns
On an FPGA, dedicated block RAM (BRAM) is far denser than building memory from flip-flops. Synthesis infers BRAM when your RTL matches a recognized pattern: a 2-D reg array with a synchronous (clocked) read and/or write. Deviating — an asynchronous read, or reading and writing weirdly — forces the tool to use flip-flops or LUT-RAM instead, wasting area. Write the pattern the tool wants.
module bram #(parameter W=32, DEPTH=1024, AW=10) (
input clk,
input we,
input [AW-1:0] waddr, raddr,
input [W-1:0] wdata,
output reg [W-1:0] rdata // registered read -> infers BRAM
);
reg [W-1:0] mem [0:DEPTH-1];
always @(posedge clk) begin
if (we) mem[waddr] <= wdata;
rdata <= mem[raddr]; // SYNCHRONOUS read is the key
end
endmoduleAsync read breaks BRAM inference
The single most common reason a memory *doesn't* map to BRAM is an asynchronous read (assign rdata = mem[raddr];). BRAMs have a registered output, so the read must be clocked. If you need async-read behavior (like a register file), the tool uses distributed LUT-RAM or flip-flops instead — fine for 32 entries, ruinous for a cache. Match the pattern to the resource.
Before moving on, you should be able to
What RTL feature is essential for a memory array to be inferred as FPGA block RAM (BRAM)?