Skip to content

GLS · Chapter 1 · RTL vs Gate-Level Simulation

Initial Blocks, Force & Constructs That Vanish

Some of what you write in RTL is not design at all. It is simulation-only, and it has no gate equivalent, so it simply vanishes in synthesis. Initial blocks, force and release, hash delays, display and monitor tasks, simulation-only assignments, and ifdef-guarded simulation code all disappear from the netlist. This matters because RTL simulation can quietly lean on a vanished construct. The most dangerous case is an initial block that sets a register to a known value, which makes RTL simulation look clean while hiding a real initialisation bug. In the netlist that initial is gone, so the register powers up unknown and the masked bug is exposed. This lesson catalogs what survives synthesis versus what vanishes, and works through the classic case where an initial block masked an uninitialised register in RTL but GLS revealed the unknown.

Foundation12 min readGLSinitial blocksforceSynthesizableX

Chapter 1 · Section 1.3 · RTL vs Gate-Level Simulation

Project thread — this is the construct fidelity axis from 1.1 at its extreme. On the D flip-flop, an initial that quietly defined q in RTL sim is exactly the kind of construct that vanishes — and the X it hides is the X of 0.1.

1. Why Should I Learn This?

A clean RTL simulation feels like proof the design initialises correctly — but if that cleanliness depends on a construct the netlist does not have, it is proof of nothing. Knowing which constructs vanish in synthesis — above all initial blocks — lets you recognise when your RTL sim is 'clean' only because a simulation-only construct is masking a real hardware gap. This is one of the single most common sources of 'GLS shows X that RTL never did,' and spotting it is the difference between trusting a false green and finding the real reset bug.

This lesson is the extreme of 1.2's transformation (constructs that do not just change but disappear) and it feeds directly into Chapter 7 (reset and initialisation), where these masked gaps are debugged in depth.

2. Real Silicon Story — the register that was 'always fine' in RTL

A block's RTL simulation is spotless — a status register comes up at a clean, known value in every test, for years. In GLS, that register is X at power-up, and the X spreads. The team's first thought: 'GLS is being pessimistic — RTL clearly shows it initialises.'

RTL showed it initialising because of one line the netlist does not have: an initial status_reg = 8'h00; sitting in the design. That initial block set the register at simulation start — so RTL simulation always saw a known value — but it is simulation-only, not synthesizable, and it vanished in synthesis. The real design has no reset on that register (nobody noticed, because the initial always covered for it), so in the netlist it powers up X. GLS was not pessimistic — it was correct, and RTL was falsely clean, its cleanliness manufactured by a construct that does not exist in hardware. The register would come up unknown in silicon exactly as GLS showed. The fix was a real reset, not a suppression of the GLS X. The post-mortem lesson: simulation-only constructs — initial blocks above all — vanish in synthesis, so RTL simulation can look clean only because such a construct is masking a real hardware gap; when GLS shows an X that RTL 'never did,' suspect a vanished initial (or force/deposit) that was hiding an uninitialised register — the bug is a missing reset, and GLS exposed it.

3. Concept — what survives synthesis, and what vanishes

Synthesis builds hardware, so only synthesizable design survives; simulation-only constructs vanish:

  • Survives (becomes gates): always_ff / always_comb (real sequential/combinational logic), continuous assign, real reset logic, parameter/localparam (folded to constants), instantiated modules. These are the design.
  • Vanishes (no gate equivalent): initial blocks (simulation startup, not hardware — a register they set powers up X in the netlist), force/release (act on the sim signal graph), # delays (sim timing, replaced by real cell delays), $display/$monitor/$strobe (output tasks), simulation-only assignments, and `ifdef-guarded sim code.
  • The danger — RTL sim leans on a vanished construct. The worst case is an initial that initialises a register the design should reset but does not: RTL sim looks clean (the initial covers the gap), the netlist has no initial (X at power-up), and GLS exposes the masked reset bug.
  • Also (foreshadows Ch5): testbench force/deposit on RTL hierarchy paths break or change on the netlist, because the hierarchy and constructs they targeted are gone.

