变量是不是也需要 VHDL 默认信号分配?

Posted

技术标签:

【中文标题】变量是不是也需要 VHDL 默认信号分配?【英文标题】:Is VHDL default signal assignment also necessary for variables?变量是否也需要 VHDL 默认信号分配? 【发布时间】:2018-09-26 14:05:35 【问题描述】:

我了解默认信号分配在 VHDL 中很有用(甚至是必要的),以避免不完整的分配和推断的锁存器。我无法发现变量是否也需要。

考虑一下这段代码:

  test_sequencer : process(fpga_clock)
    variable sequencer_count : unsigned(3 downto 0) := (others => '0');
  begin
    if rising_edge(fpga_clock) then
      start_writing   <= start_writing;
      start_reading   <= start_reading;
      sequencer_count := sequencer_count; -- is this line necessary
      if not_every_fpga_clock = '1' then
        case sequencer_count is
          when x"4" =>
            start_writing <= '1';
          when x"12" =>
            start_reading <= '1';
          when others =>
            null;
        end case;
        if sequencer_count /= 15 then
          sequencer_count := sequencer_count + 1;
        end if;
      end if;
    end if;
  end process;

是否标有“这条线是必要的吗?”必需的?我知道如果sequencer_count 是一个信号,它必须在那里。 sequencer_count是变量时是否需要?

【问题讨论】:

您将获得多个不同问题的某些方面的答案。在没有值变化的模拟信号标识分配中不会产生事件(IEEE Std 1076-2008, 14.7.3.4 信号更新),变量具有单个当前值(6.4.2.4 变量声明),标识分配在综合(IEEE Std 1076.6-2004,RTL 综合,撤回,6.2.1.1 具有敏感性列表的过程中的电平敏感存储“默认情况下,信号(或变量)的身份分配的效果应如同分配没有现在。”)。 您的评论意味着什么?身份分配没有价值是否是进一步的论点?或者您是说在某些情况下有理由使用身份分配? 【参考方案1】:

首先,默认分配仅在不存在时钟的情况下防止锁存 - 即:组合逻辑。

在寄存器/触发器逻辑中(“ifrising_edge(clock)”之后的代码),默认分配防止保持条件 - 这是寄存器逻辑的正常部分。 “如果上升沿(时钟)”下的代码永远不会产生锁存器。

OTOH,我称之为身份分配:

  start_writing   <= start_writing;
  start_reading   <= start_reading;
  sequencer_count := sequencer_count; 

身份分配不是默认分配并明确指定反馈。这些不会阻止组合逻辑中的锁存器。

默认赋值分配一个字面值或一个组合逻辑信号输出的值:

  start_writing   <= '0';
  sequencer_count := "0000";
  LedState <= LedNext;

请注意,对于进程中的变量声明,初始化仅在进程详细说明时运行 - 这是在开始时间而不是每次进程运行时:

variable sequencer_count : unsigned(3 downto 0) := (others => '0');

这与每次调用时创建和初始化变量的子程序执行不同。

【讨论】:

您的回答帮助了我的理解。身份分配是否有任何价值?如果在if rising_edge(clock) 子句中设置了一个信号或变量,它无论如何都会是一个锁存器,这足以定义行为并且标识分配是多余的。这是我从其他两个答案中理解的。 身份分配唯一有价值的时候是它覆盖了以前的设置(在同一过程中完成)。我从来没有任何机会使用它。 是否有充分的理由来定义明确的反馈(例如您所说的身份分配,或 if rising_edge(clock) then signal &lt;= … else signal &lt;= signal; 中的 else 子句)?这会改变内在功能,还是会以任何方式影响合成? 我发现使用身份分配没有任何好处。作为elseif rising_edge(Clk),综合工具不太可能支持它。同样从模拟的角度来看,这是一个额外的、不必要的动作。【参考方案2】:

这些行都不是必需的:

  start_writing   <= start_writing;
  start_reading   <= start_reading;
  sequencer_count := sequencer_count; -- is this line necessary

他们都没有做任何事情。在完全分配和锁存推理中,只是组合逻辑的问题。这是(同步)顺序逻辑。您永远不需要担心(同步)顺序逻辑的完整分配。

这是为什么?好吧,在组合逻辑的情况下,如果您没有完整的分配,将会有一些输入组合导致通过过程的路径,其中过程的输出(由它驱动的信号)确实没有被赋值。在分配新值之前,任何信号都将保持其值。因此,在分配不完整的情况下,结果电路有必要记住(存储)该输出的状态。因此,将合成某种可以存储信息的电路。那不会是触发器,因为没有时钟,没有rising_edge 函数调用等;相反,将合成锁存器来进行记忆。这是双重糟糕的,因为 (a) 锁存器从根本上来说是坏的,并且 (b) 你想要组合逻辑但得到了顺序。这是一个错误。

但是,在(同步)时序电路中,您已经有了存储空间。触发器可以被认为是 1 位存储器。因此,您无需担心(同步)顺序过程中的完整分配。您期望生成的电路能够存储东西。

【讨论】:

【参考方案3】:

在同步进程中,使用rising_edge(fpga_clock),既不需要默认变量赋值也不需要默认信号赋值,两者都会保持上升时钟之前的值,如果进程触发时没有新的赋值(执行) 作为上升时钟的结果。

关于推断锁存器,您可能想到的可能与组合过程有关,如果if 语句的某些分支未分配给驱动信号,则可以推断锁存器,例如:

process (d, en, q)
begin
    if en = '1' then
        q <= d;
    end if;
end process;

在这种情况下,q 仅在 en'1' 时更新,因此如果 en'0',则推断一个锁存器来保存 q 的值。

作为相关评论,在顺序(时钟)过程中使用变量来保持状态通常是不好的编码风格,最好为sequencer_count 声明一个信号。原因是所有触发器的编码风格都是相同的,并且更容易调试,因为在典型的仿真波形中看不到变量。

【讨论】:

以上是关于变量是不是也需要 VHDL 默认信号分配?的主要内容,如果未能解决你的问题,请参考以下文章

java成员变量默认赋值和初始化

VHDL 中的信号和变量(顺序) - 问题

将信号的值分配给变量

VHDL多路复用器实现?

在 VHDL 中阻止对 SIGNALS 的分配

在 VHDL 中,如何将输出端口列表分配给数组?