Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutRoadmapCareersInternshipsFAQContactPrivacyTerms
Skip to lesson

Course contents

  • How to Use This Course
  • The NanoSoC Tour
  • Reading Path
  • SoC Glossary10
  • SoC Metrics Reference
  • SoC Cheatsheet
  • What SoC Integration Is12
  • Architecture and Budgets21
  • Memory Maps and Address Decode26
  • Interconnect and Bus Fabrics26
  • Clock and Reset Architecture24
    • Clock Sources and PLLs
    • Dividers, Muxes and Glitch-Free Switching
      • Integer Dividers and Clock Muxes
      • Glitch-Free Switching Sequence
      • Switching Failure Modes
    • Clock Gating Architecture
    • Clock Domain Planning
    • Top-Level Crossings
    • Always-On Domain, Wake Policy and a Timer Extension
    • Reset Sources and Reset Tree
    • Reset Sequencing and Release
  • Power Architecture21
  • Interrupts, DMA and Peripherals15
  • Memories, Boot and Security21
  • IP Integration and Handoff21
  • Top-Level Verification and Bring-up21
  • Package, Pads and I/O18
  • Chip Signoff and Tapeout18
  • SoC Interview Prep16
  • Capstone: Integrate NanoSoC14
Loading lesson

←Dividers, Muxes and Glitch-Free Switching
  1. Topics
  2. SoC Design
  3. Clock and Reset Architecture
  4. Dividers, Muxes and Glitch-Free Switching
  5. Glitch-Free Switching Sequence
