9.【UPF】UPF Retention Strategies(UPF留存策略)
第一步:UPF Retention Strategies 分析与知识整理
1. 为什么学习Retention Strategies
- 电源门控会丢失所有触发器状态。保持策略通过最小保持电压保留关键状态,实现快速唤醒。
- 唤醒延迟从毫秒级(完全重新初始化)降到微秒级,使激进电源门控在响应式系统中可行。
2. 你将学到什么
- 状态保持的概念及使用场景
- 使用
set_retention定义保持策略 - 指定保持电源和控制信号
- 为关键状态实现选择性保持
3. 理解状态保持
- 问题:电源门控时,所有触发器状态丢失。唤醒后需要软件重新初始化,耗时毫秒级。
- 解决方案:保持触发器具有双电源:
- 主电源(VDD_domain):正常工作,可开关
- 保持电源(VDD_RET):常开、低电压(0.6-0.8V),用于状态保存
- 工作流程:
- 断电:断言保持控制信号 → 保持FF切换到VDD_RET → 关断VDD_domain → 保持单元用VDD_RET维持状态(极低漏电)
- 上电:恢复VDD_domain → 解除保持控制 → 保持FF切回VDD_domain → 状态恢复,无需软件初始化
- 唤醒时间:微秒级(vs 毫秒级无保持)
4. 何时使用保持
| 场景 | 使用保持? | 理由 |
|---|---|---|
| 频繁电源循环 | 是 | 快速唤醒值得保持开销 |
| 关键状态需保留 | 是 | 重新初始化代价高或不可能 |
| 长时间睡眠(小时) | 可能 | 保持漏电累积可能超过重新初始化成本 |
| 短时间睡眠(<1ms) | 是 | 重新初始化开销占主导 |
| 不频繁断电 | 否 | 罕见唤醒时简单重新初始化更优 |
5. 保持触发器单元
- 标准FF vs 保持FF:
- 保持FF额外需要VDD_RET电源和SAVE/RESTORE控制信号
- 面积:1.3-1.5倍(大30-50%)
- 活跃功耗:+5-10%
- 重要:不要对所有FF使用保持,仅对关键状态使用。非关键状态可用标准单元以节省面积。
6.set_retention语法
基本形式:
set_retention strategy_name -domain domain_name \ -retention_supply_set supply_set_name \ [options]关键参数:
strategy_name:策略名(必须)-domain:应用保持的域(必须)-retention_supply_set:保持电源的供电集(必须)-retention_condition {expr}:布尔表达式控制保持-save_signal {signal sense}:保存状态的信号-restore_signal {signal sense}:恢复状态的信号-elements {instance_list}:指定保留的实例(默认所有FF)
使用变体:
- 基本保持(域内所有FF):
set_retention RET_CPU -domain PD_CPU -retention_supply_set SS_CPU_RET -retention_condition {cpu_retention_enable} - 显式保存/恢复信号:
set_retention RET_GPU -domain PD_GPU -retention_supply_set SS_GPU_RET -save_signal {gpu_save_state high} -restore_signal {gpu_restore_state high} - 选择性保持(特定实例):
set_retention RET_CRITICAL -domain PD_CPU -retention_supply_set SS_CPU_RET -retention_condition {retention_en} -elements {cpu_inst/control_regs cpu_inst/status_regs}
- 基本保持(域内所有FF):
7. 定义保持供电集
保持需要单独的常开保持电源。
- 主电源VDD_CPU(可开关)
- 保持电源VDD_RET(常开,0.6V)
- 两个供电集:SS_CPU_ACTIVE(主)和SS_CPU_RET(保持)
- 关联主供电集到域,保持供电集在
set_retention中引用
8. 保持控制信号
-retention_condition:单信号控制,信号=1时保持激活(使用VDD_RET),=0时正常(使用VDD_CPU)-save_signal和-restore_signal:显式控制保存和恢复时序,用于复杂电源序列- 信号极性:
high或low,例如-retention_condition {!ret_en_n}表示低有效
9. 选择性保持
- 使用
-elements指定需要保持的实例,不指定则域内所有FF都替换为保持FF。 - 优点:面积小、保持漏电低、综合快
- 候选:控制寄存器、缓存标签阵列、TLB项、电源管理状态
- 不保留:数据路径寄存器(ALU操作数)、临时变量、可重新计算状态
10. 完整保持示例
原教程给出了CPU域的完整UPF:包括常开TOP域、CPU域(主电源+保持电源)、电源开关、保持策略。并描述了断电和上电序列。
11. 保持单元映射:map_retention_cell
- 语法:
map_retention_cell strategy_name -domain domain_name -lib_cells {cell_list} - 示例:
map_retention_cell RET_CPU -domain PD_CPU -lib_cells {DFFR_X1 DFFR_X2 DFFR_X4} - 综合工具将标准D触发器替换为保持变体。
12. 保持 vs 重新初始化权衡
- 保持好处:快速唤醒、软件复杂度低、响应性好
- 保持成本:面积+30-50%、常开保持电源(非零功耗)、额外控制逻辑、设计验证复杂度
- 盈亏分析:当唤醒频率 × 节省时间 × 软件代价 > 保持面积 + 保持功率 × 睡眠时间 × 唤醒频率时,使用保持。
13. 常见初学者错误
- 错误1:忘记创建保持供电集 → 必须先
create_supply_set。 - 错误2:保持供电集使用可开关电源 → 必须用常开保持电源。
- 错误3:不必要地保持所有FF → 使用选择性保持。
14. 实践练习
要求为GPU域实现选择性保持:主电源0.9V可开关,保持电源0.6V常开,仅保留配置寄存器和着色器状态,控制信号gpu_retention_enable高有效。
15. 总结
- 状态保持通过常压低电压电源保留触发器内容,实现微秒级唤醒。
set_retention定义策略,需要保持供电集和控制信号。- 保持单元面积大30-50%,需双电源。
- 选择性保持减少开销。
- 适用于频繁电源循环的域,不适用于罕见或极长睡眠。
第二步:用费曼学习法学习UPF保持策略
保持策略(Retention)就是给芯片的“记忆”配一个UPS不间断电源——主电源断了,备用小电池还能记住关键数据,一恢复主电就能瞬间醒来。作为验证工程师,我的任务是确保这个备用电池(保持电源)永远有电,切换开关(控制信号)时序正确,并且不要给每个寄存器都配电池(太浪费)。本文用“电脑休眠”的比喻,帮你彻底搞懂:为什么需要保持?保持触发器怎么工作?如何用
set_retention指定策略?以及如何避免“全盘保留”的面积陷阱。
我们着重讲什么?需要关注什么?为什么这样做?好处?如何学习使用?
着重讲解:
- 保持的本质:双电源触发器,主电断后由低电压常开电源维持状态。
set_retention的三要素:保持供电集、控制信号(条件或保存/恢复)、可选的选择性实例。- 保持 vs 重新初始化:何时用保持,何时用重启。
- 选择性保持:只保留关键寄存器,面积和漏电都省。
- 必须的电源和开关配合:保持电源必须常开,且电源门控必须与保持控制协调时序。
为什么这样做:没有保持,电源门控后唤醒需要软件重新初始化所有寄存器,耗时毫秒级,用户体验差(手机亮屏慢)。有了保持,唤醒只需微秒级,瞬间恢复。
好处:
- 快速唤醒(微秒 vs 毫秒)
- 软件简化(无需重新初始化代码)
- 允许更频繁的电源门控,进一步省电
如何学习使用:
- 先理解保持触发器结构:两个电源引脚,一个控制引脚。
- 手写一个简单的保持UPF:一个域,主电源1.0V,保持电源0.6V,一个控制信号。
- 用仿真器跑序列:断言保持控制 → 关主电 → 等一段时间 → 开主电 → 解除保持控制,检查寄存器值是否保留。
- 加入选择性保持:指定
-elements只保留一部分寄存器,观察综合报告里哪些FF被替换为保持单元。 - 分析实际设计:找出哪些状态必须保留(如配置寄存器、状态机状态),哪些可以重新计算(如数据缓冲)。
下面按知识点展开,每个部分有通俗解释、代码示例和验证工程师的实战视角。
一、保持是什么?用“电脑休眠”比喻秒懂
通俗解释:你正在写文档,突然要离开。你可以选择:
- 关机:完全断电,所有未保存数据丢失。回来要重新开机、打开软件、加载文档(毫秒到秒级)→ 相当于无保持的电源门控。
- 休眠:电脑把内存数据存到硬盘,然后断电。恢复时从硬盘读回内存,比关机快但仍有延迟 → 相当于无保持的电源门控但加了外部存储。
- 睡眠:电脑保持内存供电,其他大部分断电。一按键盘,瞬间恢复 → 这就是保持!内存(相当于寄存器)由低电压小电源维持,唤醒快如闪电。
在芯片里,保持触发器就是那个“睡眠模式下的内存”——用一个小电池(保持电源VDD_RET,0.6V)维持数据,主电源(VDD_domain,1.0V)可以完全关断。
技术实现:保持触发器内部有一个锁存器,当控制信号有效时,锁存器切换到VDD_RET供电,主电源断开后数据不丢。
二、set_retention三要素:电源、控制、范围
要素1:保持供电集(必须)
保持触发器需要第二个电源——常开的低电压电源。这个电源必须永远不断电(即使域关断)。在UPF中用独立的供电集表示。
create_supply_net VDD_CPU_RET -domain PD_CPU create_supply_set SS_CPU_RET -function {power VDD_CPU_RET} -function {ground VSS}验证检查:VDD_CPU_RET必须来自常开域(如PD_TOP),并且add_power_state中不能有off状态,只能是ON或RETENTION。
要素2:控制信号
告诉触发器何时切换到保持电源。
- 简单方式(
-retention_condition):一个信号,高电平表示保持模式,低电平表示正常模式。set_retention RET_CPU -domain PD_CPU -retention_supply_set SS_CPU_RET -retention_condition {cpu_retention_enable} - 精细方式(
-save_signal/-restore_signal):分开控制保存和恢复,适合复杂握手。set_retention RET_GPU -domain PD_GPU -retention_supply_set SS_GPU_RET -save_signal {gpu_save high} -restore_signal {gpu_restore high}
验证重点:控制信号必须来自常开域,否则断电后信号丢失,无法切换。另外,控制信号的时序必须正确:断电前先断言保持,主电源稳定后再解除。
要素3:范围(选择性保持)
默认set_retention会替换域内所有触发器为保持触发器,面积大增。通过-elements只保留关键寄存器。
set_retention RET_CRITICAL -domain PD_CPU \ -retention_supply_set SS_CPU_RET \ -retention_condition {ret_en} \ -elements { cpu_inst/control_regs cpu_inst/status_regs cpu_inst/mmu/tlb_entries }验证检查:综合后查看报告,确认只有指定的实例被替换为保持FF,其他仍是标准FF。如果发现意外替换,可能是通配符范围过大。
三、保持电源电压:0.6V的秘密
为什么保持电压通常是0.6V左右?因为:
- 太低(<0.5V):数据可能丢失,保持触发器内部锁存器翻转。
- 太高(>0.8V):漏电显著增加,失去省电意义。
- 工艺库会给出最小保持电压(V_ret_min),通常0.5-0.6V。
验证检查:确认add_power_state中定义的保持电压(如0.6V)不低于库的最小保持电压。同时检查保持电源是否独立于主电源——不能把VDD_RET和VDD_CPU短路。
四、完整序列:断电和上电的正确姿势
断电序列(以-retention_condition为例):
- 软件准备睡眠。
- 断言
cpu_retention_enable = 1→ 所有保持FF切换到VDD_RET供电。 - 等待几个时钟周期(确保切换完成)。
- 电源门控:
cpu_power_enable = 0→ VDD_CPU关断。 - 域断电,但VDD_RET仍供电,保持FF状态不丢。
上电序列:
cpu_power_enable = 1→ VDD_CPU恢复。- 等待电压稳定(通常有
power_good信号)。 - 解除保持:
cpu_retention_enable = 0→ 保持FF切回VDD_CPU。 - 释放复位,CPU从之前的状态继续执行,无需重新初始化。
验证测试:写一个仿真用例:
- 向保留寄存器写入已知值(如0x5A5A)。
- 执行断电序列,模拟电源关闭(可用
force使VDD_CPU为0)。 - 等待一段时间。
- 执行上电序列,读取寄存器,检查值是否仍为0x5A5A。
如果值改变,说明保持失效。常见原因:保持控制信号时序错、保持电源在主电断后也断了、或者该寄存器没有被替换为保持FF。
五、选择性保持:不要给整个房子装UPS
假设一个CPU有10万个寄存器,但只有1000个是关键的(配置寄存器、状态机、TLB),其余都是数据路径临时寄存器(可以重新计算)。如果对所有10万寄存器都使用保持FF,面积增加30-50%,可能多花几百万门,而且保持电源的漏电也会显著增加。
正确做法:只保留那1000个关键寄存器。其他寄存器断电后丢失没关系,软件唤醒后重新初始化即可(比如从内存加载配置)。
如何决定哪些寄存器需要保持?
- 必须保留:电源管理状态、中断控制器设置、时钟分频系数、已配置的基址寄存器。
- 可以不保留:正在处理的算术运算中间值、FIFO中的数据(可以从外部重新灌入)、缓存数据(可以从下一级缓存或内存重新加载)。
UPF实现:
set_retention RET_CPU_CORE -domain PD_CPU \ -retention_supply_set SS_CPU_RET \ -retention_condition {core_retention} \ -elements { cpu_top/ctrl_regs cpu_top/status_regs cpu_top/mmu/tlb_valid }验证检查:使用report_retention -elements查看哪些实例被保留。同时写测试:只保留部分寄存器,断电后检查未保留的寄存器是否变为X(表示未保持),而保留的寄存器值不变。
六、保持 vs 重新初始化:何时用保持?
原教程的决策表:
- 频繁电源循环(每秒多次)→ 用保持。
- 关键状态必须保留 → 用保持。
- 长时间睡眠(数小时)→ 可能不用,因为保持电源的微小漏电累计可能超过重新初始化的能耗。
- 不频繁断电 → 不用,简单重新初始化更省事。
实际例子:
- 智能手机的CPU核心:在屏幕点亮时,可能每秒多次进入空闲再唤醒。用保持非常值得。
- 物联网传感器:每隔几分钟采集一次数据,中间深度睡眠。如果保持漏电很低(nA级),也可以保持;如果漏电较高,不如完全断电后重新初始化。
验证建议:与系统架构师讨论唤醒频率和可接受的唤醒延迟。如果规格要求唤醒<50µs,则必须用保持;如果允许1ms,也许可以不保持。
七、保持单元映射:map_retention_cell
UPF的set_retention是抽象策略。综合时需要知道用库里的哪个具体单元来实现保持功能。
map_retention_cell RET_CPU -domain PD_CPU \ -lib_cells {DFFR_X1 DFFR_X2 DFFR_X4}DFFR可能是“D Flip-Flop with Retention”的缩写。X1,X2,X4表示驱动强度,工具会根据负载自动选择。
验证检查:综合后打开网表,搜索DFFR,确认数量与预期一致。同时检查没有用到不支持保持的库单元。
八、常见错误与避坑
| 错误 | 后果 | 正确做法 |
|---|---|---|
| 保持供电集使用可开关电源 | 断电后保持电源也断,状态丢失 | 保持电源必须来自常开域 |
| 忘记创建保持供电集就引用 | 工具报错 | 先create_supply_set |
| 对所有FF都用保持 | 面积爆炸,漏电增加 | 使用-elements选择性保持 |
| 控制信号来自可关断域 | 断电后控制信号悬空,无法恢复 | 控制信号必须来自常开域 |
| 断电序列中先断主电再断言保持 | 保持未激活主电已断,状态丢失 | 先断言保持,稳定后再断主电 |
九、完整代码示例:GPU域选择性保持
原练习要求:GPU域,主电源0.9V可开关,保持电源0.6V常开,只保留config_regs和shader_state,控制信号gpu_retention_enable高有效。
答案(带注释):
# 顶层常开域 create_power_domain PD_TOP -include_scope create_supply_net VDD_TOP -domain PD_TOP create_supply_net VSS -domain PD_TOP create_supply_set SS_TOP -function {power VDD_TOP} -function {ground VSS} associate_supply_set SS_TOP -handle PD_TOP add_power_state VDD_TOP -state {ON 1.2} # GPU域 create_power_domain PD_GPU -elements {gpu_inst} create_supply_net VDD_GPU -domain PD_GPU create_supply_net VDD_GPU_RET -domain PD_GPU create_supply_net VSS -domain PD_GPU # 主供电集 create_supply_set SS_GPU_ACTIVE -function {power VDD_GPU} -function {ground VSS} associate_supply_set SS_GPU_ACTIVE -handle PD_GPU # 保持供电集 create_supply_set SS_GPU_RET -function {power VDD_GPU_RET} -function {ground VSS} # 电源状态 add_power_state VDD_GPU -state {ACTIVE 0.9} -state {OFF off} add_power_state VDD_GPU_RET -state {RETENTION 0.6} # 电源开关(假设输入来自VDD_TOP) create_power_switch PSW_GPU -domain PD_GPU \ -input_supply_port {in VDD_TOP} \ -output_supply_port {out VDD_GPU} \ -control_port {ctrl gpu_power_enable} \ -on_state {on in {ctrl}} # 保持策略(选择性) set_retention RET_GPU -domain PD_GPU \ -retention_supply_set SS_GPU_RET \ -retention_condition {gpu_retention_enable} \ -elements { gpu_inst/config_regs gpu_inst/shader_state } # 映射库单元(示例) map_retention_cell RET_GPU -domain PD_GPU \ -lib_cells {RET_FF_X1 RET_FF_X2}验证步骤:
- 检查UPF语法:
check_upf -verbose - 仿真:写测试,向
config_regs写入值,断言gpu_retention_enable,关gpu_power_enable,等待,恢复电源,解除保持,读回值,验证不变。 - 检查
shader_state之外的寄存器(如gpu_inst/temp_data)是否在断电后变为X(表示未保持)。 - 综合后检查网表:只有
config_regs和shader_state对应的触发器被替换为RET_FF。
十、学习路线图
- 第1天:理解保持触发器的双电源概念,手写一个单域带保持的UPF,用仿真器跑基本序列。
- 第2天:加入电源开关,练习保持控制信号与电源门控的时序配合。
- 第3天:实现选择性保持,用
-elements只保留几个寄存器,对比综合报告的面积差异。 - 第4天:分析一个真实IP的UPF,找出其保持策略和保留实例列表。
- 第5天:编写验证测试,覆盖错误序列(如先断主电再断言保持),检查工具是否报错或仿真出现X。
推荐命令:
report_retention -domain PD_CPU:查看保持策略详情。check_mv_design -retention:检查保持电源和控制信号的合法性。
保持策略是UPF中实现“快速唤醒+低漏电”的关键。掌握了它,你就能让芯片在睡眠时几乎不耗电,醒来时瞬间恢复状态。
