Skip to content

GLS · Chapter 9 · CDC & Asynchronous Behaviour in GLS

Synchronisers Under Real Delays

The two-flop synchronizer is the workhorse of clock-domain crossing, and gate-level simulation shows how it behaves under real delays. The first flop samples the asynchronous input, and because that input can change during its aperture window, the flop may sample mid-transition, which the simulator models as an unknown. That unknown passes to the second flop, which gets a full cycle to settle and resolves it to a stable value the receiving domain can use. Because the first flop's unknown on a legitimate crossing is expected, its timing checks are usually disabled to avoid flooding the design, but only there. This lesson shows the synchronizer under real delays, explains why it works only for single-bit or gray-coded signals, and clarifies that metastability survival is quantified by MTBF, not by the simulation itself.

Foundation12 min readGLSSynchronizerCDCReal DelaysGray Code

Chapter 9 · Section 9.3 · CDC & Asynchronous Behaviour in GLS

Project thread — every crossing in the mini-SoC uses a synchronizer like this. This lesson shows it under real delays; 9.4 extends it to the async FIFO for multi-bit data.

1. Why Should I Learn This?

The synchronizer is the CDC building block — and it has two GLS gotchas.

  • The first flop's X is expected — disable its checks (only there) to avoid X-flooding (8.5).
  • It works only for single-bit / gray-coded signals — multi-bit needs a FIFO/handshake (9.4).
  • GLS shows structure/timing; MTBF verifies metastability survival (9.2).

This grounds every crossing in the chapter and the mini-SoC.

2. Real Silicon Story — the synchronizer that flooded the sim with X

A crossing used a proper two-flop synchronizer, but the gate-level run was flooded with X — hundreds of downstream signals unknown — and the team thought the synchronizer was broken.

The synchronizer was fine. Timing checks on its first flop were left enabled, so every async edge in the aperture injected X (correctly — the crossing is async), and that X propagated everywhere (8.5). Disabling timing checks on the first synchronizer flop (the expected async crossing) stopped the flood — and the synchronizer resolved cleanly as designed.

Lesson: the first synchronizer flop's X is expected on an async crossing — disable its timing checks (only there) to avoid X-flooding. The synchronizer isn't broken; the checks were misapplied.

3. Concept — the synchronizer under real delays

Structure:

  • Two flops in series in the receive domain: async_in → [flop1] → [flop2] → sync_out.
  • Flop1 samples the async input (may be metastable → X in sim, 9.2).
  • Flop2 gets a full cycle to settle the X → stable sync_out.

Under real delays:

  • The settling budget = one receive-clock cycle minus (flop1 clk-to-Q + flop2 setup).
  • MTBF quantifies whether that budget makes metastability acceptably rare (9.2) — GLS shows the timing, not the probability.

Two rules GLS teaches:

  • (1) Disable checks on flop1 (only). The first flop's X on a legitimate async crossing is expected (8.4) — disabling its timing checks avoids X-flooding (8.5). Never disable checks elsewhere (masks real violations, 8.4).
  • (2) Single-bit / gray-coded only. A two-flop synchronizer is safe for one bit (or a gray-coded value where only one bit changes, 9.4). A multi-bit bus can have different bits resolve differentlygarbage → use a handshake or async FIFO (9.4).

Scope (accuracy):

  • GLS reveals structure and real-delay timing; metastability survival is MTBF (9.2).
  • Disabling flop1's checks is targeted and justified — not wholesale (8.4).
Two-flop synchronizer: flop1 samples async input (may be X), flop2 settles it; checks disabled on flop1; single-bit onlyX settlesasync_infrom another clock domainFlop1 (may be X)samples async → metastablerisk (9.2)Flop2 (settles)full cycle to resolve →stablesync_outsafe in receive domainDisable checks onFlop1expected async X → avoidflood (8.5); ONLY hereSingle-bit / grayonlymulti-bit → handshake /async FIFO (9.4)12
Figure 1 — a two-flop synchronizer under real delays (representative). The async input is sampled by FLOP1 (receive domain); it may go metastable, modelled as X (9.2). FLOP2, given a full receive-clock cycle to SETTLE, resolves the X to a stable sync_out. Timing checks on FLOP1 (the expected async crossing) are DISABLED to avoid X-flooding (8.4/8.5) -- only there. The synchronizer is safe only for SINGLE-BIT / gray-coded signals; a multi-bit bus needs a handshake or async FIFO (9.4). GLS shows structure/timing; MTBF verifies survival.

4. Mental Model — a two-stage airlock

A synchronizer is an airlock between two pressures (clock domains).

  • Flop1 is the outer door — it takes the chaotic outside pressure (async input) and may wobble (metastable) as it seals.
  • Flop2 is the inner door — it waits a full cycle for the outer chamber to stabilize before opening into the clean domain.
  • Don't alarm the outer door for wobbling (disable flop1's checks) — that's its job. But keep alarms on the inner rooms (checks elsewhere).
  • One person at a time — an airlock passes a single value (bit); a crowd (multi-bit bus) needs a proper queue (FIFO/handshake).

