【问题标题】:VHDL: Correctly way to infer a single port ram with synchronous readVHDL:正确推断具有同步读取的单端口 RAM 的方法
【发布时间】:2019-08-09 18:42:38
【问题描述】:

我多年来一直在争论这个问题......为什么要推断一个具有同步读取的单端口 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;

或者这样:2号门

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

我是第一个版本的粉丝,因为我认为注册 vhdl 模块的所有输出是一种很好的做法。但是,许多教科书将更高版本列为使用同步读取来推断单端口 ram 的正确方法。

从 Xilinx 或 Altera 综合的角度来看,这真的很重要吗,只要您已经考虑到延迟数据与地址之间的差异(并确定它对您的应用程序无关紧要。)

我的意思是......他们仍然在 FPGA 中为您提供块 ram?对?

或者一个给你 LUTS 和另一个 Block ram?

在 FPGA 中,1 号门或 2 号门哪个会推断出更好的时序和更好的容量?

【问题讨论】:

    标签: vhdl fpga vivado


    【解决方案1】:

    差异可能很重要,这实际上取决于您所针对的特定家庭。大多数现代 FPGA 都有块 ram 选项,允许它们以任何一种方式运行,但实际上我不会指望它。

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

    说了这么多,我通常会注册BOTH地址和数据。这是一个时钟,但它有助于关闭时序,而且我通常更关心吞吐量与整体延迟。我通常还使用包装函数(例如:My_Simple_Dual_Port_RAM)并使用原语直接实例化低级块 RAM,这使得在 FPGA 供应商之间切换(或在需要时更换推断逻辑)变得容易。我只是将模块放在一个目录中(例如:Altera、Lattice、Xilinx)并在项目文件中包含适当的目录。我也对双时钟 FIFO 做同样的事情,在这种情况下,您通常很多最好使用库部件而不是尝试构建自己的部件。

    【讨论】:

    • +1 表示“查看用户指南”。根据我的经验,使用正确的推断内存,您通常可以完全避免供应商原语。
    • 不,大多数现代 FPGA 没有仅注册输出的选项。
    【解决方案2】:

    不幸的是,综合工具供应商已经制作了 RAM 推理功能,因此他们通常可以识别两种样式,而不管所讨论的 FPGA 中 RAM 的物理实现如何。 因此,即使您指定了注册输出,综合工具也可能会默默地忽略它,并改为推断带有注册输入的 RAM。这在功能上并不等效,因此实际上可能会导致不良行为,尤其是在双端口 RAM 的情况下。

    为避免此陷阱,您可以添加供应商特定属性,告诉综合工具您需要哪种 RAM。

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

    【讨论】:

    • 如果综合工具普遍需要“注册输入”到推断的 RAM,那么这可以解释为什么书中的示例更喜欢注册读取地址而不是读取数据......
    • 我的部分困惑是 vivado 警告消息:“SYNTH #1 警告实例 xxx/xx/x 的时序,实现为块 RAM,可能不是最佳的,因为没有输出寄存器是合并到块“......事实证明这个警告消息是错误的......只有当您注册作为推断SRAM的输入的“读取地址”时,警告才会消失......
    • 您请求了一个注册的输出 RAM,而合成器默默地推断出一个注册的输入 RAM,这可能会导致输出上的次优时序。这是你得到的警告。所以警告并没有错。
    • 一般来说,如果你想要一个带有注册输出的 RAM,那么你必须推断一个带有注册输入和输出的 RAM。或者从分布式逻辑构建 RAM。或者使用少数具有该功能的 RAM 的 FPGA 之一。
    • 是的...它的数字...vivado 因间接警告消息而臭名昭著,这会让您大吃一惊。相比之下,Xilinx 编译器的早期版本 ISE 并没有警告您如果你在你的 fpga 设计中使用带有异步读取的块 rams...自从 vivado 他们开始称它为“综合方法警告”...它的价值..
    【解决方案3】:

    你可以看看合成的结果。在综合您的解决方案(默认设置)后,我的 Vivado 会为我提供以下报告。

    第一个解决方案:

    • BRAM:0.5(来自 60 块)
    • IO:34
    • BUFG:1

    原理图是这样的

    第二种解决方案:

    • BRAM:0.5(来自 60 块)
    • IO:34
    • BUFG:1

    结果如下:

    因此,您会看到合成将为两种变体生成相同的输出。这取决于您要使用哪一个。我更喜欢第一个变体,因为第二个代码稍微多一些。

    【讨论】:

    • 在这种情况下是有效的,但是对于以后的读者来说,你不能总是假设因为两个原理图是一样的,所以功能是一样的。此示例中的内存块可能启用了内部读取数据寄存器,如果不查看内存块的属性,这在综合后原理图中不会很明显。
    • 这是一个有趣的例子,当它们的功能不同时,vivado 会为 RAM 推断出相同的逻辑有点可怕......也许他们还根据类型设置了一些参数......跨度>
    • pico:不,他们没有。两者在功能上是相同的。其中之一偏离了您在 VHDL 中指定的内容。这确实很可怕。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-16
    相关资源
    最近更新 更多