Metastability and MTBF
Say what metastability is and what a simulation can and cannot show about it, read the MTBF formula term by term, and see in a labelled model why the second flop of a synchronizer matters.
- Lesson
- R6.1
- Time
- 30 min
- Runs on
- Your browser
- Check
- 5 questions
A status bit from a 100 MHz domain was read in a 133 MHz domain through one flop. Every few hours the state machine reading it was found in two states at once. No RTL simulation had ever failed, because a simulated flop is never metastable.
- A change inside the window
status changes a fraction of a nanosecond before edge k. That is inside s1's setup and hold window, the short time around an edge when a flop's input must stay still.
Follow the calls, values and waits
- data change: status → s1
- The flop hovers
The flop goes metastable: its output sits between 0 and 1, then falls to one side at an unpredictable time. The longer you wait, the less likely it is still undecided.
- Two readers, two answers
At edge k+1, s1 has still not settled. idle_q's logic may see a 1 while busy_q's sees a 0, and the machine is in neither state. The opposite reading puts it in both.
Follow the calls, values and waits
- data neither 0 nor 1: s1 → idle_q
- data neither 0 nor 1: s1 → busy_q
Read the diagram as text
- status: a flop on clk_a
- clk: edges k and k+1
- s1: samples status at edge k
- idle_q: reads s1 at edge k+1
- busy_q: reads s1 at edge k+1
- status → s1: changes near edge k
- clk → s1
- s1 → idle_q: via ~s1
- s1 → busy_q: via s1
Drawn from the timing rules of a real flop. A zero-delay simulator samples exactly at the edge and always sees a clean 0 or 1.
What the chance of failure depends on
Two things must happen for a failure. The flop must enter the metastable state, and it must still be undecided when the next flop reads it. The second chance falls exponentially: every extra unit of waiting multiplies it by the same small factor.
The mean time between failures (MTBF) of a synchronizer is the average time between those events. The standard formula, as Golson writes it, is below.
MTBF = e^(tR / tau) / (T0 * fc * fd)| Term | Meaning | Who sets it |
|---|---|---|
| tR | resolution time: how long the flop may settle before the next flop reads it | your design: the period minus any logic in between |
| tau | how fast a metastable flop falls to one side | the flop's technology |
| T0 | the width of the window in which a change makes the flop metastable | the flop's technology |
| fc | the sampling clock's frequency | your design |
| fd | how often the crossing signal changes | your design |
Only tR is in the exponent. Doubling the clock or the data rate halves the MTBF; adding a period of settle time multiplies it by a huge factor.
| Illustration only | One flop, logic after it | Two flops |
|---|---|---|
| tR | 0.5 ns | 1.9 ns |
| MTBF | about 6.5 minutes | about 2.6 × 10^19 years |
Made-up constants, not from any cell library: tau = 25 ps, T0 = 50 ps, fc = 500 MHz, fd = 50 MHz. Real values come from the library vendor or from SPICE.
The second flop helps because it adds almost a whole period to tR, with nothing in between. A third flop adds another period, which very fast designs sometimes need.
A simulation needs a model to show it
The lab bench carries a metastability model, a few lines of bench code that act on the design's flops. Its random numbers come from a generator with a fixed seed, so every run prints the same lines.
Enter
If
statuschanged less than 1 ns before an edge of clk, s1 is metastable. It settles to the old or the new value, at random.Settle
Every nanosecond, an unsettled s1 stays unsettled with probability 1/2. That halving is the model's exponential.
Read
The state flops have 2 ns left after their logic. If s1 needs longer, each state flop reads its own random bit. A second flop with nothing in front has the whole 10 ns period.
- Cycle 2
Edge 13: s1 has been 1 since edge 12, and the machine is in BUSY.
- Cycle 3
Edge 14: status fell 0.70 ns before the edge. The model makes s1 metastable; it settles to the old 1, after 3 ns.
- Cycle 4
Edge 15: 3 ns is more than the 2 ns the state flops can wait. Each reads its own bit, and both read 0: the bench prints
ILLEGAL. - Cycle 5
Edge 16: s1 is a clean 0 again and the machine recovers into IDLE.
Measured on the lab bench with its model. Over 2000 edges, s1 went metastable 90 times; the state flops read it unsettled 22 times; the machine was illegal for 12 edges.
The two-flop synchronizer
A synchronizer gives a signal from another clock a known timing to this one. The standard one is two flops in series with nothing between them: s1 may go metastable, and s2 reads it a whole period later.
One flop, read by two
s1 <= status;
idle_q <= ~s1;
busy_q <= s1;
The state logic eats into s1's settle time. Model: 22 unsettled reads, 12 illegal edges.
Two flops, then the machine
s1 <= status;
s2 <= s1;
idle_q <= ~s2;
busy_q <= s2;
Only s2 reads s1, with the whole period. Model: 0 unsettled reads, 0 illegal edges.
| Measured | One flop | Two flops |
|---|---|---|
| Model, 2000 edges: metastable, unsettled reads, illegal edges | 90, 22, 12 | 90, 0, 0 |
| Latency from the sampling edge to the state flops | 1 edge | 2 edges |
| Synthesis on this flow | 4 cells, 3 flops, 1 level of logic | 5 cells, 4 flops, 1 level of logic |
The synchronizer costs one flop and one cycle of latency. The model's metastable count is the same, because the sampling flop is the same.
Keep the two flops in a named module (often sync2), drive the crossing signal straight from a flop in its own domain, and never synchronize one signal in two places. Two synchronizers on one signal can settle differently, just like the two state flops here.
| Port | Direction | Width | Meaning |
|---|---|---|---|
| clk | input | 1 | clock |
| rst_n | input | 1 | reset, asynchronous, active-low |
| status | input | 1 | from the clk_a domain |
| idle_q | output | 1 | one-hot state: IDLE while status is 0 |
| busy_q | output | 1 | one-hot state: BUSY while status is 1 |
- Clock
clk10 ns; status changes on clk_a (7.4 ns), every 3 of its edges, with no timing relation to clk- Latency
- two edges of clk from the edge that samples a change to the state flops
- Corner cases
- a change of status just before an edge of clk
The lab ships with one flop. Run it and find the ILLEGAL line and the counts. Then add s2 from the snippet below and move the machine onto it. The bench's model acts on the flops named s1, idle_q and busy_q, so keep those names. It writes into those flops directly, which only bench code may do.
logic s2;
always_ff @(posedge clk or negedge rst_n)
if (!rst_n) s2 <= 1'b0;
else s2 <= s1;
// and in the machine:
idle_q <= ~s2;
busy_q <= s2;Asked in interviews
What is metastability?
A flop whose input changes inside its setup and hold window can sit between 0 and 1 for a while before it falls to one side. The time it takes is unbounded, but the chance of still waiting falls exponentially.
Why two flops, and what is MTBF?
The second flop lets the first settle for a whole period before anything reads it. MTBF is the mean time between unsettled reads; it grows exponentially with settle time and shrinks with clock and data rates.
Can you simulate metastability?
Not in plain RTL: a simulated flop has no window and no metastable state. Benches add models that randomize the synchronizer's delay or value, and CDC tools check the structure; neither replaces the MTBF analysis.
Try it
The bench prints the first 24 edges, then runs quietly to edge 2000 and prints the counts. The model's line before edge 14 says what it decided; edge 15 shows the result.
Add s2 and move the machine onto it. The model still finds 90 metastable samples, but the last line becomes read_unsettled=0 illegal=0. Synthesize: 5 cells and 4 flops instead of 4 and 3.
Then remove the model in your head. Without it, both versions print only legal states, every time: the simulator alone cannot tell them apart.
Synthesize the design to measure its cells and inspect the mapped gates.
e0 status=0 s1=0 idle_q=1 busy_q=0 e1 status=0 s1=0 idle_q=1 busy_q=0 e2 status=0 s1=0 idle_q=1 busy_q=0 e3 status=1 s1=1 idle_q=1 busy_q=0 e4 status=1 s1=1 idle_q=0 busy_q=1 e5 status=0 s1=1 idle_q=0 busy_q=1 e6 status=0 s1=0 idle_q=0 busy_q=1 e7 status=0 s1=0 idle_q=1 busy_q=0 e8 status=1 s1=1 idle_q=1 busy_q=0 e9 status=1 s1=1 idle_q=0 busy_q=1 e10 status=0 s1=0 idle_q=0 busy_q=1 e11 status=0 s1=0 idle_q=1 busy_q=0 e12 status=1 s1=1 idle_q=1 busy_q=0 e13 status=1 s1=1 idle_q=0 busy_q=1 model: status changed 0.70 ns before e14; s1 settles to 1 after 3 ns e14 status=0 s1=1 idle_q=0 busy_q=1 e15 status=0 s1=0 idle_q=0 busy_q=0 ILLEGAL e16 status=0 s1=0 idle_q=1 busy_q=0 e17 status=1 s1=1 idle_q=1 busy_q=0 e18 status=1 s1=1 idle_q=0 busy_q=1 e19 status=0 s1=0 idle_q=0 busy_q=1 e20 status=0 s1=0 idle_q=1 busy_q=0 e21 status=1 s1=1 idle_q=1 busy_q=0 e22 status=1 s1=1 idle_q=0 busy_q=1 e23 status=0 s1=0 idle_q=0 busy_q=1 edges=2000 metastable=90 read_unsettled=22 illegal=12Original design · 4 cells · 3 flip-flops · 0 latches · 1 logic levels. Synthesis uses Yosys; counts depend on the toolchain.
Read included file: tb.sv
`timescale 1ns/1ps
module tb;
logic clk = 0;
always #5 clk = ~clk; // the sampling clock: rising edges at 5, 15, 25, ... ns
logic clk_a = 0; // the second clock: rising edges at 3.7, 11.1, ... ns
initial begin
#3.7;
forever begin clk_a = 1; #3.7; clk_a = 0; #3.7; end
end
logic rst_n = 1; // falls at 1 ns: a real edge, so asynchronous resets act before any clock
int edge_n = -1; // the number of the last rising edge of clk
always @(posedge clk) edge_n = edge_n + 1;
logic status = 0; // the clk_a domain's status flop
realtime t_change = -100.0; // when status last changed
logic idle_q, busy_q;
int n_a = 0;
always @(posedge clk_a) if (rst_n) begin // the sender: status changes every 3 edges of clk_a
n_a <= n_a + 1;
if (n_a % 3 == 2) begin status <= ~status; t_change = $realtime; end
end
bit quiet = 0; // set after the first 24 edges; the counts go on
// ---- The metastability model. It is a model: an RTL flop is never metastable. ----
// 1. When status changed less than WINDOW before an edge of clk, the flop s1 that sampled it is
// metastable. It settles to the old or the new value, at random.
// 2. Settle time: every nanosecond, an unsettled flop stays unsettled with probability 1/2.
// 3. A flop that samples s1 before it settles reads its own random bit. The state flops have
// SLACK_FSM ns left after their next-state logic; a flop with nothing in front has the period.
// The model writes into the design's flops from here. A model may; design code never should
// (IEEE 1800-2017 9.2.2.4 gives an always_ff variable one writer; Icarus and Verilator allow this).
localparam realtime WINDOW = 1.0;
localparam int SLACK_FSM = 2, PERIOD = 10;
int unsigned seed = 4; // fixed seed: every run prints the same lines
function automatic bit coin(); // a fair coin from a linear congruential generator
seed = seed * 32'd1664525 + 32'd1013904223;
return seed[31];
endfunction
int stages = 0; // flops from status to the state machine, timed once
initial begin : calibrate
int k0;
@(posedge dut.s1) k0 = edge_n; // the first change reaches s1 ...
@(posedge busy_q) stages = edge_n - k0; // ... and the state machine stages edges later
end
int metastable = 0, late = 0, illegal = 0;
bit was, v; int settle; realtime ahead;
always @(posedge clk) if (rst_n && stages > 0 && $realtime - t_change < WINDOW) begin : model
was = dut.s1; settle = 0; ahead = $realtime - t_change;
metastable++;
#0.01 v = coin() ? status : was; // the value s1 settles to
dut.s1 = v;
while (settle < 20 && coin()) settle++;
if (!quiet) $display(" model: status changed %0.2f ns before e%0d; s1 settles to %b after %0d ns", ahead, edge_n, v, settle);
if (stages == 1 && settle >= SLACK_FSM) begin // the state flops sample s1 unsettled
@(posedge clk); #0.01;
late++;
dut.idle_q = ~coin(); // each state flop read its own bit
dut.busy_q = coin();
end
else if (stages > 1 && settle >= PERIOD) late++; // the second flop samples s1 unsettled
end
always @(posedge clk) begin #1; if (rst_n && idle_q === busy_q) illegal++; end
status_rx dut (.clk(clk), .rst_n(rst_n), .status(status), .idle_q(idle_q), .busy_q(busy_q));
// Advance to the next rising edge of clk, wait for the design to settle, then print.
task automatic tick();
@(posedge clk); #1;
if (quiet) ;
else if (idle_q === busy_q) $display("e%0d status=%b s1=%b idle_q=%b busy_q=%b ILLEGAL", edge_n, status, dut.s1, idle_q, busy_q);
else $display("e%0d status=%b s1=%b idle_q=%b busy_q=%b", edge_n, status, dut.s1, idle_q, busy_q);
endtask
initial begin
#1 rst_n = 0; tick(); tick(); rst_n = 1; // asserted at 1 ns, clk edges 0 and 1 in reset, released 1 ns after edge 1
repeat (22) tick();
quiet = 1;
repeat (1976) tick();
$display("edges=%0d metastable=%0d read_unsettled=%0d illegal=%0d", edge_n + 1, metastable, late, illegal);
$finish(0); // quiet: no "$finish called" line
end
endmodule
Check yourself
Remember
- A flop whose input changes inside its setup and hold window can go metastable and settle at an unpredictable time; the chance of still waiting falls exponentially.
- MTBF = e^(tR/tau) / (T0 fc fd): settle time is in the exponent, clock and data rates divide.
- The two-flop synchronizer gives the first flop a whole period to settle; no logic between the flops, and one synchronizer per signal.
- RTL simulation never shows metastability. The lab's counts come from a labelled bench model with a fixed seed.