首页 / 资讯中心 / 文章详情

Innovus时钟树综合CTS实战:5大常见问题排查与TCL脚本优化指南

Innovus时钟树综合CTS实战:5大常见问题排查与TCL脚本优化指南 ★ FEATURED ARTICLE
1. 时钟树综合到底在做什么从概念到实战的认知对齐时钟树综合Clock Tree SynthesisCTS在数字后端实现流程里是一个承上启下的关键节点。往前它承接布局Place之后的物理信息往后它要为布线Route和时序签核STA提供一棵“干净”的时钟网络。很多刚接触Innovus的朋友会有一个误区觉得CTS就是跑一条命令、等它结束、看报告有没有violation。实际上CTS更像是在做一场精密的“交通规划”——你要把时钟信号从根节点clock root公平、稳定、低抖动地送到成千上万个触发器flop的时钟端口上同时还要兼顾功耗、面积和绕线资源。我在实际项目中见过太多因为CTS没做好导致后续hold修不掉、动态功耗飙升、甚至芯片跑不到目标频率的案例。CTS做得好后面的时序收敛会轻松很多CTS做得糙后面就是无底洞。这篇文章我会围绕Innovus环境下CTS最常见的5类问题把每个问题的现象、根因、排查思路和解决方案讲透并且附上可以直接复用的TCL脚本片段。不管你是刚入行的后端新人还是已经做过几个项目但总觉得CTS“玄学”的工程师应该都能从中找到一些能直接抄作业的东西。先明确一下这篇文章适合谁看如果你已经了解基本的数字后端流程知道什么是setup/hold、什么是skew和latency但一到CTS就心里没底那这篇就是写给你的。如果你连Innovus的GUI都没打开过建议先补一下基础流程再回来看这些实战问题会更有感觉。2. 问题一时钟树长不出来或者长得很丑——clock tree无法收敛2.1 现象描述与根因分析这是CTS阶段最让人抓狂的问题之一。你跑完ccopt_design打开Clock Tree Debugger一看发现时钟树要么根本没长到某些sink上要么长出来的树像被台风刮过一样歪七扭八skew大得离谱。常见报错包括“Cannot find a valid path to sink”“Clock tree has unbalanced structure”等。根因通常集中在几个方面。第一是blockage和obstruction太多时钟树绕不过去。比如你在place阶段设置了大量routing blockage或者macro周围没有留够haloCTS工具找不到合法的绕线通道。第二是clock root位置不合理比如clock source被放在芯片角落而大部分sink在另一侧工具要跨越整个die去长树latency和skew都很难控制。第三是sink pin分布过于分散没有做clock-aware的place优化导致工具在聚类clustering阶段就崩了。2.2 排查步骤与TCL脚本实操我一般的排查顺序是这样的先看clock tree的sink有没有全部被cover再看latency分布最后看skew的hotspot在哪里。# 检查CTS后clock tree的基本状态 report_clock_tree -summary report_clock_tree -skew report_clock_tree -latency # 查看是否有sink没有被长到 check_clock_tree -report_unbalanced check_clock_tree -report_missing_sinks如果发现missing sink先别急着调CTS参数回去看place阶段。用下面这条命令检查sink周围有没有blockage# 检查指定sink周围的blockage情况 check_place -clock_tree -verbose我自己的经验是80%的clock tree长不出来问题根源都在place阶段。特别是当设计里有大量SRAM或IP macro时如果place时没有给clock net预留足够的绕线资源CTS阶段再怎么调参数都是事倍功半。2.3 解决方案与参数调整针对blockage问题最直接的办法是在CTS之前清理掉不必要的routing blockage或者给clock net设置专门的route type。Innovus里可以用set_ccopt_property来调整clock net的绕线优先级# 给clock net更高的绕线优先级 set_ccopt_property route_type -net_type clock -value special_route # 调整clock tree的clustering参数让工具更激进地聚类 set_ccopt_property clustering_effort high set_ccopt_property max_fanout 32 set_ccopt_property max_capacitance 0.2如果clock root位置确实不合理可以考虑在floorplan阶段就做clock-aware的placement。Innovus支持在place时用set_place_mode -clock_aware true来引导工具把flop摆得更利于时钟树生长。这个选项在大型设计上效果非常明显我做过一个7nm的项目开了clock-aware place之后CTS阶段的skew直接从180ps降到了45ps。注意clock-aware place会增加place阶段的运行时间通常多出20%到30%但相比CTS阶段反复迭代的时间这笔账是划算的。3. 问题二skew压不下去——时钟偏斜超标怎么破3.1 skew的本质与影响因素Skew是时钟树综合里最核心的指标之一。简单说skew就是同一个时钟域内最早到达sink的时钟沿和最晚到达sink的时钟沿之间的时间差。skew越大留给setup和hold的余量就越小时序越难收敛。影响skew的因素很多但归根结底是路径延迟的不平衡。有的sink离root近有的远有的sink后面挂的负载大有的小有的路径经过的buffer多有的少。CTS工具的任务就是通过插入buffer、调整buffer size、做clustering来把这些延迟尽量拉平。3.2 用TCL脚本定位skew hotspotInnovus提供了很强大的clock tree debug能力关键是要会用。下面这套脚本可以帮你快速定位skew最大的那些sink# 生成skew报告并按skew值排序 report_clock_tree -skew -sort_by skew -max_rows 50 skew_report.rpt # 用Clock Tree Debugger的API获取skew最大的sink set skew_sinks [get_ccopt_clock_tree_sinks -sort_by skew -descending -limit 20] foreach sink $skew_sinks { puts Sink: $sink, Skew: [get_ccopt_property skew -sink $sink] }拿到这些hotspot之后重点看它们所在的区域。通常skew大的sink会集中在某个角落或者某个macro附近。这时候可以考虑在这些区域增加局部clock buffer或者调整clustering的granularity。3.3 实战调参从180ps到45ps的优化过程我拿一个实际项目举例。这个设计是28nm工艺时钟频率800MHzCTS之后report_clock_tree显示skew是182ps。这个值对于800MHz周期1250ps来说已经吃掉了接近15%的余量后面setup会非常难修。第一步我先看了skew的分布图发现大部分sink的skew在60ps以内但有一小簇sink的skew高达180ps。这些sink集中在芯片右下角那里有一个大的SRAM macro。很明显时钟树绕不过这个macro导致路径延迟异常。第二步我检查了macro周围的绕线资源发现place阶段给macro留的halo只有2um而时钟线宽是0.2um根本不够走线。解决方案是在CTS之前把macro的halo加大到5um并且给clock net设置non-default ruleNDR用更宽的线宽和更大的间距# 给clock net设置NDR add_ndr -name clock_ndr -width {M1 0.2 M2 0.2 M3 0.2} -spacing {M1 0.4 M2 0.4 M3 0.4} set_ccopt_property route_type -net_type clock -value clock_ndr第三步调整clustering参数。默认的clustering可能把距离很远但负载相似的sink聚在一起导致路径延迟差异大。我把clustering_effort调到high并且限制了cluster的最大半径set_ccopt_property clustering_effort high set_ccopt_property max_cluster_radius 50 set_ccopt_property cluster_size 16这三步做完重新跑CTSskew降到了48ps。后来又微调了一下buffer size的选择策略最终skew稳定在45ps左右。这个案例说明skew问题往往不是CTS本身能解决的需要回到place和floorplan阶段去找根因。3.4 常用skew优化参数速查表参数作用推荐值注意事项clustering_effort控制聚类强度high过高会增加runtimemax_fanout限制buffer扇出24-32太小会导致buffer数量暴增max_capacitance限制负载电容0.1-0.2pF根据工艺调整max_cluster_radius限制cluster半径30-50um太大skew难控太小buffer多buffer_list指定可用buffer根据库选择优先用驱动能力适中的route_type绕线类型NDR需要提前定义NDR4. 问题三clock tree功耗太高——动态功耗优化实战4.1 时钟树功耗为什么这么关键在很多高性能设计里时钟树的动态功耗能占到整个芯片动态功耗的30%到40%。这个数字一点都不夸张因为时钟网络翻转频率最高而且驱动的负载flop的clock pin数量巨大。CTS阶段如果插入过多buffer或者buffer size选得过大功耗就会失控。我见过一个设计CTS之后时钟树功耗占了总功耗的45%后来通过优化降到了28%芯片整体功耗直接降了一个档次。所以CTS不只是修skew功耗优化同样重要。4.2 功耗优化的三个抓手第一个抓手是减少buffer数量。buffer越多翻转时充放电的电容就越多功耗自然越高。减少buffer数量的关键是做好clustering让一个buffer能驱动更多的sink同时不违反max_fanout和max_capacitance。第二个抓手是选择合适驱动能力的buffer。大驱动的buffer虽然延迟小但输入电容大前一级要驱动它就需要更大的功耗。Innovus里可以通过set_ccopt_property buffer_list来限制工具只使用特定驱动范围的buffer。第三个抓手是clock gating。在CTS阶段合理插入clock gating cell可以在模块不工作时关掉时钟节省大量动态功耗。Innovus支持自动clock gating插入但需要提前在RTL或综合阶段做好clock gating的规划。4.3 功耗优化的TCL脚本与参数# 限制buffer类型优先使用低功耗buffer set_ccopt_property buffer_list {CLKBUF_X2 CLKBUF_X4 CLKBUF_X8} # 设置max_fanout和max_capacitance的平衡点 set_ccopt_property max_fanout 32 set_ccopt_property max_capacitance 0.15 # 开启clock gating优化 set_ccopt_property clock_gating true set_ccopt_property clock_gating_style {integrated} # 报告时钟树功耗 report_clock_tree -power clock_power.rpt我自己的经验是buffer_list的选择对功耗影响最大。默认情况下工具可能会用一些超大驱动的buffer来压skew但这些buffer的功耗代价很高。手动限制buffer_list只允许使用中等驱动的buffer通常能在skew略微增加比如从45ps到55ps的情况下把功耗降低20%以上。提示限制buffer_list之后一定要重新检查skew和latency确保时序仍然满足要求。功耗和性能之间的平衡需要根据项目目标来定。4.4 功耗与skew的权衡策略功耗和skew是一对矛盾体。要压skew通常需要更多、更大的buffer要降功耗就要减少buffer数量和驱动能力。我的做法是分两步走第一轮CTS先以skew为目标把时序做干净第二轮再在时序余量允许的范围内逐步替换大buffer为小buffer观察功耗和skew的变化。Innovus支持增量式的CTS优化可以用ccopt_design -incremental来在已有clock tree基础上做局部调整。这样不用每次都从头长树迭代效率高很多。5. 问题四hold violation修不掉——CTS与ECO的配合5.1 hold violation的根源在CTS很多人以为hold violation是route之后才需要关心的事其实CTS阶段就已经埋下了伏笔。Hold violation的本质是数据路径太快时钟路径太慢导致数据在时钟沿之前就到达了。如果CTS阶段clock latency做得太小或者skew方向不对后面hold就会非常难修。Innovus里有一个很重要的概念叫useful skew。通过故意给某些sink增加clock latency可以让这些sink的hold更容易满足。但useful skew是一把双刃剑用不好会把setup搞崩。5.2 用TCL脚本做hold-aware的CTS# 开启hold-aware的CTS优化 set_ccopt_property hold_aware true set_ccopt_property useful_skew true # 设置hold的目标余量 set_ccopt_property hold_target_slack 0.05 # 报告hold violation report_clock_tree -hold hold_report.rpt如果CTS之后还有hold violation通常需要在ECO阶段插入delay cell。Innovus的ECO引擎可以自动做这件事# 进入ECO模式 set_eco_mode -hold # 自动修复hold violation eco_opt -hold -effort high # 检查修复结果 report_eco -hold5.3 ECO buffer tree的插入技巧ECO阶段插buffer修hold最怕的是把clock tree搞乱。我的做法是只允许在data path上插delay不动clock path。Innovus里可以通过set_eco_mode -preserve_clock_tree true来保护clock tree不被ECO改动。另外ECO插的delay cell要尽量靠近sink这样对周围逻辑的影响最小。如果delay cell插得太靠前可能会影响一大片逻辑的时序。# 保护clock tree只在data path上做ECO set_eco_mode -preserve_clock_tree true set_eco_mode -hold -data_path_only true # 指定delay cell的类型 set_eco_mode -delay_cell_list {DELAY_X1 DELAY_X2 DELAY_X4}5.4 hold修复的常见坑与避坑指南第一个坑是ECO之后没有重新跑STA。ECO插了delay celldata path的延迟变了setup可能会受影响。每次ECO之后必须重新跑一遍STA确认setup和hold都干净。第二个坑是delay cell选得太大。有些工程师为了快速修hold直接插最大驱动的delay cell结果hold修过了setup又崩了。建议从小驱动开始试逐步加大。第三个坑是ECO影响了clock tree的skew。虽然设置了preserve_clock_tree但如果ECO插的cell离clock net太近可能会引入耦合电容间接影响clock latency。ECO之后要重新检查clock tree的skew和latency。6. 问题五CTS之后时序不收敛——post-CTS优化策略6.1 post-CTS时序为什么容易崩CTS之后时钟树从理想时钟变成了真实时钟clock latency和skew都变成了实际值。这时候STA的结果通常会比CTS之前差很多因为之前用的是ideal clock没有考虑clock tree的延迟和偏斜。Post-CTS时序不收敛的原因通常有三个一是clock latency太大吃掉了太多时序余量二是skew太大setup和hold互相打架三是CTS插入的buffer改变了data path的负载导致cell delay变化。6.2 post-CTS优化的完整流程我一般的post-CTS优化流程是这样的第一步先看clock tree的质量。用report_clock_tree -summary确认latency和skew在合理范围内。如果latency超过周期的10%就要考虑优化clock root或者减少buffer级数。第二步跑STA看setup和hold的violation分布。如果setup violation集中在某几个clock domain可能是这些domain的clock tree做得不好。如果hold violation到处都是可能是useful skew没用好。第三步做post-CTS的时序优化。Innovus提供了opt_design -post_cts命令可以同时优化setup和hold# post-CTS时序优化 set_opt_mode -post_cts true opt_design -post_cts -setup -hold -effort high # 报告优化结果 report_timing -max_paths 100 post_cts_timing.rpt第四步如果还有violation进入ECO阶段做局部修复。6.3 post-CTS常用优化命令与参数命令作用关键参数使用场景opt_design -post_cts综合优化setup和hold-effort high常规post-CTS优化ccopt_design -incremental增量优化clock tree-skew -latencyclock tree质量不佳eco_opt -setup修复setup violation-effort highECO阶段修setupeco_opt -hold修复hold violation-data_path_onlyECO阶段修holdreport_clock_tree报告clock tree状态-skew -latency -power每次优化后必看6.4 一个真实项目的post-CTS优化记录去年做一个22nm的移动芯片项目CTS之后setup WNS是-120pshold WNS是-80ps基本上属于“崩了”的状态。我先看了clock tree的报告发现latency高达450ps而时钟周期只有1000pslatency占了45%这显然不正常。排查后发现clock root被放在了一个远离核心逻辑的角落而且clock tree经过了三个大macro绕线路径非常长。解决方案是在floorplan阶段把clock root移到芯片中心位置并且给clock net设置了更宽的NDR。重新跑CTS之后latency降到了180psskew从95ps降到了38ps。然后跑post-CTS优化setup WNS改善到-30pshold WNS改善到-15ps。最后通过ECO插了少量delay cell和size up了一些关键路径上的cell时序全部收敛。这个项目让我深刻体会到CTS的问题往往要在CTS之前解决floorplan和place阶段的一个小决定可能会让CTS阶段多花好几天去弥补。7. 五个问题的速查总结与个人实操心得7.1 问题速查表问题典型现象首要排查方向核心解决手段clock tree长不出来missing sink, unbalancedplace blockage, macro halo清理blockage, 加大halo, clock-aware placeskew超标skew 100psclock root位置, clustering调clustering参数, 加NDR, 局部buffer功耗太高clock power 35%buffer数量, buffer size限制buffer_list, 优化clusteringhold修不掉hold WNS -50psuseful skew, clock latencyhold-aware CTS, ECO插delaypost-CTS时序崩setup/hold都差clock latency, skew优化clock tree, opt_design -post_cts7.2 我踩过的坑和总结的经验第一个经验是CTS之前一定要做clock-aware的place。这个选项在Innovus里默认是关的但开了之后效果立竿见影。我做过对比同一个设计开了clock-aware place之后CTS的skew平均降低40%runtime减少25%。第二个经验是不要迷信默认参数。Innovus的CTS默认参数是面向通用设计的但每个项目都有自己的特点。比如高频设计要更关注skew低功耗设计要更关注buffer数量大die设计要更关注latency。根据项目目标去调参数比盲目跑默认值强得多。第三个经验是每次CTS之后都要看clock tree debugger。不要只看report的数字要打开图形界面看clock tree的实际结构。很多时候report显示skew是50ps但打开debugger一看发现某个角落的sink根本没长到树上只是没被report出来而已。第四个经验是ECO阶段要保护clock tree。ECO插delay cell修hold的时候如果不保护clock tree很容易把之前辛苦调好的skew搞乱。set_eco_mode -preserve_clock_tree true这条命令一定要加上。第五个经验是CTS不是一次就能做好的。我做过的最顺利的项目CTS也迭代了三次。第一次跑完看整体质量第二次调参数优化skew和功耗第三次做incremental优化修局部问题。把CTS当成一个迭代的过程心态会好很多。7.3 一套可以直接复用的CTS TCL脚本模板最后分享一套我常用的CTS脚本模板涵盖了从环境设置到结果报告的完整流程# # CTS TCL脚本模板 # 适用: Innovus 20.x及以上版本 # # 1. 基础设置 set_ccopt_property buffer_list {CLKBUF_X2 CLKBUF_X4 CLKBUF_X8 CLKBUF_X12} set_ccopt_property max_fanout 32 set_ccopt_property max_capacitance 0.15 set_ccopt_property clustering_effort high set_ccopt_property max_cluster_radius 50 # 2. 绕线设置 add_ndr -name clock_ndr -width {M1 0.2 M2 0.2 M3 0.2 M4 0.2} \ -spacing {M1 0.4 M2 0.4 M3 0.4 M4 0.4} set_ccopt_property route_type -net_type clock -value clock_ndr # 3. 时序设置 set_ccopt_property hold_aware true set_ccopt_property useful_skew true set_ccopt_property hold_target_slack 0.05 # 4. 功耗设置 set_ccopt_property clock_gating true set_ccopt_property clock_gating_style {integrated} # 5. 运行CTS ccopt_design -cts # 6. 结果报告 report_clock_tree -summary cts_summary.rpt report_clock_tree -skew -max_rows 50 cts_skew.rpt report_clock_tree -latency cts_latency.rpt report_clock_tree -power cts_power.rpt # 7. 检查 check_clock_tree -report_unbalanced cts_check.rpt # 8. Post-CTS优化 set_opt_mode -post_cts true opt_design -post_cts -setup -hold -effort high # 9. 最终报告 report_timing -max_paths 100 post_cts_timing.rpt report_clock_tree -summary final_cts_summary.rpt这套脚本我在多个项目上用过基本框架是通用的具体参数值需要根据工艺节点和设计特点微调。比如28nm工艺的max_capacitance可以放到0.2pF而7nm工艺可能要降到0.08pF。buffer_list也要根据实际库里有那些cell来调整。注意脚本里的NDR定义需要根据实际金属层和工艺设计规则来改不要直接照搬。线宽和间距设得太激进会导致DRC violation设得太保守又起不到优化效果。7.4 后续还可以这样扩展CTS这个话题其实还有很多可以深挖的方向。比如multi-clock domain的CTS处理当设计里有多个异步时钟域时clock tree的做法和单时钟域完全不同。还有3D IC的CTS随着chiplet技术越来越热跨die的时钟树综合也是一个新课题。另外machine learning辅助的CTS参数调优也是最近比较火的方向Innovus新版本里已经有一些ML-based的优化引擎可以自动搜索最优的CTS参数组合。如果你已经把单时钟域的CTS做熟了建议下一步可以研究一下multi-clock domain的场景这是实际项目中最常遇到的复杂情况。我后面也会整理一些multi-clock CTS的实战经验有兴趣的可以持续关注。
阅读完成 · 觉得有帮助?
咨询建站