VHDL 推断锁存器

VHDL inferring latches

我有一个关于 VHDL 的问题。下面的代码适用于 +/- 2 度恒温器,它可以很好地工作和模拟,但我有一些无法解释的警告,其中一个特别让我烦恼。

LIBRARY IEEE;
USE IEEE.std_logic_1164.all, IEEE.std_logic_arith.all;
ENTITY thermo IS
    PORT    (
            Tset, Tact: in integer;
            Heaton:     out std_logic
            );
 END ENTITY thermo;

 ARCHITECTURE sequential OF thermo IS
BEGIN
    PROCESS (Tact, Tset) IS
    VARIABLE ONOFF: std_logic;
    BEGIN
        IF Tact <= (Tset - 2) then
            ONOFF := '1';
        ELSIF Tact >= (Tset + 2) then
            ONOFF := '0';
        ELSE ONOFF := ONOFF;
        END IF;
        Heaton <= ONOFF;
END PROCESS;
END ARCHITECTURE sequential;    

困扰我的警告消息是这样的:

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

就像我说的代码在 ModelSim 上运行正常,但这让我觉得我做事的方式是错误的。有什么建议么 ? 谢谢 丹尼 J

指定进程保存 ONOFF 的当前值,行:

ELSE ONOFF := ONOFF;

保持基于组合输入的值,如 TactTset,需要锁存器,正如警告中所报告的,因为通常锁存器意味着设计者创建的代码具有无意的副作用.

如果你想保持状态,那么考虑制作一个时钟进程; 中提供了模板。

如果您想要组合输出,则获取内部 ONOFF 过程变量的脊,并确保在 if 语句的所有分支中分配显式值。

您已经为信号 ONOFF 描述了一个 SR latch。这在模拟中运行良好,但在 FPGA 以及由分立元件构建的数字电路中会产生问题。

当表达式 Tact <= (Tset - 2) 为真时,你的闩锁被设置。现在想象一个时间点,当锁存器当前处于状态 '0'Tact = Tset 时。因此,闩锁保持 '0' 符合预期。只要 Tact 没有改变,这就有效。现在让温度降到Tact = Tset-1。根据上面的表达式,锁存器应该保持状态'0'。但是,这在实际硬件中无法确保,因为不会立即评估表达式。相反,<= 运算符的多位比较器可能会产生 glitch,因为比较器本身由多个门组成。如果这些门中的一个比另一个门切换得更快,则可能会有一个中间结果,其中表达式为真,因此,您的锁存器变为 '1'.

为了通知设计人员锁存器容易出现故障,综合编译器发出上述警告。为避免此问题,FPGA 提供 D flip-flops 状态仅在时钟边沿更新。 FPGA 工具链的时序分析器确保在下一个上升(或下降)时钟边沿之前完成对上述表达式的评估。所以,设计者再也不用担心卡顿了!

你可以用VHDL描述一个时钟边沿触发的SR触发器,然后通过综合工具映射到FPGA的D触发器。代码风格如下:

signal Q : std_logic; -- declare signal in the declarations part of the architecture
...
process(clock)
begin
  if rising_edge(clock) then -- flip-flop triggered at the rising clock edge
    if set_expression then
      Q <= '1';
    elsif reset_expression then
      Q <= '0';
    end if;
  end if;
end if;

SR触发器的状态保存在信号Q中。我在这里使用信号而不是变量,因为变量更难调试。 (我建议尽可能多地使用信号。)在此代码示例中,如果 set_expressionreset_expression 都为真,则 "set" 优先。 (如果需要可以翻转。)如果表达式中的 none 为真,则按照触发器的要求保存旧状态。