← RTL Design Interviews

Interview Question · Code Reading

The Mux with a Short Sensitivity List

L1 JuniorL2 Mid-Levelsimulation synthesis mismatchcombinational logic

The Question

The interviewer asks

What does simulation show when sel changes here? What does synthesis build?

systemverilog
module mux2 (input logic a, b, sel, output logic y);
  always @(a or b)
    y = sel ? b : a;
endmodule
Reveal the Model Answer

Simulation re-runs the block only when a or b changes. So when only sel changes, y stays stale. Synthesis builds logic from the expression, not from the list, so it gives a plain 2:1 mux. The RTL simulation now shows behaviour the chip does not have. Use always_comb, which wakes on every signal the block reads.

Two Spellings, Two Simulations, One NetlistThe lab bench, 1 ns after edges 2 to 7. y (old) is the Verilog-2001 block with always @(a or b); y (new) is its translation with always_comb.
012345clksela1133b2244y (old)112233y (new)112233stalestalestale
  1. Cycle 0

    Edge 2: a and b changed, so the old block ran. Both versions show 11.

  2. Cycle 1

    Edge 3: only sel changed. The old block never woke, so y still shows a; the new one shows 22.

  3. Cycle 3

    Edge 5: a changed, the old block woke at last, and now shows b, two edges late.

  4. Cycle 4

    Edge 6: sel alone again, and the old y is stale again.

Icarus 12 and Verilator 5.052 print the same old lines. Synthesize builds 16 cells for both versions.

The snippet on the pinned Yosys flow: one mux cell, no latch.

module mux2 (input logic a, b, sel, output logic y);
  always @(a or b)
    y = sel ? b : a;
endmodule

Self-Check

Tick each key point you covered in your answer.

What Interviewers Listen For (Junior)

A good junior answer says y goes stale when only sel changes, while the netlist is a full mux. It names this as a mismatch between simulation and synthesis.

Cross-Questions

Where the interviewer goes next. Open a node to practise that follow-up.

