slack (VIOLATED) 负值:OpenSTA worst slack 报告逐段读法与收敛路径
更新时间:2026-10-25。排错速查页,属于开源 EDA 排错系列。用 OpenLane / OpenROAD 跑完流程,打开 STA 报告一眼看到
slack (VIOLATED)和worst slack -0.95——负的这个数到底差在哪一级门、该往哪个方向修,是这篇要解决的问题。OpenSTA 报告的通用读法见 OpenROAD STA 报告解读,环境本身没装好的先看 OpenLane Docker 排错。
答案块(赶时间先看这里)
- 报错原文:
-0.95 slack (VIOLATED),末尾汇总worst slack -0.95 - 环境:OpenLane 流程内嵌 OpenSTA,sky130A 工艺,时钟周期被收紧到 0.1 ns
- 根因:最坏路径的 data arrival time(0.93 ns)超过了 data required time(-0.02 ns),建立时间不满足
- 修复方向:放宽过紧的时钟约束只是验证手段;真实收敛靠三招——降 fanout、减逻辑级数(重定时/重综合)、插 buffer 改善线延迟
- 验证:重跑 STA 后
worst slack变为正值(本次实验放宽时钟后为 18.61)
本文要回答的问题
slack (VIOLATED)这个负数的账是怎么算出来的?- 报告里 Delay / Time / Description 三列该怎么读?
- 为什么同一份报告里有的路径 MET、有的 VIOLATED?
- slack 为负之后,fanout、重定时、buffer 三种手段各自解决什么问题?
一、报错原文与现象
复现方式很直接:把 SDC 里的 create_clock 周期收到一个物理上不可能的 0.1 ns,再让 OpenSTA 读网表和约束跑 report_checks:
-0.02 data required time
-0.93 data arrival time
---------------------------------------------------------
-0.95 slack (VIOLATED)
worst slack -0.95这张实录抓住了三件事:路径属于 Path Group: clk(说明时钟本身被识别了,不是约束缺失问题);中间是一长串单元延迟累加;结尾两行红字 slack (VIOLATED) 和 worst slack -0.95。注意报告开头还有一条 Path Group: asynchronous 的 recovery 检查 slack 是 0.32 (MET)——同一次分析里有的路径过、有的不过,VIOLATED 只针对没满足的那条最坏路径,不是整个设计全废。
二、报告逐段读法:两本账和一个差值
OpenSTA 的单条路径报告结构固定,抓住「两本账」就不会迷路:
拿实录里那条最坏路径对一遍账:arrival 段从 _45_/CLK 出发,经过 and4 → nand4 → isobuf 三级组合逻辑,累计 0.93 ns 到 _51_/D;required 段捕获沿在 0.10 ns(周期 0.1 ns 的第一个上升沿),减去库单元 setup time 0.12 ns 后得到 -0.02 ns。两数相减 slack = -0.02 - 0.93 = -0.95,负值就是建立时间差了将近一整个纳秒。Description 列括号里的单元名(如 sky130_fd_sc_hd__nand4_1)是后续定位的抓手——哪一级 Delay 增量特别大,哪一级就是瓶颈。
三、VIOLATED 之后往哪修:收敛动作树
slack 为负只是症状,开药方前要先归因。常见三根因对应三条修法,可以用一张动作树串起来:
颜色按角色分:红是根因(三种都可能让 slack 变负)、蓝是排查动作(读报告归因)、橙是修复动作、绿是收敛目标。三条路的手段、成本与适用条件对比如下:
| 收敛手段 | 解决什么问题 | 改动层面 | 典型成本 |
|---|---|---|---|
| 插 buffer / 换大驱动单元 | 高 fanout 节点的负载电容 | 网表(工具可自动) | 低,面积略增 |
| 重定时 / 重综合拆逻辑 | 组合逻辑级数太深 | RTL / 综合策略 | 中,要重跑综合与验证 |
| 换低阈值电压(LVT)单元 | 单元本身延迟偏大 | 网表(ECO) | 低,漏电功耗上升 |
| 放宽时钟周期 | 约束超出物理可达 | SDC 约束 | 零电路成本,但降性能 |
选择逻辑:fanout 过大时某一级单元的 Delay 增量会比同类单元大好几倍(输出要同时充很多负载电容),修法是插 buffer 或换大驱动单元,OpenROAD 的 resizer 这一步是自动做的;逻辑级数过多时报告里单元行数一长串、每级增量都不夸张但累起来超预算,这是 RTL 结构问题,靠重定时(retiming,把寄存器边界挪进组合逻辑中间)或重综合拆逻辑,见 综合重定时实战;约束过紧(比如本篇实验故意写的 0.1 ns)则根本不是电路问题,把时钟放回真实目标即可。setup 方向的手段还有换低阈值电压单元等,可对照 setup 违例修复手段;注意别和 hold 违例混淆——hold 的修法(插延迟单元)恰好相反,见 hold 违例 buffer 插入。
还有一条经验:修 setup 时盯着 worst slack 修到正就停手是常见误区。worst 转正往往只说明「最差的那条」过了,次差的可能只差 0.01 ns,下个 corner 或温度一变又翻回去。工程上要留 margin——修完后用 report_checks -slack_max 0.1 之类的阈值把「接近不过」的路径也扫一遍,别只盯汇总数。
如果 worst slack 缺得很大(比如超过周期的 20%),基本不用怀疑是 buffer 不够——那是结构级问题,直接走重定时或约束评审;缺得小(百分之几的周期)才轮到换单元、插 buffer 这类网表级手段。缺口大小本身就是归因信息。
四、修复验证:放宽约束后重跑
本次实验的「修复」是把 create_clock -period 0.1 改回 20 ns(小计数器在 sky130 下的真实合理目标),重跑同一条 report_checks:
20.00 20.00 clock clk (rise edge)
0.00 20.00 clock network delay (ideal)
-1.00 19.00 output external delay
19.00 data required time
---------------------------------------------------------
19.00 data required time
-0.39 data arrival time
---------------------------------------------------------
18.61 slack (MET)
worst slack 18.61对比修复前后两份报告有个细节值得注意:worst 路径本身变了——修复前 worst 是 _45_ → _51_ 的三级组合路径,修复后 worst 变成 _45_ → q[0] 的输出路径。因为 worst slack 永远报「当前约束下最紧张的那条」,约束放宽后原来的瓶颈不再是瓶颈,报告自然换了一条。判断收敛不要看路径名变没变,只看末尾 worst slack 是不是非负。真实项目里如果用插 buffer / 重定时修,验证方式完全一样:改完重跑 STA,盯死这一个汇总数。
实验环境
- 机器/系统:云主机 16C32G / Ubuntu 22.04(eda-golden-v1 镜像,预装 OpenLANE 2023 版流程 + OpenSTA 2.4.0,PDK sky130A)
- 工具版本:OpenSTA 2.4.0(efabless/openlane 镜像 d054702b 内嵌)
- 日期:2026-10-24
- 完整命令:
docker run --rm -v /tmp/errlog-evidence:/tmp/errlog-evidence -v /home/ubuntu/.volare:/home/ubuntu/.volare efabless/openlane:d054702b2cce04761cc2bc598f6b95c9d8ca7c6c-amd64 sta -no_init -exit /tmp/errlog-evidence/src/c8_err.tcl(违例复现),同路径换c8_fix.tcl(放宽周期后验证)
这一篇在知识体系里的位置
本篇是开源 EDA 排错簇中「时序分析」节点的速查页:上游是 OpenROAD STA 报告解读(报告格式通用读法)与 综合约束 SDC 编写(约束怎么写才对);下游分两条线——setup 方向的手段清单见 setup 违例修复手段,签核阶段的完整 STA 流程见 PrimeTime 签核 STA;如果报告里根本没有 clk 组路径、全是 unconstrained,那是另一类问题,去看姊妹篇 unconstrained endpoint 排查。
一句话总结
slack (VIOLATED) 的账就一行:slack = data required time - data arrival time,负多少就是建立时间差多少;读报告先定 Path Group、再沿 arrival 段找 Delay 增量异常的单元归因——fanout 过大插 buffer、逻辑级数过多做重定时/重综合、约束过紧把时钟放回真实目标;改完重跑 STA,worst slack 转正即收敛,路径名变了不用慌,那是约束放宽后瓶颈自然换了一条。