ARTICLE DETAIL

资讯详情

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

UPF低功耗设计实战:从电源域划分到芯片功耗收敛的完整指南

UPF低功耗设计实战:从电源域划分到芯片功耗收敛的完整指南 这几年做数字芯片功耗已经不是一个“能省则省”的加分项而是很多项目的硬性必选项。我最早接触UPFUnified Power Format统一电源格式是在一个低功耗MCU项目的后端阶段那时候项目里要支持多种工作模式待机电流要求压到微安级别光靠架构层做降频省出来的功耗远远不够电源域划分、多电压、电源关断全部都得安排上而UPF就是把这些电源意图用标准格式写给EDA工具看的桥梁。这篇文章适合三类人看做数字前端和RTL设计的工程师被后端和物理实现逼着改UPF的验证工程师以及刚接触低功耗SoC项目、想搞清楚UPF和低功耗设计之间关系的学生。我尽量少讲空泛的概念多写实际项目里能用得上的语法、流程和踩坑经验争取你看完之后能直接上手写自己的UPF文件哪怕只是一个最小规模的模块也能理解它在整个设计流程里是怎么流转的。1. 低功耗为什么成为芯片设计的头等大事1.1 功耗问题的来源芯片功耗分为动态功耗和静态功耗两大类。动态功耗主要来自两个部分一个是CMOS电路翻转时对负载电容充放电产生的功耗另一个是PMOS和NMOS在翻转瞬间同时导通形成的短路电流功耗。一个比较直观的公式是 P_dyn αCV²f其中α是翻转活动因子C是节点电容V是工作电压f是工作频率。电压在公式里是平方项所以电压降一点动态功耗降得非常明显这也是为什么多电压域和动态电压频率调节DVFS会成为低功耗设计的核心手段。静态功耗则主要来源于漏电流包括亚阈值漏电、栅极漏电和阱漏电等。随着工艺制程不断微缩阈值电压持续降低亚阈值漏电呈指数级上升在先进工艺下静态功耗已经占到芯片总功耗的很大一部分甚至在一些待机场景下占据绝对主导。拿我前两年接触的一个用国产MCU做可穿戴设备传感器的项目举例系统在大部分时间处于低频待机状态动态功耗已经压得很低但漏电依然让电池跑不到标称时长。芯片端的低功耗设计要解决的就是动态和静态两个战场同时下手——动态靠降压降频静态靠电源关断和低漏电工艺库。1.2 低功耗设计的三道门槛第一道是续航门槛。无论是智能手表、蓝牙耳机还是工业传感器节点电池容量被物理尺寸卡死用户还要越来越长的续航这几乎是所有终端设备项目都要面对的死命题。第二道是散热和封装门槛。性能不断提高芯片功耗升高热密度跟着上去了散热成本、封装成本都在涨功耗控制不好产品的整体成本也要失控。第三道是可靠性和市场门槛。功耗过高带来的高温会加速器件老化影响可靠性同时电磁兼容、噪声问题也会加重。这也是为什么这两年低功耗MCU产品层出不穷比如华大半导体的HC32系列、Nordic的nRF系列大家都把待机电流从微安级往纳安级压。实际开发中我发现光靠掉电模式、中断唤醒这些MCU层面的软件调度还不够芯片本身必须在硬件设计上就具备多电源域和电源关断能力否则软件再优化也突破不了物理底座的天花板。硬件底子好软件才能在上面做好功耗调度。1.3 低功耗设计需要一套统一的“电源意图”描述过去做低功耗设计很多团队靠的是Excel表格和PPT——电源域有哪些、每个域正常工作电压多少、关断之后需要哪些隔离策略、哪些寄存器要保留全部记在文档里。画图一时爽等到流转给后端和验证的时候每个人的理解都会有偏差工具也不知道你的电源意图只能靠人肉在门级网表里手动插入电平转换器和隔离单元改一版迭代一遍效率极低而且容易漏。UPF要解决的就是这个问题。它用一套标准化语法把电源域的划分、供电网络的连接、电源开关策略、隔离策略、电平转换策略以及寄存器的保持策略全部描述出来前端、后端、验证、签核各环节都能读同一份文件工具可以直接基于UPF来做自动化插入和检查。本质上UPF就是把工程师脑子里的“电源设计意图”变成机器可解析的“电源规格书”是打通前后端功耗设计的关键枢纽。2. 低功耗设计技术栈与UPF的位置2.1 常见的低功耗设计手段时钟门控是门槛最低、应用最普遍的低功耗手段。很多模块在大部分时间并不需要时钟比如一个等待外设事件唤醒的接口控制器通过时钟门控把Clock切掉该模块的动态功耗几乎归零但状态存储仍然保持恢复也快成本非常低。它的本质是降低活动因子α。多电压域和DVFS是另一层思路。芯片里不同的模块对性能要求不一样CPU核心可能需要0.8V高压跑高频而GPIO接口、低速外设可能0.6V就足够。DVFS还能在运行过程中动态调节电压典型场景是手机SoC里的大小核搭配按负载自动切频切压省下来的电量肉眼可见。电源关断Power Gating是更激进的手段把空闲模块的电源直接切掉静态漏电被彻底掐断。但电源切断了数据就丢了所以需要配合保留寄存器把关键状态数据留住还需要隔离单元防止悬浮信号传到还在供电的模块里产生漏电路径。隔离单元的作用是当某个域的电源关断后把输出信号钳制到一个固定的安全电平避免关断域和常开域之间出现不受控的电流通路。电平转换器则是用来处理不同电压域之间的信号传输比如0.8V域的信号要进入到1.2V域如果不做转换驱动可能不足逻辑无法正确识别。最后还有存储器层面的处理比如SRAM工作电压单独供电、深度睡眠模式的数据驻留控制以及低功耗状态下的分块读写策略。这些都属于低功耗设计范式里一环扣一环的局部优化。2.2 为什么不用CPF而用UPF低功耗设计意图的标准行业里其实有两家流派。一个是Synopsys主推的UPF目前已经是IEEE 1801标准另一个是早期Cadence推的CPFCommon Power Format。最终市场选择了UPF作为更通用的标准原因在于UPF允许在RTL的不同层级灵活设定Scope和策略跟RTL设计结合的粒度更自由而且UPF通过“电源状态表”Power State Table来描述多域工作模式的兼容性在处理复杂多电压域场景时表达能力更强。实际项目里几乎不会有人再拿CPF做新项目了UPF已经成为主流EDA工具链的默认支持格式。无论是前端仿真、逻辑综合、DFT插入还是后端布局布线UPF文件在每一个环节都有对应的处理方式这也是它能被串联进全流程的根本原因。2.3 UPF在整个IC设计流程中的流转一份UPF文件起步时由设计架构师或者前端设计工程师编写描述的是功能级的电源意图不涉及具体SoC物理实现的细节。逻辑综合阶段综合工具读入UPF和RTL根据UPF定义插入隔离单元、电平转换器和保留寄存器同时完成电源开关逻辑的推断。综合之后的网表带上了电源管理单元UPF也跟着更新成更贴近门级网表约束的格式。到了后端布局布线阶段后端工程师把综合后生成的UPF作为约束给到APR工具工具会根据UPF中的供电网络关系来做电源网络规划、放置电源开关单元、连接隔离和电平转换单元并检查电源域的物理实现是否满足要求。功耗分析阶段工具会结合翻转率信息和UPF中描述的电压、工作模式计算各电源域的动态和静态功耗。验证环节也有专门的UPF仿真。仿真器会根据UPF描述在RTL仿真阶段模拟电源的关断、恢复、隔离行为检查设计在电源状态切换时功能是否正确。一条链路下来UPF文件虽然一直在演化但核心的电源意图从RTL到网表保持一致这就是UPF价值的放大效应所在。3. 读懂UPF核心语法从电源域到电源开关3.1 最小可用的UPF文件长什么样写UPF第一步总是定义电源域。电源域是一组逻辑模块的集合它们共享同一组供电网络。看一个最简单的例子set_scope rtl_top create_power_domain PD_CPU -include_scope create_power_domain PD_ALWAYS_ON create_supply_port VDD_CORE -domain PD_CPU create_supply_port VDD_AON -domain PD_ALWAYS_ON create_supply_net VDDN_CORE -domain PD_CPU create_supply_net VDDN_AON -domain PD_ALWAYS_ON create_supply_net VSSN connect_supply_net VDDN_CORE -ports VDD_CORE connect_supply_net VDDN_AON -ports VDD_AON connect_supply_net VSSN -ports VSS set_domain_supply_net PD_CPU -primary_power_net VDDN_CORE -primary_ground_net VSSN set_domain_supply_net PD_ALWAYS_ON -primary_power_net VDDN_AON -primary_ground_net VSSN这段代码的意思是在rtl_top这个模块下创建两个电源域PD_CPU和PD_ALWAYS_ON。PD_CPU是可以通过电源门控关断的域PD_ALWAYS_ON是常开域。接着定义两个Supply Port外部供电端口和两组Supply Net内部供电网络再用connect_supply_net把端口和网络连起来最后通过set_domain_supply_net指定每个域的主电源网络和主地网络。很多初学者会忽略set_domain_supply_net这一步只建立网络不指定域的供电关系工具在后续处理时往往会报错或者默认推断出错误结果。我写UPF的习惯是每创建完一个域马上就跟上set_domain_supply_net把供电关系一口气定义清楚避免后面遗漏。3.2 隔离单元和电平转换的表达方式电源域关断后如果输出信号没有被钳制输出会悬空下游常开域电路可能因为输入端电压不稳定形成贯通电流甚至不止是漏电的问题严重的会影响常开域的逻辑状态。所以必须给关断域的输出加隔离单元。UPF里用set_isolation来约束set_isolation iso_cpu -domain PD_CPU \ -isolation_power_net VDDN_AON \ -clamp_value 0 set_isolation_control iso_cpu -domain PD_CPU \ -isolation_signal iso_ctrl \ -isolation_sense high \ -location self第一句告诉工具PD_CPU域需要加隔离单元隔离单元本身由常开电源VDDN_AON供电输出在隔离状态下钳到0。第二句指定隔离控制信号是iso_ctrl高电平有效且隔离单元放在PD_CPU域内部边界。为什么特别强调隔离单元的供电电源是VDDN_AON而不是VDDN_CORE如果隔离模块跟着关断域一起断电那它自己都失电了还怎么承担钳制任务所有需要常开域在关断期间保持功能的逻辑供电都必须挂在常开电源网络上。这是一个非常容易踩的坑。电平转换器放在电压不同的两个域之间。UPF里的描述是set_level_shifter ls_cpu_aon -domain PD_CPU \ -applies_to outputs \ -location self \ -threshold 0.72这条命令说的是PD_CPU域的输出在送出域之前要插入电平转换器转换阈值是0.72V。当两个相邻域的工作电压差超过一定数值时工具就会根据threshold参数决定是否需要插入level shifter。阈值设置要参考标准单元库中电平转换单元的转换范围设得太激进会导致工具插一堆没必要的单元浪费面积和延迟设得太宽松又会漏插后续时序分析导出大量违例。3.3 电源开关和保留寄存器电源门控的电源开关单元在UPF里通过create_power_switch来声明create_power_switch sw_cpu \ -domain PD_CPU \ -input_supply_port {in_power VDDN_AON} \ -output_supply_port {out_power VDDN_CORE} \ -control_port {sleep_en sleep_en} \ -on_state {on_state in_power {!sleep_en}}这个命令把PD_CPU域里的内部供电网络VDDN_CORE和外部常开电源网络VDDN_AON通过一个受sleep_en控制的开关连接起来。当sleep_en为低开关导通VDDN_AON给VDDN_CORE供电当sleep_en拉高开关断开PD_CPU域彻底断电。电源关断后如果有些关键状态还需要在唤醒后恢复就需要保留寄存器。UPF里用set_retention描述set_retention ret_cpu -domain PD_CPU \ -retention_power_net VDDN_AON \ -retention_control {ret_ctrl high}这里指定PD_CPU域的保留寄存器由VDDN_AON供电ret_ctrl为高时进入保持状态。保留寄存器本质上是一个带影子锁存的寄存器主电源掉电后数据被转移到由常开电源供电的影子锁存器里唤醒时再恢复到主寄存器。代价是面积变大、时序变差所以只对关键状态寄存器使用不能无差别替换。我见过一个项目把整块RAM的地址寄存器全做了retention面积暴涨近20%实际上很多状态完全可以靠软件在唤醒后重新配置根本不需要硬件保持做了纯粹是浪费。3.4 多电压域之间的供电关系真实项目的电源域往往不止两个比如主控域、IO域、模拟域、射频域、备份域等。UPF通过电源状态表Power State Table描述多个电源域在不同工作模式下的电压和状态组合create_pst pst_main -supplies {VDDN_CORE VDDN_AON} add_pst_state active -pst pst_main -state {0.8 1.2} add_pst_state standby -pst pst_main -state {OFF 1.2}这段定义了两种工作状态active状态下VDDN_CORE为0.8V、VDDN_AON为1.2Vstandby状态下VDDN_CORE完全关断OFFVDDN_AON保持1.2V。电源状态表的完备性非常重要如果状态之间的转换没有覆盖后端工具做电源网络分析和验证时就会漏掉某些工作模式的检查。我建议把所有产品定义的工作模式列成矩阵再逐一对应到PST状态里确保没有遗漏。4. UPF落地实操从RTL到签核4.1 UPF和RTL的配合方式UPF文件在项目里一般和RTL同步维护。常见做法是RTL顶层下有一个专门的目录存放UPF文件并同步到验证环境里。前端设计在创建电源域时需要和RTL中模块的实例名严格对应最好的统一方式是直接用模块名来定义域范围避免工程名字对不上。UPF和RTL的配合还有一个关键点供电网络在不同层次Scope中的可见性。UPF的set_scope命令把后续命令的作用范围统一切到某个设计层次后续创建的域、网络、隔离约束都默认在该Scope下。如果RTL层次有较大调整比如模块下沉、改名UPF里的Scope引用就会失效工具直接报找不到对象。有个项目经历让我印象深刻重构了子系统模块的层级后UPF里引用的旧层次还在生效仿真初始阶段一切正常一到电源切换测试就报信号找不到。排查了大半天最后发现是两个UPF文件引用了同一逻辑功能但不同层次的模块这种问题靠抽检很难发现最好能写一个简单的脚本来检查UPF中引用的层次是否都能在RTL里找到。4.2 逻辑综合阶段的UPF应用综合工具读入UPF和RTL后会根据UPF描述自动插入隔离、电平转换、保留寄存器和电源开关相关的控制逻辑。综合时要注意的几点第一综合约束文件SDC里要把控制隔离和保留信号的时钟约束设对。隔离控制信号和保留控制信号往往在关断域掉电之后才有效这就意味着它们必须在常开域里稳定不变创建时钟树时要把这些信号当作与时钟同级的重要网络来处理否则时序分析会出大问题。第二UPF中声明的电源开关会在综合时推断成实际的电源开关单元这些单元和普通标准单元的时序模型不一样综合工具在优化逻辑时可能不会把它们当成普通逻辑来处理所以一定要设置好综合工具的低功耗选项让工具自动处理。第三综合后的网表和UPF文件要一起交付给DFT和后端千万不要只交付网表不交付UPF。一旦后端的UPF和综合用的UPF不一致所有和电源相关的DFT测试、扫描链生成都会出问题。4.3 UPF仿真功能验证里的电源切换演练UPF仿真在当前主流仿真器里基本都支持比如Synopsys VCS、Mentor Questa这些工具都能做UPF-aware仿真。仿真器的做法是先解析UPF建立供电网络和逻辑域的关系然后在仿真模型里加入电源行为比如某个域关断后域内寄存器的值会变成X态直到恢复电源并完成复位才重新有效。写电源切换测试序列时最重要的一条原则是测试用例必须验证“隔离控制信号要早于电源关断生效”以及“电源恢复稳定之后才能释放隔离控制信号”。这两个时序关系搞反了芯片在实际运行时会有不确定状态传播功能测试却可能一点问题都发现不了。具体仿真序列一般是这样的先让系统进入正常态然后断言隔离控制信号等隔离控制生效后拉高sleep_en关断电源模拟一段时间的掉电状态再拉低sleep_en恢复电源等待电源稳定后释放隔离控制信号最后检查保留寄存器的值和唤醒后的执行路径。整个过程需要带时序信息地在波形上确认不能用功能级代码完全替代。我踩过一次坑只验证了隔离信号钳住之后关电源但没验证“隔离信号的撤销必须先于电源恢复”这个反向时序。后来在后端时序分析阶段发现一个寄存器存在数据保持路径违例回头看仿真波形才意识到问题出在隔离撤销得太早导致数据在电源尚未完全稳定时被读走。所以仿真用例最好同时覆盖隔离与关断、恢复与撤销这四种组合的时序关系。4.4 功耗分析中的UPF输入做功耗分析时除了芯片在真实场景里的翻转率Switch Activity文件UPF提供的电源状态定义还会直接影响功耗计算的准确性。功耗分析工具会根据PST里的状态组合计算各域的动态功耗和静态功耗在standby状态下工具会把对应域的静态功耗按OFF值处理而不只是把动态功耗清零。综合和APR后做功耗优化时我通常的做法是先跑一遍基于UPF的功耗分析看哪个电源域的静态功耗占比异常再针对性检查是不是隔离单元供电接错、电源开关默认状态不对、或者某些本该属于关断域的逻辑被错误挂到常开电源上。这些问题在UPF文件里埋得很深如果分析时没有按照PST做多状态功耗计算很难暴露出来。5. 常见问题与排查技巧实录5.1 UPF仿真中的典型问题仿真中遇到最多的一类问题是掉电域内信号出现X态扩散。现象是关断域电源切掉后X态从寄存器传到常开域逻辑里导致常开域出现大量未知值。排查时先确认隔离单元有没有正确插入其次看隔离控制信号是不是在电源关断前就已经稳定。如果隔离单元没有按预期生效很可能是set_isolation的domain范围没设置正确隔离单元被放在了错误的位置。还有一类问题信号名颠倒导致的保留控制失效。UPF里retention_control的信号方向必须和RTL里电源管理单元的控制信号一致经常有工程师把高电平有效写成低电平有效仿真时看保留寄存器在掉电期间就被改写或者恢复后数据变成X态。排查时直接在波形里找到retention信号和对应寄存器数据对比时间点就能确认问题。5.2 综合和后端阶段的高频坑综合阶段见到最多的错误是两个域之间缺电平转换器。工具默认只在电压差超过一定阈值时插入但如果后端的电压降分析结果显示某些路径上的压降超过阈值level shifter可能就不够。遇到这种问题建议一是检查UPF里的threshold设置二是通过后端功耗分析结果反馈回来调整UPF策略。电源开关控制信号跨域是另一个大麻烦。控制sleep_en的信号如果从常开域传到关断域中间没有任何隔离和同步处理电源关断瞬间控制信号抖动一下就可能造成开关误动作。规范的做法是电源开关控制信号在常开域内做同步处理然后通过隔离单元传递且UPF中要用特定的约束声明这个信号不需要插入level shifter否则工具会自动插入一个电平转换器导致时序裕量不足。5.3 我个人的UPF管理习惯UPF文件和RTL一样需要版本管理而且最好和RTL在同一次提交里一起更新避免出现UPF和RTL不同步的情况。每次修改UPF之后先跑一遍UPF语法检查和UPF-aware仿真再往下流转到综合不要指望后端和验证帮你去发现UPF的问题。另外我在项目里习惯用脚本自动检查UPF引用的信号是否都在RTL中存在。这个脚本不复杂提取UPF里的信号名和RTL的端口、寄存器列表做比对跑完能节约大量手工排查时间。还有一个小技巧在综合和仿真之前先把UPF里的create_power_domain列成清单和设计规格书里的电源域定义逐一打勾确认没有多余或遗漏的域这一步虽然琐碎但每次都能拦住一些低级错误。写在最后的一点体会UPF初学的时候看着像一堆命令行拼凑出来的约束觉得比写RTL简单但真正上手做项目才发现它的难点不在语法而在对芯片电源管理架构的理解。你只有清楚知道每个电源域什么时候通电、什么时候关断、哪些信号需要隔离、哪些寄存器必须保留才能写出一份所有工具和团队都满意的UPF。这份文件写得好不好直接体现在后端物理实现的质量和验证团队的返工次数上。我个人实际项目里的建议是不要等RTL全部写完再补UPF最好在模块级规格确定后就开始搭UPF框架用最简版本把电源域和供电网络定义出来随着设计成熟再逐步补充隔离、电平和保留策略。UPF做得越早设计里能被低功耗手段优化的空间就越大后端和验证团队的日子也越好过最后芯片的功耗数据才真正扛得住产品需求。
返回列表