4. VCS低功耗仿真流程与调试
低功耗仿真的核心难点在于:UPF 描述的是电源意图,RTL 描述的是功能行为,二者必须在同一个仿真内核中被“绑定”起来,才能让电源域、电源开关、隔离单元、电平转换器、保持寄存器等低功耗结构真正参与仿真。VCS 通过 -upf 选项在编译阶段把 UPF 命令文件与 RTL 一起读入,生成带有电源感知能力的仿真模型。理解这条联合编译链路,是后续所有调试工作的基础。
一、UPF 与 RTL 联合编译的加载顺序
VCS 对 UPF 的处理分为“编译期加载”和“运行期激活”两个阶段。编译期使用 -upf 指定 UPF 文件,VCS 会解析其中的 create_power_domain、create_supply_port、create_supply_net、connect_supply_net 等命令,建立电源域与电源网络的静态结构;运行期则通过 $supply_on、$supply_off、set_port_attributes 等系统任务或 UPF 中的 add_power_state 控制电源状态切换。
一个典型的联合编译命令如下:
vcs -full64 -sverilog -debug_access+all \
-upf top.upf \
-power=upf_sim \
-lca -kdb \
-f rtl.f \
-o simv_pwr
其中 -power=upf_sim 启用 UPF 低功耗仿真模式,-lca 用于开启部分低功耗特性(不同版本可能不同),-kdb 生成知识数据库以便 Verdi 联合调试。若 UPF 中引用了 RTL 中不存在的信号或端口,编译阶段就会报 UPF-xxx 类错误,此时应优先检查 UPF 与 RTL 的命名一致性,而不是急于进入仿真。
-upf 多次加载,便于定位是哪一层出错。二、关键仿真选项与运行期控制
编译完成后,运行阶段常用选项包括:+upf_isolation_check 打开隔离单元检查,+upf_low_power_debug 输出低功耗调试信息,-power=upf_sim 在运行期继续生效。若需要观察电源状态切换对功能的影响,可在 testbench 中调用:
initial begin
$supply_on("VDD", 1.2);
$supply_on("VDD_SW", 1.2);
#100;
$supply_off("VDD_SW");
#50;
$supply_on("VDD_SW", 1.2);
end
这里 $supply_on/off 控制的是电源网络电压,而不是简单的 0/1 逻辑。当某个电源域被关断后,该域内信号会变为 X 或保持值,隔离单元输出被钳位到确定电平,保持寄存器则保留关断前的值。仿真日志中会记录 Power domain ... is switched off 等事件,这是判断低功耗行为是否按预期发生的第一手依据。
三、低功耗仿真日志的阅读方法
VCS 低功耗日志通常包含三类信息:电源域状态变化、隔离/保持单元动作、以及 UPF 命令执行结果。阅读时建议按时间顺序抓取关键行,例如:
[UPF] Power domain PD_CPU switched OFF at time 150
[UPF] Isolation cell iso_cpu_en asserted, output clamped to 0
[UPF] Retention register reg_state saved value 0xA5
[UPF] Power domain PD_CPU switched ON at time 220
[UPF] Retention register reg_state restored value 0xA5
如果日志中缺少某条预期事件,说明对应的 UPF 策略没有被正确加载或触发。例如隔离单元未动作,可能是 set_isolation 的作用域写错,或隔离使能信号本身位于被关断域内,导致它无法被驱动。
四、常见错误与调试方法
低功耗仿真中最常见的错误可以归为四类。第一类是 UPF 与 RTL 命名不匹配,典型报错为 UPF-201: Instance 'u_cpu' not found。解决方法是核对 UPF 中 create_power_domain -elements 的路径是否与 RTL 层次一致,注意 generate 块和数组实例的展开名。
第二类是 隔离使能信号位于被关断域内。当 PD_CPU 关断后,若 iso_en 也属于 PD_CPU,它就会变成 X,隔离单元无法被正确使能。正确做法是把隔离使能信号放在常开域(always-on domain),或在 UPF 中用 set_isolation -iso_signal 显式指定一个来自常开域的端口。
第三类是 保持寄存器未正确恢复。日志中看到 Retention saved 但没有 restored,通常是因为 set_retention 的 -retention_signal 没有在电源恢复时被触发,或者保存/恢复的时序与电源开关顺序冲突。调试时可在波形中同时观察电源网络、保持使能和寄存器输出。
第四类是 电源状态切换顺序错误。例如先关断 VDD_SW 再关断 VDD,可能导致中间态出现未知电平。UPF 中可用 add_power_state 定义合法状态序列,仿真时若出现非法切换,日志会给出 Power state transition not allowed 提示。
force 强行把 X 拉成 0/1 来“绕过”低功耗错误。X 的出现往往正是隔离或保持策略缺失的信号,强行覆盖会掩盖真实缺陷,导致流片后出现不可恢复的功能失效。五、调试闭环与检查清单
一个可复用的调试闭环是:先看编译日志确认 UPF 全部加载成功,再看仿真日志确认电源域切换事件与预期一致,然后在波形中检查隔离输出、保持寄存器和跨域信号,最后用 Verdi 的 UPF 调试视图回溯电源状态与信号值的对应关系。下面给出一个可直接对照使用的检查清单:
| 检查项 | 观察位置 | 通过标准 |
|---|---|---|
| UPF 是否全部加载 | 编译日志 UPF- 行 |
无 error,warning 已确认 |
| 电源域切换事件 | 仿真日志 [UPF] 行 |
ON/OFF 时间与 TB 一致 |
| 隔离单元动作 | 波形 iso_out | 关断期间为确定电平 |
| 保持寄存器恢复 | 波形 reg_state | 恢复后等于保存值 |
| 跨域信号完整性 | 波形 level_shift 输出 | 无长时间 X 传播 |
把上述流程固化为脚本化回归,每次 RTL 或 UPF 变更后自动重跑并比对日志关键行,可以显著降低低功耗验证的漏检率。真正有效的调试不是等到仿真失败才去翻日志,而是在编译阶段就把 UPF 与 RTL 的绑定关系检查清楚,在运行阶段用日志和波形交叉验证每一个电源状态切换是否符合设计意图。