The netlist contains only the survivors — so any startup value that came from an initial is simply not there:

Survives vs vanishes in synthesis: always_ff/assign/reset survive; initial/force/# delays/$display vanish; netlist has only survivors so initial startup value is gone (X)gone in gatesX exposedSURVIVES (becomesgates)always_ff/comb · assign · REAL reset logic · parameters (constants) · instancesalways_ff/comb · assign ·REAL reset logic ·parameters (constants) ·…VANISHES (no gateequivalent)initial · force/release · # delays · $display/$monitor · sim-only assigns · `ifdef SIMinitial · force/release · #delays · $display/$monitor· sim-only assigns · `ifde…NETLIST = only thesurvivorsno initial -> a reg aninitial set now powers up X(real startup value gone)DANGER: RTL sim leaned on a vanished constructDANGER: RTL simleaned on a vanished…an initial masking aMISSING RESET -> RTL clean,GLS shows the real X12
Figure 1 — synthesis keeps only synthesizable DESIGN; simulation-only constructs vanish. SURVIVES: always_ff/always_comb, assign, real reset logic, parameters (as constants), instances. VANISHES: initial blocks, force/release, # delays, $display/$monitor, sim-only assignments, `ifdef SIM code — none have a gate equivalent. The netlist contains ONLY the survivors, so a register an `initial` set to a known value has NO initialiser in the netlist and powers up X. RTL sim leaning on a vanished construct (an initial masking a missing reset) looks clean while GLS exposes the real X.

4. Mental Model — the netlist keeps the building, not the scaffolding

5. Working Example — an initial block that masks a missing reset

A register with no reset, quietly initialised by an initial block. RTL is clean; the netlist is not.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// RTL (SystemVerilog): status_reg has NO reset — but an `initial` sets it, so RTL SIM looks clean.
module status (input logic clk, input logic set_evt, output logic [7:0] status_reg);
  initial status_reg = 8'h00;          // SIMULATION-ONLY: vanishes in ASIC synthesis (masks the missing reset)
  always_ff @(posedge clk)
    if (set_evt) status_reg <= status_reg + 1'b1;   // NO reset branch -> netlist has no initialiser
endmodule

The same masking pattern in Verilog and VHDL — each uses an elaboration/simulation-time initialiser with no reset, so all three look clean in RTL sim and lose the initialiser in the netlist:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// RTL (Verilog): an `initial` masks the missing reset (sim-only; not synthesised in ASIC flows).
module status (input clk, input set_evt, output reg [7:0] status_reg);
  initial status_reg = 8'h00;                        // vanishes in ASIC synthesis
  always @(posedge clk)
    if (set_evt) status_reg <= status_reg + 1'b1;    // no reset -> netlist has no initialiser
endmodule
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- RTL (VHDL): the analog is a signal initial value at declaration (elaboration-time, NOT a reset).
signal status_reg : std_logic_vector(7 downto 0) := x"00";  -- masks the missing reset the same way
-- the process below has NO reset branch, so in ASIC this init does not create reset hardware

ASIC vs FPGA context (accuracy). These initialisers are elaboration/simulation-time only. In ASIC synthesis they are not synthesizable and vanish — a design register needs a real reset. In some FPGA flows a register's initial (or VHDL declaration) value is honoured, loaded from the bitstream at configuration, so the flop can power up defined — but relying on it for a design register is still poor practice: it does not survive an ASIC port, it is not a reset, and it hides a real initialisation gap. This lesson assumes the ASIC signoff context: initialise design state with reset.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// NETLIST (representative): the `initial` is GONE. The flops have no reset input driven -> power up X.
module status_netlist (input clk, input set_evt, output [7:0] status_reg);
  DFFX1 U0 (.D(d0), .CK(clk), .Q(status_reg[0]));   // no reset pin -> Q starts X (initial vanished)
  // ... bits [7:1] the same: all X at power-up ...
