无毛刺时钟切换:在两个都在跑的时钟之间安全换挡
更新时间:2026-09-12。本文是「集成电路大类 · 芯片设计」进阶层(intermediate)数字逻辑第五十五篇。多时钟芯片常要在外部晶振与 PLL 时钟、高速与低速时钟之间动态切换。这件看似一个 MUX 就能做的事,做错会产生致命的假时钟沿。这一篇讲标准的无毛刺时钟复用器(glitch-free clock mux)。
本文要回答的问题
- 直接
clk_out = sel ? clkA : clkB会出什么问题?什么是 runt 窄脉冲? - 为什么切换逻辑要用时钟的负沿触发器?为什么两路要互相屏蔽?
- 选择信号来自另一个时钟域,怎么保证它被安全同步?
- 一次「原子」切换的完整时序是什么?中途有没有短脉冲风险?
- 它和时钟门控 ICG、以及可测性设计(scan/DFT)有什么关系?
一、直接 MUX 为什么危险
时钟是对毛刺零容忍的特殊信号(见分频与时钟使能)。普通 MUX 的选择端 sel 是普通逻辑信号,可能在任意时刻翻转:
- 若 sel 在 clkA 正为高电平期间变化,输出可能在这半个周期中间断开 clkA,产生一个被截断的高电平(runt pulse),下游把它当一个真实边沿,多触发一次;
- 若 sel 跳变本身带组合毛刺,时钟输出直接出现尖峰;
- 切换瞬间可能短暂把 clkA、clkB 同时接通,输出是两个异步时钟的非法组合。
后果是该时钟域的触发器整体错乱,且这类问题在仿真里因延迟模型不准常常看不到,是典型的硅片级噩梦。
二、标准结构:负沿寄存 + 互斥交叉使能
经典无毛刺 mux 对每条支路做两件事:①用该支路时钟的负沿触发器来使能/关闭这条时钟路径;②两条支路的使能互相反馈、保证任一时刻最多一条导通。
// 概念结构(两路),关键:用各自时钟的 negedge 寄存选择
always_ff @(negedge clkA or negedge rst_n)
if (!rst_n) selA <= 1'b1;
else selA <= sel & ~selB_en; // 想选 A 且 B 已确实关断
always_ff @(negedge clkB or negedge rst_n)
if (!rst_n) selB <= 1'b0;
else selB <= ~sel & ~selA_en; // 想选 B 且 A 已确实关断
// 每路时钟先被自己的使能(负沿后稳定)门控,再相或
assign clk_out = (clkA & enA) | (clkB & enB);为什么是负沿:使能信号在时钟为低电平期间更新并稳定,等到下一个正沿到来时门控早已确定——这样绝不会在高电平中途把时钟切断(不会截断高电平),也就没有 runt。为什么要交叉等待对方关断:保证从 A 切到 B 时,一定先在 A 的低电平窗口关 A、确认 A 关干净,再在 B 的低电平窗口开 B,两路永不同时通,输出是「完整的 A 周期若干个,接着完整的 B 周期」,没有半个脉冲。
三、选择信号也要跨时钟域同步
请求切换的 sel 通常来自系统控制器、属于另一个时钟域(甚至异步)。它不能直接进两个负沿触发器,否则可能把亚稳态带进时钟门控。标准做法:把切换请求先在各自支路用该时钟域的同步器打两拍,再做互斥仲裁。于是完整切换序列是:
- 控制器改 sel(请求用 B);
- sel 同步到当前时钟 A 域,在 A 的某个负沿把 enA 拉低(且要等 B 支路确认未开);
- enA 关断后,A 时钟被干净地与掉,输出只剩低电平;
- sel/握手状态同步到 B 域,在 B 的某个负沿把 enB 拉高;
- 此后输出完整的 B 时钟。整个过程跨若干周期,是「慢但绝对干净」的原子换挡。
四、和 ICG、可测性的关系
- 与时钟门控 ICG 同源:ICG 是「单路时钟的开/关」(用负沿锁存稳住 enable 再与时钟,见分频与时钟使能/低功耗),glitch-free mux 可看成「两路 ICG + 互斥选择」组合;时钟树上的时钟选择、分频器输出切回都用同一类负沿门控单元。
- 库单元优先:多数标准单元库直接提供经过硅验证、带复位/测试脚的 CGMUX/clock mux,应例化它而非手写与或,手写极易因综合重排而失效。
- DFT/scan 要求:扫描测试时所有时钟要可控(ATE 直接供时钟),时钟 mux 要有测试模式旁路(test mode 下选扫描时钟、绕过内部可能停振的源),否则链上触发器无法统一移位;复位期间默认时钟也应是确定的某个源(通常是始终存在的参考时钟),呼应复位拓扑与 RDC。
五、常见错误清单
- 用普通组合 MUX 或
assign clk_o = sel ? clk1 : clk2;选时钟; - 在正沿更新门控使能(可能截断高电平产生 runt);
- 两路不互斥、切换瞬间同时接通;
- 切换请求未跨域同步,或切换时目标时钟尚未起振/未锁定(必须等 PLL lock);
- 让综合器自由优化时钟路径(时钟要走专用网络、设 don't touch、做 CTS)。
与现有篇目的衔接
总结
一句话总结:时钟对毛刺零容忍,普通 MUX 的选择信号若在某时钟为高或沿附近变化,会截断高电平产生 runt 窄脉冲、引入组合尖峰或瞬间同时接通两路异步时钟,导致整个时钟域误翻转,且常因仿真延迟不准而漏到硅片;无毛刺时钟 mux 的标准做法是给每条支路用「该时钟负沿触发器」更新门控使能(使能在时钟低电平期间稳定,绝不切断高电平),并让两路使能交叉反馈、互斥等待——先在当前时钟低电平窗口干净关掉它、确认关断,再在目标时钟低电平窗口打开新时钟,输出永远是完整周期拼接;切换请求本身跨时钟域,必须先经各域两级同步再仲裁,且目标时钟要已稳定(PLL lock);它本质是「两路带负沿锁存的 ICG 加互斥选择」,实践中应直接例化库内经过验证的 clock mux 单元、设 don't touch 并给 scan/DFT 留测试旁路,复位期间默认选择确定存在的参考时钟,切忌手写组合选时钟或在正沿更新使能。