ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

ICG时序违例修复指南:set_clock_gating_check与latency调整实战

ICG时序违例修复指南:set_clock_gating_check与latency调整实战 1. ICG时序违例的本质与修复思路拆解ICGIntegrated Clock Gating单元在数字后端设计里是个绕不开的角色。它本质上就是一个带锁存器的与门结构用来在不需要时钟翻转的时候把时钟掐断省下大量动态功耗。但省功耗的代价是它给时钟树引入了一个额外的延迟节点而这个节点的时序行为跟普通触发器完全不同——它有一个透明窗口的概念锁存器在时钟低电平期间是透明的高电平期间锁存。这个特性决定了ICG的时序检查规则跟普通setup/hold检查不是一回事。很多人第一次遇到ICG相关的时序违例时第一反应是去修setup或者hold结果发现工具报的违例路径怎么看都不太对劲修了半天也没效果。原因就在于ICG的检查项是独立的它由set_clock_gating_check这条约束来控制跟普通的时序检查是两套逻辑。如果你没有显式地设置这条约束工具会用默认值去检查而默认值往往跟你的实际设计意图不匹配违例就冒出来了。这篇文章要解决的问题很具体ICG的时序违例怎么定位、怎么通过set_clock_gating_check和latency设置来修。适合已经有一定STA基础、正在做CTS或者时序收敛的后端工程师也适合前端设计人员了解ICG约束对后端的影响。我会从约束原理讲起把参数计算过程摊开再给出一套可以直接抄的实操流程最后把我踩过的坑整理成速查表。1.1 为什么ICG的时序检查跟普通触发器不一样普通触发器的setup检查逻辑很直观数据要在时钟有效沿之前稳定一段时间。但ICG的锁存器结构决定了它的检查对象是使能信号而不是数据信号。具体来说ICG的使能信号通常叫enable或者clock_enable必须在时钟从高变低之前稳定下来这样当锁存器进入透明状态时使能值已经是确定的不会在时钟低电平期间发生翻转导致毛刺传到时钟输出端。这个检查的时间窗口就是set_clock_gating_check里定义的setup和hold值。setup值定义了使能信号需要在时钟下降沿之前提前多久稳定hold值定义了使能信号需要在时钟下降沿之后保持多久。注意这里的参考沿是时钟的下降沿不是上升沿这是ICG跟普通触发器最本质的区别。如果你把ICG的检查当成普通setup来修就会犯一个方向性错误你会去优化使能信号到ICG数据端的路径延迟但实际上真正需要关注的是使能信号相对于时钟下降沿的关系。方向错了修再多也是白费力气。1.2 set_clock_gating_check到底在约束什么set_clock_gating_check这条命令的作用是告诉STA工具对于时钟门控单元使能信号相对于时钟的setup和hold要求是多少。它的语法大致是这样的set_clock_gating_check -setup 0.2 -hold 0.1 [get_clocks CLK]这条约束的含义是对于CLK时钟域下的所有ICG单元使能信号需要在时钟下降沿前0.2ns稳定setup并在下降沿后0.1ns保持hold。如果不设这条约束工具会使用默认值。不同工具的默认值不一样有的默认setup是0有的默认是某个工艺库里的值。问题在于默认值往往偏乐观或者偏悲观跟你的实际设计场景不匹配。比如你的使能信号是从一个跨时钟域同步器过来的那它的到达时间可能很晚用默认的0去检查就会报出大量违例但这些违例可能在实际工作中并不影响功能。反过来如果你的使能信号路径很短用默认值检查可能一切正常但实际上由于ICG锁存器的透明特性在时钟低电平期间使能信号的任何抖动都可能传到时钟输出造成下游触发器的时钟脉冲被截断或者展宽这种问题在功能仿真里不一定能发现但在硅后测试中可能是致命的。1.3 latency设置为什么是修复ICG违例的关键杠杆Latency这个词在CTS语境下指的是时钟信号从时钟源到达各个时钟端点的延迟。对于ICG来说它的时钟输入端有一个latency时钟输出端到下游触发器又有一段latency。这两段latency的差值直接影响了ICG使能信号的检查窗口。举个例子假设ICG的时钟输入端latency是0.5ns输出端到下游触发器的latency是0.3ns那么ICG输出时钟相对于输入时钟就有一个-0.2ns的偏移输出比输入早到。这个偏移会改变下游触发器的setup/hold检查参考沿位置同时也会影响ICG使能信号的检查窗口。通过调整ICG输入和输出端的latency你可以把使能信号的检查窗口挪到一个更容易满足的位置。这就是为什么很多有经验的工程师在修ICG违例时第一反应不是去改使能信号的逻辑或者加buffer而是先去检查latency设置是否合理。注意latency的调整不是随便设的它必须跟CTS的实际结果一致。如果你在约束里设了一个latency值但CTS做出来的实际latency跟这个值差很多那约束就是假的修出来的时序也是假的。2. ICG约束的核心参数计算与实操配置理解了原理之后接下来要把参数算清楚。ICG的setup和hold值不是拍脑袋定的它跟工艺库、时钟频率、使能信号的来源都有关系。这一章我会把计算过程一步步摊开然后给出具体的约束配置方法。2.1 setup和hold值的计算逻辑ICG的setup值本质上是一个保护带确保使能信号在锁存器进入透明状态之前已经稳定。它的计算需要考虑三个因素锁存器的建立时间library setup time、时钟路径上的不确定性clock uncertainty、以及使能信号路径上的噪声余量。一个常用的经验公式是setup_value library_setup_time clock_uncertainty margin其中library_setup_time可以从工艺库的ICG单元datasheet里查到通常在0.05ns到0.15ns之间。clock_uncertainty包括PLL抖动、时钟树上的串扰等一般在0.1ns到0.3ns之间。margin是留给使能信号路径的余量根据设计复杂度取0.05ns到0.2ns。hold值的计算类似但方向相反hold_value library_hold_time clock_uncertainty marginlibrary_hold_time通常比setup_time小因为锁存器的保持时间要求一般比建立时间宽松。我实际项目中常用的配置是这样的对于1GHz左右的时钟setup设0.15nshold设0.08ns对于500MHz以下的时钟setup设0.1nshold设0.05ns。这个值不是绝对的你需要根据自己工艺库的实际参数和时钟不确定性来调整。2.2 约束配置的完整写法在实际的SDC文件里set_clock_gating_check通常跟其他时钟约束放在一起。一个完整的配置示例如下# 定义时钟 create_clock -name CLK -period 1.0 [get_ports clk_in] # 设置时钟不确定性 set_clock_uncertainty -setup 0.15 [get_clocks CLK] set_clock_uncertainty -hold 0.08 [get_clocks CLK] # 设置ICG检查 set_clock_gating_check -setup 0.15 -hold 0.08 [get_clocks CLK] # 设置latency set_clock_latency -source 0.5 [get_clocks CLK] set_clock_latency 0.3 [get_clocks CLK]这里set_clock_latency -source设置的是时钟源到时钟定义点的延迟set_clock_latency设置的是时钟定义点到各个时钟端点的延迟。对于ICG来说你还需要单独设置ICG输入和输出端的latency这通常通过set_clock_latency -clock [get_clocks CLK] [get_pins ICG/CP]这样的方式来指定。提示在CTS之前latency是估算值CTS之后应该用set_propagated_clock让工具用实际的时钟树延迟来计算这时候latency约束会被覆盖。所以ICG违例的修复要分两个阶段CTS前用估算latency做初步收敛CTS后用实际latency做最终检查。2.3 latency调整的具体操作方法假设你发现ICG的setup违例很严重报告显示使能信号到达时间比要求晚了0.3ns。你有两个选择一是优化使能信号路径减少延迟二是调整ICG的latency把检查窗口往后挪。优化使能信号路径的方法包括减少逻辑级数、加buffer、换用驱动能力更强的单元。但这些方法可能会增加面积和功耗而且如果使能信号是从很远的地方过来的优化空间有限。调整latency的方法更直接如果你把ICG输入端的latency设大一点相当于告诉工具时钟到ICG的时间比之前估计的要晚这样使能信号的相对到达时间就显得早了setup违例就可能消失。具体操作是# 增加ICG输入端的latency set_clock_latency 0.6 [get_pins ICG_INST/CP] # 或者减少ICG输出端的latency set_clock_latency 0.2 [get_pins ICG_INST/Q]但这里有个陷阱你不能只改ICG的latency而不改下游触发器的latency否则下游触发器的时序会出问题。正确的做法是整体调整时钟树的latency分布让ICG输入和输出端的latency差值保持在一个合理范围内。我通常的做法是先看CTS报告里ICG输入和输出端的实际latency差值如果差值超过0.2ns就说明时钟树在ICG这里不平衡需要让CTS工具去修。如果差值在合理范围内但ICG仍然违例那问题就在使能信号路径上需要从前端逻辑或者后端布局上想办法。3. 从CTS到时序收敛的完整实操流程这一章我把整个流程串起来从CTS前的约束设置到CTS后的违例分析再到具体的修复操作每一步都给出可执行的命令和判断标准。3.1 CTS前的约束准备与初步检查CTS之前时钟树还没有真正生成latency是估算的。这个阶段的重点是确保约束设置合理让工具能报出真实的违例而不是被错误的约束掩盖了问题。第一步是确认ICG单元被正确识别。你可以用report_clock_gating_check命令查看工具识别到了哪些ICG单元以及它们的检查值是多少。如果发现某个ICG没有被识别可能是它的使能信号连接方式不符合工具的要求需要检查一下。第二步是设置合理的latency估算值。对于大多数设计时钟源到ICG输入的latency可以估算为时钟树深度乘以每级buffer的延迟。比如时钟树有8级buffer每级延迟0.05ns那latency大约是0.4ns。ICG输出到下游触发器的latency可以估算为剩余级数乘以每级延迟。第三步是跑一次初步的时序分析看看ICG相关的违例有多少、分布在哪些路径上。如果违例数量很少且集中在个别ICG上可能是这些ICG的使能信号逻辑有问题如果违例数量很多且分散可能是约束设置太紧或者latency估算不准。3.2 CTS后的违例定位与分类CTS完成后时钟树的实际延迟已经确定这时候要用set_propagated_clock让工具用实际延迟重新计算时序。然后跑一次完整的时序分析把ICG相关的违例单独拎出来。定位违例的具体操作是# 报告所有ICG的时序检查结果 report_timing -to [get_pins -hier */ICG*/E] -delay_type max # 报告ICG的latency信息 report_clock_timing -type latency [get_pins -hier */ICG*/CP]从报告里你要关注几个关键信息使能信号的到达时间、要求时间、违例量slack、以及ICG输入和输出端的latency差值。根据违例的特征可以分成几类违例类型特征常见原因setup违例使能信号到达太晚使能路径逻辑级数多、latency设置不合理hold违例使能信号变化太早使能路径太短、时钟树不平衡latency差值过大ICG输入输出latency差超过0.2nsCTS没有对ICG做平衡使能信号毛刺功能仿真正常但时序报违例使能信号在时钟低电平期间翻转3.3 针对不同违例类型的修复操作对于setup违例如果违例量在0.1ns以内可以尝试微调latency# 把ICG输入端的latency增加0.1ns set_clock_latency 0.55 [get_pins ICG_INST/CP]如果违例量超过0.2ns光调latency可能不够需要同时优化使能信号路径。具体做法是在使能路径上插入buffer或者把使能信号提前一拍产生。插入buffer的位置很关键要放在使能信号的分支点之前这样能同时改善多个ICG的时序。对于hold违例通常是使能信号变化太早导致的。修复方法是在使能路径上增加延迟比如插入延迟单元或者buffer。但要注意不要引入新的setup违例需要在setup和hold之间找平衡。对于latency差值过大的问题这属于CTS的质量问题需要让CTS工具重新做时钟树平衡。你可以在CTS的约束文件里给ICG的输入和输出端设置相同的latency目标让工具去满足。实操心得我在修ICG违例时习惯先把所有ICG的latency差值列出来差值超过0.15ns的先让CTS去修剩下的再用约束和逻辑优化去处理。这样能避免在CTS质量不好的情况下白费力气。3.4 修复后的验证与迭代每次修改约束或者逻辑之后都要重新跑时序分析确认违例是否真的修掉了同时检查有没有引入新的违例。这个迭代过程可能要重复好几轮直到所有ICG的时序都满足要求。验证的时候要特别注意两点一是确认修改后的latency跟CTS的实际结果一致不能出现约束里设了0.5ns但实际是0.3ns的情况二是确认使能信号的功能没有被破坏比如插入buffer之后使能信号的极性有没有变、有没有引入毛刺。我通常会在修复完成后跑一次report_clock_gating_check把所有ICG的检查值和实际slack列出来做一个最终的确认。如果还有个别违例修不掉就要考虑是不是约束设得太紧了适当放宽setup或hold值但放宽之前一定要确认功能上能接受。4. 常见问题与排查技巧实录这一章我把实际项目中遇到的ICG相关问题整理成速查表每个问题都给出排查思路和解决方法。这些问题有些是约束设置的问题有些是CTS的问题有些是前端逻辑的问题分类整理方便你快速定位。4.1 ICG违例排查速查表问题现象可能原因排查方法解决方法大量ICG setup违例约束太紧或latency估算不准检查set_clock_gating_check的值和latency设置放宽约束或调整latency个别ICG setup违例使能路径逻辑级数多报告使能路径的逻辑级数和延迟优化逻辑或插入bufferICG hold违例使能路径太短或时钟树不平衡检查使能路径延迟和ICG latency差值增加延迟或让CTS重新平衡功能仿真正常但时序报违例使能信号在透明窗口内翻转检查使能信号的产生逻辑和时钟域调整使能信号时序或加同步器CTS后违例变多latency约束跟实际不符对比约束latency和CTS实际latency更新约束或让CTS修修完ICG违例后下游触发器违例latency调整影响了时钟树检查下游触发器的时序整体调整时钟树latency4.2 几个容易踩的坑第一个坑是把ICG的setup检查当成普通setup来修。我见过有工程师在使能路径上拼命加buffer来减少延迟结果发现违例量根本没变因为问题出在时钟下降沿的参考位置上跟使能路径的绝对延迟关系不大。正确的做法是先确认ICG的检查参考沿是下降沿然后看使能信号相对于下降沿的关系。第二个坑是latency设置跟CTS实际结果脱节。有些人在CTS前设了一个latency值CTS后忘了更新结果工具用旧的latency去检查报出来的违例跟实际不符。我的习惯是在CTS完成后第一时间用report_clock_timing确认实际latency然后更新约束文件。第三个坑是忽略了ICG使能信号的跨时钟域问题。如果使能信号是从另一个时钟域过来的那它的到达时间可能跟当前时钟域没有固定关系用固定的setup/hold值去检查可能永远修不掉。这种情况下需要考虑在使能信号上加同步器或者用set_false_path把这条路径排除掉但要确认功能上确实不需要检查。第四个坑是过度依赖latency调整。Latency调整确实能快速修掉违例但它本质上是在骗工具如果CTS的实际延迟跟约束差很多修出来的时序在硅上可能不成立。我的原则是latency调整只用于微调违例量超过0.2ns的必须从逻辑或CTS上解决。4.3 一些实用的调试命令在实际调试中这几个命令我用得最多# 查看ICG的检查值 report_clock_gating_check -verbose # 查看ICG输入输出端的latency report_clock_timing -type latency -clock CLK # 报告使能信号的路径延迟 report_timing -from [get_pins -hier */enable_reg/Q] -to [get_pins -hier */ICG*/E] # 检查时钟树上的ICG分布 report_clock_tree -clock CLK -icg这些命令能帮你快速定位问题所在。特别是report_clock_tree -icg它能显示时钟树上所有ICG的位置和latency对于判断CTS质量很有帮助。最后分享一个小技巧如果你的设计里ICG数量很多可以写一个脚本自动提取所有ICG的slack和latency差值按违例量排序优先修违例最大的那些。这样比一个个手动看报告效率高得多。我在一个包含上千个ICG的设计里用这个方法把修复时间从两天缩短到了半天。
返回列表