On this page

    Part 5 of 14, lesson 5 of 24Part 5 of 14/Clock and Reset Architecture/Lesson 5 of 24All levels

    Glitch-Free Switching Sequence

    The handshake that changes clocks without a runt pulse, a waveform proving it, and the dead-time budget of a NanoSoC switch.

    Why it matters

    NanoSoC never switches a running clock: its ratios are fixed and clk_per is the crystal. A real chip built from it will, for test, for a bypass or for a gear change, and the integrator then owns two things the circuit lesson does not: how long the clock is dead and which blocks must tolerate that. This lesson recalls the safe sequence in a few lines, proves it with a waveform, and spends the rest on the integration budget. Its one job is the sequence and its dead time; the ways it is violated are the next lesson.

    The core idea

    The circuit construction, an AND gate per source with one-hot enables that each change only while their own clock is low, is taught in Glitch-Free Clock Mux and its CDC view in Clock Gating and Muxing; it is not repeated here. What the integrator needs is the order. Drop the old enable (synchronised to the old clock); wait until the old branch is seen steady low; raise the new enable (synchronised to the new clock); only then does the output follow the new source. Between the two enables the output is dead, a stretched low phase, which is safe: a missing pulse delays an edge, a runt pulse corrupts state.

    nano_clk_mux2.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // snippet: AND-gate clock mux with one-hot enables (partial: the
    // synchronisers and the handshake controller that sequence ena/enb live
    // outside this fragment, in the clock controller).
    module nano_clk_mux2 (
      input  logic clka,
      input  logic clkb,
      input  logic ena,   // one-hot with enb; changes only while clka is low
      input  logic enb,   // one-hot with ena; changes only while clkb is low
      output logic clkout
    );
      logic gated_a, gated_b;
      assign gated_a = clka & ena;
      assign gated_b = clkb & enb;
      assign clkout  = gated_a | gated_b;
    endmodule

    Simulation: one switch each way

    The waveform below is simulation output for the wave source of this topic: a switch from the fast clock to the slow clock and back. One slot is one cycle of the fast clock, sampled shortly after its rising edge.

    How to read it: sel_req rises in slot 4 while both enables are steady. ena falls in slot 5 and clkout is low in slots 5 and 6, with neither enable raised for that stretch. enb rises in slot 6, and clkout follows the slow clock from slot 7: high in slots 7 and 9 around the low slot 8. The return trip has a longer dead stretch. sel_req falls in slot 10 and enb has already fallen in the same slot, so clkout is low in slots 10 and 11. ena rises in slot 12, while the fast clock is low, and clkout is high in slot 12 and follows the fast clock from there. In the lanes no pulse looks short, but one sample per slot cannot show a runt. The proof is the monitor in the testbench source, which measures every clkout phase at 1 ns resolution and stops the run if one is narrower than the fast half-period of 5 ns: with the enable moved to a high phase of the fast clock it reports a 4 ns pulse, and with the enable in the low phase it stays silent.

    Worked example: the dead-time budget

    Suppose a NanoSoC derivative switched clk_sys from the 96 MHz divider output to the 24 MHz crystal, for example to lower power. Both numbers below are illustrative, since NanoSoC itself never does this. The old enable is synchronised into the old clock (two clk_sys periods), then the new enable into the new clock (two clk_per periods), and the output is dead for the sum.

    Step

    Clock

    Cost

    Time

    Drop old enable, synchronised

    clk_sys 96 MHz

    2 x 10.417 ns

    20.8 ns

    Raise new enable, synchronised

    clk_per 24 MHz

    2 x 41.667 ns

    83.3 ns

    Dead time

    sum

    104.2 ns = 10 clk_sys cycles

    example.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    # Dead time of a clk_sys -> crystal switch (illustrative scenario).
    T_SYS, T_PER = 1e3 / 96, 1e3 / 24   # ns
    dead = 2 * T_SYS + 2 * T_PER
    assert abs(dead - 104.17) < 0.01
    assert round(dead / T_SYS) == 10
    
    # Who must tolerate it: an APB access normally takes 3 clk_sys = 31.25 ns,
    # the bridge timeout is 256 clk_sys = 2666.7 ns, the PLL-independent crystal
    # keeps the always-on logic alive meanwhile.
    ACCESS_NS, TIMEOUT_NS = 3 * T_SYS, 256 * T_SYS
    assert abs(ACCESS_NS - 31.25) < 0.01 and abs(TIMEOUT_NS - 2666.7) < 0.1
    
    def safe(dead_ns, in_flight):
        # An in-flight access finishes if dead time plus access fits the timeout.
        return (not in_flight) or (dead_ns + ACCESS_NS < TIMEOUT_NS)
    
    assert safe(dead, True)                # the real switch is survivable
    assert not safe(3000.0, True)          # a 3 us dead time would trip the timeout
    assert safe(3000.0, False)             # but is harmless when the bus is quiet
    print("PASS: dead time 104.2 ns = 10 clk_sys cycles; far inside the 2.667 us bridge timeout")

    The budget also shows why the switch is requested, not forced. The clock controller raises a clock-change request to every block on the affected clock; each block finishes its transfer and answers with an acknowledge when it is quiet; only when all acknowledges are high does the controller start the enable sequence, and it releases the request after the new clock is running. The bridge FIFOs and the 256-cycle APB timeout must tolerate the 10-cycle dead stretch; the acknowledge handshake keeps new accesses from starting inside it.

    What the review looks for

    • The controller that sequences the enables is named, with its request and acknowledge signals to every block on the clock.

    • Each enable change is synchronised to its own clock low phase; the evidence is a pulse-width check, not the per-slot picture.

    • The dead stretch is budgeted in cycles of the slower and faster clock, and compared with every timer and timeout on that clock.

    Verify and debug

    Assert the two invariants in simulation: the enables are never high together, and every clkout pulse meets the minimum width of the slower source, measured at fine resolution. Sweep the request timing against both clocks, because the synchroniser latency moves with phase, and run the test once with a deliberately early enable to prove the width check can fail. A glitch that appears only at one alignment points at an enable changing on the wrong phase.

    Glitchy clock mux. Symptom: random lock-ups at frequency change. Caught by clock-glitch lint and by gate-level simulation, and fixed with the handshake above plus a way to switch when a clock is dead, which the next lesson covers. The waveform source in this lesson once had its last enable at 116 ns, inside a high phase of the fast clock: the per-slot lanes looked clean while a 4 ns pulse existed, which is why the width monitor exists.

    If asked to switch clocks, say the order before drawing anything: drop, wait, raise, each enable synchronised to its own clock. Then give the cost: two periods of the old clock plus two of the new, which for 96 MHz to 24 MHz is 104 ns, and who must tolerate it. The follow-up is always the dead clock; have that answer ready too.

    Check yourself During a switch the output clock stops for a few cycles. Why is a missing pulse safe while a short pulse is fatal?

    A stretched low phase only delays the next edge; every flop keeps its state. A runt pulse can clock some flops and not others, or violate recovery on asynchronous inputs, leaving the design in a state no reset sequence planned for.

    Check yourself For a switch from the 24 MHz crystal up to the 96 MHz clock, what is the dead time?

    Two crystal periods for the old enable plus two clk_sys periods for the new: 2 x 41.667 + 2 x 10.417 = 104.2 ns. The sum is the same in either direction; only which clock takes which term changes.

    Related topics

    • Integer Dividers and Clock Muxes

    • Next: Switching Failure Modes

    • RTL: Glitch-Free Clock Mux

    • CDC and RDC: Clock Gating and Muxing

    Previous

    92 / 289

    Next: Switching Failure Modes

    Up next

    Up nextSwitching Failure Modes

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error
    clkaclkbsel_reqenaenbclkout
    Simulation output: a glitch-free switch from the fast clock to the slow clock and back