JOVANA
Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

寄生参数与签核时序

在前端课程里,你是在理想导线上检查时序的——零电阻、零电容、信号瞬间到达。可真实的金属并不理想:每一根导线都有让电流变慢的电阻,也有必须先充满电的电容,而这份拖累如今已是延迟里最大的一块。这一篇,就是时序动真格的地方。你会把这些寄生参数提取出来,在最糟糕的工艺-电压-温度角下重新检查时序,针对片上变异做降额,读懂签核后的裕量数字,再用 ECO 反复迭代,直到芯片可以安全出货。

纸上谈兵 vs 硅上见真章

在数字前端课程里,你检查时序的方式,就像城市规划师对着一张崭新蓝图估算行车时间:每条路都笔直、平整,车流都跑在限速上。那时的导线是理想的——没有电阻、没有电容,信号从一个门瞬间蹦到下一个门,毫无拖滞。对于入门来说,这种简化是对的,也大致是你的工具在设计还没布局、还没布线之前所做的假设。可硅片不是蓝图,它是一座有真实道路的真实城市。

一旦你的设计被实实在在地造了出来——单元布局好了,导线在层层堆叠的金属层布线好了——每根导线都成了一个真实的、有形的东西,带着两个甩不掉的特性。它有电阻(R):金属会阻挠电流的流动,就像一根细管掐住水流。它也有电容(C):导线和它的邻居会储存电荷,就像一只你必须先灌满的水桶,远端的电压才会升起来。要把一根导线从 0 翻到 1,你不是在拨一个比特——你是在透过一根管子去灌满一只水桶。这要花时间,而这段时间如今就是你延迟的一部分。

寄生参数提取(R 与 C)

寄生参数提取这一步,把你完成的版图变成数字。提取工具会读取每一根已布线导线的精确几何形状——它有多长、多宽、跑在哪一层金属层上、离邻居有多近——再算出每一段的电阻和电容。想象你拿着卷尺量遍城里的每一条路,把每条路有多窄、多长都记下来;提取要一次性对几百万段导线做这件事,而且依据的是实际建成的版图,而不是估算。

结果会被写进一个标准文件,叫做 SPEF(标准寄生参数交换格式)。你可以把它看成你芯片布线的竣工测绘:一张巨大的表格,写着*这条网络有这么多 R、这么多 C,分布在这些线段上*。关键在于,这是布线后的数据——它反映的是真正存在的导线,而不是工具在布局时用的那个粗略估计。正是这份 SPEF,让下一步变得货真价实。

# Extraction consumes the routed layout + a parasitic model, emits SPEF
extract_parasitics \
    -layout    routed.def \
    -tech      rc_corner.techfile \
    -output    design.spef     ;# R + C per net, fed into signoff STA

# A SPEF line, simplified: net 'clk_buf_out' carries ~12 fF of C and ~8 ohm of R
# *D_NET clk_buf_out 12.4   ;# total cap in femtofarads
提取会读取实际建成的布线和每个工艺角的 RC 模型,然后写出一份 SPEF。这个文件就是物理版图与时序工具之间的桥梁。

为什么布线后的时序才是真正的时序

现在,我们把那份 SPEF 喂回静态时序分析。还记得前端课程里那张 f_max 的图景吗?你能跑的最快时钟大致是:

f_max = 1 / (t_clk-to-q + t_logic + t_setup - t_skew)
和前端课程里是同一条公式。变的是 t_logic:它现在把提取得到的真实 R-C 导线延迟也算了进去,而不再只是门延迟。导线终于要花时间了。

在前端课程里,t_logic 只是路径上的门延迟,因为那时导线是理想的——瞬间传导。现在你提取了寄生参数,t_logic 也背上了真实的导线延迟:沿途每一次透过管子灌满水桶。在先进节点上,导线那一部分可能占主导。同一条路径,在理想导线上看着还很宽裕,一旦把金属算进来,就可能把预算撑爆。这不是意外;这正是关键所在。