Two doors, one cycle to settle, one bit at a time.

5. Working Example — the two-flop synchronizer (tri-HDL)

The synchronizer in three languages:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// SystemVerilog — 2-flop synchronizer (single-bit) in the receive domain
logic sync1, sync2;
always_ff @(posedge clk_b or negedge rst_n)
  if (!rst_n) {sync2, sync1} <= 2'b0;
  else        {sync2, sync1} <= {sync1, async_in};   // async_in -> sync1 -> sync2
assign sync_out = sync2;
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Verilog — same synchronizer
reg sync1, sync2;
always @(posedge clk_b or negedge rst_n)
  if (!rst_n) {sync2, sync1} <= 2'b0;
  else        {sync2, sync1} <= {sync1, async_in};
assign sync_out = sync2;
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- VHDL — same synchronizer
process (clk_b, rst_n) begin
  if rst_n = '0' then sync1 <= '0'; sync2 <= '0';
  elsif rising_edge(clk_b) then sync1 <= async_in; sync2 <= sync1; end if;
end process;
sync_out <= sync2;

The GLS setup for the crossing:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
# Synchronizer in GLS (tool-neutral):
#   DISABLE timing checks on sync1's D (the async crossing) -> expected X, avoid flood (8.4/8.5)
#   keep checks everywhere else
#   single-bit / gray-coded only (9.4); multi-bit bus -> async FIFO / handshake
#   GLS shows sync1 X settling through sync2 under real delays; MTBF verifies survival (9.2)

Practical context (representative, tool-neutral):

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
# Synchronizer GLS checklist (tool-neutral):
#   [ ] disable timing checks on flop1 (async crossing) -- ONLY there (8.4/8.5)
#   [ ] single-bit or gray-coded signal? (multi-bit -> FIFO/handshake, 9.4)
#   [ ] X at flop1 settles through flop2 within one receive cycle (real delays)
#   [ ] metastability survival -> MTBF, not this sim (9.2)

The X settling through the synchronizer, as a real waveform:

Two-flop synchronizer under real delays: flop1 X (risk) settles through flop2 to a stable sync_out

