为什么信号不会在过程语句中立即更新?超高密度语言
Why won't a signal be updated instantly in process statement? VHDL
在VHDL 中,您需要在流程语句中使用变量以使其即时更新。信号的使用可以完成,但不会立即更新。重复我上面的问题:为什么信号不会在过程语句中立即更新?
因为 signal
的设计类似于硬件中物理实现的值,它只会根据确定的刺激和时间的推移进行更新。
在VHDL中,这体现在信号赋值语句本身并不更新a的值signal
。相反,它安排在该信号上发生事务,当指定时间到来时,将触发信号上的事件以更改其值(如果赋值是更改值)。
事务的默认调度是在模拟中的增量延迟之后,即模拟时刻刚好在所有并发执行的进程在那个时间完成之后。因此,如果我在一个时钟进程中运行,并且我更新了一个由 rising_edge(clk)
触发的进程中的信号值,新值将无法在进程的当前 运行 中访问,但会更新 刚好在时钟的上升沿之后,当过程完成时。
存在这种差异是因为VHDL是一种硬件描述语言,而不是一种编程语言。因此,设计必须考虑硬件操作的现实情况——时间的进展、对因果刺激的需求等。因此,在良好的 VHDL 设计中,任何旨在随时间持续存在的值都将被定义为 signal
,以便设计考虑到它应该表现得像硬件的一部分。在一个过程中,variable
可以提供用于组合计算的中间值 - 合成器将确定完成该工作所需的任何逻辑,但是 variable
作为语言元素是用于计算,而不是定义持久值的方法。当然,variable
滥用是可能的并且确实存在......:^)
简短的回答是 VHDL 执行模型。 VHDL 执行模型分两个独立的步骤执行仿真循环:更新和执行。一个模拟循环的有限视角(有很多细节我已经抽象掉了)是:
- 在更新阶段,所有将在模拟周期内更新的信号都是。
- 当信号更新和变化时,对信号变化敏感的进程被标记为执行。
- 执行标记为执行的语句和进程,直到它们遇到等待语句或循环回到进程敏感列表(并且进程有一个)。
你的问题是为什么要这样做?它保证运行每个兼容的 VHDL 仿真器都以完全相同的仿真周期数执行相同的代码,并产生完全相同的结果。
要理解为什么即时更新信号会出现问题,请考虑以下代码:
proc1 : process(Clk)
begin
if rising_edge(Clk) then
Reg1 <= A ;
end if ;
end process ;
proc2 : process(Clk)
begin
if rising_edge(Clk) then
Reg2 <= Reg1 ;
end if ;
end process ;
在上面的代码中,如果信号像变量一样瞬时更新,并且进程运行的顺序是proc1然后proc2,那么在模拟器中我们会看到1个触发器A被Reg2接收. OTOH,如果按 proc2 然后 proc1 的顺序处理 运行,那么在模拟器中我们会看到 Reg2 接收 A 的 2 个触发器。
这也是为什么 VHDL 中普通类型的共享变量只是在 1993 年才临时引入并在 2000 年能够引入更合适的特性(受保护类型的共享变量)时被删除的原因。
在VHDL 中,您需要在流程语句中使用变量以使其即时更新。信号的使用可以完成,但不会立即更新。重复我上面的问题:为什么信号不会在过程语句中立即更新?
因为 signal
的设计类似于硬件中物理实现的值,它只会根据确定的刺激和时间的推移进行更新。
在VHDL中,这体现在信号赋值语句本身并不更新a的值signal
。相反,它安排在该信号上发生事务,当指定时间到来时,将触发信号上的事件以更改其值(如果赋值是更改值)。
事务的默认调度是在模拟中的增量延迟之后,即模拟时刻刚好在所有并发执行的进程在那个时间完成之后。因此,如果我在一个时钟进程中运行,并且我更新了一个由 rising_edge(clk)
触发的进程中的信号值,新值将无法在进程的当前 运行 中访问,但会更新 刚好在时钟的上升沿之后,当过程完成时。
存在这种差异是因为VHDL是一种硬件描述语言,而不是一种编程语言。因此,设计必须考虑硬件操作的现实情况——时间的进展、对因果刺激的需求等。因此,在良好的 VHDL 设计中,任何旨在随时间持续存在的值都将被定义为 signal
,以便设计考虑到它应该表现得像硬件的一部分。在一个过程中,variable
可以提供用于组合计算的中间值 - 合成器将确定完成该工作所需的任何逻辑,但是 variable
作为语言元素是用于计算,而不是定义持久值的方法。当然,variable
滥用是可能的并且确实存在......:^)
简短的回答是 VHDL 执行模型。 VHDL 执行模型分两个独立的步骤执行仿真循环:更新和执行。一个模拟循环的有限视角(有很多细节我已经抽象掉了)是:
- 在更新阶段,所有将在模拟周期内更新的信号都是。
- 当信号更新和变化时,对信号变化敏感的进程被标记为执行。
- 执行标记为执行的语句和进程,直到它们遇到等待语句或循环回到进程敏感列表(并且进程有一个)。
你的问题是为什么要这样做?它保证运行每个兼容的 VHDL 仿真器都以完全相同的仿真周期数执行相同的代码,并产生完全相同的结果。
要理解为什么即时更新信号会出现问题,请考虑以下代码:
proc1 : process(Clk)
begin
if rising_edge(Clk) then
Reg1 <= A ;
end if ;
end process ;
proc2 : process(Clk)
begin
if rising_edge(Clk) then
Reg2 <= Reg1 ;
end if ;
end process ;
在上面的代码中,如果信号像变量一样瞬时更新,并且进程运行的顺序是proc1然后proc2,那么在模拟器中我们会看到1个触发器A被Reg2接收. OTOH,如果按 proc2 然后 proc1 的顺序处理 运行,那么在模拟器中我们会看到 Reg2 接收 A 的 2 个触发器。
这也是为什么 VHDL 中普通类型的共享变量只是在 1993 年才临时引入并在 2000 年能够引入更合适的特性(受保护类型的共享变量)时被删除的原因。