ARTICLE DETAIL

资讯详情

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

ICG时序违例根因分析与set_clock_gating_check约束实战

ICG时序违例根因分析与set_clock_gating_check约束实战 1. ICG时序违例到底难在哪做数字后端的朋友十个里有八个被ICGIntegrated Clock Gating的时序违例折磨过。尤其是到了CTSClock Tree Synthesis之后打开时序报告一看ICG的setup或者hold违例红了一片那种感觉就像考试时发现最后一道大题完全没复习。我自己第一次独立负责一个中等规模模块的后端实现时就在ICG上栽了跟头——明明数据路径的时序都收敛得不错偏偏clock gating check这一项怎么都过不了工具报出来的slack差得离谱一度怀疑是约束写错了。后来踩坑踩多了才明白ICG的时序违例和普通寄存器的时序违例本质上不是一回事。普通寄存器看的是setup和hold而ICG多了一层clock gating check——工具需要确认enable信号在时钟有效沿附近是稳定的否则可能产生毛刺导致时钟被误关或者误开。这个check的严格程度直接决定了ICG能不能正常工作。更麻烦的是ICG通常分布在时钟树的各个分支上它的latency直接受CTS结果影响而CTS又反过来依赖ICG的位置和约束。这就形成了一个循环依赖约束写不好CTS做不好CTS做不好ICG时序更差。这篇文章主要面向已经有一定STA基础、正在做或者准备做含ICG设计的后端工程师。我会从ICG时序违例的根因讲起把set_clock_gating_check和latency设置这两个核心手段拆开揉碎配上我实际项目中的参数计算过程和踩坑记录。不管你是刚接触ICG的新手还是被某个顽固违例卡住的老手应该都能找到可以直接抄作业的东西。2. ICG时序检查的核心机制拆解2.1 ICG为什么需要专门的时序检查先把这个事情说清楚。普通的D触发器数据在时钟沿到来之前需要稳定一段时间setup在时钟沿之后还需要保持一段时间hold。ICG内部本质上也是一个类似锁存器的结构但它的输出不是数据而是控制时钟是否翻转的使能信号。如果enable信号在时钟沿附近发生跳变ICG的输出时钟可能会出现毛刺——本来应该完整的一个时钟脉冲可能被切成了两段或者本该没有脉冲的地方冒出一个窄脉冲。这种毛刺对下游电路是灾难性的。一个窄脉冲可能让寄存器采到错误的值也可能让整个时钟树的分支出现不可预期的行为。所以EDA工具在STA阶段会对ICG做额外的检查确保enable信号在时钟有效沿前后的一个窗口内保持稳定。这个窗口的大小和位置就是由set_clock_gating_check来控制的。注意很多新手会把这个check和普通的setup/hold混淆。clock gating check检查的是enable相对于clock的关系而不是data相对于clock的关系。约束对象搞错了后面怎么调都是白费力气。2.2 set_clock_gating_check的三个关键参数set_clock_gating_check这个命令看起来简单但里面的参数如果理解不到位很容易设出“看起来能过、实际有风险”的约束。它主要有三个维度的控制setup/hold的裕量值指定enable信号需要在时钟沿之前和之后保持稳定的时间。这个值设得越大约束越严格ICG越难满足设得太小又可能留下毛刺风险。检查的时钟对象可以针对特定时钟或者所有时钟设置也可以针对特定的ICG cell设置。精细控制的前提是你清楚哪些ICG是关键路径上的。高电平/低电平有效ICG的enable可能是高有效也可能是低有效检查的方向不同。这个必须和RTL里的实际逻辑对应上否则约束就是错的。我一般会先确认工艺库对ICG cell的时序模型是怎么定义的。大部分标准单元库会给出clock gating setup和hold的推荐值但这个推荐值往往是针对典型条件的。在实际项目中我会根据时钟频率和时钟树的质量做调整。比如时钟频率跑到1GHz以上时我会把setup裕量适当加大因为高频下时钟沿的抖动和偏差更容易吃掉裕量。2.3 latency对ICG时序的传导效应latency这个问题更隐蔽。ICG通常不是直接挂在时钟根节点上的而是分布在时钟树的中下游。从时钟源到ICG clock pin的延迟就是ICG的clock latency。这个latency会直接影响enable信号的时序要求如果ICG的clock latency很大而enable信号是从上游寄存器过来的那么enable到达ICG的时间可能比clock沿晚很多setup就会违例。更复杂的是CTS工具在平衡时钟树的时候会把ICG当作时钟路径上的一个节点来处理。如果ICG的latency没有被正确约束CTS可能会把ICG前后的时钟分支平衡得很奇怪导致某些分支的latency差异过大。这种差异在STA里就表现为ICG的clock gating check违例。我遇到过最典型的情况是某个ICG的enable信号来自一个跨时钟域的寄存器经过同步器之后到达ICG。由于同步器本身有延迟加上时钟树的不平衡enable到达ICG的时间比clock沿晚了将近200pssetup直接崩了。后来通过调整ICG在时钟树中的位置并给enable路径加约束才把这个问题解决。3. 实操前的环境确认与约束梳理3.1 确认工艺库和ICG cell的时序模型动手改约束之前先把工艺库里的ICG cell时序信息翻出来看。以常见的TSMC 28nm工艺为例标准单元库里的ICG cell比如CLKGATETST_X1这类会在.lib文件里定义clock gating setup和hold的时序弧。你需要确认几个关键点库里面有没有预定义的clock gating check值如果有是多少这个值是针对哪个工艺角corner的SS corner和FF corner下的值可能差很多。ICG cell的enable pin是哪个是高有效还是低有效我一般会写一个简单的脚本把.lib文件里所有ICG cell的clock gating时序信息提取出来整理成表格。这样在设约束的时候心里有数不会拍脑袋定值。参数典型值28nm SS典型值28nm FF说明clock gating setup80ps45psenable需在clock沿前稳定的时间clock gating hold30ps15psenable需在clock沿后保持的时间enable pinENEN高有效clock pinCPCP时钟输入提示不同工艺、不同库版本的值差异很大上表只是示例。实际项目一定要以自己用的库为准不要直接抄。3.2 梳理时钟结构和ICG分布在设约束之前先搞清楚设计里ICG是怎么分布的。我通常会用工具的命令把时钟树结构dump出来看看ICG挂在哪些层级、每个ICG的enable信号来自哪里。这一步很关键因为不同的ICG可能需要不同的约束策略。比如如果ICG的enable来自同一个时钟域的上游寄存器而且路径比较短那么约束可以相对宽松如果enable来自跨时钟域或者经过复杂组合逻辑就需要更严格的约束和更仔细的latency规划。我习惯在CTS之前先做一个粗略的时钟树规划把ICG按照时钟域和层级分组。同一组的ICG用相同的约束不同组之间根据实际情况调整。这样既不会过度约束导致CTS做不动也不会约束不足留下隐患。3.3 检查SDC中现有的clock gating约束很多项目在初期会直接使用默认的clock gating约束或者从其他项目拷贝一份SDC过来。这种做法风险很大因为不同项目的时钟频率、ICG位置、enable路径都不一样。我接手一个项目时第一件事就是检查SDC里有没有set_clock_gating_check如果有值是多少覆盖了哪些对象。常见的错误包括约束值直接用了库里的默认值但没有考虑实际时钟频率约束只覆盖了部分ICG漏掉了一些约束的时钟对象写错了导致根本没生效。这些错误在STA报告里不一定直接报出来但会在ICG的时序违例中体现。我一般会写一个检查脚本把SDC里所有clock gating相关的约束列出来和设计里的ICG实例做交叉比对。确保每一个ICG都被正确的约束覆盖到。4. 手把手配置set_clock_gating_check4.1 基础约束的写法与参数计算先看最基本的写法。假设设计里有一个时钟clk_core频率500MHz周期2ns。工艺库给出的clock gating setup推荐值是80pshold是30ps。那么基础约束可以这样写set_clock_gating_check -setup 0.08 -hold 0.03 [get_clocks clk_core]但这只是起点。实际项目中我会根据时钟频率和时钟树的质量做调整。比如500MHz下时钟周期2ns80ps的setup裕量占周期的4%这个比例是合理的。但如果时钟频率提高到1GHz周期变成1ns80ps就占了8%约束明显偏紧。这时候我会考虑适当降低setup值同时通过优化enable路径来保证实际裕量。参数计算的一个经验公式是setup裕量取时钟周期的3%到5%hold裕量取setup的1/3到1/2。但这个公式不是绝对的还要看工艺库的推荐值和实际时钟树的质量。如果时钟树做得比较平衡latency差异小可以适当放宽如果时钟树质量差就要收紧。注意set_clock_gating_check的值是绝对值不是相对于时钟周期的比例。写约束的时候一定要确认单位SDC默认单位通常是ns但有些项目会改成ps搞错了就差1000倍。4.2 针对特定ICG的精细约束全局约束设完之后通常还需要对特定的ICG做精细调整。比如某个ICG的enable路径特别长或者某个ICG在时钟树的关键分支上就需要单独设约束。set_clock_gating_check -setup 0.10 -hold 0.04 [get_cells u_icg_critical]这种精细约束的前提是你知道哪些ICG是关键。我一般会在CTS之后跑一遍时序报告把clock gating check违例的ICG列出来然后针对这些ICG做分析。如果是enable路径太长导致的除了加约束还要考虑优化enable路径或者调整ICG的位置。还有一种情况是ICG的enable信号来自跨时钟域。这时候除了clock gating check还需要考虑跨时钟域的同步问题。我通常会在同步器的输出端加一个max delay约束确保enable信号在到达ICG之前已经稳定。4.3 约束生效的验证方法约束写完之后怎么确认它真的生效了我一般用两个方法验证第一个方法是看STA报告里的clock gating check部分。工具会列出每个ICG的setup和hold slack以及使用的约束值。如果约束值和你设的不一样说明约束没生效或者被覆盖了。第二个方法是手动计算。选一个ICG找到它的clock pin和enable pin分别report timing。然后手动算一下enable到达时间和clock沿的时间差和约束值对比。这个方法比较费时间但对于关键ICG值得做。我踩过的一个坑是SDC里同时存在全局约束和针对特定对象的约束但工具的执行顺序导致特定约束被全局约束覆盖了。后来发现是约束的优先级问题调整了约束的顺序才解决。所以写完约束后一定要确认最终生效的值是什么。5. latency设置与CTS协同优化5.1 ICG latency的约束方法ICG的latency约束本质上是在告诉CTS工具这个ICG的clock pin应该放在时钟树的什么位置它的延迟应该是多少。常用的约束手段包括set_clock_latency指定时钟源到ICG clock pin的延迟。这个值可以是估算的也可以是CTS之后反标的。set_clock_tree_exceptions把ICG的clock pin设为stop pin或者exclude pin控制CTS是否穿过ICG继续平衡。set_max_delay/set_min_delay对enable路径做延迟约束间接控制ICG的时序。我一般会在CTS之前先用set_clock_latency给ICG一个估算的latency让CTS有一个初始目标。CTS做完之后再用实际反标的latency更新约束跑STA确认。# CTS前估算latency set_clock_latency -source 0.5 [get_pins u_icg/CP] # CTS后反标实际latency set_clock_latency 0.48 [get_pins u_icg/CP]提示set_clock_latency不加-source选项时指定的是时钟源到该pin的network latency加了-source则是指source latency。这两个概念不要搞混否则约束会差很多。5.2 CTS阶段对ICG的特殊处理CTS工具在处理ICG时默认行为可能和你的预期不一样。有些工具会把ICG当作普通的时钟缓冲器直接穿过它继续平衡下游时钟树有些工具则会把ICG当作一个终点不穿过它。这个行为直接影响了ICG的latency和下游寄存器的时钟延迟。我通常会在CTS的配置文件里明确指定ICG的处理方式。如果ICG的下游还有大量的寄存器需要平衡我会让CTS穿过ICG继续做树如果ICG的下游负载很小或者ICG本身就在时钟树的末端我会把ICG设为stop pin避免CTS在ICG后面做不必要的平衡。# CTS配置示例 set_clock_tree_stop_pins [get_pins u_icg/CP]这个设置的影响很大。如果ICG被设为stop pinCTS不会在ICG后面继续插缓冲器ICG的latency就是时钟源到ICG的延迟。如果ICG不被设为stop pinCTS会在ICG后面继续做树ICG的latency会包含下游的缓冲器延迟。两种情况下ICG的clock gating check约束都需要相应调整。5.3 latency与enable路径的联合优化ICG的时序问题很多时候不是单独调latency或者单独调enable路径能解决的需要联合优化。我的经验是先看enable路径的时序余量再看ICG的latency是否合理最后看两者的配合。举个例子某个ICG的setup违例了100ps。我先report enable路径的时序发现enable信号从上游寄存器到ICG的延迟是800ps而clock沿到ICG的延迟是700ps。enable比clock晚了100ps正好对应违例值。这时候有两个方向一是减少enable路径的延迟比如把enable路径上的缓冲器换成更快的或者调整布局让路径更短二是增加ICG的clock latency让clock沿来得更晚一些给enable更多时间。实际项目中我通常会两个方向都试一下看哪个对整体时序的影响更小。如果enable路径是关键路径动它可能影响其他时序那就优先调ICG的latency。如果ICG的latency已经很大了再增加会导致下游时钟树不平衡那就优先优化enable路径。6. 常见违例类型与排查速查表6.1 setup违例的典型原因与解法ICG的setup违例是最常见的。典型原因和对应的解法我整理成了表格违例原因现象解法enable路径太长enable到达时间晚于clock沿优化enable路径减少逻辑级数或换更快单元ICG clock latency太小clock沿来得太早增加ICG的clock latency或调整CTS设置约束值过紧slack为负但实际裕量够适当放宽set_clock_gating_check的setup值时钟树不平衡不同分支latency差异大优化CTS平衡ICG前后的时钟分支跨时钟域enableenable来自异步时钟域加同步器并对enable路径做max delay约束我遇到最多的是enable路径太长。尤其是在深亚微米工艺下线延迟占比很大enable信号从芯片一端走到另一端延迟可能超过1ns。这种情况下光调约束是没用的必须从物理设计上优化比如把ICG挪到离enable源更近的位置或者用更宽的金属层走线减少电阻。6.2 hold违例的典型原因与解法ICG的hold违例相对少见但一旦出现往往更难修。典型原因包括enable路径太短enable信号在clock沿之后变化太快ICG的clock latency过大clock沿来得太晚CTS在ICG后面插了太多缓冲器导致clock路径延迟过大hold违例的解法通常是增加enable路径的延迟或者在enable路径上插缓冲器。但要注意增加enable延迟可能会影响setup需要权衡。我一般会先看hold违例的严重程度如果只是差几皮秒可以通过调整约束或者微调布局解决如果差得比较多就需要在enable路径上做文章。注意hold违例的修复不能以牺牲setup为代价。我见过有人为了修hold在enable路径上狂插缓冲器结果setup崩了最后两头都修不好。正确的做法是找到一个平衡点让setup和hold都有合理的裕量。6.3 排查流程与工具命令我一般的排查流程是这样的打开STA报告找到clock gating check违例的ICG列表对每个违例ICGreport它的clock pin和enable pin的时序计算enable到达时间和clock沿的时间差确认违例的具体原因根据原因选择解法调约束、调latency、优化enable路径、调整CTS设置修改后重新跑STA确认违例是否解决同时检查有没有引入新的违例常用的工具命令包括# 报告clock gating check report_timing -to [get_pins u_icg/EN] -clock_gating_check # 报告ICG clock pin的latency report_clock_timing -type latency [get_pins u_icg/CP] # 报告enable路径的时序 report_timing -from [get_pins u_reg/Q] -to [get_pins u_icg/EN]这些命令在不同工具里的语法可能略有差异但思路是一样的。关键是要把ICG的clock和enable分开看然后再看两者的关系。7. 实操心得与避坑经验7.1 约束值不要照抄库推荐值这是我踩过的最大的坑之一。刚开始做项目时看到库里有clock gating setup的推荐值就直接拿来用了。结果发现有些ICG怎么都过不了有些又过得太轻松。后来才明白库推荐值是在特定条件下测出来的和你的实际时钟频率、时钟树质量、enable路径长度都有关系。我的做法是以库推荐值为起点根据时钟周期做比例调整然后跑STA看实际裕量。如果大部分ICG的slack都在合理范围内比如setup slack在50ps以上说明约束值合适如果很多ICG都接近零或者为负说明约束太紧如果slack大得离谱说明约束太松可能掩盖了真实问题。7.2 CTS之前先做latency规划很多新手会等到CTS做完才发现ICG的latency有问题这时候再改就麻烦了。我的经验是在CTS之前先做一个粗略的latency规划根据时钟树的预期深度和ICG的位置估算每个ICG的latency范围然后设一个初始约束。CTS工具会根据这个初始约束来优化时钟树做出来的结果更接近预期。这个规划不需要很精确但要有。比如时钟树预期插5级缓冲器每级缓冲器延迟50ps那么ICG的latency大概在250ps左右。如果ICG在第三级latency大概150ps。有了这个估算CTS就不会把ICG的latency做得太离谱。7.3 enable路径的物理优化比调约束更有效调约束只能改变工具对时序的判断不能改变实际的延迟。如果enable路径本身太长再怎么调约束实际电路还是可能出问题。所以我的原则是先优化物理路径再调约束。物理优化的手段包括把ICG挪到离enable源更近的位置用更高层的金属走enable信号减少线延迟在enable路径上换用驱动能力更强的单元如果enable路径的逻辑级数太多考虑在RTL层面做优化。这些手段比单纯调约束有效得多而且不会留下隐患。7.4 跨时钟域ICG要特别小心跨时钟域的ICG是最容易出问题的。enable信号从一个时钟域来ICG在另一个时钟域两者的时钟沿关系不确定clock gating check的约束很难设。我的做法是在enable路径上加同步器把enable信号同步到ICG所在的时钟域然后再做clock gating check。同步器的输出到ICG的路径要加max delay约束确保enable在clock沿之前稳定。提示跨时钟域的ICG除了clock gating check还要检查同步器本身的时序。同步器的第一级寄存器可能有亚稳态问题需要确保MTBF满足要求。7.5 修完违例要回归检查每次修改约束或者调整CTS设置之后不要只看ICG的违例有没有解决还要检查其他时序有没有变差。我见过有人为了修ICG的setup违例把ICG的latency调大了结果下游寄存器的setup违例了。所以修完一个违例一定要跑全芯片的STA确认没有引入新的问题。我一般会维护一个时序基线每次修改后和基线对比看slack的变化趋势。如果某个路径的slack突然变差了很多就要分析是不是修改引起的。这种回归检查虽然费时间但能避免很多后期的大问题。8. 从RTL到signoff的完整检查清单8.1 RTL阶段的ICG检查要点很多ICG的问题其实在RTL阶段就埋下了。我在review RTL时会特别关注几个点ICG的enable信号是不是来自寄存器输出如果是组合逻辑输出毛刺风险很大。enable信号的逻辑级数是不是太多级数越多延迟越大越容易违例。有没有跨时钟域的ICG如果有同步器是不是到位了ICG的时钟是不是来自同一个时钟域如果ICG的clock和enable来自不同时钟域约束会非常复杂。这些问题在RTL阶段解决成本最低。等到后端再发现可能就要改架构了。8.2 综合阶段的约束检查综合阶段要把clock gating的约束写进SDC并确认综合工具正确识别了ICG。我一般会检查综合后的网表里ICG是不是被正确推断出来了有没有被优化掉或者替换成普通逻辑。如果ICG被优化掉了clock gating check就无从谈起。另外综合阶段的时钟约束要准确。时钟频率、时钟不确定性、时钟延迟这些参数都会影响clock gating check的结果。我见过有人综合时时钟约束写错了导致ICG的时序看起来很好到了PR阶段才发现问题。8.3 PR阶段的CTS与STA协同PR阶段是ICG问题最集中的地方。CTS做完之后我会先跑一遍STA把clock gating check的违例全部列出来然后逐个分析。分析的时候要结合CTS的报告看ICG的latency是多少时钟树平衡得怎么样。如果违例集中在某几个ICG上可能是这些ICG的约束或者位置有问题。如果违例分散在很多ICG上可能是全局约束太紧或者CTS质量太差。针对不同的情况采取不同的策略。8.4 signoff阶段的最终确认signoff阶段是最后一道关。这时候所有的约束都应该已经稳定了ICG的时序也应该收敛了。我会做几件事确认所有ICG的clock gating check都过了slack有合理裕量。确认约束值和实际反标的latency一致没有用过时的估算值。确认跨时钟域的ICG有同步器且同步器的时序满足要求。确认没有因为修ICG违例而引入其他时序问题。这个检查清单看起来简单但每一项都要仔细做。我见过太多项目在signoff阶段发现ICG问题不得不返工浪费大量时间。提前做好检查比事后补救划算得多。9. 一个真实项目的调试记录9.1 问题现象与初步分析去年做一个通信芯片的模块时钟频率800MHz设计里有大约200个ICG。CTS做完之后跑STA发现有30多个ICG的setup违例slack从-20ps到-150ps不等。违例的ICG分布在不同层级没有明显的聚集。我先看了全局的clock gating约束设的是setup 60pshold 25ps。这个值是根据库推荐值SS corner下70ps稍微放宽了一点因为800MHz下周期1.25ns60ps占4.8%比例还算合理。但为什么还有这么多违例9.2 根因定位过程我选了一个违例最严重的ICGslack -150psreport它的clock和enable时序。发现enable信号从上游寄存器到ICG的延迟是950ps而clock沿到ICG的延迟是780ps。enable比clock晚了170ps减去约束的60ps正好对应-110ps左右的违例还有时钟不确定性的影响。继续追enable路径发现这条路径穿过了三个模块逻辑级数有8级线延迟占了将近400ps。这就是典型的enable路径太长导致的setup违例。9.3 解决方案与实施效果针对这个问题我采取了三个措施第一把ICG的位置从原来的模块边缘挪到了enable源附近减少了线延迟。这一步通过调整floorplan和布局实现线延迟从400ps降到了200ps左右。第二在enable路径上换用了驱动能力更强的单元减少了逻辑延迟。逻辑延迟从550ps降到了400ps左右。第三对剩余的违例ICG适当调整了clock gating约束把setup从60ps降到50ps同时确认实际裕量仍然足够。三步做完之后ICG的setup违例从30多个降到了3个剩下的3个通过微调latency解决。最终signoff时所有ICG的clock gating check都过了setup slack最小也有30ps。9.4 这个项目教会我的事这个项目让我深刻体会到ICG的时序问题不能只靠调约束解决。约束是最后的手段物理优化才是根本。enable路径的长度、ICG的位置、时钟树的质量这些因素对ICG时序的影响远大于约束值的微调。另外CTS之前的规划非常重要。如果我在CTS之前就把ICG的位置规划好把enable路径长的ICG提前挪到合适的位置后面就不用花那么多时间修违例了。前期多花一小时规划后期可能省一天调试。最后回归检查不能省。我在调整ICG位置和enable路径之后跑了全芯片的STA确认没有影响其他时序。虽然多花了一些时间但避免了后期更大的风险。
返回列表