ARTICLE DETAIL

资讯详情

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

clock_uncertainty设置指南:从综合到签核的时序约束策略

clock_uncertainty设置指南:从综合到签核的时序约束策略 1. 时序约束里最容易被低估的参数做数字IC后端或者时序签核的兄弟大概率都经历过这样的场景综合出来的网表跑PrimeTimesetup slack差那么二三十个皮秒明明逻辑级数已经压到极限了面积也快爆了时序就是过不去。这时候老手往往会问一句——你的clock_uncertainty设了多少是不是设得太保守了这个问题一出来很多时候就找到症结了。clock_uncertainty这个参数在SDC约束里看起来不起眼一行set_clock_uncertainty就完事但它对时序结果的影响极其直接你多设50ps等于凭空给每条时序路径增加了50ps的余量压力你少设了硅片上跑出来的芯片可能因为时钟抖动和偏斜直接翻车。说白了这个参数就是你在时序收敛和设计鲁棒性之间走的那根钢丝。这篇文章主要面向已经接触过SDC约束、跑过PrimeTime或者Tempus签核的读者不管你是刚入行的后端新人还是做了几年想重新梳理知识体系的工程师我都会把clock_uncertainty的构成、计算方法、不同阶段的设置策略以及和CTS、PrimeTime配合的实战细节讲透。网上很多资料只告诉你“设多少”但很少讲清楚“为什么设这个值”以及“什么阶段该改”。我踩过的坑和积累的经验尽量都放在这里。2. clock_uncertainty到底在约束什么2.1 从时序分析的基本模型说起要理解clock_uncertainty得先回到PrimeTime做setup分析的基本公式。对于一条从寄存器A到寄存器B的路径setup检查的核心表达式大致是这样的T_launch T_ck2q T_dp T_capture T_period - T_setup - T_uncertainty这里面T_launch和T_capture分别是发射时钟路径和捕获时钟路径的延迟T_ck2q是触发器的时钟到输出延迟T_dp是组合逻辑延迟T_setup是捕获触发器的建立时间。而T_uncertainty就是我们说的clock_uncertainty它被从时序预算里直接扣掉。你可以把它理解成我在做时序分析的时候故意留出一块“安全余量”用来覆盖那些我在当前分析阶段还没法精确建模的时钟不确定性因素。这个余量越大时序越难收敛但芯片流片后出问题的概率越小余量越小时序容易过但风险随之上升。2.2 clock_uncertainty的两大构成skew和jitterclock_uncertainty不是一个单一来源的量它主要由两部分组成clock skew和clock jitter。Clock skew是时钟信号到达不同触发器的时间差异。理想情况下时钟应该同时到达所有触发器但物理实现中不可能做到。时钟树上的缓冲器延迟、走线长度差异、负载不均衡都会导致skew。在CTS之前时钟树还不存在你根本不知道skew会是多少所以只能先估一个值放进uncertainty里。CTS之后skew有了实际数据就可以把预估的skew从uncertainty里拿掉换成真实的skew值。Clock jitter是时钟源本身的不确定性分为两类周期抖动period jitter时钟周期相对于理想周期的偏差影响的是单个周期的长度。周期间抖动cycle-to-cycle jitter相邻两个周期之间的差异对setup和hold的影响不同。对于setup分析我们关心的是发射时钟和捕获时钟在同一个时钟沿附近的不确定性通常用peak-to-peak jitter来衡量。对于hold分析情况稍微复杂一些因为hold检查的是同一个时钟沿的发射和捕获jitter的影响方式不同。除了skew和jitterclock_uncertainty里通常还会包含margin也就是额外留出的设计余量。有些团队会把OCVon-chip variation的降额也部分体现在uncertainty里但严格来说OCV应该用set_timing_derate来建模不应该混在uncertainty里。这一点后面会详细说。2.3 为什么不能把skew和jitter混在一起设很多新手容易犯的一个错误是在CTS之前设了一个很大的uncertaintyCTS之后也不改继续用那个值跑STA。结果就是时序过度悲观白白浪费面积和功耗去修一些根本不存在的违例。正确的做法是分阶段设置设计阶段skew处理方式jitter处理方式uncertainty典型值综合前预估skew预估jittermargin较大如0.3~0.5ns综合后预估skew可略收紧jittermargin中等如0.2~0.3nsCTS后用实际skew从uncertainty中移除jittermargin较小如0.1~0.15ns签核实际skewOCV deratejittermargin最小如0.05~0.1ns这个表格里的数值只是参考具体值取决于工艺节点、时钟频率和设计类型。比如在先进工艺节点下jitter的绝对值可能更小但skew的控制难度更大在高频设计里同样的jitter占比会更大。3. 不同阶段的设置策略与计算方法3.1 综合前拍脑袋也得有依据综合之前时钟树还不存在你手上只有RTL和时钟频率目标。这时候设clock_uncertainty本质上是在做预算分配。我的习惯是这样拆的假设时钟周期是2ns500MHz目标工艺是28nm那么预估skew28nm下一个中等规模的时钟树skew通常能控制在时钟周期的3%~5%左右。2ns的5%就是100ps。如果时钟树跨的物理区域很大或者负载很重可能要放到7%~8%。jitter取决于时钟源。如果是PLL产生的时钟查PLL手册里的period jitter参数通常几十皮秒。如果是外部晶振直接进来的jitter可能更小但要注意输入抖动。margin一般留时钟周期的2%~3%作为额外余量也就是40~60ps。加起来综合前的uncertainty大概设在0.15~0.2ns左右。但很多团队在综合前会设得更保守比如0.25ns甚至0.3ns目的是让综合工具把逻辑级数压得更紧给后端留更多空间。这个做法有利有弊好处是后端压力小坏处是面积和功耗可能过度优化。注意综合前设的uncertainty不要和set_clock_latency搞混。latency建模的是时钟从源到触发器时钟引脚的平均延迟uncertainty建模的是这个延迟的不确定性部分。两者是叠加关系不是替代关系。3.2 CTS前根据时钟树规格细化到了布局之后、CTS之前你对时钟树的拓扑结构已经有了初步规划。这时候可以根据时钟树的规格来细化uncertainty。比如你计划做一个H-tree结构的时钟树目标skew是80psjitter是30psmargin留20ps那么uncertainty就设130ps。如果你计划用clock meshskew可以做得更小比如50ps那uncertainty就可以相应降低。这个阶段还有一个重要的工作区分不同时钟域的uncertainty。比如核心时钟跑500MHzuncertainty设130psDDR接口时钟跑400MHz但jitter要求更严uncertainty可能设100ps低速外设时钟跑50MHzuncertainty设500ps都无所谓。用SDC表达就是set_clock_uncertainty -setup 0.13 [get_clocks core_clk] set_clock_uncertainty -setup 0.10 [get_clocks ddr_clk] set_clock_uncertainty -setup 0.50 [get_clocks peri_clk]对于跨时钟域的路径uncertainty的设置要特别小心。如果两个时钟域之间是异步关系通常会用set_clock_groups或者set_false_path来切断时序分析这时候uncertainty设多少就不重要了。但如果是同步但不同频的关系比如一个时钟是另一个的分频那么跨域路径的uncertainty应该是两个时钟uncertainty的某种组合具体取决于时钟树的共享程度。3.3 CTS后用真实skew替换预估skewCTS完成之后时钟树的实际skew可以从CTS工具的报告里拿到。这时候要做的事情是把uncertainty里的预估skew部分拿掉换成实际的skew值。但这里有一个容易踩的坑CTS报告里的skew是全局skew还是局部skew全局skew是所有触发器时钟到达时间的最大值减最小值这个值通常比较大。但STA分析是逐路径做的对于某一条具体的路径真正影响它的是发射触发器和捕获触发器之间的局部skew。如果你直接用全局skew去设uncertainty会过度悲观。我的做法是CTS后先用全局skew设一个保守值跑一遍STA看看时序情况。如果时序很紧张再用set_clock_uncertainty配合-from和-to选项对关键路径做更精细的局部skew设置。PrimeTime支持这种细粒度的uncertainty设置# 全局设置 set_clock_uncertainty -setup 0.08 [get_clocks core_clk] # 对特定路径覆盖 set_clock_uncertainty -setup 0.05 -from [get_clocks core_clk] -to [get_clocks core_clk] [get_pins critical_reg/D]不过这种逐路径的设置方式会让SDC变得很复杂维护成本高。除非确实有必要否则不建议大规模使用。3.4 签核阶段uncertainty和OCV derate的配合到了签核阶段clock_uncertainty应该只剩下jitter和margin两部分skew已经通过实际的时钟树延迟体现在时序分析里了。但这时候OCV derate开始发挥作用。OCV derate建模的是同一芯片上不同位置由于工艺偏差导致的延迟差异。对于时钟路径通常会对launch path和capture path施加不同的derate系数。比如set_timing_derate -early 0.95 -late 1.05 -clock set_timing_derate -early 0.97 -late 1.03 -data这时候clock_uncertainty和OCV derate是叠加的。有些团队会把OCV的一部分影响折算进uncertainty里简化约束但这样做不够精确。我的建议是uncertainty只管jitter和marginOCV用derate单独建模两者不要混。在先进工艺节点下还会用到AOCVadvanced OCV或者POCVparametric OCV这些方法会根据路径的逻辑深度和物理距离来动态计算derate值比传统的flat derate更精确。这时候uncertainty的设置可以更激进一些因为OCV的建模已经更准确了。4. 实操从SDC编写到PrimeTime验证4.1 一个完整的SDC约束示例下面是一个典型的SDC片段展示了clock_uncertainty在不同阶段的设置方式。假设设计有一个500MHz的核心时钟和一个200MHz的DDR时钟# 创建时钟 create_clock -name core_clk -period 2.0 [get_ports clk_core] create_clock -name ddr_clk -period 5.0 [get_ports clk_ddr] # 综合前保守设置 # set_clock_uncertainty -setup 0.25 [get_clocks core_clk] # set_clock_uncertainty -setup 0.30 [get_clocks ddr_clk] # CTS后收紧设置 set_clock_uncertainty -setup 0.10 [get_clocks core_clk] set_clock_uncertainty -setup 0.15 [get_clocks ddr_clk] # hold的uncertainty通常设得比较小 set_clock_uncertainty -hold 0.05 [get_clocks core_clk] set_clock_uncertainty -hold 0.08 [get_clocks ddr_clk] # 跨时钟域处理 set_clock_groups -asynchronous -group {core_clk} -group {ddr_clk}注意hold的uncertainty和setup的uncertainty是分开设的。hold分析关心的是同一个时钟沿的发射和捕获jitter的影响方式和setup不同通常hold的uncertainty会比setup小一些。4.2 在PrimeTime里检查uncertainty的影响设完约束之后怎么知道uncertainty设得合不合理PrimeTime提供了一些报告命令可以帮助分析。首先用report_clock_timing查看时钟的skew和latencyreport_clock_timing -type skew -clock core_clk report_clock_timing -type latency -clock core_clk这个报告会告诉你时钟树的实际skew分布。如果发现某些区域的skew特别大可能需要回头优化时钟树而不是简单地增大uncertainty。然后用report_timing查看具体路径的时序余量并关注uncertainty在其中的占比report_timing -from [get_clocks core_clk] -to [get_clocks core_clk] -delay max -max_paths 10在报告的路径详情里你会看到uncertainty被列为一个独立的扣减项。如果某条路径的slack是-20ps而uncertainty占了100ps那你就知道只要把uncertainty降低20ps以上这条路径就能过。但降低uncertainty意味着接受更大的时钟不确定性风险这个决策需要和时钟树设计团队一起做。4.3 参数计算一个具体的例子假设一个28nm设计核心时钟500MHz周期2nsPLL的period jitter是30pspeak-to-peakCTS后报告的全芯片skew是60ps团队决定留20ps的margin。CTS后的uncertainty计算uncertainty jitter margin 30ps 20ps 50ps但这里有一个问题CTS报告的60ps skew已经体现在时钟路径的延迟里了不需要再放进uncertainty。所以uncertainty设50ps就够了。如果是在CTS之前同样的设计uncertainty 预估skew jitter margin 80ps 30ps 20ps 130ps预估skew为什么是80ps而不是60ps因为CTS之前你没法保证skew能控制在60ps留一些余量是合理的。再考虑OCV的影响。假设时钟路径的OCV derate是±5%时钟路径的总延迟是500ps那么OCV带来的不确定性是500ps × 5% 25ps。这部分不应该放进clock_uncertainty而是通过set_timing_derate来建模。如果你发现PrimeTime报告里的OCV影响和uncertainty有重叠需要检查约束是否有重复计算。5. 常见问题与排查技巧5.1 uncertainty设太大导致时序过不了怎么办这是最常见的问题。症状是PrimeTime里大量路径setup违例但违例量都不大比如-10ps到-50ps之间。这时候先别急着去修逻辑先检查uncertainty。排查步骤用report_clock_timing -type skew确认实际skew是多少。检查SDC里的uncertainty值是否远大于实际skewjitter。如果是CTS后还在用CTS前的保守值把uncertainty收紧到合理范围。重新跑STA看违例是否消失。我遇到过一个案例一个设计在CTS后仍然用0.25ns的uncertainty导致几百条路径违例。把uncertainty降到0.08ns后违例减少了90%以上剩下的才是真正需要修的路径。5.2 uncertainty设太小导致硅后出问题反过来uncertainty设太小也有风险。硅后如果发现芯片在高温低压角下时序失败回溯原因往往是uncertainty没有覆盖足够的jitter和margin。预防措施jitter值一定要从时钟源的手册里查实际数据不要拍脑袋。margin的设定要考虑设计的使用场景。消费类芯片可以激进一些汽车电子或工业级芯片必须保守。在签核阶段跑蒙特卡洛分析看看uncertainty的设置是否覆盖了大部分工艺角组合。5.3 跨时钟域的uncertainty怎么设跨时钟域路径的uncertainty设置是另一个高频问题。如果两个时钟域是异步的用set_clock_groups -asynchronous切断分析uncertainty设不设都无所谓。但如果是同步关系比如一个时钟是另一个的2分频那么跨域路径的uncertainty应该是两个时钟uncertainty的叠加。具体来说如果core_clk的uncertainty是50psdiv_clk的uncertainty是60ps那么从core_clk到div_clk的路径uncertainty应该设110ps。这是因为发射时钟和捕获时钟的不确定性都会影响这条路径。在SDC里可以这样写set_clock_uncertainty -setup 0.11 -from [get_clocks core_clk] -to [get_clocks div_clk]5.4 CTS做tree时以一个view为主还是多个view这个问题在热搜里也出现了确实值得聊一聊。CTS阶段通常会有多个分析view比如func view、test view、low power view等。做时钟树的时候是只针对一个view做还是所有view一起做我的经验是以一个主view为主做时钟树其他view做辅助检查。主view通常是功能模式下的最差时序角比如ss corner。原因很简单时钟树是一套物理结构你不可能为每个view做一套不同的时钟树。所以必须选一个最主要的view来驱动CTS让这个view的skew和latency最优。但其他view也不能完全不管。CTS完成后要在所有view下检查时钟树的skew和latency是否可接受。如果某个view下skew特别大可能需要调整时钟树的约束或者插入额外的缓冲器来平衡。在SDC里不同view的uncertainty可以不同。比如func view下uncertainty设50pstest view下因为时钟路径可能更长uncertainty设80ps。这样STA分析时每个view都能得到合理的时序结果。5.5 常见问题速查表问题现象可能原因排查方法解决措施CTS后大量setup违例uncertainty仍用CTS前保守值检查SDC中uncertainty值收紧到实际skewjittermargin硅后高温角时序失败uncertainty未覆盖jitter和margin对比硅后测试数据和STA报告增大uncertainty重新签核跨时钟域路径违例uncertainty未叠加检查跨域路径的uncertainty设置叠加两个时钟的uncertaintyhold违例过多hold uncertainty设太大检查hold uncertainty值减小到合理范围不同view时序结果差异大时钟树未兼顾多view在各view下report_clock_timing调整CTS约束或uncertainty6. 一些实战心得clock_uncertainty这个参数说简单也简单一行SDC命令的事说复杂也复杂它涉及到时钟树设计、jitter建模、OCV分析、多view签核等多个环节。我做了这么多年时序约束最大的体会是不要把它当成一个孤立的参数来设要把它放到整个时序预算体系里去考虑。具体来说有几点经验值得分享第一分阶段设置及时更新。综合前、CTS前、CTS后、签核每个阶段的uncertainty都应该不同。我见过太多项目从头到尾用同一个值要么过度悲观浪费面积要么过于乐观导致硅后翻车。第二jitter要查手册不要猜。PLL的jitter参数是客观数据直接查手册就行。如果时钟源是外部输入的还要考虑输入抖动和板上时钟树的抖动。第三skew和OCV不要混。skew是时钟树的实际物理偏差OCV是工艺偏差的统计建模两者来源不同应该用不同的约束手段来处理。混在一起会让时序分析失去透明度出了问题很难定位。第四多view签核时uncertainty要分view设置。功能模式和测试模式的时钟路径可能完全不同uncertainty也应该不同。一刀切的做法要么让某个view过度悲观要么让另一个view过于乐观。第五留margin要有依据。margin不是越大越好也不是越小越好。我的习惯是根据设计的应用场景来定消费类芯片留时钟周期的2%左右工业级留3%~5%汽车级留5%以上。当然这只是一个粗略的参考具体还要看团队的签核标准和历史数据。最后再分享一个小技巧在PrimeTime里可以用report_clock_timing -type summary快速查看所有时钟的skew、latency和uncertainty设置一目了然。这个命令在debug时序问题时特别有用能帮你快速定位是哪个时钟的约束出了问题。
返回列表