Skip to content

GLS · Chapter 5 · GLS Testbench Adaptation

Why an RTL Testbench Breaks on the Netlist

A testbench that passes clean on RTL often breaks the moment you point it at the gate-level netlist, and the reasons are systematic rather than mysterious. An RTL testbench quietly assumes that internal signals are visible by name, that everything happens at the clock edge with zero delay, and that flops start initialized. The netlist honors none of those. Synthesis renames and flattens internal signals, real cell and net delays mean outputs settle after the edge, and gate-level flops power up unknown. None of these is a netlist bug; they are RTL-only assumptions the testbench must shed. This lesson catalogs why the RTL testbench breaks, shows an edge-aligned sample racing the clock-to-Q transition, and frames the fix as adapting the testbench rather than blaming the netlist.

Foundation12 min readGLSTestbenchNetlistTimingX

Chapter 5 · Section 5.1 · GLS Testbench Adaptation

Project thread — the counter carried Chapters 2–4. Chapter 5 introduces an FSM (a small controller) as the next design; 5.5 adapts its testbench end to end. Here we diagnose why the RTL testbench breaks at all.

1. Why Should I Learn This?

A testbench that "passes on RTL, fails on the netlist" is one of the most common GLS surprises — and usually the testbench, not the netlist, is at fault.

  • Internal references break or mis-read after synthesis renames signals.
  • Edge-aligned drive/sample races real delays.
  • Netlist flops power up X, so uninitialized assumptions surface.

Knowing these failure modes tells you what to adapt (5.2–5.4) rather than distrusting a correct netlist.

2. Real Silicon Story — the testbench that "found a netlist bug"

A team ran their trusted RTL testbench on the netlist. It reported the DUT producing X and wrong values — they filed it as a synthesis bug.

There was no synthesis bug. The testbench sampled outputs at the clock edge, before real clk-to-Q delay had settled (reading the old value), and it referenced dut.state — a signal synthesis had encoded into flops and renamed — reading X. Both were RTL-only assumptions meeting a timed, renamed netlist. Once the testbench sampled after settling and referenced ports (5.2–5.4), the "bug" vanished.

Lesson: an RTL testbench encodes assumptions (visible internals, zero-delay edges, initialized flops) the netlist doesn't honour. A pass-on-RTL/fail-on-netlist result usually means adapt the testbench, not blame the netlist.

3. Concept — the four RTL assumptions the netlist breaks

(1) Internal signal visibility.

  • RTL: dut.state, dut.count exist by name.
  • Netlist: synthesis flattens/renames internals — state becomes q_reg[*]; many nets vanish or are renamed.
  • Result: hierarchical references break or read the wrong/X value (5.2).

(2) Zero-delay timing.

  • RTL: drive and sample at the edge — everything is instantaneous.
  • Netlist: real clk-to-Q + path + net delays — outputs settle after the edge.
  • Result: edge-aligned sampling races the transition; edge-aligned driving can violate the DUT's setup/hold (5.3/5.4).

(3) Initialization.

  • RTL: flops may hold initial values / behavioural resets.
  • Netlist: gate-level flops power up X (no initial); only reset clears them (2.6).
  • Result: X propagates until reset is applied — the testbench must reset properly.

(4) Ordering / glitches.

  • #0/delta-cycle races and glitch-free assumptions from zero delay no longer hold under real delays.

Scope: these are testbench issues — adapting the TB lets real behaviour (including real timing bugs) show correctly; it does not "fix" timing, and GLS remains dynamic (STA signs off, 0.3).

RTL testbench assumptions vs netlist reality: internal visibility, zero-delay edge timing, initialization, orderingdrives5.25.3/5.4resetInternal visibilityRTL: dut.state -> netlist:renamed to q_reg[*]Zero-delay timingRTL: edge -> netlist:clk-to-Q settles AFTER edgeInitializationRTL: initialized ->netlist: flops power up XRTL testbenchmade these assumptionsGate-level netlisthonours none of themAdapt the TB5.2 refs · 5.3 stimulus ·5.4 checkers12
Figure 1 — the four RTL testbench assumptions the netlist breaks (representative). An RTL testbench assumes internal signals are visible by name, that drive/sample happen at the clock edge with zero delay, and that flops start initialized. The netlist renames/flattens internals (state -> q_reg[*]), adds real clk-to-Q and net delays (so outputs settle AFTER the edge), and powers flops up X. These are testbench assumptions, not netlist bugs — the fix is to adapt the testbench (5.2 references, 5.3 stimulus, 5.4 checkers).

