I'm trying to implement a buffer for an image processing pipeline and need to load data into BRAM.

I've been following an online tutorial (https://www.youtube.com/watch?v=n35zS__YEFQ) for implementing different parts of the system, but after synthesis and implementation, I can see that my code is using LUTRAM instead of BRAM. I have tried looking into the language templates provided by vivado for inferring single port BRAM and to me the code looks very similar, but I'm new to FPGAs and don't know much, so I'm not entirely sure how I can force BRAM to be inferred instead of LUTRAM.

Here is my Verilog code:

module buffer #(parameter NUM_ELEMENTS=10, ADDRESS_BITS=4, WIDTH=8) (
    input clk,
    input rst,
    input [WIDTH-1:0] dataIn,
    input validInput,
    input readReady,
    output wire [WIDTH-1:0] dataOut
    reg [WIDTH-1:0] mem [NUM_ELEMENTS-1:0];
    reg [ADDRESS_BITS-1:0] wrPtr;
    reg [ADDRESS_BITS-1:0] rdPtr;
    always @ (posedge clk) begin
        if (rst) begin
            wrPtr <= 0;
        end else if (validInput) begin
            mem[wrPtr] <= dataIn;
            wrPtr <= wrPtr + 1;
    assign dataOut = mem[rdPtr];
    always @ (negedge clk) begin
        if (rst) begin
            rdPtr <= 0;
        end else if (readReady) begin   
            rdPtr <= rdPtr + 1;

Simulating the module shows that it is working correctly as expected (I need to take care of some edge cases where the read pointer goes past the end of the buffer, more on that later).

My test bench code is:

`timescale 1ns / 1ps

module buffer_tb();
    reg clk;
    reg rst;
    reg [buffer.WIDTH-1:0] dataIn;
    reg validInput;
    reg readReady;
    wire [buffer.WIDTH-1:0] dataOut;
    integer i;
    buffer dut (clk,rst,dataIn,validInput,readReady,dataOut);
    initial clk = 1;
    always #5 clk = ~clk;
    initial begin
        rst = 1;
        dataIn = 0;
        validInput = 0;
        readReady = 0;
        rst = 0;
        validInput = 1;
        for (i=0; i<10; i = i+1) begin
            dataIn = 2*i;
        validInput = 0;
        readReady = 1;
        readReady = 0;

And the output of the simulation is: enter image description here

But opening project summary or the elaborated design shows the incorrect use of LUTRAM:

enter image description here

I emphasize again that I'm a total beginner and just started using FPGAs; After searching a bit on xilinx's guides, I still can't find any way of specifying the type of RAM, only that it can be inferred when using a very specific syntax, which seems odd and I haven't managed to make it work.

My main questions are:

  1. How can you infer BRAM instead of LUT? Do I have to copy the suggested example code line by line or are there changes permitted?
  2. If I have to copy the template codes directly, would it better to use the IP core generator to instantiate BRAM in the block design and write a controller for it (the buffer module acting as a wrapper), or whether to use the actual code template? To be honest I don't even know what the differences are. As I understand it, the block design gets converted to Verilog anyways.
  3. I only need to write to buffers till they are full, then read from them until they are empty. Should I be using a FIFO instead of trying to implement my own buffer code? The way I understood the online tutorial for image processing, I can create more buffers than required and fill them while processing other portions of the data, then multiplex the buffers, but I'm not sure what the advantages and downsides of a FIFO block are, compared to a hand written buffer.
  • \$\begingroup\$ Before that did u calculate how much bram is needed for a frame buffer and how much is available. A typical 7 series low end xilinx FPGA doesn't have enough bram to incorporate say 640x480 VGA frame. \$\endgroup\$
    – Mitu Raj
    May 30, 2021 at 15:40
  • \$\begingroup\$ Yes, I will be periodically filling the buffer with data from QSPI modules which give me enough capacity for all the data input. the actual image will be loaded via DMA from a ZYNQ processor but that's way in the future. I can't even get the buffer itself to work how I want it :( \$\endgroup\$
    – OM222O
    May 30, 2021 at 15:49
  • 1
    \$\begingroup\$ DMA+DDR+Processor is how usually video engines are implemented on an FPGA. BRAMs can be used to implement line buffers or FIFOs on video/image processing pipeline. But they are not big enough in most FPGAs for frame buffers especially if at least double buffering is needed. And yes, you have to follow coding guidelines and attributes to properly infer the BRAM using RTL. \$\endgroup\$
    – Mitu Raj
    May 30, 2021 at 16:03

2 Answers 2


If you only need a small buffer (<16 data entries), there's absolutely no reason to prefer BRAM over LUTRAM.

BRAMs are located in specific areas of the chip, which may mean that relatively long paths are required to get to them from your other logic. LUTRAM can always be located close to the logic that uses it.

On the other hand, larger buffers (>64 data entries) will almost always infer BRAM instead of LUTRAM. There are also synthesis directives that can force the choice one way or the other. See the documentation for the tools you're using.

And yes, FIFOs are much more commonly used in video processing. I have written generic modules for both single-clock (synchronous) and dual-clock (asynchronous) FIFOs that I use all of the time in my video pipeline designs. I allow the synthesis tools to infer the appropriate type of RAM for the specified FIFO size. If you need the absolute maximum performance, use the vendor's IP generator, which will take full advantage of any specialized support logic that is on the chip.

  • 1
    \$\begingroup\$ (* ram_style = "block" *) is the directive in Verilog. \$\endgroup\$
    – Mitu Raj
    May 30, 2021 at 16:11
  • \$\begingroup\$ unfortunately even using the directive and increasing the number of elements to 1024 still doesn't result in using BRAMs :( I will go back and start modifying the provided examples line by line to see where my mistake is, but having to run synthesis every time to double check is a bit time consuming. \$\endgroup\$
    – OM222O
    May 30, 2021 at 16:41

I am leaving an answer in case someone else fall into the same case.

(I have refered to the UG901 - v2019.1, the exact location and chapters may change in the newer versions of the document.)

The answer given by Dave Tweed is valid, however if you still need to use a BRAM slice for your memory you only need to specify it in your verilog code such that the Vivado synthesis will infer it in a BRAM slice.

Refer to Vivado Design Suite User Guide UG901 - Vivado synthesis - Section 2 - Synthesis Attributes -> RAM_STYLE attribute.

Basically in your verilog circuit, change the line,

reg [WIDTH-1:0] mem [NUM_ELEMENTS-1:0];


(* ram_style = "block" *) reg [WIDTH-1:0] mem [NUM_ELEMENTS-1:0];

to infer BRAM slices for your memory. Keep in mind that you will use an entire slice of BRAM, even if you use only a portion of it. However if you use an array declaration of a larger size than a single BRAM slice, synthesis will cascade a few of them. If you read further about the memory types available in your specific FPGA (Xilinx will have a different document explaining the logic elements and memory of a device family for example Zynq 7000, Zynq Ultrascale+), you will find the available arrangements of a block ram.

If you are still not inferring a block RAM that means you are violating the BRAM limitations.

Block RAM slices only support synchronous reads. (Refer to chapter 4 - RAM HDL Coding Techniques UG901- Table 4-1) In simple words reads from your mem should be inside a always@(posedge clk) ( or negedge) block. It is a limitation in the BRAM slices, if you use an asynchronous read anywhere in your circuit from the mem array synthesis will discard the attribute and infer it in Distributed RAM which is LUTRAM in this case.

As you can see you are using assign dataOut = mem[rdPtr]; an asynchronous read from the memory, this causes the mem to be implemented on LUTRAM. Convert the above circuit to synchronous logic. dataOut will have to be a reg and the line should be inside a always@(posedge clk) block. Furthermore, this will introduce a 1 clock cycle delay to the data output since it is highly recommended to use non blocking statements in the always@(posedge clk) blocks.

output reg [WIDTH-1:0] dataOut


always@(posedge clk)
dataOut <= mem[rdPtr];

I have just outlined the solution, you will have to go through your state machine and circuit implementation once again and do some changes to get the desired result as before, mainly due to that 1 clock cycle delay that gets introduced.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.