3、UPF基础:统一功耗格式(UPF)介绍、电源域定义、电源状态表(PST)、电平转换器(Level Shifter)与隔离单元(Isolation Cell)

好,咱们今天聊聊UPF。说实话,我刚入行那会儿,功耗设计还是个“锦上添花”的活儿。现在呢?你不做低功耗,芯片根本没法用。UPF就是用来描述这些功耗意图的标准语言。

3.1 统一功耗格式(UPF)是什么?

UPF,全称Unified Power Format。说白了,它就是一套告诉EDA工具“你的芯片该怎么供电、怎么关电”的脚本。你想想看,一个芯片里可能有几十个电压域,有的1.0V,有的0.8V,有的干脆关掉。靠人工去管?不现实。

UPF最早由Synopsys推动,后来成了IEEE 1801标准。我个人习惯用UPF 2.0版本,够用且稳定。它的核心思想就四个字:电源意图。你不需要在RTL里写电源逻辑,UPF帮你搞定。

核心要点:UPF不是硬件描述语言,它是功耗约束文件。综合、布局布线、仿真、验证,全都靠它。

3.2 电源域定义

电源域(Power Domain)是UPF里最基本的概念。一个电源域就是一组逻辑单元,它们共享同一个供电网络。比如CPU核是一个域,GPU是另一个域,SRAM可能又是一个域。

定义电源域,用create_power_domain命令。举个例子:

create_power_domain PD_CPU -elements {u_cpu_top}
create_power_domain PD_GPU -elements {u_gpu_top}
create_power_domain PD_SRAM -elements {u_sram_top}

这里有个坑——边界问题。电源域之间的信号穿越,必须经过特殊处理。我在项目中遇到过,两个域之间直接连信号,结果仿真时X态满天飞。为什么?因为一个域断电了,另一个域还在工作,信号电平乱掉了。

我的经验:定义电源域时,尽量把相关的逻辑放在同一个域里。跨域信号越少,后期头疼的地方越少。

3.3 电源状态表(PST)

电源状态表(Power State Table)定义了芯片在不同工作模式下,各个电源域的电压状态。比如:

  • 正常模式:CPU 1.0V,GPU 1.0V,SRAM 1.0V
  • 待机模式:CPU 0.8V,GPU 0.0V(关断),SRAM 1.0V(保持)
  • 休眠模式:CPU 0.0V,GPU 0.0V,SRAM 0.8V(保留)

用UPF写出来是这样的:

add_power_state PD_CPU.state_normal -state {0.9 1.1}
add_power_state PD_CPU.state_sleep -state {0.0 0.0}
add_power_state PD_GPU.state_normal -state {0.9 1.1}
add_power_state PD_GPU.state_off -state {0.0 0.0}

create_pst pst_main -supplies {VDD_CPU VDD_GPU}
add_pst_state normal -pst pst_main -state {normal normal}
add_pst_state sleep -pst pst_main -state {sleep off}

嗯,这里要注意:PST里的电压值通常是范围,不是固定值。因为实际芯片有IR Drop,电压会波动。你写死一个值,工具反而会报错。

避坑指南:我曾经把PST里的电压写成了精确值,结果综合工具死活不认。后来查手册才发现,必须写成范围。记住:-state {0.9 1.1} 而不是 -state 1.0

3.4 电平转换器(Level Shifter)

两个不同电压的域之间传信号,必须用电平转换器。比如CPU域是1.0V,GPU域是0.8V,信号从CPU到GPU,高电平是1.0V,GPU的输入可能就识别不了。电平转换器就是干这个的。

UPF里用set_level_shifter来指定:

set_level_shifter LS_CPU2GPU -domain PD_CPU -applies_to inputs -rule low_to_high -location self

这里-applies_to inputs表示在接收端插入电平转换器。-rule low_to_high表示从低电压域到高电压域。反过来也一样。

我个人习惯把电平转换器放在接收端。为什么?因为发送端的驱动能力通常更强,放在接收端可以减少对发送端的影响。当然,这也不是绝对的,具体看你的设计。

小技巧:电平转换器会引入延迟。如果你在关键路径上用了它,记得重新做STA。我有个项目就是忘了这茬,结果时序崩了。

3.5 隔离单元(Isolation Cell)

隔离单元解决的是另一个问题:当一个域断电时,它的输出信号会变成X态。如果这个信号连到了另一个还在工作的域,那接收域的逻辑就会乱掉。隔离单元的作用就是:在断电时,把输出钳制到一个确定的值(通常是0或1)。

UPF里用set_isolation来定义:

set_isolation ISO_CPU -domain PD_CPU -applies_to outputs -clamp_value 0 -location self

这个命令的意思是:在PD_CPU域的输出端插入隔离单元,断电时输出钳位到0。

你可能会问:钳位到0还是1?这取决于你的设计。如果接收端是低电平有效,那钳位到1更安全。如果接收端是高电平有效,那钳位到0更合适。没有标准答案,看具体场景。

关键点:隔离单元和电平转换器经常一起用。先隔离,再电平转换。顺序不能乱,否则隔离单元本身可能因为电压不匹配而失效。

3.6 实战中的注意事项

好了,理论讲完了。我分享几个实战中的坑:

  1. UPF和RTL要同步:RTL改了,UPF必须跟着改。我见过有人改了RTL忘了改UPF,结果仿真通过,流片回来功耗不对。
  2. 仿真验证不能省:UPF的仿真和功能仿真不一样。你得用带UPF的仿真器(比如VCS的Power-Aware模式),否则隔离和电平转换的行为看不到。
  3. 工具版本要匹配:不同版本的EDA工具对UPF的支持程度不一样。我建议用同一个工具链,避免兼容性问题。
  4. 文档要写清楚:UPF文件里最好加注释,说明每个电源域的作用、每个状态的含义。不然三个月后你自己都看不懂。

血的教训:我曾经在一个项目里,UPF里忘了给某个跨域信号加隔离单元。仿真时没发现,因为那个域一直没断电。结果流片回来,一测低功耗模式,整个芯片死机。查了三天才找到原因。从那以后,我每次都要做一遍“断电仿真”,确保所有跨域信号都处理好了。

3.7 小结

UPF是低功耗设计的基石。电源域定义、PST、电平转换器、隔离单元,这四个东西你搞明白了,大部分低功耗场景都能应付。记住:UPF不是写完了就完事的,它需要和RTL、综合、布局布线、仿真全流程配合。每一步都验证一遍,才能保证芯片在低功耗模式下正常工作。

下一章咱们聊聊更进阶的内容——多电压域的动态电压频率调整(DVFS)。到时候我会分享一些实际项目中的调优经验。