VHDL:推断单端口ram同步读取的正确方法

VHDL:推断单端口ram同步读取的正确方法,vhdl,fpga,vivado,Vhdl,Fpga,Vivado,我已经辩论了很多年了。。。推断单端口ram同步读取的正确原因是什么 假设VHDL中推断内存的接口为: library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity sram1 is generic( aw :integer := 8; --address width of memory dw :integer := 8

我已经辩论了很多年了。。。推断单端口ram同步读取的正确原因是什么

假设VHDL中推断内存的接口为:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity sram1 is
    generic(
        aw             :integer := 8; --address width of memory
        dw             :integer := 8  --data width of memory
    );
    port(
        --arm clock
        aclk   :in    std_logic;
        aclear :in    std_logic;

        waddr  :in    std_logic_vector(aw-1 downto 0);
        wdata  :in    std_logic_vector(dw-1 downto 0);
        wen    :in    std_logic;

        raddr  :in    std_logic_vector(aw-1 downto 0);
        rdata  :out   std_logic_vector(dw-1 downto 0)        
    );
end entity;
这是这边吗:门1

-- I LIKE THIS ONE
architecture rtl of sram1 is    
    constant mem_len :integer := 2**aw;

    type mem_type is array (0 to mem_len-1) of std_logic_vector(dw-1 downto 0);

    signal block_ram : mem_type := (others => (others => '0'));

begin

process(aclk)
begin
    if (rising_edge(aclk)) then
        if (wen = '1') then
            block_ram(to_integer(unsigned(waddr))) <= wdata(dw-1 downto 0);
        end if;     

        -- QUESTION: REGISTERING THE READ DATA (ALL OUTPUT REGISTERED)?
        rdata <= block_ram(to_integer(unsigned(raddr)));        

    end if;
end process;


end architecture;
——我喜欢这个
sram1的体系结构rtl是
常数mem_len:整数:=2**aw;
类型mem_type是标准逻辑向量(dw-1向下到0)的数组(0到mem_len-1);
信号块内存:内存类型:=(其他=>(其他=>“0”);
开始
进程(aclk)
开始
如果(上升沿(aclk)),则
如果(wen='1'),那么
块ram(到整数(无符号(waddr))“0”);
信号raddr_dff:std_逻辑_向量(aw-1向下至0);
开始
进程(aclk)
开始
如果(上升沿(aclk)),则
如果(wen='1'),那么

block_ram(to_integer(unsigned(waddr))您可以查看合成结果。My Vivado在综合您的解决方案(默认设置)后为我提供以下报告

第一个解决方案:

  • BRAM:0.5(来自60个区块)
  • IO:34
  • BUFG:1
示意图是这样的

第二种解决方案:

  • BRAM:0.5(来自60个区块)
  • IO:34
  • BUFG:1
结果如下:


因此,您可以看到,合成将为两个变体生成相同的输出。你想用哪一个取决于你自己。我更喜欢第一个变体,因为第二个变体的代码稍微多一些。

差异可能很重要,这实际上取决于您针对的特定系列。大多数现代FPGA都有块ram选项,允许它们以任何一种方式工作,但在实践中我不会指望这一点

如果我推断RAM,我通常从工具提供的示例设计开始(用户指南中几乎总是有“如何推断RAM”一节)。如果目标是跨平台的(例如:Altera+Xilinx),我会坚持使用“最小通用支持”功能集,合并两个示例设计


尽管如此,我通常同时注册地址和数据。这是一个多时钟,但它有助于完成计时,我通常更关心吞吐量与总延迟。我还通常使用包装函数(例如:My_Simple_Dual_Port_RAM)并使用原语直接实例化低级块RAM,这使得在FPGA供应商之间切换(或在需要时交换推断的逻辑)变得容易。我只需将模块放到一个目录(例如:Altera、Lattice、Xilinx)中,并在项目文件中包含相应的目录。我也对双时钟FIFO做了同样的事情,通常使用库部件比尝试构建自己的要好得多。

不幸的是,合成工具供应商已经开发了RAM推断功能,因此他们通常可以识别这两种样式,不管FPGA中RAM的物理实现如何。 因此,即使您指定了注册的输出,syntesis工具也可能会默默地忽略这一点,并推断出具有注册输入的RAM。这在功能上并不等同,因此实际上可能会导致不期望的行为,特别是在双端口RAM的情况下

为了避免这个陷阱,您可以添加特定于供应商的属性,告诉syntehsis工具您需要哪种RAM

一般来说,大多数FPGA在物理RAM上具有强制注册输入,并且可以在输出上添加额外的可选寄存器。
因此,使用带有注册输入的代码样式代码可能会使模拟与现实相匹配,这通常是一件好事。

在这种情况下是可行的,但对于未来的读者,您不能总是假设因为两个示意图相同,所以功能相同。本例中的内存块可能启用了内部读取数据寄存器,如果不查看内存块的属性,这在合成后的示意图中是不明显的。这是一个有趣的示例,vivado在功能不同时会为RAM推断出相同的逻辑,这有点可怕。。。也许他们也会根据哪种类型设置一些参数……皮科:不,他们没有。两者在功能上完全相同。其中一个与您在VHDL中指定的不同。这确实很可怕。+1表示“查看用户指南”。根据我的经验,使用正确的推断内存,通常可以避免使用供应商原语。不,大多数现代FPGA没有仅注册输出的选项。如果合成工具普遍要求“注册推断RAM的输入”,则,这就解释了为什么书中的示例更喜欢注册读取地址而不是读取数据…我的困惑部分在于vivado警告消息:“SYNTH#1警告实例xxx/xx/x的计时,作为块RAM实现,可能是次优的,因为没有输出寄存器合并到块中”。。。原来这个警告信息是错误的。。。仅当您注册“读取地址”时,警告才会消失,该地址是推断SRAM的输入…您要求注册输出RAM,而syntehsis默认推断为注册输入RAM,这可能会导致输出上出现次优定时。这就是你得到的警告。所以警告并不是真的错。一般来说,如果你想要一个有注册输出的RAM,那么你必须推断一个有注册输入和输出的RAM。或者从分布式逻辑构造RAM。或者使用为数不多的具有RAMs功能的FPGA。是的…它认为…vivado因间接警告信息而臭名昭著,它会让你绞尽脑汁。。相反,如果在fpga设计中使用异步读取的块RAM,Xilinx编译器的早期版本ISE根本不会警告您。。。从vivado开始,他们称之为“合成方法学警告”。。。不管它值多少钱。。
-- TEXTBOOKS LIKE THIS ONE
architecture rtl of sram1 is    
    constant mem_len :integer := 2**aw;

    type mem_type is array (0 to mem_len-1) of std_logic_vector(dw-1 downto 0);

    signal block_ram : mem_type := (others => (others => '0'));
    signal raddr_dff : std_logic_vector(aw-1 downto 0);        

begin

process(aclk)
begin
    if (rising_edge(aclk)) then
        if (wen = '1') then
            block_ram(to_integer(unsigned(waddr))) <= wdata(dw-1 downto 0);
        end if;     

        -- QUESTION: REGISTERING THE READ ADDRESS?
        raddr_dff <= raddr;        

    end if;
end process;

-- QUESTION: HOT ADDRESS SELECTION OF DATA
rdata <= block_ram(to_integer(unsigned(raddr_dff)));        

end architecture;