ARTICLE DETAIL

资讯详情

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

ICC时钟树综合CTS核心设置与优化实战指南

ICC时钟树综合CTS核心设置与优化实战指南 跑过后端流程的同学应该都对CTS这一步又爱又恨。爱的是时钟树综合能把理想时钟变成能落地的物理时钟网络恨的是它一旦失控skew爆表、hold修不完、congestion恶化后面每跑一步都在还债。ICCSynopsys IC Compiler作为当年最常见的APR工具之一CTS相关的设置和优化策略到今天还值得拿出来重新捋一遍。这篇文章我会把ICC里CTS的核心设置拆开讲从前期准备、约束写法到参数背后的原因再到实战中常见的翻车现场和修复手段一次性说透。我也希望给正在用ICC做后端的工程师一些可以直接抄作业的参考尤其是那些刚从RTL转过来、对时钟树只停留在“插buffer”层面理解的同学这篇应该能帮你把CTS这层窗户纸捅破。1. CTS开工前先把这三件事检查明白很多人一进CTS就急着跑compile_clock_tree结果一堆error、warning砸过来才开始回头补检查。其实CTS能不能做稳主动权在CTS之前就已经定了一半——时钟约束定义、库单元准备、floorplan规划这三件事任何一件埋了雷CTS阶段都会集中引爆。1.1 时钟定义是不是真的“干净”CTS的全称是Clock Tree Synthesis但它不负责定义时钟它只是按照约束去“实现”时钟网络。所以约束里时钟定义是否清晰直接决定CTS的走向。ICC做CTS之前首先要确认SDC里的时钟约束不是一堆“等价但说不清”的定义。比如create_clock的source latency、uncertainty、transition设置是否合理generated_clock的master clock和divide/multiply关系有没有对齐全这些都是老生常谈的问题但也是每次都要重新过一遍的问题。我不建议直接拿前端给的SDC原封不动去跑CTS。前端给的SDC更侧重功能验证后端要在这个基础上做物理实现。CTS阶段至少要把下面几类约束重新审视一遍确实不建议CTS上来就直接盲跑否则后面时序分析全是糊涂账false path和case analysis的设置是否保留了后端需要的时钟关系multi-cycle path是否对跨时钟域的约束有明确覆盖uncertaint是否区分了setup和hold的预算因为CTS之后skew由真实结构决定uncertainty过大会过度约束让CTS为了不切实际的skew目标疯狂插buffer说个现象很多CTS不收敛的case根子不在CTS工具参数而是SDC里时钟定义互相矛盾比如两个generated clock打到同一个sink集合上或者同一个phy pin上绑了两个主时钟。ICC的report_clock -skew和report_clock -overlap都能查这类冲突建议CTS前跑一遍别等树长歪了再回头看约束。1.2 你给CTS准备了哪些“兵”——时钟树单元库CTS不是随便拿标准单元库里的buffer/inverter就用它是从中挑一个子集来做时钟树。这个子集通常在lib里通过is_clock_gating_cell、clock_gate_integrated_cell等属性标注或者在后端流程里通过set_clock_tree_options的-clock_gating_cells、-buffer_cells、-inverter_cells来指定。实际项目中时钟树单元的选择通常遵循几个原则尽量选驱动能力中等偏小的buffer/inverter因为驱动太大会造成更大的transition和功耗驱动太小则插的级数多latency拉长时钟树用inverter比buffer省功耗因为半个周期只有一半管子动作很多设计会清一色用inverter做反相树但要注意偶数和奇数级反相器导致的相位问题memory、analog IP的时钟入口通常有lib属性标明CK pin可接受的最大transitionCTS要参考这些值完成约束设置ICC里有个常用体验是CTS库如果选得太宽工具会用很多驱动强度很大的buffer去“堆”tree结果skew是好了但功耗和congestion都爆掉选得太窄又容易出现修不动、违反transition的情况。所以库的准备最好是提前在CTS lib上做一次评估可以先用早期floorplan跑一版粗CTS用report_clock_tree看它实际用了哪些cell再决定是否收紧或放宽库列表。提示我在实际项目里通常会把CTS用的inverter和buffer各保留4到5个驱动档位再额外保留一档大驱动用于长距离走线和clock gate旁边的驱动修复其余全部剔除。1.3 floorplan规划对时钟树的“顶层设计”floorplan不只影响绕线也直接影响时钟树结构。宏单元SRAM、analog IP的位置摆放、clock pin的朝向、channel宽度、macro和std cell之间的间距都会决定CTS插入的buffer数量和走线路径。一个很典型的例子如果某个memory的clock pin朝向不对CTS不得不绕一大圈走线去接入skew自然会被拉大。工具补偿的办法只能在这一分支上插更多delay结果就是该分支latency暴涨反而拖累全局平衡。还有一类常见的问题CTS之前的floorplan如果blockage太密buffer没有插入位置工具只能把buffer塞在边缘时钟路径产出一堆长走线。长走线本身就是delay和variation的放大器后面做OCV分析时会非常痛苦。因此建议每个项目在floorplan阶段就把时钟网络的物理路径规划一遍时钟源入口在哪里哪些模块对时钟延迟敏感macros的clock pin能不能统一朝向关键路径区域的blockage能不能留出buffer的“种植带”。这些工作在CTS阶段花1小时检查能省后面3天修问题的时间。2. 时钟树综合到底在“综合”什么核心约束逐项拆解进入CTS后ICC其实是在做一件听起来简单、做起来复杂的事情从时钟源出发通过插入buffer/inverter把时钟信号送到每一个sink通常是触发器的CK端并且让所有sink的延迟尽量一致同时满足transition、fanout、capacitance等电气约束。但“尽量一致”这个目标有很多种理解方式工具行为也因此不同。这一节我把ICC里CTS相关的核心选项和它们背后的逻辑讲清楚。2.1 三个核心目标target skew、target latency、target transition先说最常碰到的三个target它们是CTS报表里最直观的指标。Target Skew时钟信号到达所有sink的最大时间差。假设一个设计有2000个触发器理想情况下大家时钟沿同时到skew 0。但物理上做不到所以要给工具一个可接受的范围。ICC默认的target skew可能比较宽松比如全局0.2ns实际工程中要根据时钟频率和工艺节点去收紧。过紧会让工具反复插buffer来平衡增加面积和功耗过松又会让时序修起来很被动。Target Latency时钟从源头到sink的总延迟。这个值不是越小越好它会直接影响时钟树的级数和每一级的电气负载。ICC里可以用-target_latency来指定期望值给一个合理目标工具会在插buffer时兼顾latency和skew的平衡。如果一个分支的物理走线天然短为了匹配长分支工具需要故意插入delay cell来补偿这就是latency约束的实际意义。Target Transition时钟信号上升/下降沿的过渡时间。transition过大会导致timing计算不准甚至可能造成毛刺过小又意味驱动级数过多。通常工艺库会给出推荐范围比如先进工艺下时钟树控制在50ps到150ps之间老工艺可以放宽。拿一个实际的例子来说假设核心时钟是1GHz周期1nsICC里我一般先设置set_clock_tree_options -clock clk_core \ -target_skew 0.05 \ -target_latency 0.5 \ -max_transition 0.1其中target skew 0.05是相对于1ns周期的一个较紧目标先跑一版看结果。如果工具report出来的实际skew是0.08但setup和hold都能收敛那这个0.05就不需要强行达到。CTS优化终究是服务于时序收敛不是追求纸面指标好看。2.2 电气约束max_fanout、max_capacitance、max_transition怎么配合ICC里的set_clock_tree_options除了上面几个目标还有电气限制条件-max_fanout单个时钟树节点最多驱动的sink数量-max_capacitance单个节点的输出负载电容上限-max_transition前面讲过的transition上限很多人会把这几个参数当成独立约束来调但实际上它们是联动关系。比如一个节点驱动20个sink如果每个sink的输入电容都很大综合后的总负载电容早就超过max_capacitance了工具必须进一步分级驱动拆成两级甚至三级buffer才能满足约束。我见过不少项目为了追求完美的transition把max_transition设得非常激进比如0.05ns结果CTS插入的buffer数量翻了倍面积和功耗明显上升后续绕线也吃紧。更合理的做法是根据库里的实际特性设置用标准单元的lib数据做一次估算看看推荐的transition范围是多少再结合时钟频率留出余量。这里分享一个我自己常用的“经验起点”逻辑库标准单元的max transition通常在lib里有明确值时钟树一般取该值的一半或更紧max fanout对时钟树而言控制在20到30之间比较常见太大会让skew恶化太小则级数过多max capacitance不用设得过分严格因为工具会自动调整级数来满足transitioncap约束主要是兜底2.3 通过clock tree exceptions给特殊路径开“后门”不是所有sink都要求CTS一视同仁地平衡。比如寄存器组里的异步复位端、扫描链的测试时钟、或者不关 timing 的虚拟负载都需要通过set_clock_tree_exceptions来特殊处理。ICC中常用的几个exception类型我要单独提一下-stop_pin让时钟树在这个pin处停止综合后续路径由其他机制处理。典型应用场景是memory内部时钟路径已经由vendor处理后端CTS不能再去动它-through_pin指定时钟必须经过某条路径通常用于跨模块的物理约束-dont_touch_subtree保留现有子树不加buffer主要是为了保住已有延迟匹配或物理约束-non_leaf/-no_distribute针对非叶子节点或不需要打散的sink这些exception如果设置不当会发生“工具为什么不敢动这棵树”的诡异现象。比如某个模块的时钟延迟特别长查了半天发现是之前工程师在memory的clk上挂了dont_touch_subtree导致CTS无法插入足够的buffer。这个经验也提醒我们给CTS增加任何例外都要在report里能明确看到对应的异常点不能“眼不见为净”。2.4 ICC里CTS的完整命令流水线ICC的CTS流程可以按下面这几步串起来这也是我日常跑CTS的基本操作顺序set_delay_calculator_options -default \ -clock_reconvergence_pessimism remove # 先让工具生成clock tree spec文件 create_clock_tree_spec \ -output ./output/clock_tree_spec.tcl # 按需编辑spec中的set_clock_tree_options set_clock_tree_options -clock clk_core \ -target_skew 0.05 -target_latency 0.5 \ -max_transition 0.1 -max_fanout 20 \ -buffer_cells [list CLKBUFX2 CLKBUFX4 CLKBUFX8 INVCLKX2 INVCLKX4] # 设置时钟树绕线层 set_clock_tree_options -clock clk_core \ -layer_list [list M6 M7] # 执行时钟树综合 compile_clock_tree # CTS后立刻传播时钟并更新latency/skew信息 propagate_clock update_clock_latency # 报告核心结果 report_clock_tree -summary report_clock_timing -type skew -nworst 20这套不是唯一的标准答案但每一步都有它的作用。create_clock_tree_spec输出一个文本spec文件所有CTS约束都集中在这里方便review和版本管理。compile_clock_tree才是真正开始插buffer/inverter的动作之后立刻把时钟传播出去让后续工具能拿到真实时钟延迟来做时序分析。我在项目里通常习惯把CTS跑完后先不急着去做布线而是用report_clock_timing横向对比各组时钟的latency/skew观察是否有异常的时钟组。这个报告信息密度很高比堆一堆warning实际得多。3. 时钟树的“骨架”怎么做才稳结构选择与绕线资源CTS不只是插buffer这么简单它是在一个物理空间里为成百上千个sink搭建一棵能平衡、能驱动、能抗干扰的树。这棵树的“骨架”决定了它的质量和后续可维修性。3.1 从时钟源到叶节点的路径认知做CTS之前首先要清楚一条完整的时钟路径长什么样时钟源clock source - CTS插入的buffer/inverter级联网络 - clock gate如果有 - 最终sink触发器的CK、memory的CK、或硬核IP的时钟pin很多设计里会出现clock gating cell这相当于把时钟树的“树干”分成两段。ICC会在clock gate前后分别做平衡从源头到各个clock gate的输入做一级平衡从clock gate输出到下游sink再做二级平衡。这两段不是完全独立的因为clock gate本身有延迟还会引入enable信号的时序约束所以CTS也必须对clock gate的输入transition做限制。我遇到比较多的问题是工程师只关注最终sink的skew忽略了clock gate输入端的skew。结果clock gate的两个输入时钟和enable之间的race condition没有控制好导致gate后面时钟沿变形sink端的skew再小也没用。这类问题定位起来很隐蔽因为report_clock_timing默认报的是最终sink你需要在report里展开中间节点才能看到。3.2 选哪种树形H-tree、平衡buffer树、还是clock meshCTS工具会自动选择合适的树形结构但设计者的物理规划会影响工具的决策。简单说一下几种常见结构的特点平衡buffer树balanced buffer tree最常见也是CTS工具自动生成的默认结构。它通过逐级分叉和插入buffer把sink分组成近似等长的路径。优点是实现灵活、迭代快缺点是skew受工艺偏差影响大在高频高负载模块中需要额外补偿。H-tree一种对称分布的结构适合全局规则的floorplan比如memory阵列或者排列整齐的计算阵列。H-tree的走线路径相对规整版图实现可控但对floorplan不规则的设计并不友好。Clock mesh网格时钟早期一些高性能芯片会采用直接在全局铺一层时钟网格再用local buffer把时钟从网格抽取到sink的方式。网格的优势是skew极低、抗本地负载波动但功耗巨大后端实现复杂度也高。一般消费级SoC不会在整芯片用mesh更多的是在局部高性能模块中尝试。在ICC里做CTS多数情况下工具会在全局用平衡buffer树局部根据密度和约束优化。设计者能介入的是通过绕线层限制、blockage、以及给重要模块设置独立的skew group来控制树形走向。如果某个模块时钟树的分叉点明显不合理我建议直接在floorplan上摆好局部sink分组给工具一个合理预期而不是把树形设计的唯一希望都放到工具的随机搜索上。经验之谈CTS结果不是越对称越好而是越符合物理布局越好。盲目追求绝对平衡会让工具四处绕路找插入点反而增加走线长度和绕线拥塞。3.3 绕线资源与shielding时钟线的“路权”时钟树用的是真实金属层走线绕线资源是有限的。CTS阶段如果占用了太多低层金属后面std cell绕线的资源就会被挤占造成congestion。所以在ICC中通常建议给时钟树的绕线设定固定层set_clock_tree_options -clock clk_core -layer_list { M6 M7 }这相当于告诉工具这棵时钟树只能走在M6/M7层上不能向下挤占M3/M4这些std cell绕线主力层。代价是如果M6/M7资源本身紧张也可能产生clock绕线阻塞所以层列表的选择要根据global routing的结果来平衡。另外时钟信号在先进工艺下容易受到相邻信号线串扰影响导致抖动和延迟变化。所以有些设计会给时钟做shielding屏蔽走线即在时钟线两侧加地线VSS/VDD的固定走线来隔离。ICC里做shielding是在CTS后、绕线时通过route_clocknet或special route来实现的这同样会占用资源需要提前规划。3.4 跨时钟域与skew group的处理设计里往往不只有一棵时钟树而是有多组时钟树同时存在。ICC用“skew group”来区分不同时钟树之间的平衡关系同一个group内的时钟要相互平衡不同group之间的时钟skew一般不做约束除非是明确需要对齐的双沿采样或者跨时钟握手信号。对于跨时钟域的路径一个容易踩的坑是CTS阶段给两个不同频率时钟设了不合理的相同skew目标或者错误地把两个时钟放进了同一个skew group导致CTS疯狂在两个domain之间插delay来“对齐”结果面积功耗全失控。正确做法是除非有确实需求比如同步器需要满足特定的relative timing否则确保不同时钟域在CTS里分属不同group并在report里确认它们的平衡关系符合预期。还有一类场景是设计里有独立的扫描时钟scan clock和功能时钟functional clock。如果CTS阶段把两者放同一个group强行对齐树会非常庞大。通常建议扫描时钟单独定义skew group或者在scan mode下单独跑CTS功能模式里只对active clock做balanced tree。CC里的具体操作一般是通过set_clock_tree_options -clock_trees指定需要综合的时钟配合clock group的划分来实现。4. CTS后的“收尾工程”分析、修时序、布局调整CTS跑完不等于万事大吉后面还有一堆排查和修复工作等着你。从经验来看CTS后的第一份时序报告往往是最能暴露问题的它把理想时钟换成了真实传播时钟所有路径的时序都会因为skew和latency的变化重新洗牌。4.1 怎么读懂CTS报告skew报表里藏着哪些信息跑完CTS后我第一件事就是看report_clock_timing -type skew重点关注几个点每个clock group的global skew是不是控制在目标附近是否有少数几条路径的skew异常大导致整体skew报表被拉高各时钟树之间的inter-clock skew是否合理当看到一组skew结果时不要只看最大值。工具报告的是worst skew但你要分析的是worst skew出现在哪类路径上、是距离远导致还是负载不均衡导致、这些路径是否与关键数据路径重合。如果worst skew来自一条无关紧要的测试时钟它对整个时序收敛的影响其实有限可以适当放松如果出现在核心流水线上那就得认真处理。report_clock_tree -summary也很关键它给出了每棵时钟树用了多少级buffer、多少cell、总电容、总面积。这些数据是评估CTS质量的主要指标。如果某个树级别数特别多往往意味着负载过重或者驱动链配置不合理。我曾见过一个低功耗模块里因为flop分布极度稀疏CTS插了十几级buffer才平衡完功耗浪费非常严重。这种情况下重构时钟结构比如加gating或调整flop分组往往比调CTS参数更有效。4.2 为什么CTS后hold最容易爆CTS对着真实时钟网络做时序分析时setup和hold都会发生变化但最容易爆破的是hold。原因是CTS给不同路径引入了真实的时钟延迟差即skew。当sink端时钟比源端晚到positive skew相当于给数据路径多了一些额外预算对setup有利但当sink端时钟比源端早到negative skewhold检查时数据必须保持住的时间变长原本在理想时钟下hold violation可能原本勉强贴合这样转成真实时钟后就直接打不过去了。所以在CTS完成后必须基于propagated clock重新做一次hold check。如果hold问题一大片常见的处理方式是在ICC里用set_fix_hold_options打开hold优化让工具在布局布线阶段自动插入delay buffer来修复。但这需要小心过多的hold fix buffer会让面积膨胀并且增加后续DLCdelay logic cell的负担所以尽早发现hold风险、尽早修正是硬道理。我在项目中习惯在CTS后立刻跑一版setup/hold的全局report哪怕还只是粗略约束set_operating_conditions -analysis_type on_chip_variation set_clock_uncertainty -setup 0.03 [get_clocks clk_core] set_clock_uncertainty -hold 0.03 [get_clocks clk_core] report_constraint -all_violators -verbose通过这个粗查可以快速判断CTS造成的时序退化主要集中在哪些模块以及需要优先处理哪些路径。如果规模太大导致全面修hold不现实则需要回到CTS阶段调整skew目标比如用useful skew技巧允许部分路径故意做正skew从而在不增加面积的前提下优化关键路径。这里有必要细说“useful skew”。所谓useful skew不是盲目让所有时钟不等时到达而是有方向地利用skew来救时序对收路径关键setup紧张的触发器让它的时钟晚到一些增加positive skew等价于延长了数据可用时间对发路径关键hold紧张的触发器让它的时钟早到一些增加negative skew来帮助数据更早稳定。现代CTS工具都支持通过约束或tcl脚本去设置这类微调ICC提供set_clock_tree_options -useful_skew和set_clock_latency来控制。但在实际落地时我会坚持“useful skew只能用来救急不要让工具全局自由使用”的原则因为一旦依赖useful skew后续工艺偏差和ECO都可能让这种微妙平衡失效。4.3 常见CTS问题与排查实录这里整理几个我实际项目中踩过的CTS问题按照“症状-原因-解法”的方式列出来。问题1CTS后skew远大于target反复优化不收敛原因通常有二一是某些sink的物理位置极端偏远或环境blockage严重工具无法在合理范围内平衡二是target设置不合理超过了物理可实现极限。 排查思路先用report_clock_tree看worst skew路径集中在哪个方向再在GUI里高亮显示这些sink。如果确实是因为某个macro的位置太偏应该回到floorplan重新摆放或调整blockage而不是靠CTS硬修。如果工具提示区域拥塞则需要配合局部区域细致优化。问题2CTS把一堆buffer插在同一个区域造成局部拥塞原因通常是sink分布不均匀或者floorplan上该区域被强制设置为buffer的可插入区域但本身布线资源紧张。 排查思路在ICC里用congestion map和cell density overlay查看定位到缓冲区堆积区。常见做法是把buffer插入区域blockage微调、增加区域面积、或者把部分sink移到其他区域之后再重新跑CTS。还有一次我们是在这个区域附近加了几个endcap顺手就缓解了buffer堆积。问题3CTS后clock gating报timing violation原因通常是enable信号的时序相对于时钟沿没有满足要求或者clock gate输入端的transition过大。 排查思路重点检查enable信号的路径延迟以及它和时钟CK的common path。许多时候enable路径上存在跨模块的信号需要增加约束或调整逻辑。CTS阶段要确保clock gate输入端也能满足transition否则gate输出波形畸变下面一级的skew会进一步恶化。问题4CTS阶段报告了clock root的transition违规原因多半是时钟源驱动能力不够或者SDC里设置的transition值与库里的真实特性不匹配。 排查思路如果时钟源来自PLL/analog IP可能需要在其输出端预留一个驱动buffer位置让ICC有足够能力去驱动这一整棵时钟树。这个buffer可以在CTS前手动插入并通过dont_touch来稳定。如果是SDC设置问题则调整target transition到合理值。5. CTS优化策略从“能跑”到“能收敛”CTS的终极目标不是产生一份合格的skew报表而是让后续的setup、hold、SI、功耗都能收敛。所以在CTS阶段做优化时眼光要放长远一些不能只盯着CTS自身的指标。5.1 合理设置OCV与derating避免“过度设计”先进工艺下片上工艺偏差OCV是CTS优化绕不开的因素。同一个时钟沿到达不同位置时因为电压温度差异和制造偏差延迟会有变化。这种变化会导致同一个时钟沿在不同路径上的有效时间不同在时序分析时表现为额外的不确定性。ICC里做CTS时如果用了OCV设置工具会更“悲观”地评估skew于是试图把树上每个分支的延迟都做得更一致以抵消这种悲观。但这意味着更多buffer和更大功耗。合理做法是确认OCV derating参数是否准确不要过度保守同时利用CPPRClock Path Reconvergence Pessimism Removal去除共同路径上的悲观给出更接近真实的分析结果。在ICC中可以通过set_timing_derate -early 0.95 -late 1.05 -clock set_clock_gating_check -setup 0.05 -hold 0.05 report_clock_timing -type uncertainty来调整和确认OCV变量。如果目标是高性能这些参数一定要和signoff工具对齐否则CTS阶段用一套数据、signoff用另一套数据结果必然来回返工。5.2 低功耗设计中的CTSclock gating与power domain的平衡现代SoC普遍有复杂的低功耗设计多电压域、动态电压频率缩放DVFS、电源关断PSO等。CTS在低功耗设计中主要关注两点clock gating cell的插入策略和跨power domain的时钟交互问题。ICC的clock gating综合可以在综合阶段就插入integrated clock gatingICGCTS阶段则要保证这些ICG的时钟端和enable端满足时序要求。此外在电压域边界上电平转换器level shifter和隔离单元isolation cell会引入额外的时钟延迟CTS阶段需要考虑这些单元对时钟路径的影响。我在之前的项目里最常见的情况是一个模块在DVFS高电压下工作正常降到低电压档位时hold大量违反。原因就是低电压下buffer延迟拉长时钟路径的延迟变化放大。这类问题单靠CTS本身很难根治需要和低功耗架构师一起确定时钟域划分考虑在电压域边界预留时钟延迟匹配路径或者在CTS约束里对跨域时钟做专门的skew管理。5.3 模块级CTS与层次化设计别忘了TOP视角遇到大型芯片时常会采用层次化hierarchical设计流程即各个子模块先单独做物理设计再在顶层拼接。CTS在这种情况下有两种做法各模块独立做CTS顶层只做时钟树连接和平衡顶层先定义时钟树结构再将约束分配到各模块模块需要dont_touch子树来配合顶层无论采用哪种方式必须统一各模块的时钟树接口信息。ICC在层次化CTS里经常使用create_clock_tree_spec和remove_clock_tree来管理顶层和子模块之间的约束传递。如果各个子模块用的target skew和target latency标准不一致顶层合的时候会爆发一组全新的violation。这也是为什么我建议即使项目是扁平化流程也把CTS约束提前做成一个可复用的tcl过程模块之间统一调用。这不仅是规范代码也是保证芯片后端流程一致性的关键手段。5.4 CTS后的ECO思维如何做增量修改后期修时序时经常需要对时钟树做局部改动比如在某个分支插入delay buffer或调整走线。如果你为了一个小改动把整棵时钟树重新综合一遍会引入大量无关的时序变化给验证带来巨大压力。更好的方式是增量ECO只对目标分支做局部改动保留其余树的结构。ICC里可以用eco_clock_tree之类的命令做局部时钟树修改配合dont_touch属性保护不受影响的分支。不过要注意任何ECO修改后都要重新跑一遍propagate_clock和full timing防止“按下葫芦浮起瓢”。我的习惯是ECO后先对比新旧两版CTS的report看改动影响范围是否符合预期再继续后续流程。6. 最后再分享一些ICC CTS实战经验CTS这部分内容越做越觉得它像是一门“平衡的艺术”。工具给你默认参数能跑通大部分设计但真正决定性能上限的是工程师对约束背后物理含义的理解以及基于实测数据反复微调的能力。下面几条经验是我在实际项目里反复验证过、对稳定提升CTS质量有帮助的习惯。第一CTS不是跑一次就结束。很多项目会在place之后、CTS之前做一轮预时钟树评估比如用report_clock_tree -before或者快速跑一版dummy CTS专门用来暴露约束和floorplan层面的问题。这一轮非常值能避开很多后期大改。第二始终保留一份“干净的CTS spec”。项目进行到后期各种例外约束会越来越多spec文件会变得非常“支离破碎”。我一般会把每个例外都写清楚注释并且定期对照约束报告做一次清理删掉已失效的设置。这个习惯帮我在好几次ECO中省下大把查问题的时间。第三多利用GUI里的时钟树高亮功能不要只盯着数字报表。skew数字异常时先高亮看一下树形很多时候一眼就能看出是某个分支走线绕了远路、还是buffer集中堆在某个角落。ICC的时钟树可视化和报告结合是效率最高的排查手段之一。第四CTS阶段要有“芯片级”视角。一个模块的CTS做得再漂亮如果和周边模块衔接不上到顶层照样崩。所以哪怕当下只做模块级心里也要时刻装着芯片全局的时钟拓扑保持skew group、clock domain的命名和划分一致。回到开头说的那个观点CTS这步能不能稳很大程度上取决于你对“时钟是要被物理实现的信号”这个认知有多深。它不是只在时序报告里出现的理想波形而是要穿过金属层、驱动一堆负载、扛住工艺偏差的真实信号。理解了这一层再看ICC里那些target skew、max fanout就是一个有物理意义的世界而不是一串玄学参数。希望这篇文章能帮你在做CTS时少一些无头苍蝇式的调参多一些有理有据的决策。
返回列表