CDC自查15项检查清单:逐条判定方法与修复手段
跨时钟域(CDC, Clock Domain Crossing)问题是数字设计里最难在仿真中暴露的一类缺陷:RTL 仿真里一切正常,上板后偶发数据错乱、状态机跑飞,复现一次要几个小时。问题根源是亚稳态——触发器采样到变化中的信号,输出可能在一段时间内既不认 0 也不认 1。本站已有 CDC 基础知识 讲清原理,本篇是它的工程落地版:一份 15 项的流片前自查清单,每项给出「怎么判定不合格」和「不合格怎么修」。
本文要回答的问题
- 一段 RTL 里哪些地方藏了 CDC 风险,怎么逐条扫出来?
- 单比特信号、多比特总线、复位信号各自的正确跨域姿势是什么?
- 哪些写法看似有同步器、实际上仍然不安全(毛刺、再汇聚、数据保持不足)?
一、分组概览
15 项检查按失效机理分四组:信号路径组查「有没有同步器」;结构组查「组合逻辑和汇聚路径」;多比特组查「总线跨域的一致性」;复位与时序组查「复位和脉冲语义」。先用这张图建立全貌,后面逐条展开。
四组的重要性不同:信号路径组合规了只能保证「信号大体过得去」,真正致命的 bug 往往出在结构组(毛刺被同步器放大、两路信号在接收域重新汇聚时错位)和多比特组(总线拆成单比特逐个同步导致采样到中间态)。这也是排查顺序建议:先扫结构组,再扫多比特组。
二、信号路径组(第 1-4 项)
第 1 项:每个跨域单比特控制信号都有两级触发器同步器。 判定:在 RTL 里搜目的时钟域 always 块的敏感信号,若某个信号来自另一个时钟域且直接进入组合逻辑或单级触发器,即不合格。修复:插入标准两级同步器(reg sync1, sync2; always @(posedge clk_b) begin sync1 <= sig_a; sync2 <= sync1; end),下游只用 sync2。为什么单比特可以直接同步、多比特不行,见 为什么双触发器同步器不能直接搬给多比特信号。
第 2 项:跨域脉冲宽度足够或被展宽。 判定:源域只持续 1 拍的脉冲送往更慢的时钟域,慢域可能整个漏采。修复:源域把脉冲翻转为电平(toggle),目的域同步后打拍做边沿检测恢复脉冲;或改用脉冲同步器/握手。详细写法见 脉冲同步。
第 3 项:电平信号同样过同步器。 判定:有人觉得电平信号「一直在那里,采慢点没关系」就直接用——错,亚稳态不区分电平还是脉冲,跳变沿落在采样窗口照样亚稳。所有跨域信号无一例外走同步器。
第 4 项:同步器级数满足 MTBF 要求。 判定:高速、高可靠性场景(如 500MHz 以上、车规)两级可能不够。修复:升到三级同步器,或在综合/后端给同步器触发器加 ASYNC_REG(FPGA)/专用同步单元(ASIC)约束,让工具把两级放近、缩短恢复时间。
三、结构组(第 5-7 项)
第 5 项:跨域路径上没有组合逻辑直穿。 判定:源信号经过与门、多路选择器等组合逻辑后才进目的域同步器,组合输出的毛刺会被同步器采样放大成随机翻转。修复:源域先把信号打一拍寄存,寄存器输出直接进同步器,中间零组合逻辑。多比特毛刺的实测现象见 多比特跨域毛刺实验。
第 6 项:同步器输出不再分叉产生毛刺。 判定:同步后的信号驱动复杂组合逻辑,其输出再次跨到第三个时钟域时中间没寄存。修复:任何「离开当前时钟域」的信号都从寄存器出发,形成「寄存→组合→寄存」的干净边界。
第 7 项:无再汇聚(reconvergence)。 判定:同一个源信号经两条不同路径(不同级数、不同逻辑深度)进入目的域,在目的域某处重新汇合比较——两条路径延迟不同,汇合时可能是信号新旧两个值。修复:只同步一次,目的域内部分发;若必须多路径,在汇合点加对齐寄存器或改握手。
四、多比特总线组(第 8-11 项)
第 8 项:多比特总线用格雷码、握手或异步 FIFO,不拆位同步。 判定:一个 data[15:0] 的每一位各自过两级触发器——采样瞬间各位可能处于新旧混合态,采到根本不存在的值。修复三选一:计数器/指针类改格雷码(每次只变 1 位,见 格雷码指针跨域);块数据用 req/ack 握手;流式数据用异步 FIFO(见 异步 FIFO 与 CDC 及 CDC 实验枢纽)。选型细化见 多比特跨域不总用异步 FIFO。
第 9 项:握手时控制信号先于数据稳定。 判定:req 拉高时 data 是否已稳定且保持到 ack 返回。修复:源域先寄存 data 再发 req;目的域 ack 返回前源域不得改 data,形成闭环四相握手。
第 10 项:数据保持时间覆盖最坏延迟。 判定:目的域从看到控制信号到采数据的间隔,要大于数据路径与同步器延迟之和。修复:目的域采数据的拍点用状态机显式拉开,或在约束中给出 set_max_delay -datapath_only 限定数据路径延迟上界。
第 11 项:总线变化率受限。 判定:格雷码方案只在「每次变化 1 位」时安全;若总线一次跳多位(比如随机数据),格雷码失效。修复:随机数据走握手/FIFO,格雷码只留给单调递增的指针和计数器。
五、复位与时序组(第 12-15 项)
第 12 项:异步复位同步释放。 判定:复位信号跨域直接打拍释放,释放沿违反 recovery/removal 时序会让目的域触发器进入亚稳态。修复:每个时钟域各配一个复位同步器,异步置位、同步释放,见 复位同步器。
第 13 项:时钟门控单元在时钟切换点无毛刺。 判定:门控使能若来自另一个时钟域,直接进门控单元会在时钟高电平期切断时钟产生半周期毛刺。修复:使能先在本时钟域同步,再进集成时钟门控单元(ICG),不手写 assign clk = clk_src & en。
第 14 项:CDC 路径约束完整标注。 判定:异步时钟组是否已在 SDC 里 set_clock_groups -asynchronous 声明,CDC 数据路径是否误被 STA 当同步路径检查或被完全忽略。修复:补时钟组声明,数据路径加 max_delay 上界,同步器单元加识别属性,见 异步时钟与 false path。
第 15 项:CDC 工具报告清零。 判定:前 14 项人工扫完后,跑 CDC 结构检查工具(商业的 SpyGlass CDC / VC SpyGlass,开源场景用 Verilator lint + 自研脚本)确认无新增违规。修复:对每条剩余 warning 要么修、要么写明豁免理由入库;报告解读方法见 CDC/RDC 报告分诊 与 CDC/RDC 验证方法学。
这一篇在知识体系里的位置
本篇是 CDC 簇的「清单层」:原理层是 CDC 基础知识(讲亚稳态与 MTBF),机制层是格雷码、异步 FIFO、复位同步器三篇,验证层是报告分诊与方法学两篇,本篇负责把它们压成一张可勾选的表,建议在流片前评审(tapeout review)时逐项过一遍。
总结
CDC自查15项检查清单按信号路径、结构、多比特总线、复位与时序四组展开:每个单比特信号过两级同步器且脉冲语义受保护;跨域边界零组合逻辑、零再汇聚;多比特只走格雷码/握手/异步 FIFO 三条正道;复位异步置位同步释放、约束标注完整、工具报告清零。清单的价值不在记住 15 条,而在于把「偶发玄学 bug」变成「逐项可判定的工程检查」——每一项不合格的代价都是一次可能的 re-spin。