3. 设计导入与约束检查

功耗感知时序优化的第一步不是急着跑 fix_eco_power 或 optimize_power,而是把设计"喂"进 PrimeTime 并确认约束是可信的。如果网表、寄生参数或 SDC 有任何一处不完整,后续所有功耗与时序的权衡都建立在错误前提上——工具可能报告"功耗已降低 12%",而实际上它只是把大量路径判成了 false path 或未约束路径,根本没有真正优化。

读取网表与寄生参数:三种输入缺一不可

PrimeTime 的功耗分析依赖三类输入:门级网表(.v)、标准单元与宏单元的库文件(.db)、以及寄生参数文件(SPEF 或 DSPF)。网表提供连接关系,库文件提供每个单元的功耗查找表(internal power)、漏电功耗(leakage power)和时序弧,寄生参数提供互连的电阻电容,决定线延迟与线功耗。

典型导入命令如下:

set link_path "* /libs/stdcell_tt_0p8v_25c.db \
                 /libs/sram_2048x32_tt_0p8v_25c.db"
read_verilog ./netlist/top_place_opt.v
current_design top
link_design

read_parasitics -format spef ./spef/top_place_opt.spef
report_annotated_parasitics -check

这里有两个容易出错的点。第一,link_path 中的库必须与网表里实例化的单元名完全匹配,否则 link_design 会报 "unresolved reference",未链接的单元不参与功耗计算,总功耗会被严重低估。第二,SPEF 必须与当前网表版本对应;如果网表在 place_opt 之后又做过增量改动,而 SPEF 还是旧版本,寄生标注会错位。用 report_annotated_parasitics -check 可以查看标注覆盖率,正常情况下应接近 100%,若出现大量 "not annotated" 的 net,说明 SPEF 与网表不匹配或存在层次名不一致。

对于功耗优化,还要特别关注 SPEF 中的耦合电容。PrimeTime 默认按总电容计算,若需要更精确的串扰感知功耗,可在读入时保留耦合信息,并在报告中区分 ground capacitance 与 coupling capacitance。线功耗对总电容敏感,而耦合电容是否计入会直接影响互连功耗的绝对值。

SDC 约束完整性验证:先保证"约束是真的"

SDC 是功耗优化的边界条件。时钟频率、输入输出延迟、多周期路径、false path 共同决定了哪些路径需要被优化、哪些可以被放松。一个常见误区是:为了"降低功耗",把大量路径设成 false path 或放宽时钟,工具确实不再优化这些路径,功耗数字下降,但设计功能已经失效。因此导入 SDC 后必须做完整性检查。

建议按以下顺序核查:

  • check_timing:检查是否存在未约束的时钟、未约束的端点、组合环、锁存器穿透等问题。重点关注 "no_clock" 和 "unconstrained_endpoint" 两类。
  • report_clock 与 report_clock_transition:确认每个时钟的周期、波形、不确定性(uncertainty)和转换时间是否与规格一致。时钟周期直接决定动态功耗上限,周期越紧,工具越倾向于用高驱动、大尺寸单元,功耗越高。
  • report_input_delay / report_output_delay:确认 I/O 延迟是否覆盖了外部器件的真实时序要求。I/O 延迟过松会让工具把边界路径当作容易满足,从而减少缓冲,功耗下降但接口时序可能不达标。
  • report_exceptions:列出所有 false path、multicycle path、max/min delay。逐条确认其来源和必要性,尤其警惕从旧版本继承下来的、已经失效的 exception。

一个实用的判断标准是:如果 check_timing 报告未约束端点数为 0、未约束时钟数为 0,且 report_exceptions 中每条 exception 都能对应到设计规格或接口协议,那么 SDC 可以认为是完整的。否则应先补齐约束,再进入功耗优化。

时钟与 I/O 延迟如何影响功耗优化

时钟周期和 I/O 延迟不是"背景参数",它们直接改变功耗优化的搜索空间。可以用一个简单的关系来理解:动态功耗近似为 P ≈ α·C·V²·f,其中 f 由时钟周期决定,α 是翻转率,C 是开关电容。时钟周期越短,工具为满足建立时间会倾向于增大单元尺寸、插入更多缓冲,C 增大,功耗上升;反之,周期放宽后工具可以用更小的单元,功耗下降,但性能余量也随之减少。

I/O 延迟的影响更隐蔽。输入延迟决定了输入端口到第一级寄存器的路径预算,输出延迟决定了最后一级寄存器到输出端口的预算。如果输入延迟设得过小(即外部要求很紧),工具会在输入路径上插入缓冲或增大驱动,增加功耗;如果设得过大,工具可能完全不优化这些路径,功耗降低但接口时序存在风险。因此,在功耗优化前应确认 I/O 延迟来自真实的接口时序分析,而不是随手填的默认值。

在功耗优化前后各跑一次 report_power,并对比 report_timing 的 WNS/TNS。只有当功耗下降且 WNS/TNS 没有恶化到违反约束时,优化才算有效。若功耗下降但出现新的时序违例,说明优化把功耗压力转移到了关键路径上。
设计导入与约束检查 → 功耗优化影响链 门级网表 .v 连接关系 / 单元实例 库文件 .db internal / leakage / 时序弧 寄生参数 SPEF R / C / 耦合电容 SDC 约束 时钟 / I/O 延迟 / exception link_design 链接检查 unresolved reference = 0 寄生标注覆盖率检查 annotated ≈ 100% check_timing no_clock / unconstrained = 0 report_exceptions 审查 false / multicycle 逐条确认 时钟周期 → 动态功耗 周期紧 → 大尺寸/多缓冲 → C↑ → P↑ 周期松 → 小尺寸 → C↓ → P↓ I/O 延迟 → 边界路径优化 延迟紧 → 插缓冲/增驱动 → P↑ 延迟松 → 少优化 → P↓ 但接口风险↑ 功耗优化结果判读 report_power 下降 且 WNS/TNS 不恶化 → 有效优化;否则需回查约束 若结果异常,回查网表/SPEF/SDC 一致性

一个可复用的导入检查清单

把上述检查固化成脚本,可以在每次设计导入后快速执行。以下清单可直接作为检查表使用:

检查项 命令 / 方法 通过标准 不通过时的处理
网表链接 link_design 无 unresolved reference 检查 link_path 库版本与单元名
寄生标注 report_annotated_parasitics -check 标注率接近 100% 核对 SPEF 与网表版本、层次名
时钟约束 check_timing no_clock = 0 补 create_clock / create_generated_clock
端点约束 check_timing unconstrained_endpoint = 0 补 set_input_delay / set_output_delay
例外审查 report_exceptions 每条 exception 有设计依据 删除失效的 false / multicycle path
功耗基线 report_power 记录 total / dynamic / leakage 作为优化前基线,供后续对比

完成以上检查后,设计才具备进入功耗优化的条件。此时应保存一份基线报告,包括 report_power 的总功耗、动态功耗、漏电功耗,以及 report_timing 的 WNS 和 TNS。后续每次功耗优化后都与这份基线对比,才能判断优化是否真正有效,而不是被约束错误或标注缺失造成的假象所误导。