What logic will be created if variables in the sensitivity list are missing

前端 未结 1 1496
借酒劲吻你
借酒劲吻你 2021-01-27 10:58

This was an interview question asked by a top 10 company of US.

Code 1:

always @(a or b or sel) begin 
  if (sel == 1)
  c = a; 
  else if (sel == 0) 
  c          


        
相关标签:
1条回答
  • 2021-01-27 11:38

    Yes, this will still synthesize to a multiplexer1. A synthesis tool will interpret this RTL as if the sensitivity list were complete.

    However, a large issue here arises because you will see different behaviour in your RTL simulations compared to the gate-level simulations/the actual silicon. In your RTL simulation, c will only change if a or b change. If only the select-signal sel of the multiplexer changes, your output c will not change in RTL simulations.

    When intending to create combinatorial logic, it is generally advisable to use

    always @(*)
    

    or

    always_comb
    

    if you can use SystemVerilog. This has the advantage that you never run into sensitivity-list related simulation/synthesis mismatches. The latter keyword furthermore has the advantage that you explicitly tell tools that you want to create combinatorial logic (rather than unintended latches, for example).

    Finally: Mills & Cummings wrote a great paper on RTL Coding Styles That Yield Simulation and Synthesis Mismatches. This issue, among many others, is described here very well. I can greatly recommend to take a look at this paper!


    Bonus: X-Propagation and simulation mismatches with actual silicon

    As you indicated in your comment, you were wondering what would happen is sel === 1'bx. To better understand this matter, I highly recommend reading I'm Still In Love With My X! by Stuart Sutherland. I will give a very brief summary on your particular example here.

    Conditional blocks in SystemVerilog are prone to X-optimism, which is defined in the aforementioned paper as:

    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.

    When looking at your code, we will see that an sel === 1'bx will not propagate to c. Rather, the simulator will hold the previous value of c and mimic a latch. This is overly X-optimistic and is a simulation mismatch with actual silicon, since the select line will not be X here: a signal is either 1 or 0. In other words, this will not be a latch in silicon!

    One solution could be to make the multiplexer X-pessimistic in simulation, so that we would detect this undetermined state. To do so, we assign X to c when sel is neither 0, nor 1:

    always_comb
        if (sel)
            c = a; 
        else if (!sel) 
            c = b; 
    `ifndef SYNTHESIS // see footnote 2
        else
            c = 'x;
    `endif
    

    This has the problem, however, that it is overly pessimistic. When both a and b have the same value, we would unambiguously know what value c would have in actual silicon (regardless of the value of sel).

    The aformentioned paper gives the conditional operator (? :) as a possible solution:

    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

    So, by using the code below, we would have a compromise between the two aforementioned solutions:

    always_comb
        c = sel ? a : b;
    

    The downside here is that the conditional operator is not suited for more complex expressions.

    The three approaches summarized:

    ╭───────────╥─────────────────────────────────────────────────╮      
    │   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    │
    └───╨───╨───╨────────────┴─────────────┘────────────┴─────────┘
    

    In his paper, Sutherland gives another solution with which I agree: It is best to use assertions to detect design issues which cause X, instead of letting X propagate through the design and spending a lot of time finding the root cause. For your particular code, this could look like this:

    always_comb
    begin
        assert (!$isknown(sel))
        else $error("sel = X!");
    
        if (sel)
            c = a; 
        else if (!sel) 
            c = b; 
     end
    

    1: I assume here that sel is a 1-bit signal. Otherwise, you would end up with a latch

    2: See my answer here for some more information on the SYNTHESIS macro identifier.

    0 讨论(0)
提交回复
热议问题