Quartus II 中的推断锁存器是否一定是透明的

Is an inferred latch in Quartus II necessarily transparent

我有一个应该表示 "distributed RAM" 的模块,其中多个寄存器可以并行写入并通过单个 MUX 读取。 一个最小的例子是:

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

entity memory is 
    port
    (
        i_clk               : in  std_logic;
        i_reset_n           : in  std_logic;
        i_write_en          : in  std_logic;
        i_some_condition    : in  std_logic;
        i_other_condition   : in  std_logic;
        i_data              : in  std_logic_vector(15 downto 0);
        i_addr              : in  std_logic_vector(3 downto 0);
        o_data              : out std_logic_vector(15 downto 0)
    );
end memory;

architecture synthesis of memory is
    type RAM_T is array (15 downto 0) of std_logic_vector(15 downto 0);
    signal ram : RAM_T;
begin
    p: process(i_clk, i_reset_n)
    begin
        if i_reset_n = '0' then     
            ram <= (others => (others => '0'));
        elsif i_clk'event and i_clk = '1' then
            if i_write_en = '1' then
                if i_some_condition = '1' then
                    ram(1) <= i_data;
                end if;
                if i_other_condition = '1' then
                    ram(2) <= i_data;
                end if;
                -- and so on
            end if;            
        end if;
    end process p;

    o_data <= ram(to_integer(unsigned(i_addr)));
end;

现在 Quartus II(14.1 网络版)警告说

Warning (10631): VHDL Process Statement warning at memory.vhd(21): inferring latch(es) for signal or variable "ram", which holds its previous value in one or more paths through the process

如果我查看 RTL 和技术图视图,我只会看到 边沿触发 触发器。如果这里的 "latch inference" 意味着 "flip flop inference",那么这正是我想要的。 但是我如何确定 "latch" 并不意味着 "transparent latch",即 level sensitiv 存储元素?我如何在警告消息中区分这一点?

(This question 是相关的,但问为什么会这样,我问的是 "latch" 这个词的术语和用法。)

如果ram的每一位都可以赋值在:

elsif i_clk'event and i_clk = '1' then
  ...
end if;

你的部分流程,那么你的代码没问题,是 Quartus 出错了。这里不应推断出闩锁。只有具有低电平有效异步复位的 DFF。

但是如果某些位从未被分配(例如ram(0)),那么,根据VHDL语义,这些位仅在

时被分配(并且它们总是被分配为'0')
  • i_clki_reset_n
  • 上有一个活动
  • i_reset_n 低。

在恢复您的过程的任何其他情况下(i_clki_reset_n 上的事件,其中 i_reset_n 不低)它们保留其价值。

有多种方法可以解释和实现此行为(请记住,VHDL 仿真语义已由语言参考手册准确定义,但综合语义的定义远没有那么明确,并且在很大程度上取决于您使用的特定综合工具):

  • 一些合成器可能会决定这些位为常量“0”并应被简化。这种解释在技术上是不正确的,因为如果 i_reset_n 从未断言,这些位将永远不会被分配并且应该保留它们的上电值,这不一定是已知的。但对于一些 FPGA 目标来说,它是有意义的。

  • 其他一些合成器可能会认为这是典型的锁存行为,具有低电平有效启用(i_reset_n)和恒定的“0”输入或类似的东西。他们可能还会通过为所有这些位保留一个锁存器来简化。

我用 Vivado 2014.4 尝试了您的代码的两个版本:

  • 您发布的那个(带有 -- and so on 评论); Vivado 为 ram.

  • 的 224 个剩余位推断出 32 个 DFF 和一个锁存器
  • 一种变体,其中 -- and so on 注释被一些可以分配 ram(15 downto 3)ram(0) 的代码替换。 Vivado 推断出 256 个 DFF 并且没有锁存器。

总结:检查ram的每一位实际上可以在

中赋值
elsif i_clk'event and i_clk = '1' then
  ...
end if;