ARTICLE DETAIL

资讯详情

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

ICG时序违例修复指南:set_clock_gating_check与latency设置实战

ICG时序违例修复指南:set_clock_gating_check与latency设置实战 ICGIntegrated Clock Gating的时序问题大概是数字后端里最让人又爱又恨的一类。爱它是因为它省功耗、面积小、逻辑简单恨它是因为一旦setup或hold违例尤其是CTS之后冒出来的那些往往不像普通寄存器路径那样“加buffer就能压下去”很多时候你越修越乱甚至把本来干净的时钟树搞得一团糟。我自己在几个中低功耗项目里都踩过ICG的坑从RTL阶段没约束好到CTS后hold崩掉再到set_clock_gating_check参数写错导致工具误报几乎每一类问题都遇到过。这篇就把我这些年处理ICG时序违例的完整思路拆开讲重点落在set_clock_gating_check和latency设置这两个最容易被忽视、却又最关键的约束点上。不管你是刚接触后端约束的新人还是已经做过几个项目但总在ICG上翻车的老手应该都能从里面找到能直接抄作业的东西。1. ICG时序违例到底难在哪先搞清楚它和普通路径的本质区别很多人修ICG违例修得痛苦根本原因是一开始就没把它当成一类特殊路径来看待。普通寄存器的setup/hold你脑子里有一套成熟的修复套路setup不够就降频率、拆逻辑、加pipelinehold不够就插delay、调时钟树。但ICG不一样它的时序检查对象、检查方式、以及CTS对它的影响都和普通路径有本质差异。不把这层差异想明白后面所有操作都是盲修。1.1 ICG的使能路径和时钟路径是两套完全不同的检查一个典型的ICG单元内部结构可以简化成“一个锁存器 一个与门”。时钟信号从CP端进使能信号EN从锁存器D端进锁存器由时钟的反相或同相版本控制最后与门输出gated clock。这里就出现了两条性质完全不同的路径使能路径EN到锁存器D这是一条普通的数据路径工具会做setup和hold检查检查的参考时钟是ICG内部锁存器所对应的时钟。时钟路径CP到gated clock输出这是时钟树的一部分工具默认不做普通setup/hold检查而是通过clock gating check来约束。问题就出在这里。很多工程师只盯着使能路径的setup/hold却忽略了clock gating check本身也会报违例而且这类违例的修复方式和数据路径完全不同。更麻烦的是这两类检查在CTS前后行为差异极大CTS之前时钟是理想化的CTS之后时钟树真实插入延迟出来了原本“看起来没问题”的使能路径可能突然hold崩掉。1.2 为什么CTS之后ICG违例特别容易集中爆发CTS之前工具用的是理想时钟所有时钟到达时间latency都是你约束里写的值路径延迟估算也比较乐观。CTS之后真实的时钟树buffer插进来了每个ICG的CP端和它上游/下游寄存器的时钟到达时间都发生了变化。这时候会出现两个典型现象第一使能路径的hold违例激增。因为使能信号往往来自某个寄存器而这个寄存器的时钟和ICG的时钟在CTS后可能产生了较大的skew。如果使能寄存器时钟到得早ICG锁存器时钟到得晚hold就很容易崩。第二clock gating check的setup违例冒出来。clock gating check要求使能信号在时钟有效沿之前稳定一段时间setup并在之后保持一段时间hold。CTS后如果时钟树插入延迟让ICG的CP端到得比预期晚而使能信号没跟着调整setup就会违例。我见过最典型的一个案例一个模块里几十个ICGCTS前时序全绿CTS后hold违例一下子冒出上百条全是使能路径。当时第一反应是去插delay结果插完发现clock gating check又开始报setup来回折腾了两天才意识到根子在latency约束没设对。1.3 一个容易被忽略的事实ICG的latency不是“一个值”很多人设latency的时候习惯性地给整个时钟域写一个统一的latency值比如set_clock_latency 1.0 [get_clocks clk]。这在CTS之前勉强能用但对ICG来说是有问题的。因为ICG的CP端和它输出驱动的下游寄存器在真实时钟树里往往处于不同的层级它们的latency天然就不一样。如果你在约束里把它们当成同一个latency工具在CTS前的优化方向就会偏等到CTS后真实latency出来违例就集中爆发。正确的做法是对ICG的时钟输入和它驱动的下游时钟分别设置合理的latency让工具在CTS前就“知道”这两者之间存在差异。这个差异不需要非常精确但方向要对。下面会详细讲怎么设。2. set_clock_gating_check参数写不对工具报的违例全是假的set_clock_gating_check这个约束是控制工具如何对clock gating单元做时序检查的核心命令。但它的参数语义比较绕很多人要么不写要么随便写一个结果工具报出来的违例要么是假的要么漏报真问题。我先把它的核心参数拆清楚再讲实际怎么用。2.1 setup和hold参数到底在检查什么set_clock_gating_check -setup value -hold value这两个值定义的是clock gating检查的额外裕量要求。注意它不是直接设定“使能信号必须提前多少时间稳定”而是叠加在工具默认检查规则之上的一个约束。具体来说工具对clock gating的默认检查逻辑是使能信号必须在时钟有效沿之前满足setup要求这个要求由库单元本身的时序arc决定并在有效沿之后满足hold要求。你通过-setup和-hold参数可以在这个默认要求上再加一层裕量。举个例子假设ICG库单元本身要求使能信号在时钟沿前0.2ns稳定你写了set_clock_gating_check -setup 0.1那么工具实际检查时要求使能信号在时钟沿前0.3ns稳定。这个额外裕量在CTS前可以用来“预留”时钟树插入延迟带来的不确定性。注意-setup和-hold的值不是越大越好。设得过大工具会拼命去满足一个过严的要求可能导致过度优化、面积膨胀甚至引入新的违例。设得过小又起不到保护作用。一般建议根据时钟树预估的skew范围来定常见取值在0.05ns到0.2ns之间。2.2 不写set_clock_gating_check会怎样如果你完全不写这个约束工具会用库单元的默认检查规则。这在简单设计里可能没问题但在以下场景会出问题时钟树skew较大的设计默认规则没有考虑CTS后的skewCTS后容易冒违例。多时钟域交叉的ICG使能信号来自另一个时钟域时默认检查可能不适用。低功耗设计中ICG数量很多的情况默认规则下工具优化力度不够CTS后违例集中。我个人的习惯是只要设计里ICG数量超过一定规模比如几十个以上就一定要显式写set_clock_gating_check哪怕值设得保守一点也比不写强。2.3 实际约束写法与常见错误一个比较稳妥的写法是这样的set_clock_gating_check -setup 0.1 -hold 0.05 [get_clocks clk_core]这里[get_clocks clk_core]指定了作用范围。如果你有多个时钟域建议分别设置因为不同时钟域的skew特性可能不同。常见的错误写法有几种第一种不指定对象直接set_clock_gating_check -setup 0.1。这样会对所有时钟生效包括那些你并不关心或者特性完全不同的时钟可能引入不必要的约束。第二种setup和hold设成一样的值。setup和hold的物理意义不同setup对应的是时钟沿前的稳定要求hold对应的是时钟沿后的保持要求两者应该分别根据实际情况设定通常hold的裕量可以比setup小一些。第三种在CTS之后才想起来设。这个约束最好在CTS之前就设好让工具在CTS前的优化阶段就考虑进去。CTS后再设工具只能做局部修补效果差很多。2.4 和set_clock_gating_check配合的derate设置除了setup/hold裕量还有一个常被忽略的点是derate。在OCVon-chip variation分析下时钟路径和数据路径的derate不同clock gating检查也会受影响。如果你发现CTS后clock gating check的违例在OCV模式下特别多可以考虑对clock gating路径单独设置derateset_timing_derate -clock_gating_check -early 0.95 -late 1.05这个设置的意思是对clock gating检查的early路径用0.95的deratelate路径用1.05的derate。具体值要根据工艺和项目要求来定不要照搬。我一般会在项目初期和STA工程师确认好derate策略避免后期返工。3. latency设置CTS前把“预期”告诉工具CTS后才不会翻车latency设置是ICG时序修复里另一个关键点也是最容易设错的地方。很多人对latency的理解停留在“CTS前给个估计值”但实际上latency设得对不对直接决定了工具在CTS前的优化方向进而影响CTS后的时序质量。3.1 source latency和network latency的区别在讲ICG的latency设置之前必须先分清两个概念source latency时钟源到时钟定义点之间的延迟比如PLL输出到芯片时钟输入端的延迟。这个值通常由时钟源特性决定CTS不会改变它。network latency时钟定义点到各个寄存器时钟端之间的延迟也就是时钟树插入延迟。这个值在CTS前是估计的CTS后会被真实值替代。对ICG来说我们主要关心的是network latency因为ICG的CP端和它驱动的下游寄存器都在时钟树网络里它们的network latency差异是导致时序问题的核心。3.2 CTS前给ICG设latency的正确姿势CTS前工具不知道真实时钟树长什么样所以需要你告诉它一个预期的latency。对ICG我通常这样设set_clock_latency -source 0.5 [get_clocks clk_core] set_clock_latency 0.3 [get_clocks clk_core] set_clock_latency 0.35 -clock [get_clocks clk_core] [get_pins icg_inst/CP]这里第一行设source latency第二行设整个时钟域的network latency估计值第三行单独给ICG的CP端设一个稍大的latency。为什么要给ICG的CP端单独设因为在实际时钟树里ICG往往比普通寄存器更靠近时钟树的某个分支点或者因为驱动能力、负载不同它的插入延迟和普通寄存器不完全一样。给它设一个略大的latency可以让工具在CTS前就意识到“ICG的时钟可能到得晚一点”从而在优化使能路径时留出更多裕量。这个“略大”是多少一般比时钟域的平均latency大0.05ns到0.1ns比较合适。设得太大工具会过度优化可能导致其他路径出问题设得太小起不到保护作用。3.3 下游寄存器latency要不要跟着调ICG驱动的下游寄存器它们的时钟来自ICG的输出所以它们的latency实际上包含了ICG本身的延迟加上ICG输出到寄存器的时钟树延迟。在CTS前你可以给这些寄存器单独设一个latencyset_clock_latency 0.4 -clock [get_clocks clk_core] [get_pins reg_downstream/CK]这个值应该比ICG CP端的latency再大一点因为信号从ICG CP端到gated clock输出还有一段单元内部延迟再加上输出后的时钟树延迟。具体大多少取决于ICG单元的CLK-to-Q延迟和预估的输出网络延迟。一般可以设成ICG CP端latency加上0.1ns到0.2ns。这样设置之后工具在CTS前做时序分析时就会知道ICG的时钟和下游寄存器的时钟之间存在一个正向的latency差从而在优化使能路径时考虑到这个因素。3.4 CTS后latency被真实值替代怎么验证设置是否合理CTS之后工具会用真实的时钟树插入延迟替代你设的network latency估计值。这时候你需要做一件事对比CTS前设的latency和CTS后真实的latency看看差异有多大。如果CTS后真实latency和你设的估计值差异在0.1ns以内说明你的估计比较准CTS前的优化方向基本正确。如果差异很大比如你设了0.3ns实际出来0.6ns那CTS前的优化可能就偏了CTS后违例会比较多。验证方法很简单在CTS后的STA报告里看clock latency的报告report_clock_timing -type latency -clock clk_core对比ICG CP端和下游寄存器CK端的latency值看看它们的差是否和你CTS前设的差一致。如果不一致就要分析原因是时钟树结构问题还是ICG位置问题还是约束本身设错了。我自己的经验是CTS前latency估计值和CTS后真实值的差异控制在20%以内比较理想。超过这个范围就要回头检查约束或者时钟树综合策略。4. 从CTS前到CTS后的完整修复链路一个真实案例的排查过程光讲理论不够我用一个实际项目里的案例把从CTS前约束设置到CTS后违例修复的完整链路走一遍。这个案例是一个中等规模的SoC模块里面有大约60个ICG时钟频率800MHz工艺是较成熟的节点。4.1 问题现象CTS后hold违例集中爆发CTS之前模块的时序报告基本干净setup和hold都有正裕量。CTS之后重新跑STA发现使能路径hold违例87条clock gating check setup违例23条部分下游寄存器setup违例15条违例集中在几个ICG密集的区域而且很多违例的slack不大在-0.05ns到-0.15ns之间。这种“小违例但数量多”的情况通常不是某个单点问题而是约束或者时钟树策略的系统性问题。4.2 第一步检查set_clock_gating_check设置我先看了CTS前的约束文件发现set_clock_gating_check只写了setup没写holdset_clock_gating_check -setup 0.1 [get_clocks clk_core]这就是第一个问题。没有设hold裕量工具在CTS前对clock gating的hold检查用的是默认规则没有预留额外裕量。CTS后时钟树skew出来hold就崩了。修复补上hold裕量改成set_clock_gating_check -setup 0.1 -hold 0.05 [get_clocks clk_core]4.3 第二步检查latency设置接着看latency约束发现只设了一个全局的network latency没有给ICG和下游寄存器单独设set_clock_latency -source 0.5 [get_clocks clk_core] set_clock_latency 0.3 [get_clocks clk_core]这就是第二个问题。工具在CTS前认为所有寄存器和ICG的latency都是0.3ns没有考虑到ICG和下游寄存器之间的latency差异。CTS后真实latency出来ICG CP端是0.42ns下游寄存器CK端是0.55ns差了0.13ns而CTS前工具是按0差异优化的hold自然崩。修复给ICG CP端和下游寄存器分别设latencyset_clock_latency 0.35 -clock [get_clocks clk_core] [get_pins icg_inst*/CP] set_clock_latency 0.45 -clock [get_clocks clk_core] [get_pins reg_downstream*/CK]4.4 第三步CTS后针对残余违例的局部修复改完约束重新跑CTS和STA违例数量大幅下降hold违例从87条降到12条clock gating check setup违例从23条降到5条。剩下的这些是局部问题需要针对性修复。对残余的hold违例我用了两种方法第一种在使能路径上插入小delay。注意这里插delay要谨慎因为使能路径的hold修复不能影响setup。我一般会在使能路径的中间节点插入一个很小的buffer或delay celldelay值控制在0.05ns到0.1ns刚好补上hold的缺口又不会让setup变差。第二种调整ICG的位置。有几个ICG离时钟树根节点太近导致它的CP端latency偏小和使能寄存器的时钟skew大。把ICG往时钟树下游挪一点让它的latency更接近使能寄存器hold就改善了。这个方法需要和时钟树综合工程师配合不能自己随便挪。对残余的clock gating check setup违例主要是检查使能信号的到达时间。有几个使能信号经过了较长的组合逻辑到达ICG锁存器D端太晚。修复方法是在使能路径上做逻辑优化减少组合逻辑级数或者把使能信号打一拍再送进ICG。4.5 第四步验证修复效果并做OCV复查修完之后不能只看typical corner的时序一定要做OCV复查。我在OCV模式下重新跑STA发现又有几条hold违例冒出来slack在-0.03ns左右。这是因为OCV下early和late路径的derate不同原本typical下刚好满足的路径在OCV下就不够了。对这几条我用了set_timing_derate对clock gating路径单独调整set_timing_derate -clock_gating_check -early 0.97 -late 1.03调整后OCV下的违例也清了。这里要说明的是derate值不能随便设要和STA工程师确认确保符合项目的signoff要求。5. 几个容易踩的坑和我的实操心得上面讲的是完整流程下面单独拎几个我踩过的坑都是文档里不会写、但实际项目中很容易遇到的。5.1 坑一set_clock_gating_check设了但没生效有一次我明明写了set_clock_gating_check但工具报的违例还是按默认规则来的。查了半天发现是因为这个约束写在了读入库之前。set_clock_gating_check依赖于库单元里的clock gating检查arc如果库还没读入这个约束就无法正确关联到具体的单元上。正确顺序是先读库再读网表再写set_clock_gating_check。这个顺序问题很隐蔽因为工具不会报错只是约束静默失效。5.2 坑二latency设了负值set_clock_latency是可以设负值的但负值在ICG场景下要非常小心。我见过有人为了让ICG的latency“看起来小一点”设了个负值结果工具在CTS前把使能路径优化得过于激进CTS后真实latency出来setup全崩。latency的物理意义是延迟负值意味着“时钟提前到达”这在真实时钟树里几乎不可能出现。除非你有特殊的时钟树结构比如时钟先从某个分支反向走否则不要设负值。5.3 坑三ICG的使能信号跨时钟域如果ICG的使能信号来自另一个时钟域clock gating check的参考时钟就变得复杂了。工具默认会用ICG CP端的时钟作为参考但使能信号的实际到达时间是由它自己的时钟域决定的。这种情况下需要额外设置clock group或者false path否则工具会报大量假违例。我的做法是对这种跨时钟域的ICG先确认使能信号是否真的需要做clock gating check。如果使能信号已经做了同步处理且同步后的信号在目标时钟域里是稳定的可以考虑对clock gating check设false path避免假违例干扰。5.4 坑四CTS后盲目插delay修hold这是最常见的错误。CTS后看到hold违例第一反应就是插delay。但ICG的使能路径插delay会影响clock gating check的setup插多了setup就崩。而且使能路径往往扇出较大插一个delay可能影响多个ICG。我的经验是CTS后修ICG hold先看latency约束是否合理再看时钟树skew是否过大最后才考虑插delay。插delay时优先在扇出小的节点插并且要同时检查setup和clock gating check。5.5 一个实用技巧用report_clock_gating_check快速定位问题很多工具都有report_clock_gating_check命令可以单独报告clock gating检查的结果。我习惯在CTS前后都跑一次对比违例数量和分布。如果CTS后违例数量突然增加很多基本可以确定是latency约束或者时钟树策略的问题而不是单点路径问题。report_clock_gating_check -verbose cts_post_icg_check.rpt这个报告里会列出每个ICG的setup和hold检查结果以及对应的slack。结合latency报告一起看能很快定位到是哪个环节出了问题。6. 关于ICG时序修复我最后想说的几点ICG的时序问题说到底是一个“约束先行”的问题。CTS前把set_clock_gating_check和latency设对CTS后80%的违例都不会出现。剩下的20%才是真正需要局部修复的。很多人把顺序搞反了CTS前约束随便写CTS后拼命修结果越修越乱。另外ICG的时序修复一定要和时钟树综合工程师紧密配合。latency设置、ICG位置调整、时钟树结构优化这些都不是后端约束工程师一个人能搞定的。我在项目里通常会拉着CTS工程师一起看ICG的latency报告和违例分布很多时候他们从时钟树结构角度给出的建议比单纯在约束上调参数有效得多。还有一点不同工艺节点、不同库单元ICG的时序特性差异很大。上面讲的参数值都是参考实际项目中一定要根据库单元的实际时序arc和项目的时钟树特性来调整。我一般会在项目初期做一个小规模的ICG时序实验把set_clock_gating_check和latency的几组典型值跑一遍看看哪组值在CTS后违例最少然后再推广到整个设计。这个前期投入看起来费时间但比CTS后大规模返工要划算得多。
返回列表