使用一些未使用的更高地址(使用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 = 8
和DATADEPTH = 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。
我错过了一些重要的东西,还是我必须为此使用一个大丑陋的生成?
答案 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。图来自 合成如下。
如果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;