这正是为什么布线后、考虑寄生参数的 STA 才是权威的时序检查——是真正算数的那一个。基于估算导线的布线前时序是有用的早期指引,就像开车前先在地图上看一眼路线。可地图并不知道路上的施工、坡道和车流。只有实际建成的数字,才能告诉你芯片到底能不能满足它的时钟。这之前的一切都是排练;[[timing-signoff|签核]]才是正式演出。

工艺角:PVT 与 MMMC

问题在这儿:产线上没有两颗芯片是一模一样的,也没有哪颗芯片只在单一环境里运行。有三样东西会变,合起来叫 PVT工艺(Process,P):制造的离散性让晶体管做出来或快一点或慢一点——这就是*快*工艺角和*慢*工艺角。电压(Voltage,V):供电会略微下垂或抬升;电压越低,晶体管越慢。温度(Temperature,T):温度会改变晶体管开关的快慢。一个工艺角,就是这几样的某一种特定的最坏组合——一个你的芯片必须挺过去的具名情景。

为什么要查工艺角,而不是只跑一次标称值?因为你出货的不是一颗芯片——而是几百万颗,进到滚烫的手机里、冰冷的服务器里,落在体质好的硅片上、也落在勉强及格的硅片上。如果时序只在典型情况下收敛,那现场就会有相当一部分器件失效。所以你要查的是极端。这里的关键洞见是:建立时间和保持时间会在*相反*的工艺角失败:

  1. 建立时间(数据到得太晚)在角最糟——慢工艺、低电压,再加上让那条路径最慢的那个温度。如果数据在这里都能赶到,那它在哪儿都能赶到。
  2. 保持时间(数据到得太早,抢在捕获沿之前冲了过去)在角最糟——快工艺、高电压。对保持时间来说,体质快的硅片才是*危险*的那一种,因为数据会一路狂奔,可能反超时钟。
  3. 每个工艺角都配上与之匹配的提取 SPEF——慢角的建立时间检查配慢 RC 导线,快角的保持时间检查配快 RC 导线——这样导线延迟才和晶体管速度保持一致。

一个工艺角一个工艺角地这么查,又慢又容易出错,所以签核用的是 MMMC——多模式多工艺角(Multi-Mode Multi-Corner)。*多工艺角*就是上面那一摊 PVT 的分布。*多模式*指的是你芯片的不同工作模式——全速模式、低功耗模式、测试模式——每一种都有自己的时钟设置和约束。MMMC 会在一次分析中,让每一种模式都对上每一个相关的工艺角,这样一个对某个情景有帮助的修改,就没法悄悄地把另一个情景弄坏。你签核的不是一颗芯片;你签核的是模式 × 工艺角的整张网格。

# An MMMC setup pairs each timing 'view' with its corner + SPEF + constraints
create_clock -name clk -period 1.0 [get_ports clk]   ;# 1 ns => 1 GHz target

# slow corner drives the SETUP check (data must still arrive in time here)
create_view  view_slow  -corner ss_0p72v_125c  -spef slow.spef  -check setup
# fast corner drives the HOLD check (data must NOT race ahead here)
create_view  view_fast  -corner ff_0p88v_m40c  -spef fast.spef  -check hold
一段不依赖具体厂商的示意:建立时间在慢角签核,保持时间在快角签核,各自配上与之匹配的 SPEF。ss/ff = slow-slow / fast-fast(慢-慢 / 快-快);数字是供电电压和温度。

片上变异

工艺角管的是芯片*之间*的变异。但变异也会发生在*同一颗芯片内部*:两个一模一样的单元并排放着,开关速度也不会完全一样,原因在于掺杂、线条边缘、局部发热和供电上的微观差异。这就是[[on-chip-variation|片上变异]],即 OCV。同一个时钟沿,可能比邻居早那么一丁点抵达某个触发器,哪怕布线看上去是对称的。给整片晶圆只挑一个工艺角的数字,就会无视这一点——而假装芯片上每个单元都一模一样,恰恰是那种会让芯片从晶圆厂坏着回来的乐观。

