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.

One flop settles late, two flops read itArrows show signals. status changes just before an edge of clk; s1 samples it and hovers; both state flops read s1 at the next edge.
One flop settles late, two flops read itArrows show signals. status changes just before an edge of clk; s1 samples it and hovers; both state flops read s1 at the next edge. input status a flop on clk_a input clk edges k and k+1 flop s1 samples status atedge k flop idle_q reads s1 at edge k+1 flop busy_q reads s1 at edge k+1 changes near edge kvia ~s1via s1
  1. 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
    1. data change: status → s1
  2. 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.

  3. 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
    1. data neither 0 nor 1: s1 → idle_q
    2. 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 grows exponentially with the settle time tR and shrinks with the clock and data rates.
MTBF = e^(tR / tau) / (T0 * fc * fd)
TermMeaningWho sets it
tRresolution time: how long the flop may settle before the next flop reads ityour design: the period minus any logic in between
tauhow fast a metastable flop falls to one sidethe flop's technology
T0the width of the window in which a change makes the flop metastablethe flop's technology
fcthe sampling clock's frequencyyour design
fdhow often the crossing signal changesyour 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 onlyOne flop, logic after itTwo flops
tR0.5 ns1.9 ns
MTBFabout 6.5 minutesabout 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.

  1. Enter

    If status changed less than 1 ns before an edge of clk, s1 is metastable. It settles to the old or the new value, at random.

  2. Settle

    Every nanosecond, an unsettled s1 stays unsettled with probability 1/2. That halving is the model's exponential.

  3. 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.

The model's bad cycle, one flopEdges 11 to 17 of the lab bench, sampled on clk, one value per edge, printed 1 ns after it.
0123456clkstatuss1idle_qbusy_q
  1. Cycle 2

    Edge 13: s1 has been 1 since edge 12, and the machine is in BUSY.

  2. 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.

  3. 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.

  4. 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.

MeasuredOne flopTwo flops
Model, 2000 edges: metastable, unsettled reads, illegal edges90, 22, 1290, 0, 0
Latency from the sampling edge to the state flops1 edge2 edges
Synthesis on this flow4 cells, 3 flops, 1 level of logic5 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.

Design brief
PortDirectionWidthMeaning
clkinput1clock
rst_ninput1reset, asynchronous, active-low
statusinput1from the clk_a domain
idle_qoutput1one-hot state: IDLE while status is 0
busy_qoutput1one-hot state: BUSY while status is 1
Clock
clk 10 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.

The second flop, and the two machine lines that read it.
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
  1. 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.

  2. 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.

  3. 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.

RTLIcarus Verilog · in your browser · Lint: Verilator service · Synthesize: Yosys service
Edit the design, then Run, Lint or Synthesize
Expected: 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=12

Original 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

Predict the outputThis is the two-flop design with no model. status rises 3 ns after edge e4, and the bench prints the edge at which busy_q first becomes 1. What does it print?
module status_rx (input logic clk, rst_n, status, output logic idle_q, busy_q);
  logic s1, s2;
  always_ff @(posedge clk or negedge rst_n)
    if (!rst_n) begin s1 <= 1'b0; s2 <= 1'b0; end
    else        begin s1 <= status; s2 <= s1; end
  always_ff @(posedge clk or negedge rst_n)
    if (!rst_n) begin idle_q <= 1'b1; busy_q <= 1'b0; end
    else        begin idle_q <= ~s2; busy_q <= s2; end
endmodule
module tb;
  logic clk = 0, rst_n = 1, status = 0, idle_q, busy_q;
  int e = -1;
  status_rx dut (.*);
  always #5 clk = ~clk;                      // rising edges at 5, 15, 25, ... ns
  always @(posedge clk) e = e + 1;           // e0 at 5 ns, e1 at 15 ns, ...
  initial begin
    #1 rst_n = 0; #1 rst_n = 1;
    #46 status = 1;                          // at 48 ns: 3 ns after e4
    @(posedge busy_q) $display("busy_q rises at e%0d", e);
    $finish(0);
  end
endmodule
Spot the bugEach option is the body of sync2, meant to be a two-flop synchronizer. The bench changes d between edges and expects q to follow two edges later. Which body fails?
Read the waveformThis is the lab bench with one flop and the model, edges 13 to 16. Which reading of the trace is right?
One flop, the model's bad cycle
0123clkstatuss1idle_qbusy_q

One value per edge, printed 1 ns after it, from edge 13 on the left. The model reported that s1 settled to 1, 3 ns after edge 14.

ConceptWhich change multiplies a synchronizer's MTBF by the largest factor?
ConceptYour design crosses a bit with one flop, and it passes 10,000 RTL simulations with random clock phases. What do the simulations tell you about metastability?

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.