ARTICLE DETAIL

资讯详情

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

低功耗芯片UPF设计避坑:Power Switch与Isolation Cell实战指南

低功耗芯片UPF设计避坑:Power Switch与Isolation Cell实战指南 芯片回来之后仿真出一堆X态、待机电流怎么压都压不下去、Power Switch 一关整个逻辑直接哑火——这些场面我在做过低功耗项目的工程师朋友那儿听过太多次。UPFUnified Power Format作为业界标准的电源意图描述格式它的核心价值就是让“哪个模块什么时候能断电、断到多低、断了之后怎么保住信号”这些事儿从架构阶段就变得可控而不是等芯片回来在实验室里抓瞎。这篇避坑指南我打算从 Power Switch 和 Isolation Cell 这两个最容易踩坑的点切入串联起 Power Domain 划分、UPF 文件编写、物理实现到仿真验证的完整流程。目标读者是正在做或准备做数字低功耗 SoC 的后端工程师、前端集成工程师以及那些拿到别人写好的 UPF 却不知道该怎么往下接的兄弟们。文章里没有教科书式的套话全是实际项目里被验证过或踩过的处理方式照着做能帮你少走一段弯路。1. 动手之前先把“电源意图”说清楚1.1 Power Domain 怎么划先有架构图再写 UPF我见过太多人拿到一个低功耗项目上来就敲create_power_domain然后发现写到一半 supply net 连不上、isolation strategy 和架构对不上最后整个文件推倒重来。这里必须强调一个原则UPF 不是设计输入它是架构决策的编码结果。你如果连哪些模块要常开、哪些模块要休眠、休眠时哪些信号必须保持有效都没想清楚写出来的 UPF 一定经不起工具和仿真的双重拷问。在做任何 UPF 编写之前我强烈建议先画一张电源架构图至少包含这几项每个模块属于哪个电源域每个电源域在正常工作、睡眠、深度睡眠状态下分别由哪路供电域与域之间的信号交互里哪些信号存在跨域风险哪些寄存器需要掉电保持保持逻辑放在哪个域。这张图画清楚了再动手写 UPF你会发现工具的报错都变得好懂很多。另一个常被忽视的问题是Power Domain 的划分粒度要和物理实现匹配。我见过一个项目把十几个功能模块拆成七八个大大小小的 power domain结果后端在摆电源开关和穿电源网格的时候痛苦不堪面积浪费严重IR drop 也差。合理的做法是先把必须断电的模块找出来再看它们是否共用相似的掉电策略尽量合并成一个 domain。常开逻辑比如唤醒控制器、PMU 本身、部分始终工作的接口单独划一个 always-on domain其他按掉电策略分组别为了“看起来满配”而把 domain 切得稀碎。1.2 UPF 文件的骨架与那些容易写错的 supply 语句UPF 文件写起来不难但它有一套自己的“语言逻辑”容易出问题的往往是 supply port / supply net / supply set 这三者之间的连接关系。简单说supply port 是电源域的对外接口supply net 是域内实际的电源线网supply set 把一组相关的电源和地组合起来方便后续统一关联。我摘一段典型的 UPF 写法配合注释说明# 1. 建立顶层电源域和基础 supply port create_power_domain PD_TOP create_supply_port VDDH create_supply_port VDDL create_supply_port VSS create_supply_net VDDH -domain PD_TOP create_supply_net VDDL -domain PD_TOP create_supply_net VSS -domain PD_TOP connect_supply_net VDDH -ports {VDDH} connect_supply_net VDDL -ports {VDDL} connect_supply_net VSS -ports {VSS} # 2. 建立 CPU 掉电域并指定包含的实例 create_power_domain PD_CPU -elements {CPU_top} # 3. 给 PD_CPU 建立独立的供电网和供电组合 create_supply_net VDDL_CPU -domain PD_CPU create_supply_set ss_CPU \ -function {power VDDL_CPU} \ -function {ground VSS} create_supply_set ss_CPU_OFF \ -function {power VDDH} \ -function {ground VSS} associate_supply_set ss_CPU -handle PD_CPU新手最容易踩的坑有两个一个是create_supply_net指定-domain时把 supply net 建到了错误的作用域里导致后续connect_supply_net找不到端口另一个是create_power_domain的-elements写成了一堆模块名但实际层次路径写错工具直接报 instance not found。我的建议是先跑一遍check_power_domain或工具自带的 UPF 检查命令确认 domain 的元素划分符合预期再往下写 supply 相关的语句。另外要注意 supply set 的 state 定义。add_port_state和add_power_state是告诉工具“这个接口/这个域在什么状态下电压是多少”如果 state 没定义或者定义得和实际电源开关行为不一致后面的功耗分析和形式验证都会出错。比如一个掉电域在 OFF 状态下的电压是off你如果漏写了工具会默认它一直是 ONisolation 插入的位置也会变得不合逻辑。2. Power Switch 和 Isolation Cell两个“重灾区”一次讲透2.1 Power Switch 怎么选、怎么摆、怎么控Power Switch 是低功耗设计里真正执行“断电操作”的器件本质是一个由控制信号驱动的电源开关管常见结构是 header switch串联在 VDD 和模块内部供电之间或 footer switch串联在 VSS 和模块内部地之间。实际项目中 header switch 用得更普遍因为电源网格通常比地网格更好布而且跟标准单元库的兼容性更好。选哪种不绝对要看你的库支持情况和后端的供电网络策略。在 UPF 里创建一个 Power Switch 大体长这样create_power_switch SW_CPU \ -domain PD_CPU \ -input_supply_port {in VDDH} \ -output_supply_port {out VDDL_CPU} \ -control_port {enable EN} \ -on_state {on_state in {enable}}这里最关键的是-on_state那个条件。enable信号为高时开关导通输出端VDDL_CPU就等于输入端的VDDH逻辑掉电域上电enable为低时开关关断内部供电断开。这条命令看起来简单但实际项目里有几个地方特别容易翻车。第一个是enable 信号必须来自 always-on 域。如果 enable 本身从将要掉电的域里产生开关一关自己也没了再上电永远等不到控制信号模块就“死”在待机状态。架构上这种信号一定由 PMU 或其他常开逻辑驱动在 UPF 里也要用-control_port明确指定。第二个是开关的驱动强度和通路电阻。我遇到过一个项目为了省面积把 Power Switch 选得偏小结果掉电域重新上电时瞬间电流把开关上的压降压得很大内部供电电压不足寄存器复位不完全仿真和实测都出现过“起不来”的现象。选型时一定要根据峰值电流、允许的 IR drop 预算反推开关尺寸留足余量。第三个是开关的摆放。Power Switch 通常要放到对应 power domain 的边界附近并且要保证它能和电源网格有效对接。后端在布局时如果把它扔在远离电源条带的地方连线电阻会把那点功耗优势全吃掉IR drop 还超标。我的习惯是在 floorplan 阶段就跟后端同事确认好 switch cell 的候选布局区域。还有一个非常容易被忽略的点掉电域内部的供电网络比如 VDDL_CPU在 UPF 中必须明确地和外部电源隔离。不要在写 UPF 时图省事直接让两个域共享同一根 supply net那 Power Switch 就完全没有存在意义了。正确的做法是内部供电网独立创建再通过 Power Switch 的-output_supply_port把它跟外部电源网关联起来。2.2 Isolation Strategy 的四种决策点掉电域和常开域之间如果有信号交互断电那一刻掉电域的输出信号会变成 X 态或者浮空这个不确定值跑到常开域里轻则让功能逻辑疯掉重则产生漏电通路。Isolation Cell 就是来解决这个问题的掉电之前把跨域信号钳位到一个确定的逻辑值。关于 Isolation Cell 的插入策略我把它拆成四个决策点想清楚了基本不会错。第一个决策点是isolation cell 放在哪一侧。业界惯例是放在接收端也就是常开的那个域里因为接收端一直有电isolation cell 才能保证在掉电期间持续输出有效电平。如果把 isolation cell 放在掉电域那侧掉电时它自己也跟着断了钳位就失效了。UPF 里控制这个行为的是set_isolation_control的-location选项-location self表示把 isolation cell 放在驱动端域内通常配合保持供电使用-location fanout表示放在接收端。实际项目里如果你不确定放哪优先考虑接收端。第二个决策点是clamp 值选 0 还是选 1。有些库的 isolation cell 复位值默认钳到 0有些可以配置成 1。选哪个不能拍脑袋要看接收端电路的默认逻辑状态如果接收端有一个高有效的睡眠标志那钳位到 0 可能更安全如果接收端的总线空闲电平是高那就得钳到 1。这个值在set_isolation里用-clamp_value指定。我踩过一次坑某个总线协议在空闲态需要保持高电平团队默认钳 0结果掉电域一关总线上的 device 全部误判为“收到无效数据”排查了半天才发现是 clamp 值选错了。第三个决策点是isolation control 信号的来源。它和 Power Switch 的 enable 一样必须由 always-on 域生成并且要在掉电域的电源真正断开之前完成钳位。这个时序就是常说的 isolation enable 和 power switch off 之间的先后关系先让 isolation 生效再关电源上电时反过来先开电源再解隔离。UPF 不直接管时序但功耗状态定义和电源状态转换的顺序必须跟实际设计一致否则形式验证和仿真都会查出控制时序错误。第四个决策点是isolation cell 的供电。看到这里你应该能猜到isolation cell 必须挂在常开电源上。就算你把它放到了接收端如果库里的 isolation cell 内部电源还是连到了掉电域那它还是会被“拖下水”。所以写完 UPF 之后一定要检查一下实际综合结果里 isolation cell 的 PG pin 是不是连到了常开电源这个检查在后端做电源连接验证时尤其重要。2.3 Level Shifter 和 Retention 也顺手一起排掉一个完整的多电源域设计不会只有 Power Switch 和 Isolation CellLevel Shifter 和 Retention Cell 也经常同时出现。Level Shifter 解决的是电压域之间电平不匹配的问题比如 1.8V 的模块信号进 0.8V 的模块高电平会被误判。UPF 里通常用set_level_shifter指定策略实际工作中最容易漏的是 high-to-low高电压域到低电压域的方向很多人只关注 low-to-high结果高低压域之间跨的信号电平翻转不充分功能仿真偶尔能过后端时序却一塌糊涂。Retention Cell 则是给断电后还要保留状态的寄存器用的。它有两个额外信号save 和 restore断电前 save上电后 restore。我见过一个项目把 retention cell 当成普通寄存器写进 RTL结果 UPF 里没有任何 retention 信息综合工具无法识别掉电后数据全部丢失整颗芯片又从 RAM 里重新加载状态待机唤醒时间长了快一倍。关于 retentionUPF 里set_retention要显式声明保留的元素和 save/restore 控制信号而且这些控制信号一样得 from always-on 域。物理上retention cell 的供电必须保持常开如果它跟掉电域共用一根内部供电网就算逻辑设计对了后端 layout 也会出问题。Level Shifter 和 Isolation Cell 在边界上经常需要同时插入顺序也有讲究一般是先隔离再电平转换或者做成 combinational 的边界单元具体要看库里面有没有提供 combinational ISOLS 的复合单元。如果有优先用复合单元面积和时序都比分开的两个单元漂亮。3. 实操从 UPF 编写到综合、布局布线的完整流程3.1 第1步把供电关系“建模”成 UPF前面铺垫了这么多这里给一个实际可运行的 UPF 编写节奏。我习惯在项目早期就搭好一个“最小 UPF 框架”里面包含顶层 always-on 域、一个可掉电的 CPU 域、一个可掉电的 DSP 域以及它们之间的隔离策略。先保证框架能通过工具的 UPF 编译再逐步补全 retention、level shifter 等细节。一个重要的建议UPF 里使用的实例名和信号名必须和 RTL 的层次结构严格一致。UPF 不像其他约束文件可以随便起别名它直接作用于你网表里的真实设计对象。我见过有人把-elements写成CPU_top/U_CPU但实际 RTL 里这个模块叫u_cpu大小写加下划线对不上综合器直接报错。养成习惯先从综合工具里 dump 出设计层次再照着层次写-elements。另外如果项目用了多个 supply set建议给每个 set 起名字的时候带上用途后缀比如ss_LOGICAL_ON、ss_LOGICAL_OFF、ss_IO。名字起得好后面读 UPF 的人大概率是三个月后的你自己能少死很多脑细胞。下面这段是 CPU 域掉电状态与电源状态转换的定义示例add_port_state VDDL_CPU -state {OFF off 0.0} -state {ON on 1.0} add_power_state PD_CPU.OFF \ -supply_expr {supply_sets/ss_CPU OFF} add_power_state PD_CPU.ON \ -supply_expr {supply_sets/ss_CPU ON}这里的add_power_state是给功耗状态机用的。PD_CPU 在 OFF 状态下它的供电组合ss_CPU必须对应到 OFF 状态。如果你之前associate_supply_set ss_CPU -handle PD_CPU但状态定义里又绑了别的 supply set那么功耗状态检查时会报 mismatch。之前有次项目评审我发现工具报了一堆 UPF 状态不匹配的 warning追查下去是有人把顶层常开域的 supply set 定义到了 CPU 域的掉电状态里等于告诉工具“CPU 掉电时还是常开的”整个隔离策略被架空。3.2 第2步综合阶段要做什么不做什么UPF 写好后综合工具一般会读入 UPF比如 Design Compiler 的-with_upf选项或者单独load_upf然后根据 UPF 里的约束自动插入 isolation cell 和 level shifter。此时要特别注意不要让综合工具自作主张地优化掉你精心设计的隔离结构。我在项目里常用的保护手段是给 UPF 中插出来的 isolation cell 和 retention cell 的实例名加上dont_touch属性或者用工具提供的 UPF-aware 编译选项让它自动保持这些单元的完整性。否则工具可能在优化阶段把两个冗余的 isolation 单元合并掉或者把 retention cell 当作普通寄存器重新映射导致 UPF 声明和网表结果不一致。综合完成后一定要再跑一遍“UPF 一致性检查”确认设计里确实插入了预期数量的 isolation cell、power switch 和 retention cell而且它们的电源连接符合 UPF 定义。还有一个容易忽视的点综合时要把 MTCMOS也就是 Power Switch相关单元显式排除在时钟树综合之外。时钟树上的时钟门控单元和 buffer 不能挂在掉电域内部的可关断电源上否则时钟树一部分断电另一部分还在跑时序完全乱套。一般做法是在时钟树综合前把掉电域内部的时钟 buffer 固定到 always-on 供电或者干脆使用专门的支持 retention 的时钟单元。3.3 第3步物理实现阶段最容易翻车的点布局布线阶段UPF 相关的坑基本都集中在电源网络和单元摆放上。第一个坑是Power Switch 阵列的布局密度。掉电域内部需要多少开关、开关之间的间距多大这些会直接影响 IR drop。开多了面积白费开少了压降超标。通常的做法是先估算掉电域的峰值电流除以单个开关允许承受的电流得到大致数量再在 floorplan 里铺开。实际项目中我会留 20% 左右的余量毕竟 IR drop 仿真模型算得再准也挡不住工艺角偏移。第二个坑是isolation cell 的摆放位置。它应该尽量靠近掉电域的边界、靠近输出端口这样到达接收域的逻辑门距离短、时序压力小。有些后端工具能根据 UPF 自动指定isolation_cell的区域约束但如果你的工具版本比较老最好还是手动加一个 region 约束。我遇到过一次isolation cell 被工具摆到了远离边界的位置绕线资源紧张时多绕了好大一圈跨域路径时序直接崩掉后来在 floorplan 里给 isolution cell 画了一个专门的 bounding box 才解决。第三个坑是Power Switch 的 PG 连接。有些标准单元库里的 Power Switch 需要显式连接 input supply 和 output supply 到对应的 PG 引脚如果你在 UPF 里只定义了逻辑连接没有在 physical implementation 阶段做 power net 的映射流片回来很可能出现“开关虽然存在但没有真正接到电源网络上”的惨状。现在主流后端流程里可以用工具自动 connect_pg_net但务必做一遍 formal 和 LVS 的电源连接验证。我在一个项目里就靠 LVS 报出的 floating 引脚揪出了一个被漏接的 switch PG pin。4. 仿真验证与功耗分析的坑4.1 RTL 仿真为什么会出一堆 X怎么解很多团队在功能验证阶段跑的是纯 RTL 仿真不带 UPF这时候低功耗行为其实是“看不见”的。等到 gate-level 仿真或者带 UPF 的低功耗仿真一开跑问题就集中爆发了——最典型的就是仿真波形里铺天盖地的 X。原因很直接掉电域真的断电了输出没有钳位逻辑接收域看到的信号就成了 X。遇到这种问题要先分清是“设计缺陷”还是“仿真环境配置问题”。我曾经排查一个 X 态问题折腾了两天最后发现是仿真库里的 isolation cell 逻辑模型没有正确例化仿真器不认识这个 cell 的 pg pin直接把它当黑盒处理。后来换了带电源语义的仿真库X 态立刻消失大半。排查顺序我建议是先确认 UPF 是否被仿真工具正确加载再确认库模型是否支持 UPF 电源行为最后再追设计本身的时序问题。别一上来就把锅甩给 RTL。另一个常见情况是复位信号的时序。掉电域重新上电后寄存器需要复位或者 restore如果复位信号和上电时序之间的约束没写对仿真器会认为某些寄存器在不确定状态产生 X。这里提一个实操技巧在仿真器里给所有非 retention 寄存器加一个初始值约束比如force -deposit先让仿真跑通再逐步放开约束去验证真实的复位行为。这样能帮你快速区分“仿真环境对未知状态的保守处理”和“实际复位逻辑缺陷”。4.2 功耗分析里那些“虚高”的数字功耗仿真出来电流大得吓人别急着怀疑工艺有问题大概率是你的 vector 不完整或者状态依赖没设置好。低功耗分析工具比如配合 UPF 做功耗分析的 PrimeTime PX 或 Voltus都需要足够代表性的翻转率数据如果你只给了一组功能模式 vector漏电功耗算出来会失真动态功耗也会因为缺少实际翻转活动而偏高或偏低。这里要给两个建议。第一做功耗分析时的 vector 必须覆盖目标低功耗状态的进入和退出过程。比如你要算 standby 功耗不能只给一个“系统空闲”的 vector还要让 vector 跑完完整的“进入 standby”、“standby 保持”、“被唤醒”三个阶段分析工具才会根据电源状态转换计算不同阶段的功耗。第二注意状态依赖功耗state-dependent leakage。同样一个标准单元输入是 0 和输入是 1 时的漏电可能差好几倍。如果你的约束里把掉电域的输出固定在了错误电平isolation clamp 值设得不对工具根据状态算出来的漏电会明显偏低因为实际芯片里那个节点可能正处于高漏电状态。我做过一个对比同一颗芯片把某掉电域的输出 clamp 值从 0 改成 1仿真出来的静态功耗差了大约 8%。虽然数字不算夸张但低功耗项目的目标往往就那么几毫瓦8% 已经能决定指标能否达成。所以 clamp 值的选择不仅影响功能还直接影响功耗报告的可信度。5. 常见问题速查与进阶提醒5.1 过一遍最容易犯的 UPF 错误速查表根据这几年做低功耗项目的经验我把高频踩坑点整理成了一个速查表适合贴显示器旁边。现象可能原因处理建议UPF 加载报 instance not found-elements写了不存在的路径或名字先从设计层次 dump 真实名字再更新 UPF掉电域输出仿真全是 Xisolation cell 没插或 clamp 策略失效检查set_isolation和set_isolation_control是否落入目标域Power Switch 关断后仍有漏电switch 的 output 没和内部供电网隔离确认内部 supply net 独立且只通过 switch 供电唤醒后寄存器数据丢失该保留状态的寄存器没加 retention用set_retention声明保留元素检查 save/restore 时序Level Shifter 缺失导致高低压跨域错误只配了 low-to-high漏了 high-to-low在 UPF 里显式声明两个方向都做 level shift功耗状态检查 mismatchadd_power_state与 supply set 关联不一致逐一核对每个域的-supply_expr对应关系后端 LVS 报 switch 引脚浮空Power Switch 的 PG pin 没连接到 supply net检查connect_pg_net和后端电源网络映射这张表只是“提醒”真正解决问题时还是得回到你的设计本身。我见过不少工程师对着工具报错硬猜其实工具报错信息里往往已经给了出错对象和坐标静下心读一遍比盲目试错高效得多。5.2 嵌入式 MCU 低功耗与芯片级 UPF 低功耗是两回事看到热词里有stm32l151c8t6a低功耗设计我多说一句。很多人刚接触低功耗时会拿 STM32L151 这类 MCU 的 Stop/Standby 模式去类比 UPF 设计其实两者层次不同。MCU 的低功耗是“用起来省电”通过软件配置寄存器关掉外设时钟、切到低频晶振、进入内置的低功耗模式这些行为是由芯片内部的 PMU 硬件模块和厂商固件库控制的你用到的只是封装好的接口。而 UPF 是“设计出来就省电”——它是在芯片设计阶段把“哪个 CPU 域在 standby 时断电、断到多低、哪些寄存器保持、跨域信号怎么隔离”这些决策写进电源意图文件最终由 Power Switch、Isolation Cell、Retention Cell 这些硬件单元在芯片里真实执行。这也解释了一个现象很多 MCU 的参考手册里会明确说某个低功耗模式下哪些外设仍然供电、哪些 RAM 内容保持更高级的 MCU 甚至会在手册里画电源域框图。如果有一天你不再满足于“调库函数进入 sleep”而是开始关注芯片内部的电源域划分那么 UPF 的知识就有用武之地了。反过来如果你只是做应用开发完全没必要去碰 UPF把精力放在合理管理外设时钟和选择合适睡眠模式上收益大得多。这两条路不冲突但别混着学否则容易两头不靠。5.3 最后分享一个小习惯不管 UPF 流程玩得有多熟我始终建议在每个低功耗项目的早期就固定下来一套“UPF 自检清单”。我自己的清单大概是这样的每次修改 UPF 后先跑一遍工具自带的 UPF 编译和 consistency check综合完成后检查 isolation 和 retention cell 的数量布局后抽三个关键跨域路径看时序和摆放位置流片前的功耗分析至少做两遍一遍用功能 vector一遍用低功耗状态切换 vector。这套流程看上去繁琐但真能帮你把问题暴露在项目早期而不是等到芯片回来再追悔莫及。低功耗设计的坑说到底大多是“架构决策没在 UPF 里表达清楚”或者“UPF 表达清楚了但物理实现没跟上”这两类。把 Power Switch、Isolation Cell、Level Shifter、Retention Cell 这几个基础单元吃透再配合严格的 UPF 检查和验证流程你手里的那颗“低功耗芯片”才能真正做到既省电又能稳稳跑起来。
返回列表