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.
| Signal | Function | Updates on |
|---|---|---|
| CLK_A | First clock source (faster for example) | Continuous oscillator |
| CLK_B | Second clock source (slower) | Continuous oscillator |
| SEL | User-controlled mux selection (0=A, 1=B) | Any time (async input) |
| EN_A | Gate enable for CLK_A path (2-FF synced) | Falling edge of CLK_A |
| EN_B | Gate enable for CLK_B path (2-FF synced) | Falling edge of CLK_B |
| GCLK | Final gated output: (CLK_A AND EN_A) OR (CLK_B AND EN_B) | Driven by OR of gated clocks |
Handshake Sequence: Switching A → B
- User asserts SEL=1. EN_A logic input becomes false:
(!SEL && !EN_B) = 0 - On the next falling edge of CLK_A, FF_A1 captures 0. One cycle later FF_A2 captures 0 → EN_A=0
- Meanwhile EN_B waits for feedback: EN_B logic =
(SEL && !EN_A). With EN_A=0, this becomes 1 - On the next falling edge of CLK_B, FF_B1 captures 1. One cycle later FF_B2 → EN_B=1
- 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
- Using rising-edge FFs in the synchronizer — rising-edge FFs update while the clock is transitioning high, which can cause the AND gate to glitch if timing is close
- Omitting the feedback cross-coupling — without !EN_B in the A path logic, both enables can briefly be 1, producing OR gate overlap and a spurious combined pulse
- Applying STA across the mux boundary — paths from en_a FF to en_b_ff1 span clock domains; they must be false-pathed or the tools report unconstrained paths
- Expecting immediate switching — the handshake takes up to 4+ cycles; controllers that assume instant switching will see stale reads during the dead zone
- Using this design for >2 clocks — for 3+ clocks, a round-robin handshake or clock switch controller with priority arbitration is needed
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.
Frequently Asked Questions
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.