复位验证:复位与初始化的检查点、SVA 与 X 传播
更新时间:2026-09-25。本文是「集成电路大类 · 数字验证」序列的一篇中间层专题。testbench 的基本结构(时钟、复位如何由 TB 唯一产生)见 SystemVerilog Testbench 实战,断言写法见 SVA 实践,复位后 X 会不会在门级网表里一路传播见 门级仿真 SDF 与 X 传播。这一篇只盯住一个场景:芯片从上电到「第一条正常事务」之间那段路,怎么验证它走得对。
本文要回答的问题
- 复位有效期间和复位撤销之后,DUT 分别应该是什么样子,怎么用断言把这两个阶段都盯住?
- 异步复位为什么要「异步生效、同步释放」,释放沿和时钟沿靠太近会出什么问题?
- 多复位域、复位有先后顺序的系统,验证要造哪些场景、收哪些覆盖?
一、复位验证在查什么:两个阶段,两类问题
复位(reset)不是一根线拉低再拉高那么简单。它把芯片切分成两个语义完全不同的阶段,复位验证就是分别给这两个阶段立规矩:
- 复位有效期间(asserted):所有寄存器被强制到已知值,FSM(有限状态机)必须停在初始态,计数器、指针、读写地址全部为零或约定值,对外输出必须是确定的 0/1——不允许出现 X(不定态)。
- 复位撤销之后(deasserted):从释放沿开始,设计要在规定的时钟周期内「醒过来」,FSM 能从初始态正常跳转,流水线上一笔陈旧数据不能残留,接口进入可以接受事务的状态。
实际项目里,复位 bug 的典型长相不是「复位完全不起作用」(那种仿真第一秒就炸),而是更隐蔽的几种:复位期某根输出是 X,RTL 仿真被掩盖、门级仿真才爆;复位释放沿贴着时钟沿,违反 recovery time(恢复时间,指复位撤销到下一个有效时钟沿之间的最小时长),某些触发器没退出复位;多复位域撤销顺序不对,A 域已经开始发请求、B 域还在复位,接口上出现一笔无人认领的事务。这些问题定向用例里把复位拉三个周期就放行,根本碰不到。
二、同步复位与异步复位:先搞清 RTL 是哪一种
验证之前必须读 RTL 确认复位类型,因为两者的失效模式和检查时序完全不同。
| 维度 | 同步复位 | 异步复位 |
|---|---|---|
| RTL 写法 | always @(posedge clk) 内判断 rst | 敏感列表含 posedge rst 或 negedge rst_n |
| 生效条件 | 必须有时钟沿,复位才被采到 | 不依赖时钟,立即生效 |
| 复位期时钟停摆 | 复位不起作用 | 仍然生效 |
| 主要风险 | 复位脉冲短于一个周期会漏采 | 释放沿靠近时钟沿,违反 recovery/removal |
| 释放处理 | 天然同步,无需特殊电路 | 需同步释放,见下节 |
同步复位要专门测「短复位脉冲」:复位只持续不到一个时钟周期,设计按规格应当忽略,TB 要确认 DUT 状态纹丝不动。异步复位则反过来,重点全在释放沿。还有一种工程上最常见的折中:异步复位、同步释放——复位生效不挑沿(保证时钟没起来时也能复位),但撤销信号经过两级触发器同步后再送给逻辑,避开亚稳态窗口。
下面这张图是异步复位同步释放的经典电路,也是验证要在 RTL 里认出、在网表里确认没被综合掉的结构。

