rising_edge()vs进程敏感性列表

时间:2018-06-18 12:03:15

标签: vhdl fpga spartan

我一直在大学课程中用VHDL开发一段时间,我认为我理解它是如何工作的,但有一段时间我意识到我实际上并没有理解它。

这是我的问题:

据我所知,如果一个信号在一个进程的敏感性列表中,只要该信号改变了值,该进程就会“执行”。

所以我问,这两段代码之间的区别是什么:

process(clk) is
begin
  if(clk = '1') then
      --Do Something
  end if;
end process;

process(clk) is
begin
   if(rising_edge(clk)) then
      --Do Something
   end if;
end process;

他们不应该表现得一样吗?

4 个答案:

答案 0 :(得分:3)

模拟:

让我们看看如何在VHDL中定义VHDL信号值。您可以在ieee.std_logic_1164库中找到这些定义。

通常,信号被声明为std_logic,这是std_ulogic已解析的子类型,定义如下:

  type STD_ULOGIC is ( 'U',             -- Uninitialized
                       'X',             -- Forcing  Unknown
                       '0',             -- Forcing  0
                       '1',             -- Forcing  1
                       'Z',             -- High Impedance   
                       'W',             -- Weak     Unknown
                       'L',             -- Weak     0       
                       'H',             -- Weak     1       
                       '-'              -- Don't care
                       );

我们可以看到,这种信号可以比通常的'0'和'1'具有其他几个值。这两个过程之间存在差异。

现在让我们看看如何定义rising_edge函数,总是在std_logic_1164库中:

  function rising_edge (signal s : STD_ULOGIC) return BOOLEAN is
  begin
    return (s'event and (To_X01(s) = '1') and
            (To_X01(s'last_value) = '0'));
  end function rising_edge;

  function To_X01 (s : STD_ULOGIC) return X01 is
  begin
    return (cvt_to_x01(s));
  end function To_X01;

  ----------------------------------------------------------
  -- table name : cvt_to_x01
  --
  -- parameters :
  --        in  :  std_ulogic  -- some logic value
  -- returns    :  x01         -- state value of logic value
  -- purpose    :  to convert state-strength to state only
  --                  
  -- example    : if (cvt_to_x01 (input_signal) = '1' ) then ...
  --
  ----------------------------------------------------------
  constant cvt_to_x01 : logic_x01_table := (
    'X',                                -- 'U'
    'X',                                -- 'X'
    '0',                                -- '0'
    '1',                                -- '1'
    'X',                                -- 'Z'
    'X',                                -- 'W'
    '0',                                -- 'L'
    '1',                                -- 'H'
    'X'                                 -- '-'
    );

此函数实际上将信号值转换为“X”或“0”或“1”。仅当转换后的新值为“1”且转换后的最后一个值为“0”时,该函数才为真。

然后rising_edge函数仅适用于[last_value; value]的以下几对:

  • [0; 1]
  • [L 1]
  • [0; H]
  • [L; H]

所有其他条件无效。

合成:

[编辑删除虚假信息]

正如@ user1155120在主要帖子评论中所解释的那样:

  

缺乏信号分配,两个过程都不​​会产生模拟事件。   缺少分配目标,第一个没有产生敏感度   合成中的顺序逻辑(透明锁存器)。缺乏一个   分配目标第二个产生无边缘触发顺序   合成中的逻辑(寄存器)。与grorel的Quartus prime不同   合成工具不能保证为他的寄存器   输出1。参见IEEE Std 1076.6-2004(撤回)6.1.2.1上升   (正)边缘时钟。,6.2.1.1来自进程的级别敏感存储   具有灵敏度列表(需要灵敏度列表中的输入信号)。

输出生成的

如下:

process(clk) is
begin
  if(clk = '1') then
      output1 <= input1;
  end if;
end process;

您必须在流程中使用边缘检测,以确保良好地创建寄存器。

答案 1 :(得分:2)

首先,如果clk更改除'1'以外的任何内容(例如'H')到&#39; 1&#39;,&#34;那么& #34;将会完成,而第二个则不会。添加异步重置说明了这一点。你需要:

process (clk, reset) is
begin
   if reset = '1' then
      --Reset something
   elsif rising_edge(clk) then
      --Do Something
   end if;
end process;

否则,&#34;某事&#34;例如,reset'1'更改为'0'后即可完成。

答案 2 :(得分:2)

从纯模拟语义的角度来看,当且仅当以下情况下,您的第一种形式是真正的上升沿检测器:

  1. 敏感度列表中只有clk(您的情况)
  2. 并且clk的类型是位
  3. clk的初始值不是'1',例如:

    signal clk: bit := '1';
    

如果这样,您的-- do something仅在clk的上升沿执行。要了解为什么我们需要使用wait语句查看等效过程(是的,敏感性列表只是更通用过程的简写):

signal clk: bit;
...
process is
begin
  if(clk = '1') then
      --Do Something
  end if;
  wait on clk;
end process;

如果clk的类型为bit,则模拟器在模拟开始时使用枚举类型bit的最左边的值对其进行初始化。声明bit时:

type bit is ('0', '1');

其最左边的值为'0',并且clk初始化为'0'。在第一次执行该过程时,if测试失败,并且该过程在wait语句上挂起。从现在开始,它将仅在clk的值更改时恢复。如果值更改是下降沿(从'1''0'),则if测试失败,该过程在wait语句上暂停。如果值的变化是上升沿(从'0''1'),则if测试通过,您的-- do something被执行,并且该过程在wait语句中暂停

因为我上面列出的条件非常严格(尤其是前两个条件),并且由于许多逻辑合成器实际上并没有进行语义分析,而是进行了语法分析(如果符合条件,则它们“ cognize ”同步过程)它们与某些编码模式匹配),则最好使用rising_edge的第二种形式。长期以来,它是标准的,足以被我所知道的所有逻辑合成器所支持。

有关条件“ 灵敏度列表中只有clk ”的更多解释:正如Matthew所解释的,只要您在灵敏度列表中有多个信号(例如,异步设置或重置),则必须使用其他内容来表达条件。 event信号属性是可能的:

process(clk, reset)
begin
    if clk = '1' and clk'event then

这实际上表示一个事件刚在clk上发生,并且clk的新值是'1'。和:

一起使用
process(clk, reset)
begin
    if clk = '1' then

如果if为高时reset上发生了事件,则clk测试通过。通常不是您想要的。

大多数合成器都可以使用if clk = '1' and clk'event来完成您想做的事情,但这还不是全部。例如,如果clk的类型不是bit,而是像std_ulogic这样的多值类型,则测试以{{1} }}。如clk'1''X''1'。通常不是您想要的,至少在仿真过程中。这是'U'函数派上用场的地方:它做对了。它使用信号参数'1'的当前值加上rising_edges。仅当您认为是真正的上升沿时,它才返回true:

s'event

您的仿真按预期工作,并且所有逻辑合成器都对此感到满意,因为它是他们识别的模式之一。

答案 3 :(得分:0)

由于所有其他答案都集中在问题的更形式化,面向仿真的方面,因此我将在综合方面进行补充,大多数工具如今都不在乎敏感度列表,但rise_edge函数仍然为了推断顺序逻辑(即触发器)必不可少。