endmodule

RTL and GLS disagree at startup — because the initial existed in one and not the other:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
# RTL SIM: the initial sets status_reg at t=0 -> clean, known start (the missing reset is MASKED)
t=0  status_reg = 00       <- from the `initial` block (simulation-only)
t=10 status_reg = 00       <- looks perfectly initialised
 
# GLS: no `initial` in the netlist, no reset in the design -> X at power-up (masked bug EXPOSED)
t=0  status_reg = xx       <- real flops power up X; nothing initialises them
t=10 status_reg = xx       <- the X persists and spreads (no reset ever clears it)

The RTL cleanliness was manufactured by the initial — a construct the netlist does not have. GLS is correct: the real design has no reset on status_reg, so it powers up X, exactly as it would in silicon. The bug is a missing reset, and the next section is diagnosing it.

6. Debugging Session — GLS shows X that RTL 'never had'

1

A register is clean in RTL simulation but X in GLS because an initial block set it in RTL (masking a missing reset) and vanished in synthesis, exposing the real uninitialised register

RTL LEANED ON A VANISHED INITIAL — THE BUG IS A MISSING RESET
Symptom

A register that has been clean in RTL simulation for the life of the project is X at power-up in GLS, and the X spreads. The instinct is 'GLS is pessimistic — RTL proves it initialises,' and pressure builds to suppress the GLS X so the run passes.

Root Cause

RTL simulation's cleanliness rested on a simulation-only construct that the netlist does not have. The register has no reset in its always_ff, but an initial status_reg = 8'h00; in the RTL set it at simulation start — so RTL simulation always showed a known value, and every functional test passed. The initial block is not synthesizable: it describes simulation startup, not hardware, so it vanished in synthesis. The netlist therefore has nothing initialising that register — no initial, and (the real gap) no reset — so the real flops power up X, and the X persists because nothing ever clears it. GLS is not pessimistic; it is correct — the register would come up unknown in silicon too. The confusion is that RTL's 'proof of initialisation' was manufactured by the vanished construct, so it proved nothing about the hardware. The tell is the pattern: an X in GLS that RTL 'never had,' on a register whose only initialiser turns out to be an initial block (or a testbench force/deposit) rather than a reset.

Fix

Add the real reset the design is missing — reset status_reg (and any other register that was only being initialised by an initial) to its intended value in the always_ff — and remove the misleading initial from the design (keep such setup in the testbench if needed, not the design). Re-run GLS and confirm the register comes up known via reset. Do not suppress the GLS X and do not 're-fake' the initial in the netlist. The lesson: simulation-only constructs (initial blocks, force, deposits) vanish in synthesis, so RTL simulation can look clean only because such a construct is masking a real hardware gap — an X in GLS that RTL 'never had' usually means RTL leaned on a vanished construct hiding a missing reset; the fix is the reset, not suppressing the X. This is one of the most common GLS failures, and it is always a real bug the netlist correctly exposed (Chapter 7 debugs this class in depth).

7. Common Mistakes

  • Trusting RTL cleanliness that rests on an initial block. initial vanishes in synthesis — a register it 'initialises' powers up X in the netlist; the cleanliness is fake.
  • Reading a GLS X as pessimism when RTL 'proved' init. If RTL's init came from a vanished construct, GLS is correct and the bug is real (a missing reset).
  • Putting initial initialisation in the design. Design registers must be initialised by reset, not initial — keep initial in the testbench only.
  • Suppressing the GLS X instead of fixing the reset. Suppression hides a real hardware gap that will misbehave in silicon.
  • Assuming testbench force/deposits carry to GLS. They act on RTL hierarchy/constructs that vanish or change on the netlist (Ch5).

