
简介面向集成电路物理实现工程师这份 Cadence 官方技术文档聚焦 Innovus 18.1/19.1 中 CCOpt 在复杂时钟网络配置与调试上的应用适合具备 CTS 基础、需要处理多时钟域与时钟偏差问题的中高级设计者。内容涵盖运行前的时钟约束与时钟树结构设置、CCOpt 主流程各阶段时钟网络分析、时钟树构建、时钟优化、后处理验证对应的调试点以及时钟树调试器使用、时钟路径追踪与跨视图探测、报告命令、借助 CCOpt 属性洞察设计并延伸至架构级时钟控制与 sink 修改如阻断数据通路进入时钟网络、有意偏斜、平衡互不交叠的时钟树等进阶技巧。压缩包共 1 个 PDF 文件约 1.3MB单份手册结构完整便于按目录检索或打印查阅。目前已有 211 人学习。1. CCOpt 跑完不报错skew group 却少了一半复杂时钟网络最容易被忽略的一类失败在 Innovus 的 CTS 流程里cadence innovus cts 这套跑法大家都很熟设 cell、给 target、extract、build、opt。但凡是时钟结构复杂一点的设计最让人头疼的情况往往不是工具报错而是它不声不响地跑完了report 里 skew 数字看起来很漂亮timing 也过可一到签核宏单元时钟直通脚上一片 hold 违例或者两路本该完全独立的时钟被合成了一个 skew group 一起 balance。这类问题在主从时钟、门控时钟共用主干、宏单元 feedthrough 同时存在的复杂时钟网络里出现得特别频繁。新手看到的是“违例莫名其妙冒出来”熟手的第一反应是回头翻 skew group 的划分对不对。这篇按我自己踩坑的顺序拆成四层配置没设对、阶段停不对、定位不到点上、结构无法调整。每一层都给出可以照着敲的命令和判断依据最后收在一套固定的快速定位顺序上。2. 配置没设对CCOpt 自动提取的 cell 和 target 为什么不能用2.1 SDC 是给 signoff 的不是给建树用的CCOpt 有能力从 library、design、SDC 里把综合时钟树需要的选项全部推理出来听起来很省事。问题在于这三个数据源里的设置原始目标都是 signoff不是“生成一棵时钟网络”。SDC 里写的东西大多是“最差也不能超过”的约束边界而不是“建树时按这个目标去优化”的期望值。两者混用结果就是时钟树上缓冲器一层层往上叠加。一个典型场景约束里只写了时钟定义和 uncertainty没给 max transition 目标。CCOpt 提取时会把 transition 目标落到 library 默认值或者干脆不设建树阶段为了满足 DRV 只能加大驱动、加级数面积和功耗一起涨。常见做法是在 extract 之前把全局的 cell 列表、target_max_trans、target_skew显式给全不依赖自动推断。位置这件事比很多人想的更要紧。建树前的 clock extraction 会被全局属性和 pin 级属性共同改写属性设早了会被后续设置覆盖设晚了不生效。我一般把这一批设置集中写在一段脚本里紧挨着 extract 命令之前执行中间不插入别的属性改动。2.2 cell 列表空着写和写满差别比想象中大cell selection 是整个配置里最容易埋雷的一项。有个细节要先记住写在 CCOpt 属性里的 cell 会覆盖 library 中定义的 dont_use从 18.1 开始用户自己加的 dont touch 会被尊重。library 的定义可以在全局、power domain、clock tree、skew group 几个粒度上给粒度越细越只能在 clock extraction 之后设置。# legacy 写法四个列表分别指定缓冲、反相、门控、逻辑单元 set_ccopt_property buffer_cells {BUF_X2 BUF_X4 BUF_X8} set_ccopt_property inverter_cells {INV_X2 INV_X4 INV_X8} set_ccopt_property clock_gating_cells {CKLNQD1 CKLNQD2} set_ccopt_property logic_cells {AND2_X1 OR2_X1 MUX2_X1} # CUI / Stylus 写法语义相同命令前缀不同 set_db cts_buffer_cells {BUF_X2 BUF_X4 BUF_X8} set_db cts_inverter_cells {INV_X2 INV_X4 INV_X8} set_db cts_clock_gating_cells {CKLNQD1 CKLNQD2} set_db cts_logic_cells {AND2_X1 OR2_X1 MUX2_X1}逻辑说明buffer 和 inverter 决定树的驱动能力梯度只给一种驱动就等于把工具的调节空间砍掉一半clock_gating_cells 和 logic_cells 一起给工具才能把门控单元和时钟路径上的组合逻辑也纳入优化从而减少后续为绕过它们而插入的缓冲器。参数说明列表里写的是 cell 名字不是 library 名名字必须和 DB 里完全一致大小写错了不会报错只会被当成不存在而过滤掉。空列表有一个特殊语义——表示“全收”不管 Vt family 和驱动能力一律纳入候选。这个语义几乎没人想要但很多人无意中触发了它列表变量拼错、变量在子脚本里被置空、条件判断分支没走到最后传给工具的都是空。如果设计里必须用 always-on cell也要显式把它们追加进列表否则会被“全收”之外的过滤逻辑排除。还有一个常见的误解传进去的 cell 不一定都会被用上。CCOpt 内部会对 library 列表做过滤和裁剪想确认某个 cell 到底为什么没被选中直接看报告# 列出每个 cell 被过滤掉的原因 report_ccopt_cell_filtering_reasons # CUI 下对应的命令 report_cts_cell_filtering_reasons输出里会告诉你是因为 dont_use、Vt 限制、驱动上限还是别的规则被剔除。这份报告我建议在第一次跑之前就看一遍比跑完再回头查省事得多。另外实例可以设成 size-only留出更多调节余地这在 cell 种类受限的工艺上很实用。2.3 target_max_trans 和 target_skew过紧的 skew 目标会反向放大时钟树这两个目标是整套配置里对结果影响最大的两个数也是最容易被抄错的。target_max_trans决定时钟网络的规模在低功耗设计里尤其关键——transition 目标放松一点工具就能用更少的级数、更小的驱动完成任务功耗和面积都会下降。流程本身仍然会避免 library 相关的 DRV 违例所以不用担心放松目标就一定会违反工艺约束。target_skew方向相反设得过紧会引发过度平衡。所谓过度平衡就是工具为了让两个本来可以差一点的 sink 对齐硬生生把一棵树的级数拉长、匹配到另一棵树上结果是 buffer 数量翻倍、功耗上去甚至因为插入级数太多真实 skew 反而更差。# 全局目标先给一个宽松可用的值后续按 clock tree / skew group 细化 set_ccopt_property target_max_trans 0.120 set_ccopt_property target_skew 0.080 # CUI 对应写法 set_db cts_target_max_transition_time 0.120 set_db cts_target_skew 0.080逻辑说明这两条必须在 extract 之前设因为它们会同时影响 clustering 阶段的分组决策。参数说明单位跟随工艺库的单位约定写之前确认是 ns 还是 ps写错一个数量级不会报错但结果会非常奇怪。extraction 之后可以针对单个 clock tree、skew group、power domain 下更细的目标那时候再按结构微调。SDC 里提取出来的 transition 和 skew 目标只在没有全局目标的时候才生效。这个优先级意味着只要全局设了值SDC 里那些辛苦写的东西就被盖掉了。调试结构性问题时我倾向于把全局目标设成一个明确的基线再按组细化而不是让两者混着生效——否则你根本说不清最后生效的是哪一个。2.4 sink_type 和 route type先把不该进树的点摘出去sink_type 用来塑造时钟网络提取的形状一共三种取值stop、ignore、exclude。它们决定了某个引脚在提取阶段被怎么对待——是被当作真正的时钟终点还是被跳过还是整个排除在外。宏单元内部时钟直通脚、只用于测试的观测点、数据通路上被误判成时钟负载的引脚都应该在这一步处理掉。# 把宏单元时钟直通脚从时钟网络的 sink 集合中排除 set_ccopt_property -pin [get_pins u_macro_a/CLK_THRU] sink_type exclude # 让某个引脚成为时钟终点不再向下继续追 set_ccopt_property -pin [get_pins u_core/CLK_GATE_EN] sink_type stop逻辑说明exclude 比 stop 更彻底前者直接把这个点从树的候选集合里删掉后者只是标记为终点不再往下延伸。用错的影响很直接——该 exclude 的用了 stop工具仍然会为它算平衡等于白设该 stop 的用了 exclude时钟可能就断在这儿了。参数说明属性要作用到具体的 pin 上不是 instance 上写错对象同样不报错只是没效果。提示sink_type 必须在 extract 之前设置extract 之后改它不会重新塑造已经提取出来的时钟网络。route type 是另一类容易被忽略的配置。时钟网络一般要用非默认规则走线需要先创建规则再把规则挂到 top、trunk、leaf 三类网络上# 创建一条用于时钟的非默认走线规则 create_route_type -name clock_ndr_a ... # 把规则按网络层级挂上去 set_ccopt_property route_type -net_type {top trunk leaf} clock_ndr_a # CUI 写法 set_db cts_route_type_top clock_ndr_a set_db cts_route_type_trunk clock_ndr_a set_db cts_route_type_leaf clock_ndr_a逻辑说明top、trunk、leaf 三段可以挂不同规则但大多数工艺下用同一条规则就够。参数说明规则必须先创建再引用顺序反了会找不到名字。如果不设时钟网络会用默认规则走线早期看不出来等到 global route 之后才发现时钟线上宽度和间距不对那时候再改就要重跑一遍。2.5 update_io_latency 与 OCV 开关改的是 latency 语义这两项不在“必须设”的清单里但在芯片级设计和时钟架构特别复杂的设计里不设就会出问题。# 关闭 latency 修改芯片级和复杂架构设计通常需要 set_ccopt_property update_io_latency false set_db cts_update_clock_latency false # OCV 延迟模式让时序分析按片上偏差来算 setAnalysisMode -analysisType onChipVariation set_db timing_analysis_type ocv逻辑说明update_io_latency为真时工具会根据时钟树的实际延迟去改写 IO 的 latency 约束这在模块级是合理的在芯片级会把外部已经确定好的 latency 关系打乱导致跨模块的时序对不上。参数说明这条一共就两个取值设成 false 之后 IO 侧 latency 保持原样时钟树自己调整。OCV 那一组决定时序分析用哪种偏差模型直接影响到工具在建树阶段对 skew 的判断标准设了 OCV 而约束里没有对应的 derate结果可能偏乐观。配置这一段的核心判断标准只有一条把工具当成一个需要明确指令的执行者而不是一个能猜出你意图的助手。所有能从 SDC 自动提取的东西都要先问一句“这个值是为签核写的还是为建树写的”。3. 阶段停不对cluster、trial、full 三个阶段能看到什么停了为什么接不上3.1 流程阶段拆开看extraction 之后才是分水岭CCOpt 的完整流程可以按调试视角切成这么几段应用 post-CTS 优化和时序设置、设走线规则、应用影响时钟提取的设置、从设计和约束里提取时钟、修改 clock 和 skew group、跑时钟构建cluster、trial、full 三段、early global route 与 conditioning、Nanoroute 与 conditioning、datapath 优化。对时钟关系复杂的设计强烈建议在中间阶段停下来分析哪怕最终 timing 和 congestion 看起来都没问题。理由是中间结果里能看出面积、runtime、timing、功耗的改进机会这些机会在流程后段已经被优化动作掩盖掉了再想看出来得费几倍力气。尤其是 cluster 阶段的分组结果它决定了后面所有平衡动作的边界分组错了后面怎么调都是在错的基础上修。分水岭在 extraction。extraction 之前改的是“怎么提取”extraction 之后改的是“提取出来的东西怎么用”。同一个属性放在这两侧效果完全不同。所以调试时第一步永远是确认我要改的这个东西属于哪一侧。3.2 cluster看分组不看时序cluster 阶段做的是把 sink 归到不同的 skew group 和 clock tree 里。这个阶段结束时时序数字基本没有参考价值因为树还没建看到的都是估算。它唯一值得看的东西是分组本身。判断分组对不对最直接的办法是数数量。多数设计里 skew group 和 clock tree 是一对一的关系复杂结构可能一个 clock tree 下挂几个 skew group。如果你预期有六组report 里只出现三组那基本可以确定有本该独立的时钟被合到一起了。这时候不要继续往下跑回到 extraction 阶段查 SDC 和 sink_type。cluster 阶段停止后有个硬限制要先知道不能重启。停下来就只能从头再跑没有“接着上次继续”这个选项。3.3 trial看结构代价是跑不完全程trial 阶段会真的开始建树能看到的是一棵初步成形的时钟网络缓冲器大致分布在哪、哪些路径明显偏长、哪些组的级数差异很大。这个阶段的价值在于“结构是否符合预期”而不是“时序是否收敛”。我一般在这个阶段做两件事一是用调试器把树的结构拉出来看一遍确认没有出现意料之外的长链二是对比不同组的级数级数差异过大的地方往往就是分组出了问题或者某组的 skew 目标设得不合理。同样地trial 阶段停下也不能重启。这条限制直接决定了调试节奏——每次停下来之前先想清楚这次要回答什么问题答案拿到就重跑不要在同一个停点上反复试探。3.4 full看最终形态但很多东西已经改不动了full 阶段跑完时钟树是完整形态时序数字可以信了。但到这一步分组、sink 集合、目标值这些基础设置都已经固化在树里想改只能回到 extraction 重来。所以 full 阶段适合做最终确认和细节优化不适合做结构性诊断。一个实际的做法是第一次跑用 full 跑通确认流程没问题之后做结构调试时把停点提前到 cluster 和 trial用多次短跑换信息量。短跑的代价是重复的 extract 时间收益是每次都能看到一个干净的中间态。3.5 基本检查先确认 skew group 和 clock tree 的对应关系任何调试都应该从这一步开始它能挡掉后面一大半无用功。# 列出时钟树和 skew group 的划分 report_ccopt_clock_trees -file ccopt_clock_trees.rpt report_ccopt_skew_groups -file ccopt_skew_groups.rpt # 看某棵树的实际结构 report_ccopt_clock_tree_structure -clock_tree ct_name -file ct_struct.rpt逻辑说明第一份报告告诉你工具认为设计里有几棵树第二份告诉你这些树被切成了几个平衡组。两份报告对照着看能立刻发现“某棵树下面挂了不该挂的组”这类问题。参数说明-clock_tree后面跟的是报告里出现的树名名字对不上会报找不到对象。报告里如果出现某个 skew group 的 sink 数量和你的预期差很远先别怀疑工具回去查 SDC 里 generated clock 的定义和 sink_type 的设置。多数情况下问题出在提取阶段把不该算进来的引脚算进来了。3.6 用属性反查确认你设的东西真的生效了这条是经验之谈。调试时最常见的困惑是“我明明设了为什么没效果”答案往往是属性设在了错误的阶段或者被更细粒度的设置盖掉了。# 查某个 skew group 上实际生效的属性值 get_ccopt_property -skew_group sg_name target_skew get_ccopt_property -clock_tree ct_name target_max_trans逻辑说明这是反查而不是设置用来确认最终生效值和你写进脚本的值是否一致。参数说明作用对象可以是全局、clock tree、skew group、pin粒度越细优先级越高所以查的时候要指定和设置时相同的粒度否则看到的是上一层继承下来的值。4. 结构无法调整SDC 描述不了时钟架构时用架构时钟控制硬处理4.1 把数据通路从时钟网络里摘出去有些引脚在网表里确实连在时钟网上但从架构上看它属于数据通路的一部分——比如某些跨时钟域握手的同步器输入、某些只在测试模式下才被驱动的控制端。这类点如果被当成正常 sink 参与平衡工具会为了让它们对齐而拉长整棵树。处理方式是回到 sink_type把这些点从树的候选集合里摘掉或者用更细的粒度把它们归到一个独立的 skew group 里让它们自己平衡自己# 把数据通路侧的伪时钟负载排除出时钟网络 set_ccopt_property -pin [get_pins u_sync/CLK_IN] sink_type exclude # 或者单独归组避免影响主树 set_ccopt_property -skew_group sg_datapath_side target_skew 0.200逻辑说明exclude 是彻底的归组是保守的。前者适合那些确定不该参与平衡的点后者适合那些需要保留在时钟网络里但不能影响主树的点。参数说明归组之前要确认这个 skew group 已经存在属性只是修改而不是创建。判断标准我一般用一条这个点的时钟到达时间对功能有没有影响有影响就归组没影响就排除。功能上完全不关心的点让它参与平衡纯粹是浪费。4.2 故意做 skewdeliberate skew 的适用边界有些结构不但不需要平衡反而需要刻意的错开。典型的例子是同一份数据被两级流水线先后采样、或者某段逻辑只有在时钟错开特定量时才不会产生竞争。这类需求在 SDC 里很难表达干净用 CCOpt 的属性反而直接。# 对特定组允许更大的内部偏差相当于放宽这个组的平衡要求 set_ccopt_property -skew_group sg_pipe_stage1 target_skew 0.150 set_ccopt_property -skew_group sg_pipe_stage2 target_skew 0.150逻辑说明把两组的 skew 目标分别放松工具就不会为了拉平它们而插入额外的匹配级数实际的相对差异由布局和布线自然形成。参数说明这里的数值不是“要求偏差正好是这么多”而是“不要求比这个更紧”理解成上限更准确。注意deliberate skew 一旦设下去后面的时序分析要能反映这个偏差否则签核阶段会看到一堆解释不了的违例。设之前先确认约束里有对应的描述。4.3 两棵本该独立的树被合并了这是复杂时钟网络里最高频的结构性问题。表现是两路时钟在架构上完全独立各自的负载各管各的但 report 里它们被归到了同一个 skew group 里工具开始费劲地让两边对齐。根因通常出在 SDC 的时钟定义上——两个时钟可能是从同一个 master 派生出来的 generated clock或者共用了一段公共路径提取阶段就自然把它们归成了一组。解决办法是显式声明互斥# 为两个需要独立平衡的时钟各自建组并声明互斥 set_ccopt_property -skew_group sg_clk_fast exclusive_skew_group true set_ccopt_property -skew_group sg_clk_slow exclusive_skew_group true逻辑说明exclusive 的含义是这两组不会共享平衡逻辑各自建各自的树。参数说明exclusive skew group 的创建属于 extraction 之后要做的事情之一属性名和写法以对应版本的命令参考为准不同版本间可能有差异。判断“该不该拆”的方法很朴素问一句这两路时钟在功能上会不会同时有效如果不会就没有任何理由让它们对齐拆开只会省 buffer。4.4 主从时钟阻止 slave clock 被一起 balance主从结构是另一类高频场景。从时钟由主时钟分频或门控产生天然派生自同一个源。工具看到这层关系很自然会把主从放在一起平衡但对很多设计来说从时钟的负载和主时钟完全不同一起平衡只会让主树的级数被迫拉长。处理思路和 4.3 一样靠 skew group 隔离。区别在于这里不能简单把两者都设成 exclusive——主从之间确实存在真实的时序关系隔离的方式要保证这层关系在时序分析里仍然成立。常见做法是让从时钟单独成组、单独给 skew 目标而不是彻底切断。4.5 宏单元 feedthrough 和输出脚上的 skew宏单元的时钟直通脚是个特殊点位信号从宏的一个脚进去、从另一个脚出来中间经过了宏内部结构。如果把它当普通 sink工具会在宏的两侧各建一段树两段之间的延迟差完全不可控。正确的做法是把直通脚的两端当作同一个平衡点处理或者在宏两侧分别建组但给一致的目标。另一类相关场景是驱动输出引脚的那部分逻辑。输出脚上的时钟需要和芯片内部的时钟保持接近的 skew否则 IO 时序怎么调都对不上。这类需求没法靠默认行为满足得单独为这部分逻辑设组并指定目标。4.6 禁掉某些时钟的综合别让工具把 buffer 堆上去有些时钟压根不需要工具去建树——比如只在测试模式下用的扫描时钟、某些始终由外部直接驱动的时钟输入。让工具去优化它们结果就是一串没必要的缓冲器挂在上面面积功耗都白花还可能干扰邻近的走线。处理方式是让这些时钟不参与综合。具体写法各版本差异较大稳妥的做法是先把它们下面的 sink 标记成忽略再确认报告里这些树不再出现在构建列表里。判断是否成功的方法很简单跑完之后看这些时钟网络上有没有新增的缓冲器没有就对了。“防止过量缓冲”这条思路贯穿全文几乎所有 buffer 数量失控的问题追到根上都是“某个本不该参与平衡的对象被拉进来了”。找到那个对象比反复调 target 有效得多。5. 常见问题与避坑五条踩坑记录5.1 skew group 数量只有预期的一半现象跑完 extractionreport 里出现的 skew group 数量明显少于设计里实际的时钟域数量某些本该独立的时钟在报告里归到了同一组。原因SDC 里两个时钟被定义成从同一个 master 派生的 generated clock提取阶段自然把它们归成了一组或者某个时钟的 sink 集合被上游的 stop 属性截断导致下游部分被并到了别的组里。解决先确认 SDC 里这两个时钟的派生关系是不是真的必要不必要就改成独立定义必要的话用 exclusive skew group 显式声明互斥再重跑 extraction 并对照报告确认组数。5.2 时钟树上的缓冲器数量翻倍现象功能上没问题的设计跑完 CCOpt 之后时钟网络上的缓冲器数量比预期多出一倍功耗超预算面积也涨了。原因两个方向都可能。一是target_skew设得过紧工具为了对齐而过度平衡二是 SDC 里没有显式的 transition 目标工具落到了 library 默认值只能靠加大驱动和加级数来满足 DRV。解决先把全局的target_max_trans和target_skew显式给出来给一个宽松可用的基线再看 buffer 数量变化。如果还是多用报告确认是哪个组在贡献级数对那个组单独放松目标。5.3 宏单元时钟直通脚上一片 hold 违例现象签核时发现某个宏的时钟直通脚附近成片 hold 违例而 report 里 skew 数字看着很好。原因宏的两侧被当成两个独立的 sink 分别建树两侧的延迟差没有被约束住工具只保证各自的 skew不保证跨宏的对齐。解决把直通脚的两端归到同一个 skew group或者分组建树但给一致的目标值同时检查 sink_type 有没有把不该排除的脚排掉。改完必须重跑 extraction因为这件事发生在提取阶段。5.4 属性改了重跑结果一模一样现象在脚本里改了某个属性重跑 CCOpt结果和上一次完全一致像是改动根本没生效。原因属性设在了 extract 之后而它只对提取阶段生效或者属性设在了更粗的粒度上被更细粒度的设置盖掉了还有一种可能是属性名拼写不严格工具静默忽略。解决用反查命令确认实际生效值作用粒度要和设置时一致确认这条属性属于提取前还是提取后放错位置的挪回去。5.5 cell 列表里写了某个缓冲器报告里从没用过现象脚本里明明把某个型号的 buffer 放进了列表跑完统计发现一次都没被选中。原因被 library 的 dont_use 挡掉了、被 Vt family 过滤掉了或者列表在某条分支里被置空触发了“全收”语义实际生效的根本不是你以为的那份列表。解决直接跑 cell 过滤原因报告输出会逐条说明每个 cell 被剔除的理由同时检查列表变量的赋值路径确认传给工具的不是空值。6. 快速定位一套可以照着走的排查顺序遇到 CCOpt 结果不对我现在的习惯是把这个顺序走一遍八成的问题在前三步就能收敛。顺序本身不重要重要的是每次都走一遍不要跳步——跳过去的那一步往往就是问题所在。步骤看什么用什么判断标准1cell 列表是否真的生效report_ccopt_cell_filtering_reasons目标 cell 出现在候选里没有意外剔除2全局 target 和 SDC 目标谁在生效反查target_max_trans/target_skew生效值等于脚本里写的值3skew group 与 clock tree 的数量关系report_ccopt_clock_trees/report_ccopt_skew_groups组数与预期一致没有意外合并4分组边界是否合理CCOpt clock tree debugger每组内部的 sink 属于同一个功能时钟域5单条路径的延迟构成路径追踪配合视图交叉探测长链段有明确原因不是匹配出来的6结构是否被 SDC 带偏对照 SDC 里的 clock 定义派生关系、公共路径与架构一致第三步之后的判断靠报告已经不够了得把时钟树当黑匣子打开看。CCOpt 自带的时钟树调试器就是干这个的它把树的结构、每组包含哪些 sink、缓冲器挂在哪一级都摆出来比对着文本报告猜快得多。路径追踪则配合设计视图做交叉探测把一条路径从根到末端逐级拉出来看哪一级是因为匹配别的组而插进去的一眼就能看出来。验证改动有没有效果别只看最终的 skew 数字。我的做法是固定看三个指标该组的缓冲器数量、该组的最长路径级数、跨组之间的实际延迟差。前两个降下来、第三个还在允许范围内这次改动才算真的有效。只盯着 skew 一个数很容易调出“数字好看但功耗翻倍”的结果。注意cluster 和 trial 阶段停下之后不能续跑验证改动一律从 extraction 重来。想省时间就缩小调试范围不要指望接着上次跑。从那以后我每次开 CCOpt 之前都强制先跑一遍 cell 过滤原因报告和 skew group 数量对照哪怕这个设计上周刚跑过一遍。血泪经验是这两步加起来不到两分钟能挡掉的返工按小时算。希望帮到你。本文还有配套的精品资源点击获取