读图的要点:复位拉低那条通路是直通的,所以任何时刻都能立即复位;而复位变高后要穿过两级触发器,内部复位 rst_n_sync 的撤销永远落在时钟沿之后一个干净的位置。验证时要检查两级触发器真实存在(复位树审查),还要造「外部复位在时钟沿附近撤销」的用例,确认同步器后面的逻辑看不到毛刺。
三、复位期间的检查:输出必须确定,状态必须归零
复位有效期间最核心的一条铁律:任何对外可见的输出和内部关键状态,都不允许是 X。RTL 里寄存器若没有复位初值,仿真初值就是 X;功能仿真中 X 有时被后续逻辑「碰巧」掩盖,但门级仿真和硅后不会跟你讲道理——这正是 X 传播问题,详见 门级仿真 SDF 与 X 传播。
用 SVA(SystemVerilog Assertion,断言)把复位期的规矩固化下来:
// 复位有效期间,关键输出不得为 X/Z
property p_reset_outputs_known;
@(posedge clk) (!$isunknown({valid, ready, data_out}));
endproperty
a_reset_out: assert property (p_reset_outputs_known)
else $error("X/Z during reset at %0t", $time);
// 复位期间接口必须静默:valid 类信号恒为 0
a_reset_idle: assert property (@(posedge clk)
!rst_n |-> !valid)
else $error("interface active while in reset");
// 复位撤销当拍起,FSM 必须回到 IDLE,计数器归零
a_rst_fsm: assert property (@(posedge clk)
$rose(rst_n) |=> (fsm_q == IDLE) && (cnt_q == '0))
else $error("FSM/counter not initialized after reset");注意第三条用的是 |=>(下一周期成立),因为撤销当拍寄存器输出还是旧值。这类断言应该在整条回归里常驻,而不是只跑一个复位专用用例——复位可以在任何随机用例中途重新到来,任何时刻复位后都必须满足这些性质。
复位期还要检查的一组点:FIFO 的读写指针和 full/empty 标志、存储器模型的输出是否被隔离(存储体内容通常不复位,但输出端口必须给出确定值)、三态总线是否进入高阻而非 X、中断等 sticky(粘滞)状态是否被清掉。
四、复位释放与恢复:制造「贴边」的时序用例
异步复位释放沿和时钟沿的关系,是复位验证最容易漏、也最容易在硅上出事的地方。两个时序参数要心里有数:
- recovery time(恢复时间):复位撤销到下一个时钟有效沿的最小间隔。间隔不够,触发器可能这一沿没认出「复位已结束」。
- removal time(撤离时间):复位撤销沿相对于时钟沿的最小保持时间,和保持时间是一个道理。
功能仿真没有真实延迟,沿对沿永远「刚好」,这类问题只能靠两类手段夹击。一是门级仿真带 SDF(标准延迟格式)反标,专门让复位在时钟沿前后抖动撤销;二是在功能级就把随机复位时序写进用例,把空间探出来。
// 随机复位:长度随机,且释放点相对时钟沿有随机偏移
task automatic random_reset;
int len;
len = $urandom_range(1, 50); // 复位长度 1~50 周期
rst_n = 0;
repeat (len) @(posedge clk);
#($urandom_range(0, 9999)); // 皮秒级随机偏移,贴沿释放
rst_n = 1;
endtask配合这个任务,回归里要反复做「运行中突然复位」:在流水线满载、FIFO 半满、有未完成事务的时刻拉复位,然后检查陈旧数据没有漏到复位后的第一笔正常事务里。复位撤销后再观察若干周期,确认 FSM 从 IDLE 正常起步、计数器从 0 计数、接口握手能正常建立。
五、多复位域与复位顺序
稍大的芯片几乎都有多个复位域:上电复位(POR,Power-On Reset)、硬复位、软复位、各子系统独立复位、调试复位。要验证的不是单个域,而是它们之间的关系。
- 复位顺序规格:有些系统要求时钟先稳定、再解除 PLL 复位、最后解除逻辑复位;撤销顺序错了,逻辑会在没有时钟时跑出 X,或向仍在复位的模块发请求。
- 部分复位(局部软复位):只复位某一个 block 时,它与未复位邻居之间的接口必须被安全隔离,valid 不能在对端复位期间漏过去。
- 复位交叉:A 域复位、B 域不复位时跨域请求的行为,要和 CDC(跨时钟域)检查联动;复位本身也是一种需要同步的异步信号。
覆盖(coverage)要把这些场景显式收进来,否则跑没跑到全凭感觉:
| 覆盖组 | 采样点 |
|---|---|
| 复位长度 | 1 周期、2–5 周期、长复位(如 >20 周期)分箱 |
| 复位时系统状态 | 空闲时复位、事务中途复位、满载时复位、错误状态中复位 |
| 复位中事件 | 复位期间到达的请求/中断(应被忽略且不残留) |
| 释放时序 | 复位撤销沿相对时钟沿的位置(贴沿场景必须命中) |
| 多域组合 | 各复位域有效/无效的组合、撤销顺序的合法与非法序列 |
| 复位后恢复 | 撤销后到第一笔成功事务的周期数 |
这一篇在知识体系里的位置
时钟、复位由 TB 产生的基本原则见 SystemVerilog Testbench 实战;本文用到的断言语法与
$isunknown等系统函数见 SVA 断言实践;复位期 X 为何会带到门级和硅上见 门级仿真 SDF 与 X 传播;多复位域的跨域问题与 CDC/RDC 报告分拣同源;低功耗场景下隔离单元、电源域复位的验证则延伸到 UPF 功耗感知验证。
总结
复位验证的核心是把复位拆成「有效期间」和「撤销之后」两段分别立规矩:复位期所有输出必须是确定值、FSM 停初始态、计数器指针归零,用常驻 SVA 盯住任何时刻的重新复位,绝不让 X 漏到门级;异步复位要认准异步生效、同步释放电路,并用随机复位长度与贴沿释放用例去压 recovery/removal;多复位域还要覆盖复位顺序、局部复位和复位中事件——复位之后设计能干净地从零开始,后面所有功能验证才有意义。