
1. 时序报告怎么看先分清Cell Delay和Net Delay的账1.1 一条时序路径的延迟到底是怎么算出来的做数字后端的人几乎每天都要跟PTPrimeTime打交道。不管是做综合后的快速评估还是布局布线后的signoff时序收敛最后所有问题都会汇总到那一份份时序报告里。而报告里最常出现、也最容易让人看得头大的两个名词就是Cell Delay和Net Delay。Cell Delay说白了就是信号经过一个标准单元比如与非门、反相器、触发器内部所花费的时间。这个值取决于单元的工艺模型、输入转换时间Input Transition、输出负载电容还有单元本身的驱动强度。Net Delay则是信号在这个单元的输出引脚到下一个单元输入引脚之间的互连线上花费的时间。在先进工艺下Net Delay通常由线电阻、线电容和耦合电容决定情况复杂得多。很多刚入行的朋友一看到时序违例第一反应就是“这条路径太长了”但如果连到底是Cell Delay占大头还是Net Delay占大头都没分清楚后面所有的优化动作都会跑偏。我们来算一笔最简单的账。假设有一条路径数据从A触发器的Q端出发经过两级组合逻辑到达B触发器的D端。你在PT里报出来的路径延迟可能是这样Startpoint: reg_A/CK (rising edge-triggered flip-flop clocked by clk) Endpoint: reg_B/D (rising edge-triggered flip-flop clocked by clk) Path Group: clk Path Type: max Capture clock edge 5.000 Launch clock latency 0.300 Clock network delay 0.200 (propagated) ------------------------------------------------ Data required time 4.900 Data arrival time -4.720 ------------------------------------------------ Slack 0.180这个例子slack是正的不违例。但假如中间某一段组合逻辑特别重arrival time变成了5.010slack变成-0.110那问题就来了。你需要在报告里往下翻逐行看每个pin上的transition、每个cell的delay、每段net的delay。你会发现某些cell的delay特别扎眼比如一个INV_X1在负载很大的情况下delay能有100多ps而旁边同样功能的INV_X4只有40ps左右。另一条路径上一个跨模块的长走线net delay甚至能占到总延迟的60%以上——这时候去换cell驱动强度就是白费力气问题出在物理位置上。1.2 没看清报告就动手改是最容易踩的坑我很早以前犯过一个典型错误。当时拿到一个新工艺节点的后端项目有一条setup violation大概违了150ps。我看了前几行报告发现中间有个LATENCY很大的时钟路径就顺手把CTS的target skew调紧了一点结果重新跑完PT违例非但没变好旁边几条原本干净的路径反而开始出现hold violation。后来才发现真正的问题根本不在时钟路径上而是数据路径里某个逻辑锥末端接了太多负载那个输出cell的transition已经大到快1ns了完全可以把中间那级cell直接换成驱动能力更高的型号。当时我只盯着时钟网络属于典型的“没看完全部报告就动手”。所以拿到一份PT时序报告我现在的习惯是“三步走”第一步看路径的起点、终点和slack搞清楚是哪一种违例setup还是hold、在哪个时钟域、哪条path group。第二步横向扫一遍整个路径的delay分配把每个cell delay和net delay都列出来看占比。如果cell delay总和占80%以上那就是逻辑和单元的问题如果net delay占40%以上优先怀疑物理实现和拥塞。第三步再往下看transition和capacitance是否违反DRC上限——很多时候timing问题只是表面现象真正要处理的是transition violation。这三步走完心里基本就有数了。如果一上来就急着优化很容易把简单问题越改越复杂。2. 定位Cell Delay违例先分清“是慢还是快”2.1 从逻辑级数和transition看第一个warning signCell Delay占主导的场景最常出现在逻辑级数偏长的路径里。比如一个复杂的加法器、比较器或者数据选择器综合工具在一开始可能没有把逻辑深度压到足够小最后到了布局布线阶段多出来的那一级逻辑就会变成实打实的延迟。打个比方Cell Delay就像你开车经过城市的每一个红绿灯路口每个路口都要停车等灯就算每段路很短红绿灯多了整个行程也会很慢。逻辑级数就是红绿灯的数量transition就是每个路口的起步速度。如果某个cell的输入transition特别大意味着前一级的输出信号“爬坡”太慢这一级cell翻转得就不干脆延迟自然就上去了。我之前遇到过一个实际案例某条路径上有8级组合逻辑其中第4级是一个NOR2_X1fanout有6个输出负载超过了1.2pFtransition直接到了0.93ns。PT报告里显示这个cell的delay是0.18ns而同一路径上另一个NOR2_X2的delay只有0.07ns。这里有两个问题叠加在一起一是这级cell的驱动能力太弱带不动6个fanout二是6个fanout本身就意味着下游负载过大相当于一辆小排量车拖着一辆大挂车跑不快是必然的。所以在定位Cell Delay违例的时候我通常先看两点第一路径上有没有transition特别大的pin一般先进工艺下超过0.2ns ~ 0.3ns就要警惕第二有没有fanout特别集中的netfanout一多就算后面的每个cell本身不大累计的输入电容也会拖慢前级。这两个信号在PT报告里都很明显只要不是只看最底下的slack summary基本都能发现。2.2 换cell、调驱动、降load的先后次序如果确认了某条路径上Cell Delay占大头接下来就是怎么改的问题。很多人第一个念头就是“把cell换大”——把X1换成X2X2换成X4。这个思路本身没错但不是所有时候都管用。我自己的经验排序是先降load再换驱动最后才考虑改逻辑结构。先降load就是说把某个cell后面挂着的重负载分摊出去。常见做法包括把fanout大的net做buffer tree或者在逻辑允许的前提下复制一份逻辑把负载拆成两路。这样做的好处是几乎不改变原来的逻辑结构风险最低。比如上面那个NOR2_X1带6个fanout的例子我第一个动作就是在中间插一级BUF_X4把负载一分为二让NOR2_X1的transition从0.93ns降到了0.4ns以下。光是这一个改动路径总延迟就能吃掉一大截。再换驱动就是把原来驱动能力不够的单元换强一点。这里有一个容易被忽略的细节直接换大cell有时候会引入新的hold问题而且功耗和面积都会涨。所以换的时候要有度不要一上来就把所有cell都换成X4。通常我会挑transition最大、delay占比最高的两三处换完之后重新评估。至于改逻辑结构那是最后的手段。比如把串联的长逻辑链拆成并行或者把某些数据选择逻辑提前到前一级做这种改动的风险相对较高需要回归验证功能。一般只有在单元级优化效果有限、确实没有别的办法时才动这一层。3. 定位Net Delay违例不是所有线长都能怪绕线3.1 线延迟占比高第一反应看floorplanNet Delay的优化思路和Cell Delay完全不一样。Cell Delay是单元内部的事Net Delay是单元之间的事。当你看到一条路径里net delay加起来比cell delay还高的时候不要第一时间觉得“绕线工程师不行”而要先去查物理位置——是不是这两个cell在floorplan上隔得太远了。我见过的最典型的例子是一条跨模块的数据总线起点在模块A的角落里终点跑到模块B的另外一侧中间跨越了大半个芯片。绕线工具已经尽力走最短路径了但物理距离摆在那里线延迟降到一定程度就再也降不下去了。这种问题你在PT报告里反复优化cell驱动是没用的因为延迟的大头在互连线上它跟线长、线宽、层数和耦合电容有关。那怎么判断是物理距离的问题还是绕线路径的问题一个很实用的方法是看net的layer和总长度。如果整条net都在M4、M5这些中间层上绕来绕去而且长度动辄几百微米多半是floorplan或者Pin assignment的锅。如果报出来的net长度并不夸张但delay很大那就要怀疑是绕线路径经过了太多via或者旁边有长距离并行线带来了较大的耦合电容。处理这类违例我一般从三个方向入手。第一检查两端cell的相对位置能不能在floorplan层面把距离缩短跨模块的关键路径最好在早期就做好约束和budget。第二看route guidance和blockage是不是关键路径被某些macro或者hard block挡住导致绕线工具只能绕远路。第三必要时可以直接给这条net加route_type的约束让它走高层金属高层金属电阻小、绕线宽度大延迟会低不少。3.2 从congestion map到具体layer调整的实操如果距离没问题那就继续往下查是不是拥塞导致绕线工具走了弯路。有一个很直观的类比Net Delay就像快递配送cell是发货点和收货点绕线资源是道路。如果某一片区域道路拥堵严重快递员只能绕行那就算发货点和收货点就在隔壁配送时间也会很长。优化Net Delay本质上就是给快递员开通一条高速通道或者错开拥堵区域。怎么做呢在布局布线工具里先打开congestion map看那条违例net附近的绕线资源情况。如果红色拥塞区域刚好覆盖了net的路径那就先通过调整blockage、soft macro placement或者cell padding来降低拥塞让绕线工具能够选一条更直的路径。如果整体拥塞不严重只是某条net本身走线质量差那就直接在SDC或route constraint里指定net的layer范围比如允许它走M6、M7同时关闭该区域的blockage限制。实操中还有一个细节不要只看timing报告里的那一条net要多看它周围的sibling net。一段区域如果同时出现多条net delay偏大大概率是局部拥塞或者电源网络PG遮挡住了绕线资源单独修一条net是修不完的要从布局层面想办法。4. 真实案例分析一条违例路径从PT报告到收敛的全过程4.1 案例背景和原始违例报告这里分享一个真实项目中处理过的案例。工艺节点是7nm模块规模大概200万门运行频率1GHz。后端流程走到place route之后做第一版signoff时序收敛时出现了一条setup violation违例量是负的180ps左右。我把PT报出来的数据路径delay打开逐行看延迟分布Data arrival time: ------------------ reg_A/CK (clock network delay) 0.120 reg_A/Q (CK-to-Q delay, seq cell) 0.082 U1234/ZN (NAND2_X2, cell delay) 0.064 n1234 (net delay) 0.311 U2345/ZN (NOR2_X1, cell delay) 0.148 n2345 (net delay) 0.087 U3456/ZN (BUF_X8, cell delay) 0.055 n3456 (net delay) 0.121 U4567/ZN (AOI22_X1, cell delay) 0.077 n4567 (net delay) 0.093 reg_B/D (setup requirement) -0.020 ------------------------------------------------注意看n1234这一段的net delay居然有0.311ns而前后cell delay都只有0.06~0.08ns的量级。这条路径上总数据延迟大概1.17ns光n1234这一段就占了将近27%。而这条net从NAND2_X2的输出到NOR2_X1的输入物理距离并不算特别夸张问题在于它跨过了两个macro之间的窄通道绕线工具只能走M2/M3层几经波折才连上中间还打了好几个via层间寄生电阻一叠加delay自然就大了。4.2 修复过程按报告逐级排查我当时的处理顺序是这样第一步先看floorplan里这两个cell的物理位置。打开布局图确认NAND2_X2在模块左下角NOR2_X1在右侧靠近macro的位置中间刚好夹着一个SRAM macro和一条电源strip导致绕线资源很紧张。第二步检查这条net是不是需要跨区域连接。确认了它不是跨模块的关键路径只是模块内部因为macro摆放过密导致绕线受阻。于是我先尝试了给这条net手动加一条局部routing guide让它走M5绕开macro区域。重新跑了一遍route和PTnet delay从0.311ns降到了0.204ns但离目标还差一点。第三步调整cell位置。把NAND2_X2从macro边上往右挪了大概100um让它更靠近NOR2_X1的入口方向重新布局布线后net delay降到了0.132ns。与此同时NOR2_X1那个0.148ns的cell delay在新的负载条件下也降到了0.094ns因为net短了total load也变小了。第四步确认没有引入新的Violation。重新跑完PT、DRC和LVSsetup slack从-0.180ns变成了0.045ns这条path成功收敛。同时相邻几条路径没有出现新的违例说明这个局部修改没有造成附带损伤。4.3 最后的结果和复盘这个案例最终只改动了两个cell的placement和一条routing guide没有动逻辑、没有换工艺库也没有牺牲功耗和面积。整个过程花了大半天大部分时间耗在定位那条0.311ns的net delay上。复盘下来有一个很关键的教训第一版时序报告出来的时候如果光看slack是负数很容易让人焦虑然后病急乱投医。但只要把报告里每个delay分量摊开找到那个明显不合理的异常点问题往往就变成了“为什么这条net这么慢”而不是“为什么这条路径违例”。从异常点入手比从违例结果入手要高效得多。5. 常见坑与排查技巧5.1 CRPR和时序报告里的那些“隐身延迟”有一个细节很多做后端一段时间的朋友也容易忽略PT报告里的clock network delay并不等于时钟到达触发器的真实时间里面还藏着CRPRClock Reconvergence Pessimism Removal的处理逻辑。简单说launch clock path和capture clock path在时钟树中会有一段公共路径这段路径上的延迟是共享的PT在计算时序时会把这段公共路径的悲观量去掉。CRPR本身是好事它避免了因为公共路径的片上偏差被重复计算而导致的过度悲观。但它也带来一个副作用你在报告里看到的某些数值不是实数而是经过correction之后的“可用余量”。有些新手看到某个cell delay特别大想去优化但仔细一查那是公共路径上的cellCRPR已经把它对slack的影响抵消掉了——这种情况下动手优化它效果会非常有限。另外一个常见的“隐身延迟”是OCVOn-Chip Variation的derate factor。在signoff模式下PT会对cell delay和net delay分别加一个early/late derate系数。报告里一行行看下来有些delay看起来偏大可能就是被derate放大了。这种情况下优化方向不一定是改cell或net而是看能不能通过调整时钟结构的平衡性、减小时钟路径上的公共部分偏差来释放悲观量。5.2 timing budget多模块协同时的另一个维度前面聊的都是在单个模块内部处理违例的经验但实际项目中很多路径是跨模块的这时候就绕不开timing budget的问题。简单说timing budget就是在顶层芯片划分多个子模块时把顶层时序路径的约束分配到各个子模块头上让每个模块在做独立收敛时都能有自己的时序目标。如果不做budget模块A以为自己只要跑到2ns就够了结果到了顶层集成的时候发现路径总预算只有1.8ns这时再回头做收敛成本会高出很多。我在实际项目里比较常用的做法是先用顶层网表跑一遍全局时序把每一条跨模块路径按物理边界切分然后用PT导出每个模块的接口约束包括输入延迟、输出延迟、虚拟时钟等再把这些约束反标回子模块的时序脚本里。这样每个子模块在设计的时候并不知道顶层链路上别的地方是什么样但时序约束已经替它”预留“好了余量。这里有一个经验要分享timing budget不要把余量压得太死。接口约束上留出5%到10%的余量既能逼着模块内做到足够好又不至于让前端团队在逻辑综合阶段就失去优化空间。预算一旦定死后期修改成本很高所以最好在项目早期就跟前端、Floorplan团队对齐清楚。5.3 几个实用的排查技巧速查整理几个我自己用的比较多的绕坑技巧希望能有帮助看PT报告时先过滤出所有transition超过阈值的pin很多时候transition大就是cell delay偏大的第一原因先处理这里比盲目换cell更有效。修setup违例时优先看路径上的“高叶子浓度”节点也就是驱动很多单元的节点在这些节点附近插buffer或换驱动效果通常最明显。如果一条net的delay明显偏高但长度并不长优先排查它是否走了低层金属或者中途经过太多层切换via数量多。via的寄生电阻在高频下很可观能让net delay成倍上涨。注意hold time分析中的clock skewsetup修完之后一定要重新跑一遍完整PT确认hold没有恶化。后端流程中setup和hold往往是一个跷跷板按下葫芦浮起瓢的情况太常见了。数据路径过长时优先确认有没有不合理的多周期约束multicycle path。有时候路径不需要在同一个时钟周期内完成约束改对了违例自然消失根本不用去动物理实现。结尾个人经验收尾我在实际项目里最常说的一句话是时序报告不是用来“看”的是用来“审”的。每一行delay数值背后都是一段具体的物理实现可能是某个cell的驱动能力选小了可能是floorplan里某个macro挡住了路也可能只是约束里忘了一条multicycle path。多问几个为什么把问题拆成Cell Delay和Net Delay两大块去排查大部分违例都能找到明确的优化方向。希望这篇从PT时序报告实战出发的拆解能帮你在下次遇到负slack的时候少走一些弯路。记住真正有经验的工程师不是没有遇到过违例而是知道从报告里最快锁定那一个值得改的地方。