A flop with an asynchronous reset has two timing requirements at release: recovery (reset must go away at least t_rec before the next clock edge) and removal (and not within t_rem after the previous one). If reset releases at a random instant, it may violate one of them.
The flop can then go metastable, like a data input that changes at the wrong moment. The fix passes the release through a short chain of flops clocked by the domain clock.
The chain's flops reset asynchronously, so assertion is immediate. Their input is a constant 1, so only the release travels down the chain, one stage per clock edge.
The first flop in the chain can go metastable if the release lands in its recovery window. The second flop gives it a full clock period to settle, as with a data synchroniser.
Two stages are the usual minimum. Three suit very fast clocks or high-reliability designs. In the code below STAGES must be 2 or more: an elaboration-time check rejects 1, because a single flop has no second stage to let a metastable output settle.
srst_n rises, and what is the hazard at the first flop?In ideal RTL, exactly two subsequent rising edges. Phase changes elapsed time, not that edge count. In hardware the first stage can violate recovery/removal and resolve late, delaying release; there is no deterministic three-edge ceiling. Reliability requires characterised cells and implementation timing.
The waveform below is simulation output for one asynchronous source released through a two-flop synchroniser in each of two unrelated clock domains. How to read it: one slot is one cycle of clk_a, and each slot shows the values just after that slot's rising clk_a edge; clk_b shows its own level at each slot, so a clk_b rise drawn at a slot boundary happened during the slot before. The release is driven 1 ns after the slot-2 clk_a edge (t = 26 ns), so it is drawn before the edges that release each domain.
While arst_n is low (slots 0 and 1) both rst_a_n and rst_b_n are low: assertion needs no clock.
arst_n rises in slot 2. rst_a_n follows in slot 4, after two clk_a edges (slots 3 and 4).
rst_b_n stays low until slot 5, after two edges of the slower clk_b (the rises drawn in slots 3 and 5), so the two domains leave reset at different times.
Each domain releases on its own clock; no domain logic sees the raw arst_n.
`timescale 1ns/1ps
// Asynchronous assert, synchronous release.
module reset_sync #(parameter int STAGES = 2) (
input logic clk,
input logic arst_n, // asynchronous reset input (from a pin or another domain)
output logic srst_n // reset for this clock domain
);
if (STAGES < 2) begin : g_stages_check // legal range: STAGES >= 2
$error("reset_sync: STAGES must be at least 2");
end
logic [STAGES-1:0] sr;
always_ff @(posedge clk or negedge arst_n)
if (!arst_n) sr <= '0; // assert: immediately, no clock needed
else sr <= {sr[STAGES-2:0], 1'b1}; // release: shifts in 1s, one stage per clock
assign srst_n = sr[STAGES-1];
endmodule
Property | How the test checks it |
|---|---|
Assertion is immediate | 0.001 ns after |
Release is aligned to the clock | Every rising edge of |
Ideal release takes two clock edges | Exactly two rising edges strictly after the release instant |
Finite phase coverage | 200 pseudo-random release instants, not exhaustive or physical reliability evidence |
Source checker, run with Icarus Verilog 13.0 (2026-10-16): prints PASS. It uses 200 pseudo-random releases to check ideal, zero-delay RTL assertion and exactly two subsequent release edges. Release is offset from clock edges to avoid simulator scheduling races. The finite check contains no analogue resolution model and proves neither MTBF nor recovery/removal signoff.