ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

低功耗设计绕不开的UPF:电源域、隔离与保持策略全解析

低功耗设计绕不开的UPF:电源域、隔离与保持策略全解析 做低功耗设计的工程师尤其是刚接触数字后端或者开始折腾先进工艺项目的朋友大概率都绕不开两个词低功耗和UPF。我最早看UPF的时候也懵一堆create_power_domain、set_isolation、set_retention的命令堆在一起不知道和RTL代码里那些always块、门控时钟到底是什么关系也不知道这东西到底该谁写、写到什么程度后端才能用。这文章我想换个方式聊不按用户手册的顺序一条条念命令而是从一个实际项目的角度把低功耗设计和UPF串起来讲清楚包括它是怎么诞生的、里面每个核心概念替我们解决了什么物理问题、写的时候常见坑在哪儿。无论你是刚接手低功耗项目的数字前端还是准备开始接触UPF的后端工程师这篇应该能帮你少走一些弯路。1. 低功耗设计到底在设计什么低功耗不是一个功能而是一整套在性能、面积、功耗之间找平衡的约束体系。芯片的功耗大致分两类动态功耗和静态功耗。动态功耗来自电路翻转时对负载电容充放电还有短路电流静态功耗主要是漏电先进工艺下漏电占比越来越高甚至成为待机场景下的主要矛盾。解决动态功耗常见手段是时钟门控也就是把没事干的寄存器时钟关掉这在设计里已经是标配操作工具也会自动插入。解决静态功耗核心思路是断电把不工作的模块电源直接切掉但断电带来一个新问题模块关了里面的寄存器状态没了再开起来怎么办所以又有了状态保持策略用更省电的电源域单独给需要保活的寄存器供电。这一套动作如果全靠RTL代码和手工处理几乎没法维护于是UPF成了低功耗设计的标准描述载体。需要说明的是这里的UPF是Unified Power Format是芯片设计里描述电源意图的标准格式后来被IEEE吸收为1801标准。它和我们平时搜索时偶尔看到的5G核心网里的UPFUser Plane Function完全是两码事那个是通信网元做包转发和会话管理的别搞混了。低功耗设计本身也不是什么新技术但UPF把“电源设计意图”从RTL阶段一路流到后端实现、时序收敛和功耗分析让前端和后端有了一个统一语言这才是真正的价值所在。通常行业里也会提到CPFCommon Power Format那是Synopsys之外的另一种格式现在基本都统一到UPF上了。1.1 一个没有UPF的低功耗项目会是什么样子没有UPF的年代后端工程师处理多电源域的办法很原始前端告诉后端哪个模块要常开、哪个要关断、哪个要隔离全靠文档和邮件然后后端拿着一张纸去手动约束库单元的电源连接关系。前端改了设计后端可能根本不知道导致隔离单元插错位置、电平转换漏插芯片跑起来直接漏电或者逻辑乱套。而且没有UPF时验证也很痛苦。仿真时没法模拟模块断电后信号的行为隔离输出呈现X态后面一堆逻辑全被X污染根本无法定位问题。有了UPF之后仿真工具能理解电源域的状态断电时知道该输出什么、什么时候输出有效验证效率完全不在一个量级。所以UPF解决的本质问题是把功耗设计意图从“人脑里的想法”变成“机器可读的、可验证的、可实现的规格”。1.2 常见低功耗手段和UPF的对应关系先看一张对应关系表把设计手段和UPF概念对应起来后面展开讲就不会觉得UPF里的概念是空中楼阁。设计需求物理解决方案UPF核心概念模块可以断电电源开关create_power_switch断电后输出不能悬空隔离单元set_isolation关键状态需要保持常开电源域/保持寄存器set_retention不同电压域接口转换电平转换单元set_level_shifter定义电压域和供电关系电源域/供电网络create_power_domain/create_supply_net/connect_supply_net这张表建议保存下来写UPF的时候每次回头对照一下就不容易丢东西。2. UPF的核心概念拆解UPF文件本身是文本格式语法接近Tcl但别被它长得像脚本这点骗了。它描述的不是行为逻辑而是电源架构图是物理实现意图。理解UPF最重要的是建立“电源域”这个空间思维。2.1 电源域Power Domain是UPF的第一原则电源域是一个逻辑和物理的集合把一组需要同吃同住、同开同关的单元划在一起。举个例子一个AI芯片里NPU计算阵列、SRAM、控制逻辑这三个模块供电策略可能完全不同。NPU计算阵列可以整块断电SRAM的部分bank需要保持数据控制逻辑必须一直活着。UPF里就用三个power domain把它们分开描述。创建电源域的命令是create_power_domain典型写法是create_power_domain PD_TOP create_power_domain PD_NPU -elements {npu_core npu_mem} create_power_domain PD_CTRL -elements {ctrl_logic}-elements可以指定模块路径的集合。如果没有指定工具会把当前作用域里没被其他domain包含的单元全部归到默认域。这个默认域通常就是顶层常开域也是所有电源的源头。我在实际项目里踩过的一个坑是domain划分边界和RTL模块边界不一样。比如一个模块里既有需要常开的寄存器也有可以断电的逻辑如果简单把整个模块划成可关断域那常开的寄存器会丢电后端的isolation和retention策略就会很难受。正确做法是在RTL里调整层次把需要常开的寄存器单独拉出去或者在UPF里用-elements细化到具体instance路径。2.2 供电网络描述端口、网络和连接UPF里的create_supply_port、create_supply_net、connect_supply_net三个命令配合使用把“哪个电源网络给哪个域供电”说清楚。create_supply_port VDD create_supply_port VSS create_supply_port VDD_NPU create_supply_net VDD -domain PD_TOP create_supply_net VSS -domain PD_TOP create_supply_net VDD_NPU -domain PD_NPU connect_supply_net VDD -port VDD connect_supply_net VSS -port VSS connect_supply_net VDD_NPU -port VDD_NPU这里头有个理解难点网络net和物理端口port不是一回事。create_supply_net创建的是一个逻辑供电网络的名字它需要靠connect_supply_net连到具体的电源端口上工具综合时才会去建立物理连接。如果一个domain里的单元没有被正确的supply net覆盖后端工具会报出大量unconnected或者undefined的电源错误很头疼。另外UPF里还有一个重要概念叫supply set是把正电源和地成对打包描述。比如{VDD VSS}和{VDD_NPU VSS}可以分别定义成两个supply set后续做isolation和level shifter约束时可以直接引用这个集合写起来干净很多。2.3 电源状态表告诉工具什么能开、什么能关create_pstPower State Table是整个UPF里最像“规格说明书”的部分。它列出了系统所有可能的供电状态组合每个组合里各supply set的电压是多少、是开还是关。工具根据这个表去分析哪些信号会跨越不同电源状态从而决定哪些地方需要特殊处理。create_pst pst_chip -supplies {VDD VDD_NPU} add_pst_state normal -pst pst_chip -state {ON ON} add_pst_state npu_off -pst pst_chip -state {ON OFF} add_pst_state all_off -pst pst_chip -state {OFF OFF}电源状态表也是验证功耗意图的重要依据。仿真时工具需要知道当前处于哪个state才能正确模拟断电行为。有些设计会用PST做功耗估算把每个状态下的时间占比和电流加起来算出平均功耗。没有PSTUPF就是不完整的后面综合和PR工具甚至会直接报错。我见过有的团队UPF里PST写得非常简单只写了OFF和ON两种状态结果做功耗分析时漏算了某些中间电压场景比如降电压模式。建议PST的状态要覆盖芯片所有实际工作模式包括active、idle、retention、deep sleep这些而且状态名称最好和系统软件里定义的工作模式一一对应方便后期做功耗校准。2.4 断电之后怎么办隔离、保持、电平转换这部分是UPF最核心、也是最容易出问题的地方。隔离Isolation解决的是“断电域的输出信号悬空”问题。一个可关断域的输出如果直接接到常开域的逻辑断电后输出可能是高阻或不确定态常开域的逻辑会收到乱七八糟的信号引起漏电甚至逻辑错误。所以需要在可关断域的输出路径上插入隔离单元。UPF的命令是set_isolation iso_npu_out -domain PD_NPU -isolation_supply_set {VDD VSS} -clamp_value 0 set_isolation_control iso_npu_out -domain PD_NPU -isolation_signal {iso_ctrl} -isolation_sense high -location self关键参数是-clamp_value确定断电时输出钳到0还是1。我个人的经验是默认情况下能钳0就钳0除非对端模块对复位极性有特殊要求。钳0的好处是逻辑简单、漏电路径明确而且大部分标准单元库里clamp-to-0的隔离单元面积更小。-location参数也很重要。self表示隔离单元放在可关断域内部fanout表示放在接收端常开域一侧。这个选择直接影响后端布局布线和功耗。如果可关断域的输出负载很大fanout方式会更节省关断域的面积和动态功耗但代价是常开域这边必须始终有电而且隔离控制信号要跨越电源域边界时序约束要小心处理。保持Retention解决的是“断电后寄存器状态丢失”问题。有些寄存器在模块休眠时必须记住当前状态比如状态机的主状态、DMA的配置寄存器。UPF里用set_retention描述set_retention ret_npu_cfg -domain PD_NPU -retention_supply_set {VDD_ALWAYS VSS} -elements {npu_cfg_regs} set_retention_control ret_npu_cfg -domain PD_NPU -save_signal {save_n} -restore_signal {restore_n} -save_sense low -restore_sense low实现时工具会把这些寄存器替换成带供电控制脚的 retention flop。这种单元通常有两个电源引脚一个接常开电源一个接可关断电源。仿真时save信号来临前寄存器先把数据锁到常开的影子锁存器里断电恢复后用restore信号把数据灌回去。这里有个容易忽略的细节save和restore信号本身的时序要求。save必须在电源关断之前完成restore必须在电源稳定之后才能释放这些sequence约束往往要前端在SDC或者UPF注释里写清楚否则后端工具不知道应该怎么优化时序。另外retention单元的面积比普通寄存器大不少一个retention flop大概比普通DFF大30%到50%如果你的功耗目标是靠retention方式实现的面积预算要提前留够。电平转换Level Shifter解决的是“不同电压域之间信号电压不匹配”问题。现在很多芯片内部有多个电压域核心逻辑0.8V、IO接口1.8V两个域之间直接连信号肯定不行。UPF里set_level_shifter ls_npu_out -domain PD_NPU -applies_to output -location self -threshold 0.9工具会根据PST里定义的电压值自动判断哪些路径需要插电平转换单元。-threshold参数表示电压差超过多少就需要插。实际项目中如果库里的电平转换单元类型很丰富可以按电压组合分别指定如果库里只有少数几种那-threshold就得谨慎设置设太低了会到处插面积回报差设高了又会漏掉真正的跨压路径芯片流片后直接挂。2.5 电源开关单元物理断电的执行者前面说的断电动作最终靠电源开关完成。UPF里create_power_switch描述这个开关create_power_switch sw_npu -domain PD_NPU -output_supply_port {VDD_NPU_SW} -input_supply_port {VDD_NPU} -control_port {npu_pd_en} -on_state {on_state VDD_NPU} -off_state {off_state}电源开关在物理上是一组高边PMOS管控制信号拉低时导通拉高时断开。-on_state和-off_state是告诉工具开关的两种稳定状态分别对应什么电压。这里要特别提醒电源开关本身也有压降和泄漏。大量电流经过开关会有IR drop严重时导致实际到达模块的电压不满足库单元工作条件。所以做电源网络分析时要把开关的导通电阻考虑进去必要的时候加宽电源走线或者多放几个开关并联。另外电源开关的开关速度不能太快也不能太慢。太快会产生很大的电流变化率引起电源噪声太慢则会导致模块还没完全断电就去访问它的输出逻辑出错。这些时序关系通常在硬件设计阶段就定好UPF只是把结果表达出来真正去做电源关断时序控制的往往是PMUPower Management Unit里的状态机。3. UPF文件应该怎么组织写UPF不是把命令随便堆一块儿就能用。命令行顺序、作用域、和RTL层次的关系都会影响最终结果。尤其格式稍微老一点的工具对UPF的解析顺序很敏感。3.1 合理规划UPF的文件结构和作用域大型SoC的UPF通常不只有一个文件。推荐的做法是顶层一个UPF文件负责创建电源域、PST、以及各子系统的供电连接每个低功耗子系统单独一个UPF文件由顶层的load_upf加载进来。load_upf ./upf/PD_NPU.upf load_upf ./upf/PD_AUDIO.upf每个子模块的UPF文件里第一行通常是set_scope /top/npu_subsystem set_design topset_scope很关键它告诉工具当前UPF命令的作用对象是谁。如果不加工具默认在当前设计顶层解析后面create_power_domain -elements {npu_core}里的路径就全不对了。我见过好几次这种错排查半天发现是scope写错导致domain里一个单元都没圈进去工具也没有报错只是后续分析结果全偏了。3.2 UPF和RTL层次的关系UPF可以写在RTL综合之前也可以写在综合之后。前端的做法通常是在RTL freeze之后、综合脚本跑之前就把UPF写好这样综合工具可以直接用UPF做低功耗优化比如自动插isolation和level shifter把retention寄存器映射到库里的retention flop。但记住一点UPF里的instance路径必须和RTL层次严格对应。RTL改了模块名字或者层级UPF没跟着改工具会报一堆“unresolved reference”错误。这种错误本身好定位但麻烦的是它往往不直接报在你的UPF行上而是报在后端工具里某个莫名其妙的电源连接错误上。所以RTL freeze之后UPF里的路径引用也相当于freeze了这个规则要在团队里立下来。如果你用SystemVerilog做设计配合UPF还能做UPF-aware的低功耗验证。验证环境里可以定义power_state对象在仿真的特定阶段切到OFF状态检查隔离、保持行为是否和预期一致。这一块建议能早做就早做等后端做完再发现问题修起来成本差一个数量级。3.3 工具链对UPF的支持差异不同EDA工具对UPF的支持程度不太一样我把自己用过的情况大致列一下给还没选型的朋友参考环节工具举例UPF主要用途RTL仿真VCS / Questa功耗意图仿真、低功耗断言检查逻辑综合Genus / Design Compiler低功耗单元插入、UPF语法检查布局布线Innovus / IC Compiler II电源网络实现、单元布局优化功耗分析PrimeTime PX / Voltus基于UPF的功耗仿真和IR drop分析跨工具时最容易踩的坑是UPF版本兼容问题。UPF有2.0、2.1、3.0、3.1等版本老工具可能只支持2.0新工具默认按3.1解析如果用了3.1才有的语法比如某些supply set的扩展功能老工具要么报错要么静默忽略了。团队协作时最好在UPF文件头部注释清楚目标工具链和版本比如## UPF 2.1, for Genus 19.1 / Innovus 21.13.4 从零搭建一个最小UPF实例假设我们要做一个双电源域的芯片PD_TOP常开PD_OFF可关断可关断域输出需要隔离内部有一个寄存器需要保持。## 顶层UPF set_design tb_top set_scope /tb_top/dut # 电源端口 create_supply_port VDD create_supply_port VSS create_supply_port VDD_OFF # 供电网络 create_supply_net VDD -domain PD_TOP create_supply_net VSS -domain PD_TOP create_supply_net VDD_OFF -domain PD_OFF # 电源域 create_power_domain PD_TOP create_power_domain PD_OFF -elements {off_module} # 电源连接 connect_supply_net VDD -port VDD connect_supply_net VSS -port VSS connect_supply_net VDD_OFF -port VDD_OFF # 电源状态表 create_pst pst_chip -supplies {VDD VDD_OFF} add_pst_state normal -pst pst_chip -state {ON ON} add_pst_state off -pst pst_chip -state {ON OFF} ## 隔离 set_isolation iso_off_out -domain PD_OFF -isolation_supply_set {VDD VSS} -clamp_value 0 -applies_to output set_isolation_control iso_off_out -domain PD_OFF -isolation_signal {iso_ctrl} -isolation_sense high -location self ## 保持 set_retention ret_off_reg -domain PD_OFF -retention_supply_set {VDD VSS} -elements {off_module/state_reg} set_retention_control ret_off_reg -domain PD_OFF -save_signal {save_n} -restore_signal {restore_n} -save_sense low -restore_sense low实际项目里还会有一堆细节比如多个开关的开关控制时序、per-domain的isolation策略、时钟和复位的处理但核心骨架就是上面这套。4. 低功耗设计中的常见问题与排查思路UPF写出来只是第一步真正折腾人的是后面跑仿真、跑综合、跑PR时的各种诡异错误。下面这些是我在实际项目里遇到过、也看同事踩过的典型问题整理出来给你排查时当参考。4.1 RTL仿真里全是X态到底是谁的锅低功耗仿真最烦的就是X态传播。模块断电前没隔离好输出飘了或者隔离控制信号时序不对仿真时模块已经切到OFF但iso_ctrl还没有拉高对端逻辑收到一堆X。排查思路可以按顺序来先看隔离控制信号的波形确认它和PST状态切换的时序。如果iso_ctrl拉高的时间晚于模块真正断电的时间那就是控制逻辑有问题。再看隔离单元的电源是否来自常开域。如果隔离单元的VDD也一起断掉了那它根本没法工作输出还是X。最后检查UPF里-elements路径是否覆盖了所有需要隔离的输出。有些内部逻辑的输出虽然不直接出domain但通过组合逻辑路径间接到了domain边界工具不一定能自动识别这时需要手动加set_isolation -applies_to output -elements细化范围。我用过一个比较笨但很有效的办法仿真时把PST强制设成全部ON如果X态消失说明问题出在电源状态切换如果还有X那就是RTL本身的问题。这样能快速二分定位。4.2 后端布局布线时电源网络连接错误PR阶段的UPF错误多半出在supply net的连接上。常见告警是“Net not connected to power supply”或者“Cell has undefined power pin connection”。这类问题的根源往往不是UPF本身而是库单元的定义和UPF不一致。比如库里某个IO buffer的电源引脚叫VDDPST但UPF里只定义了VDD工具没法自动把两者对应起来。解决方法是在工具里设置库单元的电源引脚映射或者用connect_supply_net显式指定connect_supply_net VDD -cell_pin {pad_inst/VDDPST}这类问题不复杂但数量多而且每个库的命名习惯不一样需要耐心逐个处理。建议在项目开始时先拿一个空设计跑通最小UPF流程确认库单元映射没问题再上全芯片。4.3 综合后面积爆炸隔离和电平转换单元太多综合工具的自动优化有时候会过度插入。明明只需要对可关断域的输出做隔离结果工具把domain内部一些中间信号也加了隔离单元面积白涨。这时可以检查综合log看工具实际插了多少cell再对照UPF里的domain边界逐个核对。如果确实插多了可以在UPF里收紧约束。比如用-applies_to output -domain PD_OFF限定只对domain输出加隔离不加在内部。部分工具还支持设置-isolation_threshold只有扇出超过一定值的信号才插隔离单元。这个参数能控制面积和可靠性的平衡需要根据项目功耗目标反复试。另外一个不太让人注意的原因是多个supply set之间电压没定义清楚工具认为所有跨域路径都需要电平转换。如果两个域电压完全相同应该在PST里把电压值写成一样工具就不会去插没意义的电平转换单元。4.4 功耗分析结果和估算对不上UPF做功耗分析时工具需要知道每个power state的持续时间或者概率。如果PST里只写了状态名没有给状态概率工具默认按某种均匀分布算结果自然和实测差异大。建议在PST里显式给出-probability或者通过仿真波形反标状态的时间占比。还有一个常见问题是retention域在睡眠状态下的漏电没算对。retention flop在睡眠时主锁存器断电、影子锁存器常开漏电应该按影子锁存器的尺寸计算。如果工具里没有正确识别retention cell的leakage属性报告出来的睡眠功耗会明显偏高或偏低。这种情况一般不是UPF的问题而是库的功耗特性文件没配好需要找库供应商要准确的.lib和功耗模型。4.5 UPF版本和工具兼容性踩坑不同工具版本对UPF的支持深度不同特别是从综合到后端、从仿真到功耗分析同一份UPF在不同工具里解析出来的语义可能有细微差异。我吃过一个亏用新版本工具写出set_isolation -isolation_supply_set {VDD VSS}老版本综合工具也接受了但后端工具跑出来发现隔离单元被插在了关闭域内而且供电还是断的。查了半天发现是综合工具识别不了-isolation_supply_set默认把隔离单元供电接到了domain自己的电源上后端自然就错了。后来我们定了个规矩所有UPF文件在项目启动时先在所有环节工具上跑一遍空设计验证确认语法兼容再开始正式设计。这个前置成本很低但能省掉后面大量的扯皮时间。5. 低功耗设计流程之外一些延伸思考低功耗不是芯片设计独有的问题。手机SoC、物联网MCU、可穿戴设备甚至最近很火的低功耗蓝牙和语音唤醒场景本质上都在做同一件事让系统在不需要高性能的时候尽量少耗电在需要响应的时候能快速醒来。这些应用里UPF和MCU低功耗之间的联系也很紧密。比如华大HC32系列单片机的低功耗模式用户手册里会讲sleep、stop、standby各种模式怎么配寄存器但如果你理解了芯片内部的电源域切分就会明白这些模式本质上就是在做电源状态切换和UPF里PST的状态迁移是一个道理。搞懂了低功耗设计的底层逻辑再去看任何一款MCU的低功耗手册都会轻松很多。另一个有意思的方向是低功耗验证和软件协同。UPF里的PST定义了硬件支持哪些电源状态但真正决定系统何时进睡眠、何时唤醒的是软件里的电源管理策略。软硬件协同的低功耗设计越来越多地要求UPF的设计从一开始就和固件里的状态机对应上这已经不是单纯前端或者后端的事情而是架构层面的事情。我自己在做项目时的体会是UPF这个东西写起来简单写对难验证和收敛更难。它不像RTL那样有直观的功能逻辑可以仿真它的正确性往往要等到综合、PR甚至流片回来才能显现出来。所以越早把UPF纳入设计流程越早开始做功耗意图验证整个项目越稳。最后分享一个实用的小技巧手里没有复杂工具的时候可以用upf相关的文本检查脚本做简单的静态检查比如确认所有create_power_domain里创建的domain都有对应的set_isolation或set_retention配置确认PST里所有supply set的状态覆盖了正常工作模式。这类脚本不需要很复杂但用来拦截低级错误非常有效。我的习惯是每次改完UPF先跑一遍这种检查再提交给团队能省掉很多评审时的口水。
返回列表