← RTL Design Interviews

Interview Question · Debug

RTL Passes, Gate-Level Simulation Fails

L1 JuniorL2 Mid-LevelL3 Seniorsimulation synthesis mismatchdebuggate level
  • Likely at Arm

The Question

The interviewer asks

All 412 RTL tests pass. Zero-delay gate-level simulation fails three. Here is the summary. Where do you look first?

log
RTL regression (zero delay):   412 tests, 412 pass
Gate-level, zero delay:        412 tests, 3 fail
  tst_scale_mode  @ 1240 ns: y = 4'd6, expected 4'd3 ... (gates)  RTL showed 4'd3
  tst_boot        @   80 ns: cnt = 4'bxxxx            ... (gates)  RTL showed 4'd0
  tst_err_inject  @ 2210 ns: grant = 2'bxx            ... (gates)  RTL showed 2'd0
Reveal the Model Answer

Zero delay rules out timing, so these are mismatches between RTL and netlist. A wrong value where RTL was right points to a sensitivity problem, such as always @* with a function. An X in gates where RTL showed 0 points to a missing reset. Either an inline initializer acted as the reset, or X optimism hid an unreset flop. Fix the RTL, not the netlist.

Three Tools Read the Same ListArrows show what each tool does with always @(a or b).
Three tools read the same listArrows show what each tool does with `always @(a or b)`. component always @(a or b) reads a, b and sel component Simulators Icarus 12, Verilator5.052 component Lint Verilator -Wall component Synthesizer Yosys 0.70, slang component Stale y edges 3, 4 and 6 component 8 MUX + 8 flops the full choice obey the listno messagetreats it as @*runnetlist
  1. Simulation

    Both simulators obey the list, so y is stale whenever sel changes alone.

  2. Lint

    Lint reads the block and prints nothing at all about the list.

  3. Synthesis

    The synthesizer warns non-edge sensitivity on a signal will be synthesized as @* sensitivity and builds the full mux. It gives that warning for a complete list too.

Read the diagram as text
  • always @(a or b): reads a, b and sel
  • Simulators: Icarus 12, Verilator 5.052
  • Lint: Verilator -Wall
  • Synthesizer: Yosys 0.70, slang
  • Stale y: edges 3, 4 and 6
  • 8 MUX + 8 flops: the full choice
  • always @(a or b) → Simulators: obey the list
  • always @(a or b) → Lint: no message
  • always @(a or b) → Synthesizer: treats it as @*
  • Simulators → Stale y: run
  • Synthesizer → 8 MUX + 8 flops: netlist

Measured in lesson R7.4: the simulators obey a short sensitivity list, but synthesis builds the full mux. That is one way RTL and gates disagree.

Self-Check

Tick each key point you covered in your answer.

What Interviewers Listen For (Junior)

A good junior answer notes that zero delay rules out timing. It maps each failing line to a likely RTL construct.

Cross-Questions

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

