3
\$\begingroup\$

What is a correct way to infer a RAM with some unused higher addresses (using block RAMs)?
Using the code below (default values for generics, Xilinx synth and map) I get a RAM sized the same as if depth was set to 2**ADDRWIDTH:

entity foo is
    generic (
        DATAWIDTH : positive := 8;
        DATADEPTH : positive := 5000;
        ADDRWIDTH : positive := 13
    );
    port (
        clk_a  : in std_logic;
        we_a   : in std_logic;
        addr_a : in std_logic_vector(ADDRWIDTH-1 downto 0);
        di_a   : in std_logic_vector(DATAWIDTH-1 downto 0);
        do_a   : out std_logic_vector(DATAWIDTH-1 downto 0)
    );
end foo;

architecture bar of foo is
    type myram_type is array (DATADEPTH-1 downto 0) of std_logic_vector(DATAWIDTH-1 downto 0); --! type for ram content
    shared variable myram : myram_type; --! ram
begin
    process (clk_a)
    begin
        if rising_edge(clk_a) then
            if we_a = '1' then
                myram(conv_integer(addr_a)) := di_a;
            end if;
            do_a <= myram(conv_integer(addr_a));
        end if;
    end process;
end bar;

For example, I want a RAM with DATAWIDTH = 8 and DATADEPTH = 5000, so the address has to be ADDRWIDTH = 13 because ADDRWIDTH = 12would only allow to address 4096 RAM locations. Lets assume one block RAM ressource on my FPGA can hold 8192 bits. If I handcoded this I required 5000*8/8192 rounded upwards = 5 block RAM ressources. However, with the code above, synthesis and map of Xilinx results in 8 block RAM ressources being used, because thats what can be addressed by 13 bit wide addresses...
Nontheless, this is not really efficient use of ressources since 3 of the 8 block RAMs will never be used.
I tried to check if the address at the input is larger than DATADEPTH and then assign don't cares for the data, but that results in the whole ram being implemented as distributed RAM / LUTRAM.
Am I missing something important or do I have to use one big ugly generate for this?

\$\endgroup\$
3
\$\begingroup\$

Actually, using 8 BRAMs in an 8K×1 configuration, rather than 5 BRAMs in a 1K×8 configuration, is more efficient in several important ways.

With the 8 BRAMs, you can simply connect all of the address and control lines to all of the BRAMs, and one bit from the data input and data output buses to each of the BRAMs. No other logic is required at all.

On the other hand, with the 5-BRAM configuration, you'll need extra logic to decode the upper 3 address bits to enable one BRAM at a time, and you'll also need a 5:1 multiplexer on the data output bus to select the data from correct BRAM when reading. This uses extra resources within the FPGA, and it also adversely affects the timing, reducing the maximum clock frequency you can use.

If you really need to use the BRAM capacity as efficiently as possible, and you don't care about the timing and resource issues, then you'll have to explicitly code your memory as a module that uses five 1K×8 memories internally.

\$\endgroup\$
  • \$\begingroup\$ A better 5-BRAM configuration in this case would be four 4Kx2 and one 1Kx8, with a 2:1 output mux and a single address bit decoder for writing. \$\endgroup\$ – apalopohapa Oct 24 '13 at 13:31
2
\$\begingroup\$

Inferring hard modules (like block rams) from code is a rather fragile proposition, so synthesizers usually provide coding guidelines, of which I presume you used Xilinx's "RAMs Hardware Description Language (HDL) Coding Guidelines".

When reading those guidelines and realizing that certain coding styles that would seem perfectly valid (like using signals instead of shared variables for a dual port ram) won't actually work, you get a feeling of how limited inference techniques are.

Therefore I think either there is such a limitation with Xilinx, or the tool is choosing not to minimize BRAM usage in favor of other optimizations (as mentioned in Dave Tweed's answer).

So it seems you are unfortunately limited to:

  • Explicitly cascading the required BRAMs.
  • Cascading multiple memories coded in the simplistic 'guideline' way.
  • Using the CORE generator.
  • Letting the extra BRAMs go to waste and move on - maybe when the conditions are right the tool will do what you expected and use 5 BRAMs.
\$\endgroup\$
0
\$\begingroup\$

If you need to use 13 address bits for your RAM then those 13 physical address signals for a BRAM must be allocated to your RAM. The address lines can't be easily shared with some other module, so you effectively get all of the physical RAM that is accessed by those 13 address lines. If you need 5000 words then you will get 8192 words of BRAM. As you noted, if you synthesize the RAM from LUTs you can make a RAM with only 5000 words but you lose the efficiency of the BRAM.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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