如果敏感列表中的变量缺失,将创建什么逻辑

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 模拟中,如果 ab 发生变化,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

然而,这有一个问题,那就是它过于悲观了。当 ab 具有相同的值时,我们将明确知道 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 宏标识符的更多信息。