WhyWhat IfProve ItBreak ItCompare

  1. RTL Passes, Gate-Level Simulation Fails
  2. WhyWhy One Simulator Did Not Show the MismatchL2 Mid-Level

    A colleague reruns the always @* test on Verilator and it passes. Why might one simulator hide the mismatch?

    Reveal the Model Answer

    Verilator does not follow every event rule of the standard. On this example it recomputed y as plain logic, so it printed 6. Icarus follows the @* rule and keeps 3. A design whose result depends on the simulator is depending on code the gates do not have. Fix the code.

    Self-Check

    Tick each key point you covered in your answer.

    Tool as Truth

    "Verilator passes, so the RTL matches the gates."

    Here Verilator happens to agree with the gates. Another team's event-driven simulator will not, and the code still has the mismatch.

    Source Measured: the root twin on Verilator: y=6, Verilator 5.052

  3. CompareLint vs Gate-Level Simulation for MismatchesL2 Mid-LevelL3 Senior

    Compare lint with gate-level simulation as ways to catch simulation-synthesis mismatches.

    Reveal the Model Answer

    Lint reads the RTL and flags risky constructs, such as short sensitivity lists, inline initializers and blocking writes in clocked blocks. It runs in seconds and needs no test. Gate-level simulation finds a mismatch only when a test exercises it, and it runs slowly. Use lint as the gate on every commit, and a small gate-level set as the net.

    Self-Check

    Tick each key point you covered in your answer.

    Half-Truth

    "Lint is clean, so gate-level simulation is not needed."

    Lint finds patterns it knows. Some mismatches, such as X behaviour in reset paths, show only when a real netlist runs a real test.

    Source Sutherland, RTL Modeling with SystemVerilog (2017) ch. 1.7 SystemVerilog lint checkers

  4. Break ItWhat Zero-Delay Gate Simulation MissesL3 Senior

    How can a design pass both RTL and zero-delay gate-level simulation and still fail in silicon?

    Reveal the Model Answer

    Zero-delay gates still have no setup or hold time, so metastability and clock crossings look perfect. Real timing faults need static timing analysis, not simulation. Power-up values and analog effects are absent too. Gate simulation catches netlist mismatches, not the physics.

    Self-Check

    Tick each key point you covered in your answer.

    What Interviewers Listen For (Senior)

    A good senior answer lists what each sign-off step proves and what it cannot. It covers simulation, equivalence, static timing and CDC analysis.

    Half-Truth

    "Gate-level sim with SDF covers all timing."

    It checks only the paths and cases your tests happen to exercise. Static timing analysis checks every path in every corner.

    Source Sutherland, RTL Modeling with SystemVerilog (2017) ch. 8.1.6 Multiple clocks and clock domain crossing

  5. What IfSimulation-Only Code Inside RTLL1 JuniorL2 Mid-Level

    What if the RTL also contains $display calls and checks? How do they behave in synthesis?

    Reveal the Model Answer

    Synthesis cannot build a print or a check as logic. Tools ignore such code, reject it, or keep it as a cell with no output. Wrap simulation-only code in translate_off and translate_on pragmas, or in an ifndef SYNTHESIS guard. Then synthesis sees exactly the design.

    Self-Check

    Tick each key point you covered in your answer.

    Half-Truth

    "A $display in the RTL changes nothing in the gates."

    Usually true, but a check written around a design signal can keep extra logic alive or confuse a tool. Guard it so the netlist is predictable.

    Source Sutherland, RTL Modeling with SystemVerilog (2017) ch. 2.2 SystemVerilog language rules (synthesis pragmas)

  6. Prove ItSolve R1.3.1: The Decoder That RememberedSimulator-graded

    Show it, don't just say it: this Silicon Lab problem is graded by the simulator.

    Open Problem R1.3.1

What People Get Wrong

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

Misconception

"always @* wakes on everything the block reads."

It misses signals read inside a called function. The twin keeps y=3 after shift_en changes, like the first failing test.

Run It

A function that reads shift_en, called from always @*, then from always_comb. Both synthesize to the same 4 cells.

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
See the Fix
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_comb 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("PASS: always_comb also wakes on signals read inside the function");
  end
endmodule

Prints: a=3, shift_en=1: y=6 PASS: always_comb also wakes on signals read inside the function

Misconception

"logic [3:0] cnt = 0; resets the counter."

An inline initializer sets the value once at simulation start. ASIC flops power up unknown, so the gates show X, as in the second failing test.

Source Sutherland, RTL Modeling with SystemVerilog (2017) ch. 3.4 Variable types, Best Practice Guidelines 3-5 and 3-6

Half-Truth

"Gate-level failures are timing problems. Check the SDF."

This run has zero delay, so there is no timing to blame. These are RTL constructs that simulate differently from what synthesis built.

Source Sutherland, RTL Modeling with SystemVerilog (2017) ch. appendix C.3 An optimistic X

Delivery

Opens the netlist first and starts tracing gates.

The fast path is the RTL construct behind each failure. Gate tracing is the last resort, after the likely RTL causes are ruled out.

Learn It, Then Prove It