Clock Domain Crossing

Glitch-Free
Clock Mux

Why a simple 2-to-1 MUX creates fatal clock glitches, and how the mutual exclusion handshake guarantees clean transitions between asynchronous domains.

1. The Clock Glitch Problem

When a chip needs to switch operating frequency — for DVFS, test mode, or power management — it must transition its downstream registers from one clock to another. The obvious implementation is a simple combinational 2-to-1 mux: SEL=0 routes CLK_A, SEL=1 routes CLK_B.

This design is catastrophically wrong. If the SELECT signal changes while CLK_A is high, the output transitions from CLK_A to CLK_B mid-cycle, creating a runt pulse — a partial clock edge that is too short for downstream flip-flops to process reliably. A single runt pulse can cause every register in the clock domain to capture incorrect data simultaneously.

The runt pulse hazard: If SEL changes at the worst moment — while CLK_A=1 and CLK_B=0 — the output produces a narrow glitch as CLK_A is gated off. Any flip-flop whose setup time window straddles that glitch captures garbage. Even if only 1 in 1000 switches produces a glitch, the chip fails in the field.

2. Glitch-Free Architecture

The standard solution uses a mutual exclusion handshake: each clock path has its own two-stage synchronizer, and the two synchronizers are cross-coupled through feedback to ensure only one clock can be active at any time. The key insight is that the enable for each path is sampled on the falling edge of its own clock — ensuring the AND gate that gates the clock only changes state when the clock is low, preventing partial pulses.

SignalFunctionUpdates on
CLK_AFirst clock source (faster for example)Continuous oscillator
CLK_BSecond clock source (slower)Continuous oscillator
SELUser-controlled mux selection (0=A, 1=B)Any time (async input)
EN_AGate enable for CLK_A path (2-FF synced)Falling edge of CLK_A
EN_BGate enable for CLK_B path (2-FF synced)Falling edge of CLK_B
GCLKFinal gated output: (CLK_A AND EN_A) OR (CLK_B AND EN_B)Driven by OR of gated clocks

Handshake Sequence: Switching A → B

  1. User asserts SEL=1. EN_A logic input becomes false: (!SEL && !EN_B) = 0
  2. On the next falling edge of CLK_A, FF_A1 captures 0. One cycle later FF_A2 captures 0 → EN_A=0
  3. Meanwhile EN_B waits for feedback: EN_B logic = (SEL && !EN_A). With EN_A=0, this becomes 1
  4. On the next falling edge of CLK_B, FF_B1 captures 1. One cycle later FF_B2 → EN_B=1
  5. GCLK now routes CLK_B. Switch complete with no glitch

Why falling edge? The AND gates gate the clock with their enable. If the enable changes when the clock is low (which falling-edge FFs guarantee — they update at the falling edge, so EN is committed while CLK=0), the AND gate output can never produce a partial high pulse. The enable is stable before CLK rises again.

3. RTL Implementation

module clk_mux_gf (
  input  logic clk_a, clk_b, sel,
  output logic gclk
);
  logic en_a_ff1, en_a, en_b_ff1, en_b;

  // PATH A: 2-FF falling-edge synchronizer
  // Enable A = !sel AND !en_b (mutual exclusion)
  always_ff @(negedge clk_a)
    en_a_ff1 <= !sel & !en_b;

  always_ff @(negedge clk_a)
    en_a <= en_a_ff1;

  // PATH B: 2-FF falling-edge synchronizer
  // Enable B = sel AND !en_a (mutual exclusion)
  always_ff @(negedge clk_b)
    en_b_ff1 <= sel & !en_a;

  always_ff @(negedge clk_b)
    en_b <= en_b_ff1;

  // Output gate: mux produces gated clocks via AND, combined via OR
  assign gclk = (clk_a & en_a) | (clk_b & en_b);

endmodule

Synthesis Constraints

# SDC: Tell STA not to analyze paths crossing the mux boundary
# The falling-edge FFs are in different clock domains
set_false_path -from [get_ports sel] -to [get_cells en_a_ff1]
set_false_path -from [get_ports sel] -to [get_cells en_b_ff1]

# Exclude cross-feedback paths from timing analysis
set_false_path -from [get_cells en_a] -to [get_cells en_b_ff1]
set_false_path -from [get_cells en_b] -to [get_cells en_a_ff1]

4. Timing Characteristics

Switch Latency

2 cycles of old clock (to deassert EN_old) + 2 cycles of new clock (to assert EN_new). Worst case: slower clock frequency dominates.

Dead Zone

During handover both EN_A and EN_B are 0 — GCLK stops. This brief glitch-free pause must be tolerable for downstream logic.