WhyWhat IfCompareScale It

  1. The Mux with a Short Sensitivity List
  2. WhyWhy Synthesis Ignores the Sensitivity ListL1 Junior

    Why does synthesis build a full mux when the list leaves sel out?

    Reveal the Model Answer

    Gates have no event list. A gate output follows its inputs all the time. Synthesis reads the assignments to learn the function, and the function of sel ? b : a is a mux. A sensitivity list only tells a simulator when to re-run the code.

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "The sensitivity list tells synthesis which inputs to connect."

    The inputs come from the expressions in the block. A signal used in the block but left out of the list is still wired in.

    Source Sutherland, RTL Modeling with SystemVerilog (2017) ch. 7.2 The always and always_comb procedures

  3. What IfAn Extra Signal in the Sensitivity ListL1 Junior

    What if the list has an extra signal that the block never reads?

    Reveal the Model Answer

    The block runs more often than needed, which costs a little simulation time. Each run computes the same value, so the output never goes stale. There is no mismatch with the gates. The real danger is always a missing signal, never an extra one.

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "An extra signal adds an input to the gates."

    Synthesis wires only signals the assignments use. An unread signal in the list connects to nothing.

    Source Sutherland, RTL Modeling with SystemVerilog (2017) ch. 7.2 The always and always_comb procedures

  4. CompareAlways @* vs Always_combL1 JuniorL2 Mid-Level

    Compare always @* with always_comb. Here the block calls a function that reads shift_en. What does Icarus print?

    systemverilog
    module scale (input logic [3:0] a, input logic shift_en, output logic [3:0] y);
      function automatic logic [3:0] f(input logic [3:0] x);
        return shift_en ? x << 1 : x;    // reads shift_en, which is not an argument
      endfunction
      always @*   y = f(a);
    endmodule
    module tb;
      logic [3:0] a = 4'd2, y; logic shift_en = 0;
      scale dut (.a(a), .shift_en(shift_en), .y(y));
      initial begin
        #1 a = 4'd3;                  // y = 3
        #1 shift_en = 1; #1;          // y should become 6
        $display("a=3, shift_en=1: y=%0d", y);
        if (y !== 4'd6) $display("FAIL: always @* did not wake on shift_en, which is read only inside the function");
      end
    endmodule
    
    Reveal the Model Answer

    Icarus prints y=3 and the FAIL line. always @* waits only on what the block names, including function arguments, and shift_en is read inside the function. always_comb also waits on signals read inside called functions, so it gives 6. It also runs once at time zero, and it forbids other writers.

    RUNIcarus Verilog · in your browser
    Edit the code, then run it
    Expected: a=3, shift_en=1: y=3 FAIL: always @* did not wake on shift_en, which is read only inside the function

    Self-Check

    Tick each key point you covered in your answer.

    Tool as Truth

    "Verilator gives 6, so always @* is fine."

    Verilator updated y here, but Icarus follows the event rule and keeps 3. One tool's result does not make the code correct.

    Source Measured: the snippet on both tools: Verilator printed y=6, Icarus Verilog 12; Verilator 5.052

  5. Scale ItFixing Sensitivity Lists in Legacy RTLL2 Mid-LevelL3 Senior

    You own a legacy Verilog-2001 IP with hundreds of hand-written sensitivity lists. How do you remove this class of bug safely?

    Reveal the Model Answer

    Run lint to list every incomplete sensitivity list. Convert combinational blocks to always_comb, which also checks for latches and second writers. Re-run the full regression, because a fixed list can change what the old tests saw. Then run an equivalence check of the old netlist against the new one, which should match.

    Self-Check

    Tick each key point you covered in your answer.

    What Interviewers Listen For (Senior)

    A good senior answer plans the change as a risk. It takes a lint inventory and converts the blocks mechanically. Then regression and an equivalence check prove the netlist did not change.

    Wrong Altitude

    "Replace each list with @* and ship it."

    @* misses signals read inside functions, as the always @* question shows. And without a regression and an equivalence check, you cannot show nothing broke.

What People Get Wrong

Common wrong answers and why they fail. Run It shows the wrong belief failing on a real simulator.

Misconception

"If the RTL simulation passes, the gates do the same thing."

The list controls simulation only. In the twin, simulation keeps y at 0 after sel rises, while the netlist is the same one-mux circuit as the fix.

Run It

The snippet with a bench, then always_comb. Both synthesize to the same single mux.

RUNIcarus Verilog · in your browser
Edit the code, then run it
Expected: sel=1, a=0, b=1: y=0 FAIL: simulation is not the gates; y stayed stale because sel is not in the list
See the Fix
module mux2 (input logic a, b, sel, output logic y);
  always_comb
    y = sel ? b : a;
endmodule
module tb;
  logic a = 1, b = 1, sel = 0, y;
  mux2 dut (.a(a), .b(b), .sel(sel), .y(y));
  initial begin
    #1 a = 0;                     // y follows a: 0
    #1 sel = 1; #1;               // y should now follow b: 1
    $display("sel=1, a=0, b=1: y=%b", y);
    if (y !== 1'b1) $display("FAIL: simulation is not the gates; y stayed stale because sel is not in the list");
    else $display("PASS: y follows sel");
  end
endmodule

Prints: sel=1, a=0, b=1: y=1 PASS: y follows sel

Tool as Truth

"Synthesis would reject a wrong sensitivity list."

Many synthesizers build the full logic and at most warn. A clean synthesis run says nothing about what your simulation showed.

Source Sutherland, RTL Modeling with SystemVerilog (2017) ch. 7.2 The always and always_comb procedures

Misconception

"The stale output means synthesis builds a latch."

Nothing in the code holds a value on a path; the hold comes only from the simulator not waking. The run shows one mux and zero latches.

Source Measured: the run on this question, Yosys 0.70+290 (OSS CAD Suite 2026-11-02), slang front end, synth -flatten with ABC, ltp -noff

Learn It, Then Prove It