做数字芯片验证的人都有一个体会:仿真跑得越多,心里越没底。仿真只能证明“在跑过的场景里没出错”,没跑过的场景永远是个问号。形式验证走的是另一条路:它不跑具体场景,而是用数学方法证明,在所有可能的输入组合下,某个性质都成立。这两种方法不是替代关系,而是互补:仿真擅长发现“想得到”的问题,形式验证擅长抓住“想不到”的问题。

先说清楚形式验证能干什么。最常用的是属性检查:工程师写一条断言,比如“请求发出后,响应必须在限定周期内到达,且不能出现两个同时有效的授权”,工具会穷举所有状态空间,检查这条性质有没有反例。如果有反例,工具会给一条最短的复现路径;如果没有,结论是在给定模型下性质恒成立。等价性检查是另一大类:综合、重定时、时钟门控之后,网表和RTL在逻辑上是不是等价,形式工具可以给出证明,而仿真只能抽查几个向量。

哪些bug是仿真很难抓、形式验证容易抓的?第一类是深状态空间里的角落:状态机要经过几十步特定序列才进入的错误状态,随机仿真可能跑几亿个周期都碰不到,形式工具却能通过反向搜索直接找到。第二类是并发与仲裁的竞争:多个请求同时到达、优先级翻转、饥饿,仿真需要恰好构造出那个时序窗口,形式验证把并发组合全部展开,窗口藏不住。第三类是跨时钟域和复位序列的组合:复位中途来请求、时钟切换瞬间有未完成事务,这类场景写定向用例很费劲,形式化描述却相对直接。

第四类特别值得提:综合工具“偷偷改掉”的逻辑。比如综合时对常量传播、逻辑优化的误处理,或者时钟门控插入后改变了时序行为,导致RTL仿真通过、网表仿真才暴露问题。等价性检查就是专门对付这类bug的:它不依赖测试向量,直接比较两个设计的逻辑等价性,仿真要达到同样的覆盖几乎不可能。还有一类是协议层面的死锁和活锁:握手协议在某种请求序列下互相等待,仿真里表现为挂死,但很难定位是哪一步的组合出了问题,形式工具的反例路径可以直接指出死锁环。

但形式验证也有自己的边界,不是万能的。首先是状态爆炸:设计规模一大,状态空间指数增长,工具可能跑不完,需要抽象、切分、加约束,把问题规模控制在可处理范围。其次是性质写错的风险:断言本身就是人写的,如果断言漏了关键条件,证明通过也只是证明了“写错的性质成立”。所以断言评审和仿真一样重要,不能把形式验证当成免检章。第三是形式验证不擅长性能和时序之外的东西:功耗、信号完整性、模拟行为,这些还是要靠仿真和实测。

实用的分工是这样:仿真负责“常见路径跑通、性能达标、系统级场景联调”,这是形式验证替代不了的;形式验证负责“关键性质穷举、接口协议无死锁、综合前后等价”,这是仿真覆盖不了的。落地建议是:新项目先给核心控制逻辑和接口协议写断言,跑属性检查;每次综合、重定时、时钟门控之后跑等价性检查;仿真团队把形式工具给出的反例转成回归用例,沉淀下来。验证的信心不是来自某一种方法跑了多少,而是来自两种方法各自覆盖了对方的盲区。仿真告诉你“常见的都对了”,形式验证告诉你“极端情况也没错”,两者拼在一起,才算一份完整的验证结论。