如果敏感列表中的变量缺失,将创建什么逻辑
What logic will be created if variables in the sensitivity list are missing
这是美国前10大公司问的面试问题。
代码 1:
always @(a or b or sel) begin
if (sel == 1)
c = a;
else if (sel == 0)
c =b;
end
这将创建一个多路复用器。
代码 2:现在“SEL”已从灵敏度中删除。它还会创建 mux 吗?
对于下面的代码?如果没有,将创建什么逻辑?
always @(a or b) begin
if (sel == 1)
c = a;
else if (sel == 0)
c =b;
end
是的,这仍然会合成一个多路复用器1。综合工具会将此 RTL 解释为敏感性列表已完成。
但是,这里出现了一个大问题,因为与门级 simulations/the 实际硅片相比,您会在 RTL 模拟中看到不同的行为。在您的 RTL 模拟中,如果 a
或 b
发生变化,c
将 仅发生 变化。如果只有多路复用器的 select 信号 sel
发生变化,您的输出 c
在 RTL 模拟中不会发生变化。
当打算创建组合逻辑时,通常建议使用
always @(*)
或
always_comb
如果你可以使用 SystemVerilog。这样做的好处是您永远不会 运行 进入与敏感度列表相关的 simulation/synthesis 不匹配。后一个关键字还有一个优点,即您可以明确地告诉工具您想要创建组合逻辑(而不是意外的闩锁,例如)。
最后:Mills & Cummings 在 RTL Coding Styles That Yield Simulation and Synthesis Mismatches 上写了一篇很棒的论文。此处很好地描述了这个问题以及许多其他问题。我强烈建议您看看这篇论文!
奖励:X 传播和模拟与实际硅不匹配
正如您在评论中指出的那样,您想知道 sel === 1'bx
会发生什么。为了更好地理解这件事,我强烈推荐阅读 Stuart Sutherland 的 I'm Still In Love With My X!。我将在这里对您的特定示例进行非常简短的总结。
SystemVerilog中的条件块容易出现X-optimism,在上述论文中定义为:
X-optimism has been defined [...] as any time simulation converts an X value on the input to an operation or logic gate into a 0 or 1 on the output. [...] SystemVerilog can be overly optimistic, meaning an X propagates as a 0 or 1 in simulation when actual silicon is still ambiguous.
在查看您的代码时,我们会发现 sel === 1'bx
将 不会 传播到 c
。相反,模拟器将保留 c
的先前值并模拟一个锁存器。这是对 X 过于乐观并且是与实际硅的模拟不匹配,因为 select 线在这里不会是 X:信号是 1 或 0。换句话说,这将 不是 成为硅中的锁存器!
一个解决方案可能是在仿真中使多路复用器 X 悲观,这样我们就可以检测到这个未确定的状态。为此,当 sel
既不是 0 也不是 1 时,我们将 X 分配给 c
:
always_comb
if (sel)
c = a;
else if (!sel)
c = b;
`ifndef SYNTHESIS // see footnote 2
else
c = 'x;
`endif
然而,这有一个问题,那就是它过于悲观了。当 a
和 b
具有相同的值时,我们将明确知道 c
在实际硅片中的值是多少(无论 sel
的值如何)。
上述论文给出了条件运算符(? :
)作为可能的解决方案:
condition ? expression1 : expression2;
If the condition evaluates to unknown, the operator does a bit-by-bit comparison of the values of expression1 and expression2. For each bit position, if that bit is 0 in both expressions, then a 0 is returned for that bit. If both bits are 1, a 1 is returned. If the corresponding bits in each expression are different, or Z, or X, then an X is returned for that bit
因此,通过使用下面的代码,我们可以在上述两种解决方案之间做出折衷:
always_comb
c = sel ? a : b;
这里的缺点是条件运算符不适合更复杂的表达式。
总结的三种方法:
╭───────────╥─────────────────────────────────────────────────╮
│ input ║ sel(t) │
├───╥───╥───╫────────────┬─────────────┬────────────┬─────────┤
│sel║ a ║ b ║ optimistic │ pessimistic │ compromise │ silicon │
╞═══╬═══╬═══╬════════════╪═════════════╡════════════╪═════════╡
│ X ║ 0 ║ 0 ║ sel(t-1) │ X │ 0 │ 0 │
│ X ║ 0 ║ 1 ║ sel(t-1) │ X │ X │ 0/1 │
│ X ║ 1 ║ 0 ║ sel(t-1) │ X │ X │ 0/1 │
│ X ║ 1 ║ 1 ║ sel(t-1) │ X │ 1 │ 1 │
└───╨───╨───╨────────────┴─────────────┘────────────┴─────────┘
Sutherland 在他的论文中给出了另一个我同意的解决方案:最好使用断言来检测导致 X 的设计问题,而不是让 X 在设计中传播并花费大量时间寻找根本原因.对于您的特定代码,这可能如下所示:
always_comb
begin
assert (!$isknown(sel))
else $error("sel = X!");
if (sel)
c = a;
else if (!sel)
c = b;
end
1:我这里假设sel
是1位信号。否则,你最终会得到一个 latch
2: 有关 SYNTHESIS
宏标识符的更多信息。
这是美国前10大公司问的面试问题。
代码 1:
always @(a or b or sel) begin
if (sel == 1)
c = a;
else if (sel == 0)
c =b;
end
这将创建一个多路复用器。
代码 2:现在“SEL”已从灵敏度中删除。它还会创建 mux 吗? 对于下面的代码?如果没有,将创建什么逻辑?
always @(a or b) begin
if (sel == 1)
c = a;
else if (sel == 0)
c =b;
end
是的,这仍然会合成一个多路复用器1。综合工具会将此 RTL 解释为敏感性列表已完成。
但是,这里出现了一个大问题,因为与门级 simulations/the 实际硅片相比,您会在 RTL 模拟中看到不同的行为。在您的 RTL 模拟中,如果 a
或 b
发生变化,c
将 仅发生 变化。如果只有多路复用器的 select 信号 sel
发生变化,您的输出 c
在 RTL 模拟中不会发生变化。
当打算创建组合逻辑时,通常建议使用
always @(*)
或
always_comb
如果你可以使用 SystemVerilog。这样做的好处是您永远不会 运行 进入与敏感度列表相关的 simulation/synthesis 不匹配。后一个关键字还有一个优点,即您可以明确地告诉工具您想要创建组合逻辑(而不是意外的闩锁,例如)。
最后:Mills & Cummings 在 RTL Coding Styles That Yield Simulation and Synthesis Mismatches 上写了一篇很棒的论文。此处很好地描述了这个问题以及许多其他问题。我强烈建议您看看这篇论文!
奖励:X 传播和模拟与实际硅不匹配
正如您在评论中指出的那样,您想知道 sel === 1'bx
会发生什么。为了更好地理解这件事,我强烈推荐阅读 Stuart Sutherland 的 I'm Still In Love With My X!。我将在这里对您的特定示例进行非常简短的总结。
SystemVerilog中的条件块容易出现X-optimism,在上述论文中定义为:
X-optimism has been defined [...] as any time simulation converts an X value on the input to an operation or logic gate into a 0 or 1 on the output. [...] SystemVerilog can be overly optimistic, meaning an X propagates as a 0 or 1 in simulation when actual silicon is still ambiguous.
在查看您的代码时,我们会发现 sel === 1'bx
将 不会 传播到 c
。相反,模拟器将保留 c
的先前值并模拟一个锁存器。这是对 X 过于乐观并且是与实际硅的模拟不匹配,因为 select 线在这里不会是 X:信号是 1 或 0。换句话说,这将 不是 成为硅中的锁存器!
一个解决方案可能是在仿真中使多路复用器 X 悲观,这样我们就可以检测到这个未确定的状态。为此,当 sel
既不是 0 也不是 1 时,我们将 X 分配给 c
:
always_comb
if (sel)
c = a;
else if (!sel)
c = b;
`ifndef SYNTHESIS // see footnote 2
else
c = 'x;
`endif
然而,这有一个问题,那就是它过于悲观了。当 a
和 b
具有相同的值时,我们将明确知道 c
在实际硅片中的值是多少(无论 sel
的值如何)。
上述论文给出了条件运算符(? :
)作为可能的解决方案:
condition ? expression1 : expression2;
If the condition evaluates to unknown, the operator does a bit-by-bit comparison of the values of expression1 and expression2. For each bit position, if that bit is 0 in both expressions, then a 0 is returned for that bit. If both bits are 1, a 1 is returned. If the corresponding bits in each expression are different, or Z, or X, then an X is returned for that bit
因此,通过使用下面的代码,我们可以在上述两种解决方案之间做出折衷:
always_comb
c = sel ? a : b;
这里的缺点是条件运算符不适合更复杂的表达式。
总结的三种方法:
╭───────────╥─────────────────────────────────────────────────╮
│ input ║ sel(t) │
├───╥───╥───╫────────────┬─────────────┬────────────┬─────────┤
│sel║ a ║ b ║ optimistic │ pessimistic │ compromise │ silicon │
╞═══╬═══╬═══╬════════════╪═════════════╡════════════╪═════════╡
│ X ║ 0 ║ 0 ║ sel(t-1) │ X │ 0 │ 0 │
│ X ║ 0 ║ 1 ║ sel(t-1) │ X │ X │ 0/1 │
│ X ║ 1 ║ 0 ║ sel(t-1) │ X │ X │ 0/1 │
│ X ║ 1 ║ 1 ║ sel(t-1) │ X │ 1 │ 1 │
└───╨───╨───╨────────────┴─────────────┘────────────┴─────────┘
Sutherland 在他的论文中给出了另一个我同意的解决方案:最好使用断言来检测导致 X 的设计问题,而不是让 X 在设计中传播并花费大量时间寻找根本原因.对于您的特定代码,这可能如下所示:
always_comb
begin
assert (!$isknown(sel))
else $error("sel = X!");
if (sel)
c = a;
else if (!sel)
c = b;
end
1:我这里假设sel
是1位信号。否则,你最终会得到一个 latch
2: SYNTHESIS
宏标识符的更多信息。