Back to Learn

Learn / Concept

Reset & X-convergence

At power-up, every flip-flop that is not driven to a known value by a reset holds an unknown — modelled as x in simulation, and a real but indeterminate 0 or 1 in silicon. Leaving the reset off a flop is a legitimate area-and-timing optimization, not automatically a bug. The question that matters is whether that initial unknown can reach a control point or a module output before valid data overwrites it. This guide explains reset-less flops, X-convergence, why simulation alone cannot answer the question soundly, and what a structural analyzer can tell you.

Reset-less flops are not automatically wrong

A register that is overwritten with valid data before its uninitialized value is ever observed needs no reset. Resetting it anyway costs area (a reset port on the flop), routing (the reset tree has to reach it), and sometimes timing. Deep pipeline data stages, large register files, and datapath staging are routinely left reset-less on purpose. So a tool that flags every reset-less flop is too noisy to act on. The useful signal is which reset-less flops let their power-up unknown escape — reach an FSM state register, an if/case condition, another flop’s enable or reset, or a module output.

X that reaches control vs X that is masked

The damaging case is an unknown on a control net. If a power-up x reaches a case selector, an if condition, or an enable, it can steer control flow into an undefined branch and the design can latch a state it can never legitimately recover from. The same unknown on a module output port can be observed by whatever is downstream of this block.

// Reset-less flop whose X reaches CONTROL.
// state has no reset arm, so its power-up value is unknown. It is then
// used as a case selector -- an unknown that can steer control flow in
// the first cycles after power-up. This is the dangerous case.
reg [1:0] state;            // no reset -> power-up X
always @(posedge clk)
  state <= next_state;

always @* begin
  case (state)              // X on a control net: branch is undefined
    2'b00: y = a;
    2'b01: y = b;
    default: y = c;
  endcase
end

The benign case is an unknown that is masked: it stays on a data path, the flop is loaded unconditionally every cycle (so its unknown lives at most one cycle), and it never reaches a control net or an output before being overwritten. Output-facing and control flops carry the reset; the interior data stages do not need it.

// Reset-less flop whose X is MASKED.
// pipe0/pipe1 have no reset, but each is loaded UNCONDITIONALLY every
// cycle and only flows on as DATA -- never to a control net or output
// condition. The power-up X lives one cycle and is gone. Legitimate.
reg [7:0] pipe0, pipe1;
always @(posedge clk) begin
  pipe0 <= data_in;         // overwritten every cycle, no enable
  pipe1 <= pipe0;           // pure data path -> result is registered
end
always @(posedge clk)
  if (rst_n == 1'b0) result <= 8'h00;  // the OUTPUT-facing flop IS reset
  else               result <= pipe1;

Why X-propagation simulation is not enough

Four-valued RTL simulation does model the power-up unknown as x, but it does so unsoundly in both directions. X-optimism hides real bugs: a conditional can resolve an x input into one definite branch and the unknown silently disappears, so the simulation looks clean when the silicon is not. X-pessimism invents fake bugs: an x spreads to nets that the real gates would have driven to a clean value, so the simulation looks broken when the silicon is fine. A clean X-prop run does not prove X-safety, and a dirty one does not prove a bug. A deterministic structural analysis of where the unknown can flow is a sound complement to it.

What a structural reset/X analyzer reports

A structural analyzer works on the parsed netlist of flops and combinational logic. It identifies reset-less flops conservatively — it treats a flop as reset only when it can positively find a constant assigned in the reset arm, so it never silently calls a reset-less flop “reset” and skips it. It then traces each reset-less flop’s combinational fan-out (clocked blocks are register barriers that stop the trace) and classifies it:

  • Exposes X — the value structurally reaches a module output or a control net (an if/case condition, another flop’s enable or reset). This is the case to review first.
  • Likely masked — no structural X-exposure path found, and the flop is loaded unconditionally every cycle, so its unknown lives one cycle and only flows on as data. Structural evidence of safe-by-construction, not a proof.

This is structural evidence, never a proof. The analyzer does not model electrical metastability, it does not simulate, and it cannot certify that a likely-masked flop is electrically safe in every corner. It gives you a deterministic, reviewable map of where a power-up unknown can and cannot go — the signal commercial lint buries under per-flop noise and X-prop sim reports unsoundly.

How ChipVerify AI helps

ChipVerify AI (a pre-signoff RTL evidence tool, currently in closed beta, not a foundry signoff tool) runs this reset/X-convergence analysis on uploaded RTL and separates the reset-less flops whose power-up unknown reaches control or an output from the ones whose X is structurally masked — so the area-saving optimization stays an optimization and the dangerous ones get reviewed.

Related reading

Try the public scanner at /tinytapeout or request access.

FAQ

Is a flop without a reset always a bug?

No. Leaving the reset off a flop is a legitimate area-and-timing optimization when the flop is guaranteed to be overwritten with valid data before its uninitialized value is ever observed — a deep pipeline data stage is the classic example. The real question is not whether a flop is reset-less, but whether its power-up unknown can reach a control point or a module output before it is overwritten. Commercial lint that flags every reset-less flop is too noisy to act on; the useful signal is which reset-less flops expose their X.

Why can't I just rely on X-propagation in simulation to find these?

Four-valued RTL simulation models the power-up unknown as x, but it does so unsoundly in both directions. X-optimism hides real bugs: a conditional can resolve an x input to a definite branch and lose the unknown. X-pessimism invents fake ones: an x can spread to outputs that the real silicon would have driven to a clean value. So a clean X-prop simulation does not prove the design is X-safe, and a dirty one does not prove it is broken. A structural analysis of where the X can flow is a deterministic complement.

What does it mean for a reset-less flop's X to be 'masked'?

Masked means the analyzer found no structural path by which the flop's value reaches a module output or a control net (an if/case condition, or another flop's enable or reset), and the flop is loaded unconditionally every cycle so its unknown lives at most one cycle and only flows on as pipeline data. That is structural evidence that the X is safe-by-construction, not a proof: the analyzer reports it as likely-masked, and metastability and electrical-level effects are out of scope.

Map where power-up X can flow in your RTL

Sign in and point ChipVerify AI at your design. It separates reset-less flops whose power-up unknown reaches control or an output from the ones whose X is structurally masked — pre-signoff structural evidence to review, not a foundry signoff and not an electrical X-safety proof.