Skip to content

Verilog · Chapter 18.3 · Timing Checks

$recovery, $removal & $recrem in Verilog — Asynchronous Reset Timing

Setup and hold guard synchronous data against the clock. This page guards asynchronous control such as reset, set, and preset against the clock, which is a genuinely different hazard. An asynchronous reset takes effect the instant it is asserted, with no clock required, so the danger is not the assertion but the release. When an async reset deasserts, the very first active clock edge after that release must find the flop settled. If the release lands too close to the edge, the flop can go metastable and the design comes out of reset in an unknown state. Verilog checks this with recovery for the setup-like case, removal for the hold-like case, and a combined check. This page covers all three and the async-assert, sync-deassert discipline that avoids the problem entirely.

Intermediate13 min readVerilogTiming Checks$recovery$removalAsync Reset

Chapter 18 · Section 18.3 · Timing Checks

1. The Engineering Problem

A design works perfectly in RTL simulation, then powers up in gate-level simulation with flops stuck at X — and the X spreads until half the design is unknown. Reset is asserted, then released, exactly as intended. So why does the design fail to come out of reset cleanly?

comes-out-of-reset-in-x.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   // An async-reset flop. Reset CLEARS it immediately when asserted — fine.
   // The hazard is when reset is RELEASED:
   //
   //   rst_n:  0 ________|‾‾‾‾‾‾‾‾   (deasserts — released — here)
   //   clk  :  __|‾|_|‾|_|‾|_|‾|_     (first active edge after release: ↑)
   //                     ↑
   //   If the release lands too CLOSE to that first clock edge, the flop is
   //   still settling out of reset when the edge tries to capture — it can
   //   go METASTABLE → q = X on the first cycle → X propagates.

This is not a setup or hold violation on data — it is a timing violation on the release of an asynchronous control signal. Asynchronous reset is a different beast: it asserts whenever it likes, but its deassertion must still respect a window around the clock edge.

Asynchronous control (reset/set) asserts immediately, but its release must be timed against the clock: far enough before the next edge (recovery) or far enough after the previous edge (removal). Violate that, and a flop comes out of reset metastable — X in simulation.

2. Mental Model — Assertion Is Free; the Release Is Timed

3. The Hardware View

The checks watch the release edge of the async control against the clock.

Visual A — the release is the checked event

Async reset — assertion immediate, release timed against the clock

data flow
Async reset — assertion immediate, release timed against the clockreset assertedflop clears immediately (untimed)reset releasedthe timing-checked eventfirst activeclock edgemust find the flop settled
Asserting an async reset clears the flop immediately, with no timing requirement. The release is different: the flop must return to normal operation and be settled before the first active clock edge. Recovery and removal check the release against that edge.

Visual B — the recovery/removal keepout window

The release keepout window around the clock edge

data flow
The release keepout window around the clock edgerecovery: releasebeforerelease ≥ t_rec before the edgeclock edgefirst capture after resetremoval: releaseafterrelease ≥ t_rem after the edge
Like setup/hold for data, recovery and removal define a keepout window for the async control's RELEASE around the clock edge. Recovery guards the run-up (release must be early enough); removal guards the moment just after (release must not be too soon). A release inside the window risks metastability.

4. $recovery — Release Before the Clock (Setup-Analog)

$recovery checks that the async control was released at least t_rec before the active clock edge.

recovery.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   // active-low reset: the RELEASE is the rising edge (0 → 1) of rst_n.
   // Temporal order: release first, then clock → (release, clock).
   $recovery(posedge rst_n, posedge clk, t_rec, notifier);
   //        ^release       ^clock        ^t_rec  ^notifier
  • Fires when the clock edge arrives less than t_rec after the reset release — the reset deasserted too late, too close before the capturing edge.
  • It is the recovery-time analog of setup: just as data must settle before the clock, the async release must settle before the clock.
  • Worst at the slow corner — like setup, a late-arriving release (long reset-tree delay) is most dangerous when everything is slow.

5. $removal — Release After the Clock (Hold-Analog)

$removal checks that the async control's release comes at least t_rem after the active clock edge — i.e., the reset must remain asserted long enough past the edge.