GCLK Continuity

No partial pulses ever reach GCLK. A switched clock is always a complete cycle of either CLK_A or CLK_B, never a hybrid.

5. Common Design Errors

Interactive Lab — Glitch-Free Switch Simulator

Press "Switch to CLK_B" to trigger the mutual exclusion handshake. Watch EN_A deassert on CLK_A's falling edge, then EN_B assert on CLK_B's falling edge — GCLK transitions cleanly.

ACTIVE: CLK_A
Mutual Exclusion Handshake — Internal Connections
CLK_A CLK_B SEL AND ¬SEL ¬ENb FF_A1 negedge 1 FF_A2 negedge 1 AND ENa CLKa AND SEL ¬ENa FF_B1 negedge 0 FF_B2 negedge 0 AND ENb CLKb OR GCLK
CLK_A CLK_B SEL EN_A EN_B GCLK

Frequently Asked Questions

A glitch on the clock — even a single runt pulse — creates a spurious rising edge that downstream flip-flops cannot distinguish from a real clock. Any flip-flop whose setup time window overlaps the glitch captures garbage data. Since all registers in a domain share the same clock, one glitch corrupts the entire domain simultaneously.
Each enable is synchronized using falling-edge flip-flops, meaning EN_A and EN_B can only change when their respective clock is low. The AND gate gating each clock path only sees enable transitions while the clock is 0 — so the gated output can never produce a partial high pulse. The cross-coupled feedback ensures only one enable is active at a time.
Falling-edge FFs update their output at the falling edge of the clock, which means EN_A transitions to its new value while CLK_A=0. The downstream AND gate (CLK_A AND EN_A) can only produce a 1 output when CLK_A=1 — but by then EN_A has already stabilized from the falling-edge update. Rising-edge FFs would update EN_A during the rising transition, potentially creating a window where both CLK_A=1 and EN_A is changing.
At minimum: 2 cycles of CLK_A (for EN_A to deassert through 2 FFs) + 2 cycles of CLK_B (for EN_B to assert through 2 FFs). If CLK_A and CLK_B are asynchronous and CLK_B is very slow, the wait for EN_B can be several microseconds. Designers must ensure downstream logic tolerates this clock-pause dead zone.

Clock Mux in Professional ASIC Design

In production ASIC design, the glitch-free clock multiplexer appears at several critical junctions. The most common is in the clock management unit (CMU) or PLL output mux: during system startup, the chip must operate from a safe low-frequency test clock (typically 24 MHz or 32 kHz from an oscillator) until the PLL locks and reaches its target frequency. Once the PLL lock flag is asserted, the clock mux switches the domain from the test oscillator to the PLL output. This transition must be glitch-free — a spurious clock edge during PLL lock-up can corrupt the boot sequence and cause the chip to hang.

A second common application is functional mode switching in low-power designs. A high-performance SoC may run its CPU cluster at 2 GHz for compute-intensive tasks, then dynamically switch to a 200 MHz divided clock during idle periods to save power. The clock mux enables this frequency transition without resetting the logic — all register state is preserved across the switch. The firmware driver sends a "switch to low-power clock" command, waits for the handshake to complete (typically 10–20 clock cycles), then reduces the PLL frequency. This sequence is critical in mobile SoC power management and is verified extensively in pre-silicon simulation.

In physical design, the glitch-free clock mux cell is treated differently from ordinary combinational logic. The cell typically uses a special-purpose library cell (often called CKMUX or CKMUX2) that is characterized with clock input delay, glitch rejection specifications, and worst-case output transition time. The physical design tool places these cells near the clock tree root and applies specialized clock routing rules — clock nets use wider wires, avoid crossing signal layers where possible, and are shielded with ground on both sides to reduce coupling capacitance. The static timing analysis tool applies clock-specific analysis modes to verify that the mux output is glitch-free across all PVT (Process, Voltage, Temperature) corners.

For RTL verification, the glitch-free clock mux requires a dedicated testbench strategy. Pure RTL simulation with zero delays cannot trigger glitches — it simply switches from one clock event stream to another. The real risk of glitches only appears in gate-level simulation with SDF (Standard Delay Format) back-annotation, where actual cell delays expose the narrow timing window around the falling-edge FF updates. Verification teams run gate-level simulation with worst-case and best-case timing libraries and check that no spurious GCLK edges appear during the handshake. Additionally, formal verification using clock-domain crossing tools (SpyGlass, JasperGold) verifies the mutual exclusion property: EN_A and EN_B are never simultaneously high at the AND gate inputs.