[Verilog] RTL Design: Glitch-free Clock Mux

As low-power design becomes more important, Dynamic Frequency Scaling (DFS) technique, which uses a high-speed clock (PLL) when the chip is busy and switches to a low-speed clock (Oscillator) when in standby mode, has become essential.

The most common mistake beginner RTL engineers make at this point is treating the clock as data.

// Code you should never do
assign clk_out = select ? clk_fast : clk_slow;

Using a MUX this way causes glitches. When switching occurs while the clock is high, the clock pulse is truncated, creating a very short "runt pulse." This short pulse violates the minimum pulse width requirement of the D-FlipFlop, causing the entire chip to enter a metastability state and malfunction.

In this article, we will learn about the principles and implementation code of a Glitch-free Clock Mux that safely switches clocks whenever a switching signal is sent.

1. Basic principle: “Turn on after the current clock is off.”

The core principle of preventing glitches is simple: Break-before-make.

  1. When the select signal changes, we should not immediately switch to the new clock.
  2. Wait until the currently used clock (clk_current) goes Low (0) and then disconnect.
  3. After verifying that the output is perfectly 0, connect a new clock (clk_next).

This process prevents the High section of the clock from being cut off.

2. Circuit Structure: Secure Handshake Between Asynchronous Clocks

To switch two clocks (Asynchronous Clocks) with completely different frequencies and phases, a synchronizer and a feedback loop are required.

Core Components

  1. Falling-Edge Flip-Flop: When turning the clock on or off, we use a F/F that operates on the negative edge to avoid touching the high clock period. This ensures that the Enable signal changes only when the clock is low.
  2. Feedback Path: To check if the other party's clock is completely off, I get the other party's state value as my Enable condition (Mutual Exclusion).
  3. 2-DFF Synchronizer: Since the select signal does not know which clock it will come in on, it must be synchronized to each clock domain.

3. Verilog Implementation

module glitch_free_clk_mux (
    input  wire clk0,    // Clock Source A
    input  wire clk1,    // Clock Source B
    input  wire select,  // 0: clk0, 1: clk1
    input  wire rst_n,   // Asynchronous Reset
    output wire clk_out  // Glitch-free Output
);

    reg [1:0] q0, q1; // Synchronizers (Rising Edge)
    reg       g0, g1; // Gating FFs (Falling Edge)

    // --- Path for CLK 0 ---
    // Request activation when the opponent (g1) is off (!g1) and the selection is 0 (!select)
    always @(posedge clk0 or negedge rst_n) begin
        if (!rst_n) q0 <= 2'b00; // Safely reset to 0
        else        q0 <= {q0[0], ~select & ~g1}; // Sync & Logic
    end

    // Actual gating is performed at the falling edge (high pulse protection)
    always @(negedge clk0 or negedge rst_n) begin
        if (!rst_n) g0 <= 1'b0;
        else        g0 <= q0[1];
    end

    // --- Path for CLK 1 ---
    // Request activation when the opponent (g0) is off (!g0) & selection is 1 (select)
    always @(posedge clk1 or negedge rst_n) begin
        if (!rst_n) q1 <= 2'b00; // Safely reset to 0
        else        q1 <= {q1[0], select & ~g0}; // Sync & Logic
    end

    // Actual gating is performed at the falling edge
    always @(negedge clk1 or negedge rst_n) begin
        if (!rst_n) g1 <= 1'b0;
        else        g1 <= q1[1];
    end

    // --- Output Logic ---
    // Only the active clock passes (AND-OR structure)
    wire clk0_gated = clk0 & g0;
    wire clk1_gated = clk1 & g1;
    
    assign clk_out = clk0_gated | clk1_gated;

endmodule

4. Motion Scenario Analysis

What happens if the user changes select from 0 to 1?

Glitch free clock mux waveform
Glitch free clock mux waveform
  1. Request: select=1.
  2. CLK0 Blocked: The input to the CLK0 logic is ~select, so it becomes 0. On the falling edge of CLK0, g0 drops to 0. The CLK0 path is now blocked.
  3. Dead Zone: The g0=0 signal passes to CLK1. At this time, both clocks are blocked, and the output remains at 0. (Safe Zone)
  4. CLK1 Activation: The CLK1 logic checks that select=1 and is named g0=0. On the Falling Edge of CLK1, g1 transitions to 1.
  5. Output: clk_out now follows CLK1.

This process ensures that switching never occurs while either clock is high.

5. Conclusion: Clock is uncompromising.

Glitch-free muxes have higher latency than regular muxes. It takes several clock cycles (synchronization process) after the select signal is given for the actual clock to change.

But this delay comes at the cost of safety. A single glitch on the clock line can trigger a time bomb that could trigger an error anywhere among billions of transistors.

  • If you use clocks of different frequencies: Be sure to use the asynchronous handshake circuit introduced above.
  • If it is a synchronous clock (multiplier relationship) coming from the same PLL: A slightly simpler circuit is possible, but if you are confused, it is safest to just use the circuit above.

References: VLSI tutorials

Similar Posts