有效地使用未使用的地址推断BRAM

时间:2013-10-24 07:41:28

标签: vhdl fpga

使用一些未使用的更高地址(使用Block RAM)推断RAM的正确方法是什么? 使用下面的代码(泛型,Xilinx合成器和映射的默认值),我得到的RAM大小与深度设置为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;

例如,我想要一个带DATAWIDTH = 8DATADEPTH = 5000的RAM,因此地址必须为ADDRWIDTH = 13,因为ADDRWIDTH = 12只允许寻址4096个RAM位置。假设我的FPGA上的一个块RAM资源可以容纳8192位。 如果我手动编码,我需要5000 * 8/8192向上舍入= 5块RAM资源。 但是,使用上面的代码,Xilinx的综合和映射会导致使用8个块RAM资源,因为13位宽的地址可以解决这个问题...
尽管如此,这并不是真正有效地使用资源,因为永远不会使用8个Block RAM中的3个 我试图检查输入的地址是否大于DATADEPTH,然后分配不关心数据,但这导致整个ram实现为分布式RAM / LUTRAM。
我错过了一些重要的东西,还是我必须为此使用一个大丑陋的生成?

1 个答案:

答案 0 :(得分:2)

分离地址总线宽度(ADDRWIDTH)和RAM数量的原理 条目(DATADEPTH)很好,并且可以使合成工具自由 实现设计而不使用比所需更多的RAM位。

您可能会看到使用的RAM位数多于最低要求的RAM位数 综合工具可以选择使用更多内部RAM的实现 原始数量超过绝对最小值,如果存在则通常会出现 大量的免费RAM原语,或者如果需要,以便关闭时序。

如果您尝试使用DATAWIDTH,DATADEPTH和DATAWIDTH的设置进行试验 ADDRWIDTH,您将看到合成工具确实使用更少的内部 RAM原语比将DATADEPTH简单地舍入到新的2 ** N那样 需要。

使用DATAWIDTH = 72,DATADEPTH = 17 * 1024,ADDRWIDTH = 16需要 最小72 * 17 Kib = 1224 Kib。在一个综合试验中,这可以适应 76 Spartan6的RAMB16,因此总共76 * 18 Kib = 1368 Kib。图来自 合成如下。

enter image description here

如果DATADEPTH四舍五入到最接近的2 *边界,那么它将是32 * 1024 需要72 * 32 Kib = 2304 Kib。所以Xilinx综合工具确实做到了 智能适应。

顺便说一下,信号应该用于RAM,而不是共享变量, 因为我希望共享变量可能会在某些综合中引起问题 工具。

建议代码,包括使用条款:

library ieee;
use ieee.std_logic_1164.all;

entity foo is
  generic (
    DATAWIDTH : positive := 72;
    DATADEPTH : positive := 17 * 1024;
    ADDRWIDTH : positive := 16
    );
  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;

library ieee;
use ieee.std_logic_unsigned.all;

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
  signal 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;