对策是降额(de-rating):刻意地、悲观地去调整延迟,让分析假设的是那个倒霉的情况。对建立时间检查,你把数据路径调得比标称值一点,把捕获时钟路径调得一点——从两头一起挤压预算。对保持时间检查,你把它反过来:发射路径跑得快,捕获时钟跑得慢,把任何竞争都暴露出来。你同时对两边都施加这份怀疑,这样这条路径就必须挺过最坏的、合乎情理的失配,而不只是平均情况。

# Classic OCV: de-rate late paths slower, early paths faster (worst-case both ways)
set_timing_derate -late   1.05    ;# late paths run +5% slower than nominal
set_timing_derate -early  0.95    ;# early paths run -5% faster than nominal
一个简单的 OCV 降额。现代流程会用 AOCV/POCV 来把它做得更精细——降额量会随路径变长而缩小(随机变异会被平均掉),并用统计分布来取代单一的固定数值——但思路是一样的:把悲观预先内建进去,好让硅片的变异吓不到你。

裕量,签核定案

在提取、所有工艺角、所有模式以及 OCV 降额都做完之后,每一项时序检查最终仍会收拢到你在前端课程里见过的那一个数字——只不过这一次,它是挣来的裕量,就是信号*被要求到达*的时刻与它*实际到达*的时刻之间的余量:

slack = required - arrival       ;# must be >= 0 to sign off

#  slack > 0  : pass, with margin to spare
#  slack = 0  : exactly on the deadline
#  slack < 0  : FAIL — the path violates timing at this corner
每条路径的判决。设计里最差的那一个裕量就是 WNS(最差负裕量,worst negative slack);所有违例加起来就是 TNS(总负裕量,total negative slack)。

签核的规则既不留情面又很简单:在每一条路径、每一种模式、每一个工艺角、加上 OCV 之后,建立时间和保持时间的裕量都必须 ≥ 0。这张网格里只要哪儿出现一个负数,芯片就没签核通过。最差的那一个裕量是 WNS(最差负裕量);所有失败路径加总起来是 TNS(总负裕量)。WNS 告诉你最差那条路径有多糟;TNS 告诉你到底有*多少*条路径在受伤。两个你都要看。

收敛闭环与 ECO

万一签核查出了负裕量怎么办?你不会从头把整个布局布线重做一遍——到了这个阶段,版图大体上已经干净、已经DRC正确了,你也不想去惊动那成千上万条已经通过的路径。你要做的,是一处微小而精准的改动:一个 [[engineering-change-order|ECO]](工程变更单,Engineering Change Order)。ECO 是对网表和版图的一次最小限度的修改,它在修好违例的同时,尽可能少地碰到其它东西——就像连夜补好一条裂开的路,而不是把整座城市重建。

典型的 ECO 手法:把一个单元换成更快(驱动能力更强)的型号,把建立时间的裕量赢回来;或者插入一个延迟缓冲器,靠拖慢一条太心急的路径,来修掉保持时间的违例。工具会在出问题的单元附近找到空位,只对它扰动到的那几条网络重新布线。然后——而这正是让它成为一个*闭环*的地方——你要针对改动过的部分重新提取寄生参数,并重跑签核 STA,因为你的修改自己也带来了新的导线、新的 RC。只有重新提取之后,那些数字才是真的。

  1. 跑一遍完整的签核 STA——提取的寄生参数、所有模式、所有工艺角、加上 OCV——把每一条带负裕量的路径都收集起来(按 WNS 从最差的排起)。
  2. 生成一个针对这些违例的 ECO:为建立时间调整单元尺寸或更换单元,为保持时间插入延迟缓冲器,并挑选那些不会弄坏已通过路径的修法。
  3. 把这个 ECO 应用到网表和版图上,只对改动过的单元和网络做布局和布线。
  4. 对受影响的部分重新提取寄生参数——这次修改挪动了金属,RC 也就变了——再写出一份新的 SPEF。
  5. 重跑签核 STA。确认被针对的那些路径现在通过了,而且这次修改没有把邻近的某条路径推成负的。
  6. 如此反复,直到在每一种模式、每一个工艺角下,建立时间和保持时间的 WNS 都 ≥ 0。此时时序就收敛了——设计便可以朝着物理验证和流片推进。