8. Industry Best Practices

  • Initialise design registers with reset, never initial. Reserve initial for the testbench; any design register needing a known start needs a reset.
  • Treat a GLS X that RTL 'never had' as a vanished-construct mask. Suspect an initial (or force/deposit) hiding a missing reset — fix the reset.
  • Audit the design for initial blocks before GLS. A design-side initial on a register is a masked initialisation gap waiting to appear in GLS.
  • Never suppress a startup X to pass GLS. It is a real hardware indeterminacy; fix its source.
  • Keep simulation-only constructs out of the design. force, # delays, sim-only assigns belong in the testbench, not synthesizable code.

Senior Engineer Thinking

  • Beginner: "GLS shows X but RTL is clean — GLS must be pessimistic."
  • Senior: "Why was RTL clean? If the register's only initialiser is an initial block, that vanished in synthesis — RTL's cleanliness was fake and the missing reset is real. I add the reset; I do not suppress the X."

The senior distrusts RTL cleanliness that depends on non-synthesizable constructs and asks what made RTL clean before believing it.

Silicon Impact

If this escapes, the register that was 'always fine' powers up unknown in silicon exactly as GLS showed — the initial that hid the gap does not exist in the chip. The result is power-up in a nonsensical state, intermittent boot behaviour, and the poisoning of everything that register feeds. Worse, because RTL sim 'proved' it initialised, the team may ship with confidence and be blindsided by a field return whose root cause — a register initialised only by a simulation-only construct — is embarrassing and expensive to find post-silicon. Catching it in GLS is a one-line reset fix; catching it in silicon is a respin.

Engineering Checklist

  • No design register relies on an initial block for its startup value.
  • Every register needing a known start is driven by a reset in its always_ff.
  • Treated a GLS X that RTL 'never had' as a vanished-construct mask (missing reset), not pessimism.
  • Did not suppress a startup X to pass GLS.
  • Kept force, # delays, and sim-only assignments in the testbench, not the design.

Try Yourself

  1. Simulate the status RTL — it looks clean, because the initial sets status_reg.
  2. Change: delete the initial line (leave only the synthesizable part) to mimic what the netlist actually contains.
  3. Observe: in a four-state run, status_reg now starts X — the masked gap is revealed.
  4. Expect: adding a real reset branch (if (!rst_n) status_reg <= 8'h00;) makes it start known without the initial. That reset is the fix; the initial was only hiding its absence.

A standard four-state simulator shows this — no paid tool required. On an FPGA the initial may hold, but the point stands: a design register should reset.

Interview Perspective

  • Weak: "GLS shows X but RTL is clean, so GLS is being pessimistic."
  • Good: "RTL may be clean only because an initial — which vanishes in ASIC synthesis — masked a missing reset."
  • Senior: "I ask what initialised the register in RTL. If it is an initial and the design has no reset, the X is real: I add the reset, I don't suppress the X. On an FPGA an initial can hold, but design registers should still reset for portability and signoff."

Quick Revision

The netlist keeps the building, not the scaffolding. In ASIC synthesis, initial, force, # delays, $display vanish. A register initialised only by a vanished initial powers up X in the netlist — RTL's cleanliness was fake, the bug is a missing reset. Fix the reset, never suppress the X. (FPGA flows may honour initial, but design registers should still reset.) Next: 1.4 — why a two-state simulator hides the very X this exposes.

9. Interview / Review Questions

10. Key Takeaways

  • Synthesis builds only synthesizable design; simulation-only constructs vanishinitial blocks, force/release, # delays, $display/$monitor, sim-only assignments, and `ifdef-guarded sim code have no gate equivalent.
  • The netlist contains only the survivors (always_ff/assign/reset/parameters/instances), so a value that came only from a vanished construct is gone — a register an initial set powers up X.
  • The dangerous case: RTL simulation leans on a vanished construct — an initial masking a missing reset — so RTL looks clean while GLS exposes the real X.
  • An X in GLS that RTL 'never had' is usually a vanished-construct mask, not GLS pessimism — the bug is a missing reset; fix the reset, never suppress the X or re-fake the initial.
  • Initialise design registers with reset, not initialinitial, force, and # delays belong in the testbench, never as a design register's initialiser. Next: 1.4 — why a two-state simulator would hide this very X.