
做时序签核STA signoff最怕的不是一两条violation而是整个分析结果根本不可信。我见过不少项目跑完PR后时序报告看着挺干净结果到了交付前复查发现约束漏写了一大片、寄生参数只标了85%、覆盖率低得没法看——这种情况下前面所有优化动作都等于在沙子上盖楼。所以我现在每接手一个block交付前必跑四个命令check_timing、report_annotated_parasitics、report_analysis_coverage、report_delay_calculation。这四个命令单独拎出来都不算复杂串起来就是一套完整的数据质量体检流程今天就把这套组合拳的用法和踩坑经验一次讲清楚。这套流程适合谁后端工程师、STA工程师、以及刚入门想弄明白“为什么时序报告不能全信”的数字IC学生。读完你会知道约束质量问题怎么定位、寄生参数标注完整度怎么看、分析覆盖率低该怎么查以及一条路径的延迟到底是怎么被工具“算”出来的。1. 先把四个命令串成一条验收链1.1 这四个命令各自看什么很多人习惯上来就抓violation盯着某条path改到天荒地老却忽略了更基础的问题分析环境本身是不是可信的。这四个命令分别守住了不同关口我列个表说明命令关注点解决的问题check_timing约束质量有没有路径根本没被约束、有没有组合环、有没有误设常量report_annotated_parasitics寄生参数标注延迟计算用的RC数据是全的还是缺的report_analysis_coverage分析覆盖率时序引擎到底分析了几成endpoint多少路径是盲区report_delay_calculation延迟计算细节单条路径的cell delay和net delay是怎么算出来的你可以这么理解check_timing查的是“题目有没有出对”寄生参数报告查的是“给定的物理信息够不够”覆盖率查的是“有多少题根本没人做”delay_calculation查的是“某一道题的具体解题步骤”。如果前三个没过关后面看多少violation都是白费劲。1.2 建议的执行顺序与组合套路我自己的习惯是固定按这个顺序跑check_timing → report_annotated_parasitics → report_analysis_coverage → report_delay_calculation。逻辑很简单先保证约束是完整的否则谈覆盖率没有意义再确认物理数据是完整的否则看delay没意义然后评估整体盲区最后才针对具体路径抠细节。实际项目里我已经把下面这段脚本固化成了回归的一部分每次交block前必须跑一遍并留档# 1. 约束质量检查 check_timing -verbose check_timing.log # 2. 寄生参数标注汇总 report_annotated_parasitics annotated_parasitics.log # 3. 覆盖率统计 report_analysis_coverage -verbose coverage.log # 4. 关键路径延迟计算明细比如 setup critical path report_delay_calculation -from [get_pins regA/CK] -to [get_pins regB/D] -delay_type max -nosplit delay_calc.log这套顺序跑下来的好处是每一步的异常都能作为下一步分析的线索。比如覆盖率低往往会追溯到check_timing报出来的一批unconstrained endpoints寄生标注有缺漏又会导致后面delay_calculation里看到某些net delay异常。四个命令彼此印证排查效率会高很多。2. 先跑 check_timing把约束问题挡在门外2.1 check_timing 输出里最该盯的几类问题check_timing的输出项在不同工具版本里略有差异但核心检查项基本一致。下面这些是我每次必看的检查项含义危险程度unconstrained_endpoints有endpoint根本没有被任何时序约束覆盖高直接导致漏报constant_value某些pin被set_case_analysis或常量逻辑固定相关路径不分析中误设会掩盖真实violationcombinational_loops组合逻辑环高会导致计算不收敛generated_clocksgenerated clock来源缺失或配置错误高时钟关系全错no_input_delay / no_output_delay端口没设input/output delay中端口路径成盲区disabled_timing_arcs某些timing arc被disable低但要确认理由这里最坑的是 unconstrained_endpoints。它意味着时序引擎根本不会去分析到达这些点的路径不管真实延迟多大报告里都不会出现。我见过一个项目某模块的输出端口漏了一组约束结果那部分路径晚了一个周期才稳定硬是在后仿真阶段才暴露出来改版代价非常大。2.2 实战怎么区分真问题和“噪音”check_timing报出来的东西不一定都要改关键是要有判断力。举个例子scan_mode信号如果在top层用set_case_analysis固定为0那么所有扫描链相关的路径在功能模式下确实不需要分析这在check_timing里不会报unconstrained。但如果你只固定了scan_mode忘了固定scan_en那扫描逻辑可能残留一部分不受约束的路径这时候就要补约束。还有一种常见“噪音”tie celltie high/tie low的输出。这类cell输出电平恒定连接它的逻辑永远处于常量状态相关路径本来就不需要做时序分析。面对这种情况正确做法是确认逻辑确实被tie死然后显式用set_case_analysis或者set_constant处理并把依据写在约束注释里。check_timing跑完不要只看最后有没有“Error”要看具体条目。我的经验是把每一项的数量都记下来和上一次跑的结果对比。如果某个检查项的数量突然暴增那大概率是近期约束改动引入了新问题比一条条翻报告快得多。2.3 约束质量不达标后续分析全是白搭很多人忽略了一点check_timing和report_analysis_coverage的结果是强相关的。约束漏得越多覆盖率自然越低因为大量endpoint没被约束嘛。我曾经见过一个blockreport_analysis_coverage只有85%一查check_timing发现有一整组bus的output delay没设endpoint从这一侧全部变成unconstrained。所以如果覆盖率低我一般都会先回头翻check_timing而不是急着去检查哪条路径。约束这块没什么捷径只能老老实实补。但补的时候有个原则能补真实约束就补真实约束实在不能补的再用set_false_path而且set_false_path必须写明理由。否则三个月后没人记得这条false_path是“真伪路径”还是“懒得约束”这才是最危险的。3. report_annotated_parasitics寄生参数没标完延迟就是猜的3.1 寄生参数从哪来标注完整度怎么看post-layout阶段工具做时序分析的RC数据通常来自SPEFStandard Parasitic Exchange Format文件由StarRC、QRC这类寄生提取工具生成。PR工具在优化时用的寄生参数和signoff时用的寄生参数可能来自不同的提取条件所以我们到了签核阶段要做两件事读入正确的SPEF然后确认它被完整地标注到了每个net上。report_annotated_parasitics的输出会分成几个统计块核心信息是net的标注情况类似下面这样Net Annotation Summary ---------------------- Total nets : 120000 Nets annotated : 119000 Nets annotated with RC: 118700 Nets annotated without RC: 300 Nets not annotated : 1000注意“annotated without RC”和“not annotated”的区别前者是工具知道这个net存在但没有收到RC值后者是工具压根没拿到这个net的寄生信息。不管哪一种对应的net delay计算都不是基于真实版图数据的。最理想的情况是100%的net都有RC标注但实际项目中这并不容易做到特别是大型SoC的top层或ECO之后的重叠金属层。通常的项目验收标准会要求在99%以上但对时钟网络和高频关键路径所在的net必须做到一个都不能缺。3.2 如何快速定位缺失的 net只看summary肯定不够一定要配合详细模式跑一遍把没标注的net拉出来逐个过目。在PrimeTime里可以用下面这类命令report_annotated_parasitics -format detailed -net -not_annotated missing_rc.log也可以结合工具提供的API把所有未标注net的名字打出来再和时钟树、关键路径做交叉比对foreach net [get_annotated_parasitics -net -not_annotated] { set net_name [get_attribute $net full_name] puts Missing RC on net: $net_name }一旦定位到缺失的net原因通常就那几类缺失原因典型场景SPEF版本与版图不一致金属层叠信息更新后忘记重新提取ECO新增net未覆盖逻辑ECO后新增的绕线没有重新提寄生特殊网络被排除power/ground或某些模拟宏的net在提取时被过滤层次不匹配top-down工作流里子模块和top的SPEF合并出问题3.3 标注缺失时的处理套路处理流程一般是这样先确认SPEF是不是最新的确认版图数据没有改动过然后重新读入寄生参数。PrimeTime里的典型操作是remove_parasitics read_parasitics -format spef top_latest.spef update_timing -full重新读入后再跑一次report_annotated_parasitics看结果。重点检查两个时刻update_timing用的是不是最新的RC值以及读入时有没有被工具自动忽略的net。有些ECO场景下整份SPEF重新提取成本太高也可以对局部net做标注修复但我不建议把局部标注作为常规手段。因为工具在计算delay时对标注方式很敏感部分net用SPEF、部分net靠估算会造成延迟数据的口径不一致后期排查问题会非常痛苦。我的原则是要么不用新数据要用就全量统一。4. report_analysis_coverage看看到底分析多少路径4.1 覆盖率到底在统计什么report_analysis_coverage千万别拼成coverge这是个单词错误输出的是setup、hold还有clock gating等检查的覆盖率信息。它的输出通常长这样Coverage Summary ---------------- Total Endpoints: 10000 Constrained Endpoints: 9500 Unconstrained Endpoints: 500 Setup Coverage: 95.0% Hold Coverage: 95.0% Clock Gating Coverage: 95.0%首先要搞清楚“endpoint”在这里指的是什么。简单说所有需要被时序分析覆盖的终点包括寄存器的D端、输出端口以及其他需要检查时序的单元pin。工具会统计有多少endpoint被完整约束并参与了分析有多少因为各种原因被排除二者相除就是覆盖率。覆盖率低绝对是个危险信号。如果只有90%意味着每20条路径里就有1条完全没被分析。而这个比例放到真实芯片上可能就是一颗功能失效的样片。4.2 最常见的“未覆盖”路径与处置方式导致覆盖率不足的因素大部分来自约束问题。我总结了几类高频原因和对应处理办法输出端口没设output delay端口完全没约束。处理方式是补set_output_delay如果端口确实是伪路径再set_false_path并写明原因。寄存器没有时钟寄存器D端在功能模式下没有时钟到达。通常是时钟约束缺失补clock或generated clock。异步信号路径被set_false_path或set_clock_uncertainty等排除的路径会进入“排除”名单如果排除数量过多覆盖率也会下降但这类属于有意排除。常量逻辑路径set_case_analysis把某些信号固定后相关路径不参与分析。这类和check_timing里的constant_value是对应的。处置逻辑分三步能补约束就补约束不能补的确认是伪路径再set_false_path所有排除理由都要留痕。最忌讳的就是为了把覆盖率数字拉上去看到unconstrained endpoint就随手set_false_path这样数字好看了风险全埋进去了。4.3 覆盖率卡在90%不动的排查经验我遇到过最头疼的情况是覆盖率卡在某个值上不去不是95%也不是97%永远是90.2%左右。查来查去最后发现是一个lockup latch的D端和Q端都接到了同一个常量信号上连续十几个实例全是这样。这类单元在功能上确实是冗余的但如果你不显式处理它就是会占用endpoint名额。处理这类问题的正确姿势并不是把所有lockup latch全部set_false_path。锁存器本身也是有时序要求的随意排除会丢掉时钟沿竞争信息。正确做法是确认这些latch在功能模式下是否真正处于常量状态然后对特定输入pin用set_case_analysis把原因写清楚。另一个容易遗漏的点是异步复位的释放路径。复位释放的时序检查往往被单独约束或排除如果约束写得不完整也会产生一批unconstrained endpoints。建议在做覆盖率清理时专门把异步复位相关的endpoint拉出来核对一遍。5. report_delay_calculation把延迟计算掰开揉碎5.1 一条路径的延迟是怎么被算出来的先讲点底层原理不然你不知道这个命令输出的是什么。标准单元的数字电路路径延迟主要分两部分cell delay和net delay。cell delay是信号从cell输入端到输出端的延迟工具通常用查找表来算。以经典的NLDMNon-Linear Delay Model为例延迟大小是输入transition时间和输出负载电容output load的二维函数。输入信号上升得越慢、负载电容越大cell delay就越大。输出port还有CCSComposite Current Source模型考虑的东西更细但本质思想一致。net delay是信号从cell输出pin到负载pin的传输延迟计算依赖net的RC信息。常见算法是Elmore延迟模型和有效电容模型。这些算法会综合考虑driver的驱动电阻、net自身的电阻电容、以及接收端的负载电容。所以你在report_delay_calculation里看到的每一个delay数字都不是工具拍脑袋猜的而是基于transition、capacitance、resistance这些物理量通过库模型和RC模型计算出来的。这也是为什么check_timing和寄生参数标注的问题最终都会反映到延迟计算上。5.2 report_delay_calculation 命令怎么用这个命令最核心的用法是拿一条具体路径来审视看它每一级的延迟组成。典型命令如下report_delay_calculation -from [get_pins u_regA/CK] -to [get_pins u_regB/D] -delay_type max -nosplit -transition_time -capacitance这里解释一下选项-from/-to指定起点和终点。起点通常是时钟pin或输入port终点通常是数据pin或输出port。-delay_type max/-minmax对应setup分析min对应hold分析。-nosplit默认工具可能会把路径按cell边界分段展开加上这个选项会保持一条完整路径不拆段。-transition_time在report里额外显示每个pin的transition时间。-capacitance显示每个pin的负载电容。输出内容会按从起点到终点的顺序列出每一级cell的延迟组成、net的延迟组成、以及累加的arrival time。我截图里的一个典型输出每一步都标明了driver pin、load pin、input transition、output load、cell delay、net delay。看到这些数据后你就能判断延迟到底被谁吃掉了。5.3 延迟异常时该往哪几个方向查依据我自己的排障经验碰到delay_calculation结果异常优先查这四点现象排查方向某级cell delay偏大是不是input transition太大或output load过高某段net delay异常偏大是不是net没标注RC或绕线特别长net delay为0是不是寄生数据缺失net被当成理想线transition值异常大是不是驱动cell驱动能力不够或扇出过大有一次我排查hold violation发现某条路径的net delay算出来是0.5ps明显不对劲。翻寄生标注报告发现那个net恰好就是报告里“annotated without RC”的那批之一。重新补了RC数据后net delay变成15pshold violation直接变了性质。由此可见delay_calculation和前三个命令是联动的排查问题时要养成交叉验证的习惯。再补充一个细节工具在做delay calculation时如果cell delay超出了查找表范围会采用外推方式估算误差会显著变大。所以看到transition或者load离库模型边界很近时要特别注意最好回查constraints或者物理实现是不是驱动cell选小了或者扇出过大了。6. 常见问题排查实录与经验清单6.1 四个命令的异常输出速查表我平时排查问题基本按下面这个表来快速定位节省了很多时间症状可能原因处理建议check_timing报大量unconstrained endpoints约束缺失或set_case_analysis没做全补真实约束不能伪修覆盖率低未被约束endpoint过多配合check_timing清理约束盲区覆盖率卡住不动lockup latch、常量信号、异步复位清理不彻底逐个确认后set_case_analysis或set_false_path寄生标注缺netSPEF过期、ECO未重新提取重新读入最新SPEF再update_timing某net delay异常偏低RC数据缺失检查report_annotated_parasitics对应net状态cell delay外推transition或load超出库查找表范围优化驱动强度或减小扇出6.2 一次真实项目的时序数据质量QA复盘最后分享一个具体案例。上个项目里有颗中小规模的子芯片交付前我按老规矩把四个命令全跑了一遍。第一步check_timing报出47个unconstrained endpoints。逐一核对后发现其中31个和scan_en/scan_mode的case_analysis没设全有关补上约束后消失12个是tie cell输出连着的常量路径确认后按常量处理剩下4个是真漏约束出在某个调试接口的output delay上补约束解决。第二步report_annotated_parasitics显示net标注完成率99.2%但缺了8个net。查下来全是ECO之后新加的网没有重新提取寄生。解决方法是让后端重新出SPEF然后统一读入更新后完成率回到100%。第三步report_analysis_coverage从最初的88%一路处理到97.6%。剩下的2.4%主要是异步复位的释放路径和几个模拟宏接口都是经过确认的合理排除项。这个流程走下来最直观的感受是整个timing报告的可信度完全不一样了。之前看到的violation我们敢去改因为知道约束完备、物理数据齐全、分析覆盖到位不会出现改了半天结果发现是约束坑了的尴尬情况。以我个人的习惯现在每次做signoff前都会把这四个命令按顺序完整跑一遍结果归档到项目记录里。这套检查看着简单但它能拦住绝大多数“分析环境不可信”导致的大坑。如果你正在为某个timing问题反复折腾却找不到根源不妨先退一步把这套体检做一遍多数时候问题就自己浮出来了。