removal.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   // Temporal order: clock first, then release → (clock, release).
   $removal(posedge clk, posedge rst_n, t_rem, notifier);
   //       ^clock        ^release       ^t_rem  ^notifier
  • Fires when the release arrives less than t_rem after the clock edge — the reset deasserted too soon after an edge that should still have seen it asserted.
  • It is the hold analog: just as data must hold after the clock, the async control must hold (stay asserted) after the clock.
  • Worst at the fast corner — like hold, a too-early release is most dangerous when delays are shortest.
  • Note the argument order reverses versus $recovery, exactly as $hold reverses $setup: recovery is (release, clock), removal is (clock, release).

6. $recrem — Both in One Call

$recrem combines the recovery and removal checks for one async-control/clock pair, as $setuphold combines setup and hold.

recrem.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   $recrem(posedge rst_n, posedge clk, t_rec, t_rem, notifier);
   //      ^release       ^clock        ^t_rec ^t_rem  ^notifier
  • One task declares the whole release keepout window: t_rec before the edge and t_rem after it.
  • It is the form real cell models use for async pins, mirroring how $setuphold is used for data pins.
  • Semantically it is a $recovery plus a $removal on the same signals, sharing one notifier.

7. Why Asynchronous Release Is Its Own Hazard — and the Fix

Recovery/removal exist because asynchronous control creates a problem synchronous data does not: the control can change independently of the clock, so without discipline its release will eventually land in the keepout window of some flop. The design-level cure is a coding discipline, not a check:

  • Async-assert, synchronous-deassert. Let the reset assert asynchronously (so the chip can be forced into reset instantly, even without a running clock), but synchronize its release to the clock using a small reset synchronizer (typically two flops). The deassertion then changes only just after a clock edge, comfortably outside the recovery/removal window of every downstream flop.
  • This is why recovery/removal violations almost always trace back to an un-synchronized async deassertion — a reset whose release is combinational and therefore lands wherever the reset-tree delay puts it. The timing check detects the hazard; the reset synchronizer removes it.

So recovery and removal are the instruments; "async-assert / sync-deassert" is the design rule they motivate.

8. Common Mistakes

  1. Deasserting an async reset combinationally (un-synchronized). The release lands at an arbitrary time and violates recovery/removal at some flop — the design comes out of reset in X (§7, DebugLab).
  2. Swapping recovery/removal argument order. Recovery is (release, clock); removal is (clock, release) — the same reversal as setup/hold (§5).
  3. Treating it as a setup/hold problem on data. Recovery/removal are about an asynchronous control signal's release, not synchronous data — different pins, different fix (§2).
  4. Wrong release edge. For active-low reset the release is posedge rst_n; for active-high it is negedge rst. Referencing the wrong edge checks the assertion, not the release.
  5. Expecting them to synthesise. Like all timing checks, they are simulation-only (Chapter 17 overview).

9. Debugging Lab

The design that powered up in X

10. Interview Q&A

11. Exercises

Exercise 1 — Recovery or removal?

For each, name the check: (a) an async reset is released 0.1 ns before the clock edge, but the flop needs 0.4 ns of recovery; (b) an async reset deasserts 0.05 ns after a clock edge that should still have seen it asserted.

Exercise 2 — Argument order

Write the $recovery and $removal calls for an active-low reset rst_n against posedge clk, with t_rec = 0.5 and t_rem = 0.2. Mind the order.

Exercise 3 — Explain the power-up X

A design comes out of reset in X in gate-level sim but not RTL. Explain in two sentences why RTL missed it and what timing check fired in GLS.

Exercise 4 — The design fix

Describe how an async-assert/sync-deassert synchronizer makes the recovery/removal violation impossible, and why the reset still asserts asynchronously.

12. Summary

$recovery, $removal, and $recrem are the asynchronous control timing checks:

  • The hazard — async reset asserts untimed, but its release must respect a keepout window around the clock edge, or a flop comes out of reset metastable (X).
  • $recovery(release, clock, t_rec) — release far enough before the edge (setup-analog); fires when released too late; worst at the slow corner.
  • $removal(clock, release, t_rem) — release far enough after the edge (hold-analog); fires when released too soon; worst at the fast corner. Argument order reverses, like setup/hold.
  • $recrem — both at once, like $setuphold.
  • The fixasync-assert, synchronous-deassert: a reset synchronizer aligns the release to the clock, outside the window. The check detects; the synchronizer removes.

The crux to keep: recovery/removal violations almost always mean an un-synchronized async deassertion — and "the design powers up in X" is its signature.

The next sub-topic leaves data-vs-clock and control-vs-clock behind for a signal's own waveform: Chapter 18.4 $width, $period, $nochange & $skew — minimum pulse width, clock period, no-change windows, and skew.