我一直在大学课程中用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;
他们不应该表现得一样吗?
答案 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]的以下几对:
所有其他条件无效。
[编辑删除虚假信息]
正如@ 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)
从纯模拟语义的角度来看,当且仅当以下情况下,您的第一种形式是真正的上升沿检测器:
clk
(您的情况)clk
的类型是位和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_edge
和s
。仅当您认为是真正的上升沿时,它才返回true:
s'event
您的仿真按预期工作,并且所有逻辑合成器都对此感到满意,因为它是他们识别的模式之一。
答案 3 :(得分:0)
由于所有其他答案都集中在问题的更形式化,面向仿真的方面,因此我将在综合方面进行补充,大多数工具如今都不在乎敏感度列表,但rise_edge函数仍然为了推断顺序逻辑(即触发器)必不可少。