ARTICLE DETAIL

资讯详情

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

静态时序分析STA入门:从建立保持时间到时序违例实战

静态时序分析STA入门:从建立保持时间到时序违例实战 凌晨两点群里弹出一条消息“样片回来了功能pattern全跑过了但一到高频case就随机乱码。”我第一反应是PLL没锁住或者电源纹波太大。前前后后查了三天最后打开时序报告才发现约束文件里漏了一条异步信号的false_path那条路径在硅片上真的violation了。做数字IC的人看到“STA”这三个字母条件反射基本都是Static Timing Analysis——静态时序分析。玩无线的人想到的是station站点做网络抓包的人会想到站点连接报文但在芯片设计里STA就是替你在投片前把每一纳秒都算清楚的那本时间账。这个系列我打算从零开始讲静态时序分析第一篇先把地基打牢建立时间和保持时间、四大时序路径、SDC约束到底在约束什么、工具怎么算出报告里的数字以及我实际遇到时序违例之后的完整处理思路。适合刚接触数字IC的前端、后端、验证工程师也适合想系统理解工具背后逻辑的读者。1. 为什么芯片的“时间账本”必须提前算清静态时序分析的真实角色1.1 动态仿真验证不出来的那一类bug很多刚入行的朋友会有个疑惑功能仿真都过了post-sim也过了为什么还要花大量时间跑STA原因很简单动态仿真依赖你写的testbench测试向量的覆盖率永远不可能穷尽所有输入组合更别说还要叠加工艺角、电压、温度这些条件。你用一个确定的波形去激励电路只能证明“在这组激励下”功能是对的但芯片在真实世界里面对的是千变万化的输入任何一个组合逻辑路径延迟超标都可能在某个瞬间采到错误数据。逻辑功能正确并不等于时序正确。一个加法器的真值表肯定是对的但数据如果在时钟有效沿到达之前还没稳定下来触发器就可能采到旧值甚至采到介于0和1之间的亚稳态值。STA做的事情是把网表里所有寄存器到寄存器的路径、输入到寄存器的路径、寄存器到输出的路径全部枚举出来用标准单元的延迟模型逐一检查setup和hold是否满足。它不需要测试向量也不需要产生波形所以能把动态仿真跑不到的极端情况都覆盖到。打个比方动态仿真像随机抽查员工考勤能抓到部分迟到早退但总会有漏网之鱼静态时序分析则是把所有人的作息、班车时刻表、工位距离全部摊开一张一张核对时间能不能衔接上。前者是抽检后者是全检。这也是为什么STA工具在signoff阶段地位那么高——PrimeTime、Tempus这类工具跑出来的时序报告是流片前必须被承认的“最终判决书”。1.2 静态分析为什么叫“静态”“静态”这两个字常常让初学者误以为STA只分析直流通路或者固定电平其实完全不是。STA之所以叫静态是因为它不依赖输入激励的序列而是把电路抽象成一个有向图寄存器是存储节点组合逻辑是节点之间的边输入输出端口是边界。每条边上的延迟由单元库和寄生参数决定然后工具沿着路径把所有延迟累加算出数据到达时间和数据需求时间。这个过程看起来要遍历海量路径实际上工具只会关心那些最差路径setup检查看数据到达时间最晚的路径hold检查看数据到达时间最早的路径。其他路径只要裕量足够就只需要记录结果不需要展开成报告。所以STA跑完一个百万门级设计也只需要几十分钟到几个小时比动态仿真跑一个case快好几个数量级。它不是仿真不生成波形也不管逻辑功能是否正确。STA回答的问题非常单一“是否存在某条路径在某个工艺角、某个电压、某个温度下数据到达时间不满足要求” 如果存在就报violation如果全部满足就给出MET。这个“单点回答”的性质决定了它非常适合作为签核工具。1.3 谁需要读懂STA前端RTL工程师写约束如果不懂STA综合出来的网表可能时序一团糟后端看到一堆violation还得回头找你改逻辑。后端工程师更不用说了布局布线、时钟树综合、ECO每一步都要看时序报告。验证工程师也需要懂SDC否则仿真环境里的时钟约束和真实芯片不一致仿真过了也是白过。DFT工程师做扫描链插入同样要关注扫描时钟的时序。我见过不少前端把约束随便一写以为后端能自动修好结果流片回来功能时好时坏最后拿示波器一测发现是某条异步路径没有做同步处理。这种问题在RTL阶段如果懂STA完全可以提前发现。所以我一直觉得STA不是后端工程师的专属技能而是所有数字IC工程师共享的底层语言。2. 建立时间、保持时间与时序路径STA的地基我用大白话讲一遍2.1 建立时间与保持时间为什么芯片会“变脸”建立时间setup time和保持时间hold time是数字电路时序里最核心的一组概念。建立时间指的是在时钟有效沿到来之前数据输入端必须提前稳定下来的最短时间。保持时间指的是在时钟有效沿到来之后数据输入端必须继续保持稳定的最短时间。这两个时间窗口共同构成了触发器采样的“不可侵犯边界”。我给学生讲的时候喜欢用拍集体照类比。快门就是时钟沿快门按下去之前所有同学必须站好位置这个提前量就是setup快门按下去之后大家不能立刻撒腿跑开这个停留时间就是hold。如果有人快门前最后一秒才冲进画面或者快门刚按下就转头照片里就会留下残影。对应到电路上残影就是亚稳态触发器的输出可能既不是0也不是1甚至长时间振荡把下一级逻辑全部搞乱。一个很容易踩的误区是有人觉得setup和hold都是“越慢越好”或者“越快越好”其实它们是对数据相对时钟沿的两种约束。setup限制数据不能来得太晚hold限制数据不能变得太早。高频时候setup容易违例因为周期变短了数据在下一个沿到来之前没有足够时间稳定但hold跟频率无关它只关心数据在同一个沿之后能保持多久所以哪怕你降到1Hzhold违例照样存在。很多人一开始想不明白这一点等看到后仿报告里低频下还报hold violation才反应过来。2.2 四大时序路径in2reg、reg2reg、reg2out、in2outSTA工具把设计里的时序路径分成四类输入端口到寄存器输入端in2reg、寄存器到寄存器reg2reg、寄存器到输出端口reg2out、输入端口直接到输出端口in2out。其中in2reg、reg2out和in2out属于边界路径需要外部约束来定义输入输出边界条件reg2reg是设计内部的路径完全由时钟和逻辑决定。reg2reg路径是数字IC设计里最常见的路径一个发射触发器launch flop的Q端经过组合逻辑到达捕获触发器capture flop的D端。STA工具会计算发射时钟沿到捕获时钟沿之间这段路径的延迟是否满足建立时间和保持时间。如果组合逻辑级数太多数据到达时间晚于需求时间就是setup violation如果组合逻辑太短数据在hold窗口内就发生了变化就是hold violation。in2reg路径从芯片输入引脚开始到达内部第一个寄存器的D端。工具不知道芯片外面是什么情况只能靠set_input_delay告诉它外部数据相对时钟沿的到达时间。reg2out路径从内部寄存器的Q端出发到达输出引脚同样需要set_output_delay来描述外部接收端的要求。in2out路径比较少见一般出现在纯组合的IO路径或某些特殊接口上约束方式类似。四大路径在工具里的处理逻辑不一样但核心思想是一致的数据到达时间必须落在数据需求时间允许的窗口内。窗口的上下边界一个由setup决定一个由hold决定。2.3 一条真实寄存器的路径账本只看定义还是虚的我拿一个最简单的寄存器到寄存器路径手算一遍。假设发射触发器是reg_a捕获触发器是reg_c中间经过两级组合逻辑。时钟周期Tcycle1ns时钟网络完全对称不考虑skew。reg_a的CLK到Q延迟Tclk2q0.2ns两级组合逻辑布线总延迟Tcomb0.6nsreg_c的建立时间Tsetup0.1ns。setup检查的公式是数据到达时间 ≤ 数据需求时间。数据到达时间0.20.60.8ns数据需求时间1-0.10.9ns。slack0.9-0.80.1ns满足要求。如果组合逻辑变成0.75ns数据到达时间0.95nsslack-0.05ns就违例了。hold检查的公式是数据最早变化时间 ≥ 数据保持需求。假设Tclk2q的最小值是0.15nsTcomb的最小值是0.25ns那么数据最早变化时间0.150.250.40ns。如果reg_c的保持时间Thold0.35ns那么slack0.40-0.350.05ns勉强满足。如果Tcomb的最小值只有0.1ns数据最早变化时间0.25nshold就violation了。这个手算过程看起来简单却是理解STA报告的钥匙。工具报告里所有的数字本质上都是在算这两个不等式。我建议每位读者都在纸上手算一遍后面看report_timing时你才会有“啊原来这个数字是这样来的”这种顿悟感。3. 没有约束的STA就是白算从时钟定义到SDC实战3.1 先给自己一个干净的时钟create_clock和时钟树STA的第一步永远是定义时钟。没有时钟工具连路径的起点和终点都找不准。最基础的命令就是create_clock。比如给芯片主时钟引脚创建一个10ns周期的时钟可以这样写create_clock -name clk -period 10 -waveform {0 5} [get_ports clk]-period 10表示周期10ns-waveform {0 5}表示上升沿在0ns下降沿在5ns也就是50%占空比。如果不写waveform工具默认从0开始占空比50%。定义时钟之后还要处理两类延迟时钟延迟和时钟不确定性。时钟延迟clock latency是时钟源到触发器时钟端之间的物理延迟在综合阶段还没有时钟树需要人为设定一个估计值等后端做完时钟树综合工具会从实际网表和寄生参数里算出精确的clock network delay。时钟不确定性clock uncertainty是时钟沿可能出现的抖动和偏差包括PLL的jitter、时钟树上的工艺偏差等工具会把它从时序预算里扣掉。实际操作中uncertainty设置过大或过小都会出问题。设得太大工具会很保守报一堆假violation后端只能靠加buffer硬撑白白浪费面积和功耗设得太小又可能掩盖真实的时序风险流片回来才随机出错。这个值怎么定要结合PLL数据手册的jitter指标、供电噪声评估和过往项目的经验不是一个拍脑袋数字。3.2 输入输出边界怎么“翻译”成约束芯片内部路径好查但外部世界工具看不到必须通过约束来建模。set_input_delay告诉工具在时钟有效沿之后外部数据到达芯片输入引脚需要多长时间。这里有个常见误区set_input_delay不是让你设内部组合逻辑延迟而是设外部上一级芯片或器件的延迟。举个例子假设外部上游器件在时钟沿后2ns把数据送到我们的输入引脚din。对内来说这个2ns就是我们要接受的“起跑延迟”内部路径的数据到达时间要从这个2ns开始往后累加。SDC写法set_input_delay 2.0 -max -clock clk [get_ports din] set_input_delay 0.5 -min -clock clk [get_ports din]-max对应setup检查用的最晚到达时间-min对应hold检查用的最早到达时间。为什么需要两个值因为外部器件的最小输出延迟和最大输出延迟不一样工具在检查setup时看最晚情况检查hold时看最早情况。set_output_delay则是从输出端口往外看描述外部接收端对数据到达时间的要求。比如外部接收寄存器需要数据在时钟沿前0.8ns就稳定那么set_output_delay 0.8 -max -clock clk [get_ports dout]这个0.8ns相当于内部路径必须预留出外部寄存器的setup时间。如果外部还有很长的走线延迟也要一并算进去。边界约束的本质是把芯片外面的时序环境完整映射成内部STA可计算的数学条件。3.3 容易出问题的三个约束细节约束文件里最容易翻车的点我总结三个。第一个是false_path和max_delay的混用。跨时钟域的异步信号比如两个无关时钟域之间的握手信号理论上不能用setup/hold去检查因为两个时钟沿之间没有固定相位关系。这时可以设set_false_path让工具跳过。但如果一条路径只是“很难满足”而不是“真的不需要检查”千万不要图省事设false否则等于把这条路径从安检名单里划掉流片后随机出问题都没人知道。可以用set_max_delay来给一个宽松但不失守的约束。第二个是generated clock没有定义。分频器、倍频器输出的时钟必须用create_generated_clock定义清楚和master clock的关系。否则工具会把分频器输出当成普通数据信号去查时序时钟路径上冒出大量诡异violation。定义分频时钟的SDC示例create_generated_clock -name clk_div2 -source [get_ports clk] -divide_by 2 [get_pins reg_div/Q]第三个是set_clock_groups没有写全。设计里有多个异步时钟域时必须在set_clock_groups -asynchronous里把所有有异步关系的时钟对都列出来漏掉任何一对工具就会把它们当成同步时钟去检查产生海量假violation真实违例反而被淹没在噪音里。我在实际项目里见过太多人把大量时间花在清理假违例上结果真正重要的路径反而没仔细看。约束文件写得好不好直接决定后面整个时序收敛的效率。4. 工具到底在怎么算setup和hold从lib库到报告数字的全链路4.1 lib文件不是一堆表格而是“延迟行为说明书”标准单元库的.lib文件在外行看来就是一堆表格但它是STA工具的粮食。每一个单元的每个引脚都定义了从输入到输出的延迟而这个延迟通常是输入转换时间input transition和输出负载电容output capacitance的二维函数。这个模型叫NLDM查表方式和我们初中学的xy坐标找函数值差不多。举个例子某个反相器的延迟表格可能长这样input transition \ output cap0.005 pF0.01 pF0.02 pF0.01 ns0.008 ns0.011 ns0.017 ns0.05 ns0.020 ns0.024 ns0.031 ns0.10 ns0.035 ns0.040 ns0.048 ns工具拿到真实的transition和cap后先查表没落在表格节点上就做插值。cell delay之外还有net delay综合阶段用wire load model估算signoff阶段则用寄生参数提取工具生成的SPEF文件里面记录着每根net的电阻电容。STA把cell delay和net delay累加就得出了路径延迟。所以你会发现寄生参数没提准后面所有时序分析都是空中楼阁。setup和hold本身也在.lib里它们的值和数据引脚的transition、时钟引脚的transition都有关。这也是为什么一条路径上的transition变差不只是cell delay变大连接收触发器的setup时间也会变差双重打击。4.2 时钟路径上的OCV为什么有人用derate又为什么有CRPR早期STA假设同一颗芯片上所有器件延迟都按一个固定值计算非常理想化。实际硅片上不同位置的晶体管沟道长度、阈值电压都存在工艺偏差导致两条物理上本应完全相同的路径实际延迟可能一个偏快一个偏慢。这个现象叫OCVon-chip variation。为了应对OCV工具引入了derate机制给特定路径段的延迟乘一个大于1或小于1的系数人为制造悲观条件确保真实硅片在最差情况下也能满足时序。比如发射路径上的cell delay乘1.1表示假设它偏慢捕获路径上的cell delay乘0.9表示假设它偏快这样setup检查就变得更严格了。这里出现一个问题发射时钟路径和捕获时钟路径在时钟树上有很长一段是公共的从时钟根节点到分叉点之前两根路径走的物理布线完全一样。如果把这部分也分别乘上1.1和0.9那等于假设同一段金属线既慢又快明显不合理。于是工具用CPPRcommon path pessimism removal也叫CRPR把这段共同路径上的重复悲观量减掉。你可以想象两个骑手从同一车站出发送快递前半段路线一模一样后半段才分开。OCV只应该假设他们在分开的后半段一个骑快、一个骑慢前半段既然是同一条路速度差异不会凭空出现。CPPR就是工具自动完成这个“只对分歧之后的部分计入偏差”的修正。理解CRPR对读懂报告的required time非常重要。很多新手看到report_timing里clock uncertainty和derate一加一减数字对不上查半天其实是没理解OCV和CPPR对时钟路径的共同作用。这部分后面我打算单独写一篇展开AOCV和POCV这里先把概念立住。4.3 看懂report_timing纸上谈兵不如直接看报告。下面是一份PrimeTime风格的setup检查报告的精简示意路径是reg_a到reg_c中间经过两级组合逻辑周期1nsPath Group: clk Path Type: max Startpoint: reg_a/Q Endpoint: reg_c/D clock clk (rise edge) 0.00 0.00 clock network delay 0.20 0.20 reg_a/Q (dff) 0.18 0.38 u_comb_1/Z (and2_1) 0.12 0.50 u_comb_2/Z (xor2_2) 0.15 0.65 net delay 0.30 0.95 data arrival time 0.95 clock clk (rise edge) 1.00 1.00 clock network delay 0.25 1.25 clock uncertainty -0.05 1.20 reg_c/D (setup) -0.10 1.10 data required time 1.10 slack (MET) 0.15第一列是路径经过的对象第二列是当前段延迟增量第三列是从起点累加的时间。data arrival time就是数据实际到达endpoint的时间包含发射时钟路径延迟、CLK到Q延迟、组合逻辑延迟和net delay。data required time则是捕获时钟沿加上时钟网络延迟扣除clock uncertainty和setup time之后允许数据最晚到达的时间。slack就是两者的差正数满足负数violation。拿到报告先看什么我习惯先看startpoint和endpoint确认路径是不是真的需要检查再看clock uncertainty和derate设置是不是过于保守最后拉长路径上的delay分段找出哪一段拖后腿最严重。如果net delay占总延迟比例特别高说明布局太散或者线太长要优先处理物理实现如果cell delay占大头考虑换驱动能力更大的cell或者优化逻辑级数。5. 一次真实setup violation的排查从报告到修buffer的完整链路5.1 违例发生时我第一眼看报告的哪里早年我拿到一个violation报告第一反应就是打开工具想插buffer结果被老工程师拦住了。他让我先回答三个问题这条路径该不该查约束对不对violation是cell delay还是net delay引起的这三个问题不看电路结构是无法回答的。第一步确认endpoint和startpoint是否在合理的路径上。如果这条路径属于两个异步时钟域之间而约束里没有设false_path或clock_groups那这个violation很可能是个假违例不要急着改电路。第二步检查clock uncertainty和derate值。我见过某个项目把uncertainty设到0.8ns实际PLL jitter只有0.2ns白白多背了0.6ns的包袱后面把值改合理违例瞬间少了三分之一。第三步看delay分段判断是逻辑级数太多还是某个cell的transition太大、net太长。这里有一个很实用的技巧看report_timing的时候把每一段的incr delay扫一遍如果发现某个cell的输入transition已经接近或超过了它的输出transition说明它前面那级的驱动能力不够如果某段net delay远大于cell delay说明布局布线不够优化靠插buffer不一定解决得了可能要调整floorplan。5.2 一个具体case的复盘提频之后-0.3ns是怎么修到MET的之前做一个数据通路模块原来跑100MHz项目要求直接提到200MHz。综合之后一看report_timing最差路径setup violation是-0.3ns。路径结构很典型MUX选择器 16位加法器 一级逻辑 寄存器总共8级组合逻辑。第一步没有动电路先查约束。发现clock uncertainty当初按100MHz设计时留了0.5ns实际PLL jitter和时钟树评估下来0.2ns就够把uncertainty从0.5ns改到0.2nsslack立刻改善了0.3nsviolation基本消失仅剩-0.05ns左右的尾巴。这一步告诉我们约束里的每个值都是有代价的宁缺毋滥但也不能为了报告好看而把uncertainty压得比真实jitter还小。第二步处理剩下那点尾巴。0.05ns的裕量确实很小但报告里显示最大的一跳延迟出现在那个行波进位加法器上。行波进位加法器的延迟随位宽线性增长改成超前进位carry lookahead加法器之后这级逻辑延迟明显下降slack从-0.05变成了0.10ns。如果这样还修不完我会按这个顺序继续先看RTL能不能拆流水把一级大逻辑拆成两级小逻辑再不行就在综合选项里换更激进的重定时策略最后才考虑物理层手段比如插buffer改善transition、调整单元摆放距离。为什么把插buffer放最后因为buffer本身也有延迟插错了地方只会越修越差。5.3 Hold违例为什么比Setup更阴险相比setuphold violation更像一个“潜伏者”。setup不满足通常表现为最高工作频率上不去测试时很容易测出来改低频可能就正常了。hold不满足则和频率无关它更常出现在特定电压、特定温度、特定数据组合下可能跑几十个小时才随机错一次定位难度让人头疼。我之前碰到过一个case芯片在低温老化测试时偶发数据错误正常电压温度怎么跑都没事。一开始怀疑存储器单元后来怀疑PLL最后翻出hold report才发现全芯片有三四条路径的hold slack趴在0附近CRPR和derate的margin只要稍微调一下立刻变成负数。而这几条路径恰好都在一条低频慢速接口上所有人都没在意。Hold修复还有一个特点它经常发生在时钟树综合之后。时钟树把capture时钟延迟拉得比launch时钟晚hold检查时就会更严格。所以后端的hold ECO是普遍操作但正因为普遍很多人把它当成机械劳动忽略了扫描模式下的hold检查、IO路径上的hold要求这些边角。我的经验是每次修完hold把report里所有slack绝对值小于0.05ns的路径全部过一遍哪怕只是肉眼确认也不要觉得“既然工具没报violation就没问题”。6. 我建议初学者按这个顺序吃透STA路线与系列预告6.1 从手算一条路径到独立分析报告经常有人问我STA怎么学效率最高我的答案永远是先手算再开工具。找一个简单的RTL工程综合出网表挑一条寄存器到寄存器的路径根据.lib里的延迟值和网表结构人工把data arrival time和data required time算一遍然后打开report_timing对照。这个过程痛苦但只要你算通一次后面所有报告在你眼里就不是一串神秘数字了。我当年就是这么被老工程师逼着算过来的算到半夜差点想转行但第二天看到报告里每一个数字都能对上自己的计算时那种通透感是刷多少教程都换不来的。初学阶段不要急着背SDC命令先想清楚“数据到达”“数据需求”“slack”这三个词到底意味着什么。之后可以循序渐进先掌握基础约束和四类路径接着练习generated clock和clock groups然后进入OCV、CRPR、多周期路径这些进阶主题。每学一个概念就在小设计里改一遍约束看报告怎么变化。工具只是计算器脑子里的模型才是判断力。6.2 系列安排与一点个人体会这个系列打算沿着我自己的学习路径往下写第二篇计划写时钟约束的进阶内容包括generated clock、时钟分组和跨时钟域检查的具体案例第三篇想聊OCV、AOCV和CRPR的数学细节附带几个“为什么signoff环境要这么设”的实际场景后面还会涉及多电压域、多时钟域、报告分析与脚本化处理这些后端工程师天天面对的问题。最后分享一个我自己的习惯每次改完约束或者修完timing我都会把violation list和修复前后的报告截个图存下来标注当时的判断思路。这些记录比任何培训材料都值钱因为时序分析说白了是一个靠经验积累“直觉”的领域。看多了违例你会慢慢对哪些路径容易出问题、哪些约束容易被误设产生条件反射式的敏感。说到底把“数据到达时间”和“数据需求时间”这两个词刻在脑子里比背一百条命令都有用。希望这个系列能帮你把STA从“工具会跑但我不懂”变成“我知道工具在算什么也知道该怎么控制它”。
返回列表