ARTICLE DETAIL

资讯详情

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

PrimeTime时序报告实战:从report_timing到report_delay_calculation的精细解读

PrimeTime时序报告实战:从report_timing到report_delay_calculation的精细解读 1. 为什么时序报告读得好后端能少加班干数字IC后端或者做signoff的人应该都有这种经历拿到的PrimeTime时序报告看着全是路径密密麻麻几百行setup违例、hold违例、max_transition违例混在一起不知道先看哪条修时序的时候又经常发现改了placement和CTS结果前几轮修的那条路径根本没动白费力气。说句实话读报告不是能看懂就行而是要能从报告里快速判断出这条路径到底卡在logic delay、net delay、还是clock skew上这样才能决定下一步是优化逻辑、加大驱动还是动时钟树。我这个帖子里不打算讲PrimeTime的基本操作手册那些看UG就行。我想花点篇幅结合我自己跑过的项目把从report_timing到report_delay_calculation这一整套实战用法拆开揉碎讲一遍包括每个命令选项背后的含义、报告每一列怎么快速定位问题、以及一些常被忽略的坑。适合刚接触STA的初学者也适合做了几年后端但一直停留在看个slack数阶段的工程师把读报告这个基本功补扎实。2. 先把report_timing的底子打好别只盯slack那一列2.1 常用选项的功能分组思路report_timing可能是我们用的最多的PrimeTime命令但很多人用的时候就是report_timing -from A -to B打一条出来看个数字完事。其实把这个命令的选项按选什么路径、报告里展示什么、怎么过滤三个维度来记会清晰很多。选路径用的选项包括-from、-to、-through、-rise_through、-fall_through、-from_rise、-to_fall这一类起点终点相关的约束也包括-delay_type min/max、-path_type full/short、-group这些按路径属性筛选的选项。展示层面的选项包括-transition_time、-capacitance、-nets、-attributes、-input_pin、-net、-format、-sort_by这些决定报告里打印哪些细节。过滤类的选项有-nworst、-slack_lesser_than、-slack_greater_than、-max_paths、-unique_pins等用来控制报告条数。我自己的习惯是只要路径数不是特别多一般会加-transition_time -capacitance -nets三个选项一起打这样每级cell的transition、load capacitance和net delay都能在报告里看到后面分析问题就不用反复去翻别的命令。特别是调试max_transition违例或者high fanout net的时候这些信息是救命级的。2.2 一份完整报告怎么从上往下读report_timing打印出来的典型max delay报告分几个区块。头部是Startpoint、Endpoint、Path Group、Path Type下面紧跟的往往是一条clock uncertainty或者clock skew信息然后是整条路径的明细最后算出一个slack。很多人只盯着最后的slack值实际上头部信息量很大。举个我最近调试的例子报告开头长这样Startpoint: reg_a_reg/CK (falling edge-triggered flip-flop clocked by clk_div) Endpoint: reg_b_reg/D (rising edge-triggered flip-flop clocked by clk_div) Path Group: clk_div Path Type: max看到Startpoint和Endpoint的clocked by后面的时钟名字要立刻和你在SDC里定义的时钟对上。如果这里出现了意外的时钟域比如clk_div和clk_osc混在一起那就说明clock crossing约束可能没写对或者时钟定义有交叉这种问题光修data path是没用的得回去看时钟约束。再往下数据路径明细部分通常会用类似这样的格式clock clk_div (rise edge) 10.0000 clock network delay (propagated) 1.5000 clock reconvergence pessimism -0.1000 clock uncertainty 0.2000这四行信息是判断时钟侧有没有问题的关键。clock network delay的值如果是propagated就说明CTS之后跑的数值本身能反映时钟树长短clock reconvergence pessimism就是CRPR扣除的量如果没有这行或者一直是0可能你还没有使能CRPR或者时钟结构比较简单没有公共路径clock uncertainty则是你在SDC里设的它包含PLL jitter、clock tree margin等。常见的一种情况是setup违例数据路径delay并不长但slack还是很差这时候多半是uncertainty设得太大或者capture clock path比launch clock path慢太多导致看起来时间不够。我后面在delay_calculation部分会专门讲怎么拆开算。2.3 数据路径明细里最容易被忽略的几列路径明细的每一级cell通常打印三行信息cell的internal delay、net delay和到达时间。用-transition_time -capacitance之后会额外看到每一级的transition和load。这里我想强调两点。第一注意internal delay大但net delay小的情况。比如一个Buffer的internal delay占了整个路径的三分之一说明它的驱动能力可能选小了输入transition太大导致自身延迟变大。这种问题你加大级间buffer尺寸往往能立竿见影。反过来net delay占比很高大到几百ps甚至ns级别那十有八九是绕线太长或者congestion导致绕线绕远了这时候改cell size帮助不大优先考虑换位置、换floorplan或者加buffer切断长线。第二留意报告的Location信息。打印路径时加上-attribute或者用report_timing -full_clock可以看到cell的物理位置。碰到net delay异常大的情况我会立刻比对launch clock path上最后一个clock buffer和data path上第一个cell的距离两者如果隔着大半个block那基本是布局不合理的锅。这种经验值很有用——不是所有违例都该无脑插buffer先看空间关系再动手。3. 路径分组和违例筛选从海量报告里快速锁定真问题3.1-group和path group到底怎么用很多工程师知道report_timing -group可以选路径组但对path group到底怎么划分的、为什么有时候分组结果和想象的完全不同并不清楚。实际上path group默认是按照endpoint上有效的时钟来分的也就是说一个寄存器如果由clk_1驱动那它作为endpoint的路径就归入clk_1组。但SDC里的group_path命令可以改变这个归属这也是实现异步路径单独分组的常用手段。实际项目中我经常会在SDC里对异步信号、复位信号、或者一些特殊的IO路径单独设置group_path然后流片前signoff时用report_timing -group分别检查避免这些特殊路径稀释了主要时钟域问题的注意力。比如下面这种写法group_path -name async_paths -from [get_pins rst_n_reg/CK] group_path -name io_paths -to [get_ports data_out*]设置完之后在PrimeTime里可以用report_path_group查看当前path group列表再用report_timing -group按组分析。这个方法对于收敛时序很有帮助因为不同路径组的敏感度和修复策略其实差异很大混在一起看容易误判。3.2-nworst、-max_paths和-slack_lesser_than的正确搭配如果不做任何过滤report_timing针对一个endpoint默认只报一条最差路径用-nworst可以增加每个endpoint报出的路径数用-max_paths控制总体报出的条数。这两个选项的区别我经常看到有人搞混简单说-nworst是per endpoint维度-max_paths是全局条数。做全局signoff的时候我会用类似这样的命令report_timing -delay_type max -max_paths 1000 -slack_lesser_than 0.05 \ -transition_time -capacitance -nets -path_type full这里-slack_lesser_than 0.05过滤出slack小于50ps的路径保证即使不写-nworst也不会把关键的临界路径漏掉。还有一个细节-nworst默认可能把同一条物理路径因不同capture edge而重复报很多次浪费条数所以signoff阶段通常还要加上-unique_pins选项避免同一条路径反复出现在报告里。3.3 怎么判断违例是真违例还是约束假象有一次我收到一个项目的setup违例报告数据路径只有2ns时钟周期是5ns但slack还是负的当时就很纳闷。后来一条一条看报告发现capture clock的clock network delay是2.8nslaunch clock的clock network delay只有0.5ns两者的差值加上uncertainty之后把本来充裕的余量全部吃掉了。这种违例的根源并不在数据路径上而在于clock skew不平衡。面对这种report首先要做的是确认CTS是不是最终版本clock tree的skew目标是不是真的没有收敛到预期。如果CTS已经做完但skew仍然这么大就要检查是不是clock net上有congestion、clock buffer是否插得合理、clock routing有没有绕线异常。修这种问题光在data path上插buffer是没有用的甚至可能越修越差因为你在data path上加delay只会让setup更紧张。4. 深入report_delay_calculation把工具算出来的数拆开验证4.1 这个命令到底解决了什么痛点report_timing给你的是结果但为什么是这个结果它不会解释得特别细。比如说某一级cell的internal delay到底是怎么由输入transition和output load推出来的为什么net delay是这么多report_delay_calculation就是把这些计算细节全部拉开按library里的delay model公式一步步展开给你看。我用一个自己在调试max_transition违例时遇到的场景举例。某条路径上有一个AND2X2的cell输入transition是180psviolation报告显示它超过lib里的max_transition但奇怪的是这个cell的输出pin接的net并不长负载也不大。理论上不应该超过。后来用report_delay_calculation一查发现这个cell的输入transition根本不是我预期的前一级输出而是因为输入pin前面还有一段很长的clock netclock transition在这个pin上已经衰减到很大了。这种问题看report_timing其实也能看出来但如果你没加-transition_time或者路径比较长没顾得上注意就只有用report_delay_calculation才能快速定位到具体是哪个pin造成的。4.2 一条实际路径的delay_calculation输出怎么读假设我输入如下命令report_delay_calculation -from reg_a_reg/CK -to reg_b_reg/D -delay_type maxPrimeTime会按照时序弧的顺序把从startpoint到endpoint每一条cell delay和net delay逐段列出。以一级buffer为例输出类似Cell: buf_1 Library: slow_corner_typ Pin: buf_1/A Related pin: buf_1/Y Delay type: rising_edge ... Input transition: 0.1200 ns Total output load capacitance: 0.0350 pF Delay intrinsic (input_transition * slope) (load_cap * delf) 0.0230 0.1200 * 0.3100 0.0350 * 0.5200 0.0230 0.0372 0.0182 0.0784 ns这里面intrinsic、slope、delf这些系数全部来自library的lookup table或者NLDM模型工具会读取lib里对应的index值然后做插值。看懂这个公式之后你就能明白想把cell delay降下来要么减小输入transition把上一级cell改强要么减小output load拆fanout、就近摆放要么换一个库里面delay更小的cell。这三个方向对应不同操作看公式一目了然。很多人看到一堆浮点数就头疼但我觉得恰恰是这种拆解让修timing变得有依据。毕竟EDA工具没有魔法每一个ps都是算出来的。4.3 NLDM、CCS模型对delay calculation的影响这里稍微展开说一下模型层面的差异因为report_delay_calculation能不能直接看到上面那样的公式跟你用的库模型有直接关系。老一点的工艺库多用NLDMNon-Linear Delay Model计算简单报告里很容易还原出input_transition * slope load * delf这种线性化过程而先进工艺节点更常用CCSComposite Current Source模型delay计算的底层是一个电流源的瞬态仿真查表用户在report_delay_calculation里看到的信息会更加简洁不一定直接给你系数。但这不代表CCS下delay_calculation就没用了。它依然可以告诉你某个pin上的transition和load是怎么来的、是哪一级贡献的以及有没有因为输入波形形状slew导致的额外延迟。做先进工艺项目的时候我一般会结合report_thresholds来看信号到达threshold的时间点这样对波形失真导致的hold问题能有更直观的理解。5. 实战排查setup违例、hold违例和max_transition的完整分析Flow5.1 setup违例排查清单拿到一条setup违例路径我的排查顺序基本是固定的。先看启动时钟和捕获时钟是不是同一个是的话检查clock network delay的差异不是的话先确认跨时钟域的约束有没有问题尤其是有没有设set_clock_groups或者set_false_path否则工具可能报出完全不存在的伪违例。接下来看数据路径的级数和总delay。如果cell数量很多、逻辑级数超过正常预期就去检查综合阶段是否做了retiming或者logic restructuring如果逻辑级数不高但每级delay都很大就要重点检查transition、load、cell drive strength。最后才是看net delay排除congestion和长线问题。我整理了一个速查表基本覆盖了我在项目中用到的判断方向现象优先怀疑方向修复手段data path delay整体偏大逻辑级数过高/综合策略偏保守重新综合优化、retiming、增加pipeline某级internal delay大cell驱动不足/输入transition大换size、插buffer某级net delay异常routing绕线/congestionfloorplan调整、加buffer断线capture clock path明显偏慢CTS skew不均衡调整clock tree、优化clock routingslack接近0但各段均正常uncertainty/OCV余量过紧和前端确认约束余量5.2 hold违例的易容术为什么report_timing -delay_type min经常看到clock pathHold分析看的是数据到达得太早而capture edge来得太晚。所以常规修复是加delay buffer来推迟数据。可是如果你打开一条min delay report发现数据路径只有三四级buffer但clock path上有一长串clock buffer那就要当心了这条hold违例大概率不是数据path本身的问题而是launch clock和capture clock的结构性失配。在CTS做完之后工具通常会做useful skew优化让capture clock适当晚到从而缓解setup。但这种优化做过头就会牺牲hold。遇到这种情况先确认CTS的约束和优化目标是不是合理不要一股脑地往数据路径上插delay buffer否则后面setup又崩了。我处理过一个项目为了修hold在数据路径上加了10多个buffer结果setup margin全被吃光后来发现其实只要调整CTS的clock tree到某几个寄存器的距离问题就解决了大半。这也是为什么我建议修hold之前一定要把min path的clock部分也看完整而不是只看data delay。5.3 max_transition违例的定位流程report_timing的最大transition违例通常不在这条路径的slack上反映出来所以很多人会忽略。但max_transition过大直接影响延迟计算精度和功耗signoff必须干净。定位max_transition问题我喜欢用report_checks加physical context或者report_timing -transition_time -capacitance然后逐级看哪一级的transition超过了库限制。如果违例出现在某个高扇出net的末端优先考虑插入buffer做fanout tree或者优化原本的high fanout net synthesis。如果违例出现在时钟树的leaf cell上那问题可能出在CTS阶段对slew的约束太松需要回到CTS重新设置max_transition。还有一种常见情况是net本身不长、负载也不大但transition就是很大。这种多半是输入波形很烂上一级cell驱动太弱这时候去看report_delay_calculation把上一级cell的output transition打印出来基本就能证实了。6. 实战进阶几条能明显提升效率的命令组合与小技巧6.1 快速对比多corner结果的习惯在multi-corner signoff流程里我习惯在跑完所有corner后用脚本把每一个corner的报告统一抓出来按slack排序列成一张总表。这样能快速判断当前项目最差的corner是哪个。很多人只在worst corner上修timing但如果setup和hold的worst corner不是同一个就会陷入按下葫芦浮起瓢的循环。拿report_timing分别检查所有corner的top违例路径记录下来你会发现每次的瓶颈往往集中在某几条物理路径上后续修timing会更有针对性。具体操作上可以写类似这样的Tcl循环foreach corner {ss_0p99v_125c ff_1p08v_m40c ss_0p99v_m40c} { current_session -corner $corner report_timing -delay_type max -slack_lesser_than 0 -max_paths 10 \ ${corner}_setup.rpt report_timing -delay_type min -slack_lesser_than 0 -max_paths 10 \ ${corner}_hold.rpt }这样产出的一份报告集合比单独打开一个corner来回看要直观得多。对于经验不太多的工程师我强烈建议从一开始就养成这种全corner全局对比的习惯而不是只盯着实验室或者默认的某个corner。6.2 用group_path配合report_timing -delay_type做分类签核在最终signoff的时候除了普通的setup/hold检查我还会用group_path对特殊路径做分类比如IO interface path、async path、clock gating check path等。然后对每一类单独出报告避免它们混在普通路径里影响判断。拿clock gating检查举例常见的clock gating setup/hold检查和普通寄存器到寄存器的时序约束不太一样它关注的是enable信号相对于clock的稳定窗口。在PrimeTime里如果要专门看clock gating path可以按SDC里定义的set_clock_gating_check相关约束配合report_timing -through来看。如果这类路径违例通常需要在clock gating cell的enable端加delay或者对gating cell的clock端做特殊约束。这个场景下report_delay_calculation同样有用因为你可以查看gating cell的clock pin和数据使能pin各自到达的时间差精确找到是哪一段贡献了多余的延迟。6.3 保存session和分批报告别在老跑全量PrimeTime打开一个大设计本身就要不少时间大家应该尽量利用session机制。在跑完一次完整timing之后用save_session把当前环境保存下来后续调试就不用反复重新加载网表和库能省非常多时间。save_session ./pt_debug_session # 下次启动直接加载 restore_session ./pt_debug_session然后在这个session里想怎么report_timing、report_delay_calculation、report_clock_timing都可以随时执行不用等待重新读数据。我个人的一个工作习惯是每次跑到一个关键阶段都会存一个命名清晰的session比如after_CTS.session、after_route.session、final_signoff.session每个阶段的问题分析都在对应session里做效率和可追溯性都大幅提升。7. 最后再分享一点实用的经验读时序报告这件事说到底不是会用命令而是会从报告里还原出电路的真实行为。report_timing给了你最终答案report_delay_calculation帮你把答案拆成一步步的计算过程而真正值钱的是你知道该在什么时机去看哪一份报告、什么样的数值组合背后对应什么样的物理问题。我自己最开始学STA的时候也是一条路径一条路径地抄下来算后来逐渐形成自己的排查套路现在基本拿到一条违例路径扫一眼头部和中间几级就能判断出大概方向。建议大家在日常项目中不要只满足于用工具自动修多花点时间、手动去解析一两条典型违例路径试试用report_delay_calculation把每一级delay都核一遍这个过程积累出来的感觉比看十篇文档都管用。等你能不看报告就预判出某条路径是修cell size还是修placement的时候时序收敛对你来说就不再是玄学了。
返回列表