不完整的分配和闩锁
Incomplete assignment and latches
当不完整地分配一个值时,我得到了一个锁存器。但是为什么我在下面的例子中得到了闩锁?我认为不需要 F
输出的锁存器,因为它是在 SEL
.
的所有值处定义的
Verilog 代码:
always @ (ENB or D or A or B pr SEL)
if (ENB)
begin
Q=D;
if (SEL)
F=A;
else
F=B;
end
推断逻辑:
虽然它在 SEL
的所有值中定义,但并未在 ENB
的所有值中定义。如果 ENB = 0
,您的代码表示 Q
和 F
都应保留上一个循环的值。这也是在您链接的图像中推断出的:仅更新 Q
和 F
如果 ENB = 1
.
如果你想让Q
成为闩锁而F
不是,你可以这样做:
always @ (ENB or D or A or B or SEL)
begin
if (ENB)
Q=D;
if (SEL)
F=A;
else
F=B;
end
编辑:附加信息
正如评论中所指出的,我只展示了如何在不过多修改代码的情况下实现组合逻辑和锁存器。但是,有些事情可以做得更好。因此,非 TL;DR 版本:
- 虽然可以将组合逻辑和锁存器放在一个程序块中,但最好将它们分成两个块。您正在设计两种不同类型的硬件,因此最好在 Verilog 中将它们分开。
在对锁存器建模时使用非阻塞赋值而不是阻塞赋值。克利福德 E. 卡明斯 (Clifford E. Cummings) 写了一篇关于阻塞和非阻塞分配之间的区别以及为什么了解区别很重要的优秀论文。我还将使用这篇论文作为来源:Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!
首先,了解 Verilog 中的竞争条件是什么很重要 (Cummings):
A Verilog race condition occurs when two or more statements that are scheduled to execute in the same simulation time-step, would give different results when the order of statement execution is changed, as permitted by the IEEE Verilog Standard.
简单地说:always
块可能以任意顺序执行,这可能导致竞争条件,从而导致意外行为。
要了解如何防止这种情况发生,了解阻塞赋值和非阻塞赋值之间的区别很重要。当您使用阻塞赋值 (=
) 时,右侧的计算(在您的代码 A
、B
和 D
中)和左侧的赋值-手边(在您的代码 Q
和 F
中)是在没有任何其他 Verilog 语句(即 "it happens immediately")中断的情况下完成的。但是,当使用非阻塞分配 (<=
) 时,左侧仅在时间步结束时更新。
正如您所想象的,后一种分配类型有助于防止竞争条件,因为您可以确定分配的左侧将在什么时候更新。
经过对此事的分析,Cummings 得出结论,i.a,如下:
Guideline #1: When modeling sequential logic, use nonblocking assignments.
Guideline #2: When modeling latches, use nonblocking assignments.
Guideline #3: When modeling combinational logic with an always block, use blocking assignments.
我想从上述论文中强调的最后一点是 "why"。除了您确定推断出正确的硬件这一事实外,它还有助于将预综合模拟与实际硬件的行为相关联:
But why? In general, the answer is simulation related. Ignoring the above guidelines [about using blocking or nonblocking assignments on page 2 of the paper] can still infer the correct synthesized logic, but the pre-synthesis simulation might not match the behavior of the synthesized circuit.
如果你想严格遵守 Verilog2001,这最后一点是不可能的,但如果你可以自由选择你的 Verilog 版本,请尝试使用 always_comb
组合逻辑和 always_latch
用于锁存器。这两个关键字都会自动推断出敏感度列表,工具更容易发现您是否真的编写了您打算设计的逻辑。
The always_latch
construct is identical to the always_comb
construct except that software tools should perform additional checks and warn if the behavior in an always_latch construct does not represent latched logic, whereas in an always_comb construct, tools should check and warn if the behavior does not represent combinational logic.
有了这些提示,您的逻辑将如下所示:
always_latch
begin
if (ENB)
Q <= D;
end
always_comb
begin
if (SEL)
F = A;
else
F = B;
end
当不完整地分配一个值时,我得到了一个锁存器。但是为什么我在下面的例子中得到了闩锁?我认为不需要 F
输出的锁存器,因为它是在 SEL
.
Verilog 代码:
always @ (ENB or D or A or B pr SEL)
if (ENB)
begin
Q=D;
if (SEL)
F=A;
else
F=B;
end
推断逻辑:
虽然它在 SEL
的所有值中定义,但并未在 ENB
的所有值中定义。如果 ENB = 0
,您的代码表示 Q
和 F
都应保留上一个循环的值。这也是在您链接的图像中推断出的:仅更新 Q
和 F
如果 ENB = 1
.
如果你想让Q
成为闩锁而F
不是,你可以这样做:
always @ (ENB or D or A or B or SEL)
begin
if (ENB)
Q=D;
if (SEL)
F=A;
else
F=B;
end
编辑:附加信息
正如评论中所指出的,我只展示了如何在不过多修改代码的情况下实现组合逻辑和锁存器。但是,有些事情可以做得更好。因此,非 TL;DR 版本:
- 虽然可以将组合逻辑和锁存器放在一个程序块中,但最好将它们分成两个块。您正在设计两种不同类型的硬件,因此最好在 Verilog 中将它们分开。
在对锁存器建模时使用非阻塞赋值而不是阻塞赋值。克利福德 E. 卡明斯 (Clifford E. Cummings) 写了一篇关于阻塞和非阻塞分配之间的区别以及为什么了解区别很重要的优秀论文。我还将使用这篇论文作为来源:Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!
首先,了解 Verilog 中的竞争条件是什么很重要 (Cummings):
A Verilog race condition occurs when two or more statements that are scheduled to execute in the same simulation time-step, would give different results when the order of statement execution is changed, as permitted by the IEEE Verilog Standard.
简单地说:
always
块可能以任意顺序执行,这可能导致竞争条件,从而导致意外行为。要了解如何防止这种情况发生,了解阻塞赋值和非阻塞赋值之间的区别很重要。当您使用阻塞赋值 (
=
) 时,右侧的计算(在您的代码A
、B
和D
中)和左侧的赋值-手边(在您的代码Q
和F
中)是在没有任何其他 Verilog 语句(即 "it happens immediately")中断的情况下完成的。但是,当使用非阻塞分配 (<=
) 时,左侧仅在时间步结束时更新。正如您所想象的,后一种分配类型有助于防止竞争条件,因为您可以确定分配的左侧将在什么时候更新。
经过对此事的分析,Cummings 得出结论,i.a,如下:
Guideline #1: When modeling sequential logic, use nonblocking assignments.
Guideline #2: When modeling latches, use nonblocking assignments.
Guideline #3: When modeling combinational logic with an always block, use blocking assignments.
我想从上述论文中强调的最后一点是 "why"。除了您确定推断出正确的硬件这一事实外,它还有助于将预综合模拟与实际硬件的行为相关联:
But why? In general, the answer is simulation related. Ignoring the above guidelines [about using blocking or nonblocking assignments on page 2 of the paper] can still infer the correct synthesized logic, but the pre-synthesis simulation might not match the behavior of the synthesized circuit.
如果你想严格遵守 Verilog2001,这最后一点是不可能的,但如果你可以自由选择你的 Verilog 版本,请尝试使用
always_comb
组合逻辑和always_latch
用于锁存器。这两个关键字都会自动推断出敏感度列表,工具更容易发现您是否真的编写了您打算设计的逻辑。The
always_latch
construct is identical to thealways_comb
construct except that software tools should perform additional checks and warn if the behavior in an always_latch construct does not represent latched logic, whereas in an always_comb construct, tools should check and warn if the behavior does not represent combinational logic.
有了这些提示,您的逻辑将如下所示:
always_latch
begin
if (ENB)
Q <= D;
end
always_comb
begin
if (SEL)
F = A;
else
F = B;
end