9 cycles
The first synchronizer flop shows X from the async crossing; the second flop resolves it to a stable value a cycle laterflop1 X (checks disabled)flop1 X (checks disabl…settled → safesettled → safeclk_basync_insync1 (X risk)Xsync2 = sync_outXt0t1t2t3t4t5t6t7t8
Representative. async_in crosses into clk_b. sync1 samples mid-transition and shows X (risk, checks disabled here to avoid flooding). sync2, a cycle later, resolves to a stable value — sync_out is safe in the receive domain. GLS shows the structure/timing; MTBF (not this sim) verifies metastability survival. Single-bit only; a bus needs a FIFO (9.4).

6. Debugging Session — X-flood from a synchronizer's first flop

1

A gate-level run floods with X from a proper synchronizer because timing checks on its first flop were left enabled, injecting the expected async-crossing X everywhere; disabling checks only on the first synchronizer flop stops the flood without masking real violations

DISABLE CHECKS ON THE FIRST SYNC FLOP (ONLY) — EXPECTED ASYNC X
Symptom

A crossing uses a correct two-flop synchronizer, but the run is flooded with X — the synchronizer looks broken.

Root Cause

Timing checks left enabled on the first synchronizer flop. The first flop samples an asynchronous input, so data legitimately changes in its aperture window every crossing — firing a $setup/$hold check and injecting X (correctly, 9.2/8.5). But that X propagates downstream (8.5), flooding the design. The crucial point: this X is expected on a legitimate async crossing — the check is not physically meaningful there (8.4). Leaving it enabled turns a working synchronizer into an X-fountain. The synchronizer isn't broken; the timing checks are misapplied to an async crossing.

Fix

Disable timing checks on the first synchronizer flop's async input — a targeted, justified disable on a legitimate async crossing (8.4) — to stop the expected-X flood. Keep checks everywhere else (disabling wholesale would mask real violations, 8.4). The synchronizer then resolves cleanly under real delays (flop1 X → flop2 settled). Two related checks: confirm the crossing is single-bit / gray-coded (a multi-bit bus through a 1-bit synchronizer is a real bug — different bits resolve differently → garbage → use a FIFO/handshake, 9.4); and remember metastability survival is MTBF, not this sim (9.2). The lesson: the first synchronizer flop's X on an async crossing is expected — disable its timing checks (only there) to avoid X-flooding, keep checks elsewhere, and ensure the crossing is single-bit/gray-coded. (GLS shows structure/timing; MTBF verifies survival; STA signs off timing, 0.3.)

7. Common Mistakes

  • Leaving timing checks on the first synchronizer flop. Expected async X floods the sim (8.5).
  • Disabling checks wholesale to stop the flood. Masks real violations elsewhere (8.4).
  • Sending a multi-bit bus through a 1-bit synchronizer. Bits resolve differently → garbage (use FIFO/handshake, 9.4).
  • Thinking GLS proves the synchronizer beats metastability. That's MTBF (9.2).
  • Not giving flop2 a full cycle to settle. The settling budget is the point.

8. Industry Best Practices

  • Disable timing checks only on the first synchronizer flop (async crossing, justified).
  • Keep checks everywhere else — never wholesale.
  • Use synchronizers for single-bit / gray-coded signals; FIFO/handshake for multi-bit (9.4).
  • Verify metastability survival with MTBF (9.2), not GLS.
  • Confirm the settling budget (flop1 clk-to-Q + flop2 setup within one cycle).

Senior Engineer Thinking

  • Beginner: "The synchronizer floods the sim with X — it's broken."
  • Senior: "The first flop's X is expected on an async crossing — I disable its checks (only there) to stop the flood. And is this signal single-bit? A bus through a 1-bit synchronizer is the real bug."

The senior disables checks only on the first sync flop and verifies single-bit/gray-coded usage.

Silicon Impact

The two synchronizer gotchas map to two silicon realities. (1) Leaving checks on the first flop doesn't cause a silicon bug, but it buries real violations under an X-flood, so a genuine timing bug elsewhere gets masked (or the team disables checks wholesale to cope, 8.4 — and that ships a real bug, 0.3). (2) A multi-bit bus through a one-bit synchronizer is a real, serious silicon bug: different bits resolve independently, so the receiving domain can latch a value that never existed — a classic CDC data-corruption failure, fixed only by a gray code, handshake, or async FIFO (9.4). GLS reveals both (the flood, and — with real delays — the multi-bit skew), while MTBF handles the metastability probability. Correct synchronizer usage under real delays is foundational to every safe crossing.

Engineering Checklist

  • Disabled timing checks only on the first synchronizer flop (async crossing).
  • Kept checks everywhere else (no wholesale disable, 8.4).
  • Confirmed the crossing is single-bit / gray-coded (else FIFO/handshake, 9.4).
  • Verified the settling budget (flop1 clk-to-Q + flop2 setup ≤ one cycle).
  • Left metastability survival to MTBF (9.2), not GLS.

Try Yourself

  1. Build a two-flop synchronizer and drive async_in to change in flop1's aperture; run with flop1's timing checks enabled — watch X flood downstream.
  2. Observe: the flood comes from the expected async X on flop1 (8.5).
  3. Change: disable timing checks only on flop1's async input.
  4. Expect: the flood stops; X settles cleanly through flop2. Then push a 2-bit bus through and watch the bits resolve independently — the real bug a FIFO/handshake fixes.

Any free Verilog simulator with two async clocks and configurable timing checks reproduces this. No paid tool required.

Interview Perspective

  • Weak: "A synchronizer just delays the signal two cycles."
  • Good: "The first flop may go metastable (X in sim); the second settles it. Disable timing checks on the first flop's async input."
  • Senior: "Under real delays, flop1's clk-to-Q plus flop2's setup must fit in a cycle to settle. Flop1's X on an async crossing is expected, so I disable its checks (only there) to avoid X-flooding — never wholesale. Synchronizers are single-bit/gray-coded only; a bus needs a FIFO/handshake. GLS shows structure/timing; MTBF verifies survival."

9. Interview / Review Questions

10. Key Takeaways

  • A two-flop synchronizer places two flops in series in the receive domain: flop1 samples the async input (may be metastable → X in sim, 9.2), flop2 gets a full cycle to settle it to a stable sync_out.
  • Under real delays, the settling budget is one receive-clock cycle minus (flop1 clk-to-Q + flop2 setup) — MTBF quantifies the metastability probability, GLS shows the timing (9.2).
  • Disable timing checks on flop1 only — its X on a legitimate async crossing is expected (8.4); leaving them on floods the sim (8.5); disabling wholesale masks real violations (8.4).
  • A synchronizer is safe only for single-bit / gray-coded signals — a multi-bit bus needs a handshake or async FIFO (9.4), or bits resolve independently into garbage.
  • GLS shows structure and real-delay timing; metastability survival is MTBF's job (9.2); STA signs off timing (0.3). Next: 9.4 — asynchronous FIFO behaviour in GLS.

Quick Revision

2-flop synchronizer: flop1 samples async (may be X, 9.2), flop2 settles it within one receive cycle. Disable timing checks on flop1 ONLY (expected async X → avoid flood, 8.5); keep checks elsewhere. Single-bit / gray-coded only — multi-bit bus → FIFO/handshake (9.4), else bits resolve independently → garbage. GLS shows structure/timing; MTBF verifies survival (9.2). Next: 9.4 — async FIFO in GLS.