4. Mental Model — the RTL testbench speaks a dialect the netlist doesn't

An RTL testbench speaks RTL dialect: "I can see any inner signal, everything happens on the tick, and flops know their value." The netlist speaks gate dialect: "inner names changed, transitions take time, and I wake up not knowing anything."

  • The two dialects overlap on the ports — that's the reliable common ground.
  • They diverge on internals, timing, and initialization.
  • Adapting the testbench is translating it into gate dialect: talk through ports, respect delays, apply reset.

A "netlist bug" report is often just a translation error.

5. Working Example — an RTL-only testbench and where it breaks

A representative RTL testbench with the classic assumptions:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// RTL-only testbench — REPRESENTATIVE. Works on RTL, BREAKS on the netlist.
module tb_dut;
  logic clk = 0, rst_n; logic [3:0] out;
  dut u_dut (.clk(clk), .rst_n(rst_n), .out(out));
  always #5 clk = ~clk;
 
  initial begin
    // (3) assumes flops start known — no proper reset sequence
    @(posedge clk) drive_inputs();       // (2) drives AT the edge -> races clk-to-Q
    // (1) references an INTERNAL signal that synthesis renames/removes
    if (u_dut.state != EXPECTED) $error("bad state");
    // (2) samples AT the edge -> reads pre-transition value in a timed netlist
    @(posedge clk) if (out != golden) $error("mismatch");
  end
endmodule

Practical context (representative, tool-neutral):

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
# Same testbench, two DUTs:
tb_dut + rtl/dut.v         -> PASS   (internals visible, zero-delay, flops init)
tb_dut + netlist/dut.vg + sdf  -> FAIL   (renamed internals, real delays, X at power-up)
# The DELTA between these two runs is the list of RTL assumptions to fix (5.2-5.4).

An edge-aligned sample racing clk-to-Q, as a real waveform:

Edge-aligned sampling races clk-to-Q: the checker reads the OLD value in a timed netlist

8 cycles
At the clock edge the output has not yet updated due to clk-to-Q delay, so a sample at the edge reads the previous valuesample here → RTL sees 3, netlist sees 0sample here → RTL sees…clkout (RTL)out (netlist)t0t1t2t3t4t5t6t7
Representative. In RTL (zero-delay) out updates exactly at the edge, so sampling at the edge is fine. In the timed netlist, out updates a clk-to-Q delay AFTER the edge — so a checker that samples AT the edge reads the previous value and reports a false mismatch. The fix is to sample after settling (5.4).

6. Debugging Session — "the netlist is buggy" (it is the testbench)

1

An RTL testbench passes on RTL but reports X and mismatches on the netlist, and is filed as a synthesis bug — but it references renamed internal signals and samples at the clock edge before clk-to-Q settles, both RTL-only assumptions the netlist does not honour

PASS-ON-RTL / FAIL-ON-NETLIST = ADAPT THE TB
Symptom

A trusted RTL testbench passes on RTL but, on the netlist, reports X on an internal reference and output mismatches. It is filed as a synthesis/netlist bug.

Root Cause

RTL-only assumptions meeting the netlist, not a netlist defect. The X/wrong internal read comes from referencing a signal (dut.state) that synthesis renamed and encoded into flops (5.2) — the old name no longer denotes what the testbench thinks. The output mismatches come from sampling at the clock edge, before real clk-to-Q delay has settled, so the checker reads the previous value (5.4); edge-aligned driving can likewise violate the DUT's setup/hold in a timed run (5.3). And any pre-reset comparison reads the flops' power-up X (5.1(3)). Each is the testbench assuming RTL semantics the gate-level netlist does not provide — the netlist is behaving correctly.

Fix

