0

推断具有一些未使用的较高地址的 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 = 8and的 RAM DATADEPTH = 5000,所以地址必须是ADDRWIDTH = 13因为ADDRWIDTH = 12只允许寻址 4096 个 RAM 位置。让我们假设我的 FPGA 上的一个块 RAM 资源可以容纳 8192 位。如果我手动编码,我需要 5000*8/8192 向上舍入 = 5 个块 RAM 资源。然而,使用上面的代码,Xilinx 的综合和映射会导致使用 8 个块 RAM 资源,因为这可以通过 13 位宽地址来寻址......
尽管如此,这并不是真正有效地使用资源,因为 8 个中的 3 个永远不会使用块 RAM。
我试图检查输入的地址是否大于DATADEPTH然后分配不关心数据,但这导致整个 ram 被实现为分布式 RAM / LUTRAM。
我是否遗漏了一些重要的东西,或者我必须为此使用一个大而丑陋的生成器?

4

1 回答 1

2

单独的地址总线宽度 (ADDRWIDTH) 和 RAM 条目数 (DATADEPTH) 的原则很好,并且可以让综合工具自由地实现设计,而无需使用比所需更多的 RAM 位。

您可能会看到使用的 RAM 位比最低要求多的原因是,综合工具可能会选择使用比绝对最小值更多的内部 RAM 原语的实现,如果有大量可用 RAM 原语,或者如果有,通常会发生这种情况需要以关闭时间。

如果您尝试使用 DATAWIDTH、DATADEPTH 和 ADDRWIDTH 的设置,您会发现综合工具使用的内部 RAM 原语确实比将 DATADEPTH 简单四舍五入为新的 2 ** N 所需的数量更少。

使用 DATAWIDTH = 72、DATADEPTH = 17 * 1024 和 ADDRWIDTH = 16 至少需要 72 * 17 Kib = 1224 Kib。在一项综合试验中,这可以装入 Spartan6 的 76 个 RAMB16,因此总共 76 * 18 Kib = 1368 Kib。合成图如下。

在此处输入图像描述

如果 DATADEPTH 舍入到最接近的 2 * 边界,它将是 32 * 1024,因此需要 72 * 32 Kib = 2304 Kib。因此,赛灵思综合工具确实非常适合。

顺便说一下,信号应该用于 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;
于 2013-10-24T11:10:58.953 回答