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; end end assign dataOut = mem[rdPtr]; always @ (negedge clk) begin if (rst) begin rdPtr <= 0; end else if (readReady) begin rdPtr <= rdPtr + 1; end end endmodule
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; #10; rst = 0; validInput = 1; for (i=0; i<10; i = i+1) begin dataIn = 2*i; #10; end validInput = 0; #40; readReady = 1; #100; readReady = 0; $stop; end endmodule
but opening project summary or the elaborated design shows the incorrect use of LUTRAM:
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:
- 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?
- 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.
- 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.