第二章:静态时序分析基础

各位同学,今天我们来聊聊静态时序分析。说实话,我刚入行那会儿,觉得STA就是个跑脚本的工具,跑完看个报告就完事了。直到有一次,我负责的一个芯片在post-sim阶段发现时序违例,折腾了两周才找到根因——从那以后,我才真正重视起STA的基础概念。

静态时序分析,说白了就是检查你的芯片能不能跑在目标频率上。它不像动态仿真那样需要输入激励,而是穷举所有可能的路径,计算信号从起点到终点需要多长时间。嗯,这里要注意:STA只检查时序,不检查功能。

2.1 STA的基本概念

静态时序分析的核心,就是回答三个问题:

  • 信号什么时候到?—— arrival time
  • 信号最晚什么时候必须到?—— required time
  • 有没有余量?—— slack

如果slack是负数,说明时序违例了。我见过不少新手看到负slack就慌了,其实有时候是约束没写对。我个人习惯是先检查约束,再查路径。

关键公式:

slack = required time - arrival time

slack > 0 → 满足时序

slack < 0 → 时序违例

你想想看,STA为什么叫"静态"?因为它不需要动态仿真,而是基于网表和时序库进行静态分析。这意味着它速度快、覆盖全,但缺点是不能检测功能错误。

2.2 时序路径类型

在STA中,我们把路径分成四类。我记得刚学的时候总是搞混,后来画了个图才理清楚。

时序路径分类 路径1:输入到寄存器 input port → D pin of FF 路径2:寄存器到寄存器 CK pin of FF → D pin of FF 路径3:寄存器到输出 CK pin of FF → output port 路径4:输入到输出 input port → output port 路径类型说明 • 路径1和路径3:涉及I/O接口,需要set_input_delay/set_output_delay约束 • 路径2:最核心的路径,占芯片中90%以上的时序路径 • 路径4:纯组合逻辑路径,通常需要加约束或插入寄存器

这四种路径中,寄存器到寄存器是最常见的,也是我们优化的重点。我曾经在一个项目中,发现某条寄存器到寄存器的路径slack只有5ps,差点就违例了。后来通过调整逻辑级数和优化cell size才搞定。

2.3 建立时间与保持时间

这两个概念是STA的基石。说白了:

  • 建立时间(setup time):数据必须在时钟有效沿之前稳定下来的时间
  • 保持时间(hold time):数据必须在时钟有效沿之后保持稳定的时间

我的经验:setup violation通常可以通过降低频率或优化逻辑来解决;但hold violation一旦出现,往往意味着芯片已经流片了才发现——那就只能祈祷了。所以我在做后端时,对hold time格外小心。

为什么会这样?因为setup和hold的检查方式不同:

检查项 检查条件 违例后果 修复方法
Setup time 数据路径延迟 < 时钟周期 - 建立时间 芯片频率上不去 降频、优化逻辑、加流水线
Hold time 数据路径延迟 > 保持时间 芯片功能错误 加buffer、调整时钟树

嗯,这里有个容易混淆的地方:setup检查的是同一个时钟沿的下一周期,而hold检查的是同一个时钟沿。你想想看,setup关心的是数据能不能在下一个时钟沿之前准备好,而hold关心的是数据会不会在当前时钟沿之后被冲掉。

避坑指南:我曾经遇到过一个案例,综合后的setup slack是正的,但hold slack是负的。当时觉得hold违例没关系,反正后端可以修。结果后端工程师告诉我,hold违例太严重,需要加大量buffer,导致面积暴增20%。从那以后,我学会了在综合阶段就要关注hold time。

2.4 时序分析的流程

STA的流程其实不复杂,我总结为三步:

  1. 读入数据:网表、时序库(.lib)、约束文件(.sdc)
  2. 计算时序:工具自动计算每条路径的arrival time和required time
  3. 生成报告:输出slack、违例路径、关键路径等信息

在实际项目中,我一般会先跑一遍STA,看看有没有明显的违例。如果有,先检查约束是否正确——我见过太多因为约束写错导致的"假违例"。

一个典型的STA命令示例:

# 读入网表和库
read_verilog top_netlist.v
read_lib -liberty slow.lib

# 读入约束
read_sdc top_constraints.sdc

# 检查时序
report_timing -nworst 10 -path_type full
report_timing -delay_type min -nworst 10  # 检查hold

你可能会问,为什么要有slow.lib和fast.lib?因为芯片在不同工艺角下表现不同。slow.lib对应最差情况(温度高、电压低),用于检查setup;fast.lib对应最好情况(温度低、电压高),用于检查hold。

好了,关于STA的基础概念就讲到这里。记住:setup看的是能不能跑得快,hold看的是能不能跑得稳。两者缺一不可。

个人习惯:每次做完一个模块,我都会先跑一遍STA,哪怕只是粗略看看。这就像出门前照镜子——花不了几分钟,但能避免很多尴尬。

可可精品资料库