Adapt the testbench (the rest of this chapter): reference ports (or use bind/preserved signals, 5.2); drive stimulus clear of the clock edge (5.3); sample on a strobe after settling (5.4); and apply a proper reset before comparing (handling power-up X). The lesson: a pass-on-RTL/fail-on-netlist result usually means the testbench carries RTL-only assumptions — visible internals, zero-delay edges, initialized flops — that the netlist doesn't honour; adapt the testbench, don't blame the netlist. (Adapting the TB lets real behaviour show correctly — it doesn't fix timing, and GLS stays dynamic; STA is signoff, 0.3.)

7. Common Mistakes

  • Blaming the netlist for a TB assumption. Pass-on-RTL/fail-on-netlist usually means adapt the TB.
  • Referencing internal signals by RTL name. Synthesis renames/flattens them (5.2).
  • Driving/sampling at the clock edge. Races real clk-to-Q delay (5.3/5.4).
  • Skipping a proper reset. Netlist flops power up X (2.6).
  • Assuming adapting the TB "fixes timing." It reveals real behaviour; STA signs off (0.3).

8. Industry Best Practices

  • Diff RTL vs netlist runs to separate DUT issues from TB assumptions.
  • Talk through ports on the netlist; treat internal refs as fragile (5.2).
  • Make stimulus and checkers timing-aware (5.3/5.4).
  • Always reset before comparing on the netlist.
  • Keep GLS/STA roles distinct — adapting the TB doesn't close timing.

Senior Engineer Thinking

  • Beginner: "The testbench fails on the netlist — synthesis broke something."
  • Senior: "It passes on RTL and fails on the netlist? That's the signature of RTL-only TB assumptions — renamed internals, edge sampling, uninitialized flops. Let me adapt the testbench before doubting the netlist."

The senior reads pass-on-RTL/fail-on-netlist as a testbench signal and adapts before blaming synthesis.

Silicon Impact

Mis-attributing testbench assumptions to "netlist bugs" wastes engineering time and, worse, can mask real issues: teams may add workarounds or waivers to silence false failures, blunting the very GLS run meant to catch genuine gate-level problems (uninitialized state, timing-dependent behaviour) before tape-out (0.3). A properly adapted testbench does the opposite — it lets the netlist's real behaviour (power-up X, timing-sensitive capture) surface correctly, so real bugs are caught and false ones disappear. Knowing why the RTL testbench breaks is the first step to a GLS run you can trust.

Engineering Checklist

  • Compared RTL vs netlist runs to isolate TB assumptions from DUT issues.
  • Replaced internal-signal references with ports / bind / preserved signals (5.2).
  • Made stimulus clear of the clock edge (5.3).
  • Sampled outputs after settling, on a strobe (5.4).
  • Applied a proper reset before comparing (power-up X).

Try Yourself

  1. Run a small RTL testbench on the RTL DUT — it passes (internals visible, zero-delay, flops init).
  2. Observe: point the same testbench at the synthesized netlist — it reports X/mismatches.
  3. Change: reference an output port instead of an internal signal, and sample one #delay after the edge.
  4. Expect: the false failures clear. Then remove the reset sequence and watch power-up X reappear — proving the assumption set.

Any free Verilog simulator reproduces this with an RTL DUT and its synthesized netlist. No paid tool required.

Interview Perspective

  • Weak: "If the testbench fails on the netlist, the synthesis is wrong."
  • Good: "RTL testbenches assume visible internals, zero-delay edges, and initialized flops — the netlist breaks all three."
  • Senior: "Pass-on-RTL/fail-on-netlist is the signature of RTL-only TB assumptions: renamed internals, edge-aligned drive/sample racing clk-to-Q, and power-up X. I adapt the testbench — ports, timing-aware stimulus, strobed checkers, proper reset — before doubting the netlist. And adapting it reveals real behaviour; it doesn't close timing — STA does."

9. Interview / Review Questions

10. Key Takeaways

  • An RTL testbench breaks on the netlist because of four RTL-only assumptions: internal visibility, zero-delay edge timing, initialized flops, and ordering/glitch assumptions.
  • Synthesis renames/flattens internals (stateq_reg[*]), so hierarchical references break or read X (5.2).
  • Real clk-to-Q and net delays mean outputs settle after the edge — edge-aligned drive/sample races them (5.3/5.4).
  • Gate-level flops power up X (no initial) — the testbench must apply a proper reset before comparing (2.6).
  • These are testbench issues: a pass-on-RTL/fail-on-netlist result means adapt the testbench, not blame the netlist — and adapting reveals real behaviour, it doesn't close timing (STA does, 0.3). Next: 5.2 — hierarchical references & bind after synthesis.

Quick Revision

RTL TB breaks on the netlist via 4 assumptions: visible internals (renamed → q_reg[*]), zero-delay edges (real clk-to-Q settles after the edge → edge sampling races), initialized flops (netlist powers up X → need reset), and ordering/glitch. Pass-on-RTL/fail-on-netlist = adapt the TB (5.2 refs, 5.3 stimulus, 5.4 checkers), not a netlist bug. Reveals real behaviour; STA still signs off timing. Next: 5.2 — hierarchical references & bind.