Showing results for 
Show  only  | Search instead for 
Did you mean: 
Registered: ‎11-23-2018

Issue with Inferring BRAM

Unable to infer the BRAM with the following declaration:  reg [C-1:0] [d_width-1:0] RAM [depth-1:0]

Please guide.

0 Kudos
2 Replies
Registered: ‎08-07-2014


Please consult the Vivado Synthesis guide, UG901, Chapter 4.

There you have Verilog code snippets for BRAM inference.

------------FPGA enthusiast------------
Consider giving "Kudos" if you like my answer. Please mark my post "Accept as solution" if my answer has solved your problem

0 Kudos
Registered: ‎05-21-2015

I deal with several problems involved in implementing RAM in my beginners tutorial.  In general, I proposed the following rules to help make certain inference happens like it should:

  1. Any RAM access should be contained in its own always block (its own process for VHDL types)
    always @(posedge i_clk)
    if (write)
       ram[write_addr] <= write_value;
    always @(posedge i_clk)
    if (read)
      read_value <= ram[read_addr];
  2. RAM can only ever be initialized once.  The following code is therefore illegal
    always @(posedge i_clk)
    if (i_reset)
      // This will not infer a block RAM--block RAM cannot be re-initialized
      for(i=0; i<ramsize; i=i+1)
        ram <= 0;
    end else if (write)
      ram[write_addr] <= write_value
  3. Don'e place a RAM access within a cascaded if, sometimes known as a priority encoder.  It will get replacced by FF's
    // Don't do this if you want to infer RAM
    always @(posedge i_clk)
    if (A)
      value <= ram[addr_a];
    else if (B)
      value <= something_else;
    else if (C)
      value <= ram[addr_b];
    else if (D)
      // logic continues
  4. Don't put an entire RAM in a port list.  I'm not sure how Vivado handles this myself, but it's not recommended
  5. Don't put a RAM in a block with other things
    // Many synthesizers will turn this into FFs
    always @(posedge i_clk)
    if (write_enable)
        B <= // some logic;
        C <= // something else
        ram[addr] <= value;
  6. Vivado (thankfully) allows byte enables.  They're really nice to use in some applications
    always @(posedge i_clk)
    if (write_enable)
        if (en[1])
            ram[write_addr][15:8] <= write_value[15:8];
        if (en[2])
            ram[write_addr][ 7:0] <= write_value[7:0];
  7. Xilinx has a special syntax they use for implementing a write-through memory, where the value written is available on the same clock as the write.  There's an ugly issue associated with the expression being non-language compliant as I recall, so expect simulation/synthesis mismatch issues if you aren't careful, or use tools from multiple vendors.
    // Write-through capability
    // ---- Not Verilog spec compliant!
    always @(posedge i_clk)
        if (write_enable)
            mem[addr] <= write_value;
        read_value <= mem[addr];
  8. Most modern Xilinx hardware also support distributed RAM, allowing you to access a RAM without going through a clock first
    always @(*)
        read_value = ram[read_address];
    This is a *really useful* capability, and one I really like

So, it's not so much how you define the array that causes it to be placed into block RAM, but rather how you use it that determines whether or not it gets placed into block RAM in the first place.

Also, you need to be aware that not all hardware architectures are the same.  Block RAM inference is limited by the hardware architecture.  So while reading from a RAM asynchronously is (pleasantly) supported on a Xilinx device (for example), not all architectures have this capability.


P.S. Regarding the two-dimensional memory inference ... depending on how you set that up, a multiply would be required to implement it and most tools are designed so as to let you (the designer) control all pipelining--so you won't find that implemented in general.

0 Kudos