第一章:形式化验证的核心概念

大家好,我是老李,做芯片验证十几年了。今天咱们聊聊形式化验证的几个核心概念。说实话,我刚入行那会儿,觉得形式化验证特别玄乎,什么属性规约、模型检查,听着就头大。后来踩了不少坑,才慢慢摸到门道。

你想想看,形式化验证说白了就是——用数学方法证明你的设计是对的。跟传统仿真比,它不需要跑几百万个测试用例,而是直接告诉你:「这个功能,百分之百没问题」或者「这里有个bug,你看」。嗯,就是这么硬核。

核心要点:形式化验证不是替代仿真,而是互补。仿真覆盖的是「你想到的场景」,形式化覆盖的是「所有可能的场景」。

1.1 属性规约(Property Specification)

属性规约,说白了就是「你想验证什么」。你得先把需求翻译成形式化的语言,告诉工具你要检查什么。

我个人习惯把属性规约分成三类:

  • 安全属性(Safety)——「坏事永远不会发生」。比如:两个master不能同时写同一个地址。
  • 活性属性(Liveness)——「好事最终会发生」。比如:请求发出去后,最终一定会收到响应。
  • 公平性属性(Fairness)——「资源不会被饿死」。比如:每个请求者都能轮到访问总线。

我在项目中遇到过最典型的例子:一个AHB总线仲裁器,仿真跑了三天都没问题,结果形式化一跑,发现某个优先级低的master永远拿不到总线。这就是活性属性没写全。

我的小技巧:写属性规约时,先写安全属性,再写活性属性。安全属性容易漏,活性属性容易错。先保底,再追求完备。

1.2 断言(Assertion)

断言是属性规约的具体实现。在SystemVerilog里,我们用assert property来写。你想想看,断言就像是在代码里埋了个「监控探头」——一旦违反,立刻报警。

举个例子:

// 检查:当valid拉高时,data必须在两个周期内准备好
property p_data_ready;
  @(posedge clk)
  valid |-> ##[1:2] data_ready;
endproperty

assert property(p_data_ready)
  else $error("data_ready not asserted within 2 cycles after valid");

嗯,这里要注意:断言不只是用在形式化验证里。仿真也能用断言,但形式化验证里断言是「主角」——工具会穷举所有可能,确保断言永远不被打脸。

我曾经犯过一个低级错误:断言里用了$past,但忘了考虑复位后的第一个周期。结果形式化工具报了一堆假错,排查了两天才发现。所以啊,写断言时一定要想清楚边界条件。

避坑指南:断言不是写得越多越好。我曾经见过一个项目,断言写了三千多条,结果形式化跑了一周没跑完。后来砍掉一半冗余断言,三天就跑完了。记住:精准比数量重要。

1.3 模型检查(Model Checking)

模型检查是形式化验证的核心引擎。它的原理其实不复杂:把设计建模成一个有限状态机,然后遍历所有状态,检查属性是否成立。

我打个比方:你设计了一个密码锁,有10个状态、4个按键。模型检查就是——把所有可能的按键序列都试一遍,看看有没有办法在不输对密码的情况下开锁。嗯,暴力穷举,但用数学方法优化过。

下面这张图展示了模型检查的基本流程:

模型检查(Model Checking)基本流程 设计模型(FSM) 属性规约(断言) 模型检查引擎 状态空间遍历 BDD / SAT求解 反例生成 ✅ 属性通过 ❌ 反例(Counterexample) 反例反馈 → 修正设计或属性

模型检查最大的优势是「全覆盖」——只要你的状态空间是有限的,它就能告诉你所有可能性。但缺点也很明显:状态爆炸。一个32位计数器就有2^32个状态,硬跑肯定不行。所以实际项目中,我们会用抽象、对称性简化、归纳法这些技巧来缩小搜索空间。

关键认知:模型检查不是万能的。对于数据通路密集的设计(比如浮点运算单元),模型检查效率很低。这时候等价性检查更合适。

1.4 等价性检查(Equivalence Checking)

等价性检查,顾名思义——比较两个设计是不是「一样」。最常见的场景是:RTL代码和综合后的门级网表,功能上是否一致?

我举个例子:你写了一段RTL,综合工具把它变成了门级网表。你怎么知道综合没出错?靠仿真?跑不完的。靠等价性检查?嗯,这个靠谱。

等价性检查的核心思想是:把两个设计都建模成布尔函数,然后用数学方法证明它们对所有输入组合的输出都相同。说白了就是——你俩算出来的结果,必须一模一样。

对比维度 模型检查 等价性检查
验证目标 设计是否满足属性 两个设计是否功能一致
适用场景 控制逻辑、协议验证 RTL vs 网表、ECO验证
输入要求 设计 + 属性规约 两个设计(参考 vs 实现)
输出结果 通过 / 反例 等价 / 不等价 + 反例
状态爆炸风险 高 低(组合逻辑为主)

我记得有一次做ECO(工程变更),只改了两行RTL,但综合后的网表变了三千个门。用等价性检查一跑,发现有个地方不等价——原来综合工具把一条路径优化错了。要是没做等价性检查,这颗芯片流片回来就是废的。

我的建议:等价性检查是「守门员」。每次RTL修改后、综合后、扫描链插入后,都跑一遍。虽然跑一次要几个小时,但比起流片失败的成本,这点时间不值一提。

1.5 四个概念的关系

这四个概念不是孤立的。我画个关系图你就明白了:

属性规约 定义「要验证什么」 断言 属性的具体实现 模型检查 验证设计是否满足属性 等价性检查 比较两个设计是否一致 典型应用场景 • 总线协议验证 • 仲裁器/调度器 • 状态机验证 • RTL vs 网表 • ECO验证

你看,属性规约和断言是「输入」,模型检查和等价性检查是「引擎」。没有好的属性规约,模型检查就是无米之炊。没有断言,形式化工具不知道要检查什么。反过来,没有模型检查和等价性检查,属性规约和断言也只是纸上谈兵。

嗯,这四个概念,你搞清楚了,形式化验证的大门就算打开了。后面我们会一个个深入讲,包括怎么写好的断言、怎么避免状态爆炸、怎么选工具。但今天先把骨架搭好——属性规约定方向,断言写具体,模型检查找bug,等价性检查保底线。

我个人觉得,形式化验证最难的不是技术,而是思维方式的转变。仿真思维是「我喂什么,设计吃什么」,形式化思维是「设计所有可能的行为,我都要管住」。这个转变,需要时间,也需要踩坑。没关系,慢慢来。

最后提醒一句:别指望形式化验证解决所有问题。它擅长的是控制逻辑、协议、状态机这类「离散」的问题。对于模拟电路、混合信号、大规模数据通路,还是得靠仿真和硬件加速。工具是死的,人是活的,选对工具比会用工具更重要。


可可精品资料库