第二章:测试激励基础——激励的类型与覆盖率的关系
大家好,我是老李。做芯片验证这么多年,我越来越觉得一个道理:测试激励的质量,直接决定了验证的成败。你想想看,设计再复杂,如果激励写不好,覆盖率就是虚的,bug 也跑不出来。
这一章,我们来聊聊测试激励的基础。我会结合自己的项目经验,把定向激励、随机激励、约束随机激励这些概念讲透。更重要的是,我会告诉你它们和覆盖率之间到底是什么关系。
2.1 激励的三种基本类型
我个人习惯把激励分成三类:定向、随机、约束随机。这三类各有各的用处,也各有各的坑。
2.1.1 定向激励
定向激励,说白了就是「我明确知道要测什么」。比如我要测一个加法器,我就直接给它输入 3 和 5,然后检查输出是不是 8。
优点:
- 目标明确,能快速验证特定功能
- 调试方便,出问题一眼就能看出来
- 适合回归测试中的关键场景
缺点:
- 覆盖范围有限,你只能测到你想测的
- 写起来费劲,尤其是复杂协议
- 容易遗漏边界情况
2.1.2 随机激励
随机激励,就是让工具自动生成各种输入组合。你想想看,如果让一个加法器随机跑 10000 次,它能覆盖到多少种情况?
优点:
- 覆盖范围广,能发现你没想到的 bug
- 自动化程度高,写一个随机生成器就能跑很多 case
- 适合压力测试和长时测试
缺点:
- 完全随机可能产生大量无效场景
- 覆盖率提升慢,很多随机值其实在重复测同一个功能
- 调试困难,复现问题需要固定种子
2.1.3 约束随机激励
约束随机,就是给随机加一些「规矩」。比如我要测一个 FIFO,我可以约束:写操作和读操作的比例在 3:1 到 1:3 之间,这样既能随机,又能保证场景有效。
优点:
- 兼顾了随机性和有效性
- 能定向覆盖边界条件
- 覆盖率提升效率最高
缺点:
- 约束写不好,可能过度限制随机性
- 调试时约束冲突比较头疼
- 需要一定的经验来设计约束
2.2 激励与覆盖率的关系
很多人问我:「老李,激励和覆盖率到底是什么关系?」
嗯,这个问题问得好。我打个比方:激励就像你撒出去的网,覆盖率就是网眼的大小。网撒得再大,如果网眼太大,小鱼小虾(小 bug)还是会漏掉。
2.2.1 激励决定覆盖率的「广度」
你想想看,如果只写定向激励,你的覆盖率就是「点状」的——只覆盖了你想到的那些点。而随机激励能帮你覆盖到「面」——那些你没想到的输入组合。
举个例子:
// 定向激励:只测几个固定值
write_data(0x0000);
write_data(0xFFFF);
write_data(0xAAAA);
// 约束随机:覆盖整个地址空间
rand bit [15:0] addr;
constraint c_addr {
addr inside {[0:65535]};
addr % 4 == 0; // 对齐约束
}
你看,定向激励只测了 3 个值,而约束随机能测到 16384 个对齐地址。这就是广度上的差异。
2.2.2 激励决定覆盖率的「深度」
广度重要,深度更重要。什么叫深度?就是同一个功能点,你用不同的激励去反复验证。
我记得在一个 AXI 总线项目中,我们测「写响应」这个功能点。定向激励只测了「正常写完成」和「写错误」两种情况。但约束随机能生成:
- 正常写完成
- 写错误(地址不对)
- 写错误(数据不对)
- 写错误(保护属性不对)
- 写错误(多个错误同时发生)
- 写完成但延迟很大
- 写完成但乱序返回
这就是深度。同一个功能点,用不同的激励去「敲打」它,才能发现隐藏的 bug。
2.2.3 覆盖率反馈驱动激励优化
这里我要说一个很重要的理念:覆盖率不是终点,而是起点。
我见过很多团队,跑完一轮回归,看一眼覆盖率报告就完事了。这不对。正确的做法是:
- 跑一轮回归,收集覆盖率
- 分析哪些功能点覆盖率低
- 针对性地优化激励
- 再跑一轮,看覆盖率是否提升
- 重复这个过程,直到达标
2.3 三种激励的覆盖率对比
为了让你更直观地理解,我整理了一个对比表:
| 激励类型 | 代码覆盖率 | 功能覆盖率 | 断言覆盖率 | 适用场景 |
|---|---|---|---|---|
| 定向激励 | 低(20-40%) | 低(10-30%) | 中(30-50%) | 关键路径、回归测试 |
| 随机激励 | 高(60-80%) | 中(40-60%) | 低(20-40%) | 压力测试、长时测试 |
| 约束随机 | 高(70-90%) | 高(60-85%) | 高(50-70%) | 主流验证场景 |
你看,约束随机在三种覆盖率上表现都比较均衡。这也是为什么它成为主流的原因。
2.4 知识体系图
下面我用一张 SVG 图来总结本章的核心逻辑:
2.5 避坑指南
最后,我分享几个我在项目中踩过的坑:
我曾经在一个项目中,觉得随机能搞定一切,结果跑了两个月,覆盖率死活上不去。后来发现,有些边界条件随机根本碰不到。从那以后,我学会了「定向+随机」混合使用。
有一次我写约束,为了让覆盖率好看,把随机范围限制得很小。结果覆盖率是上去了,但 bug 一个都没发现。后来我才明白,覆盖率是手段,不是目的。我们的目标是发现 bug,不是刷覆盖率。
随机激励需要固定种子才能复现问题。我建议每个回归测试都记录种子号,这样出了问题才能回放。我见过有人跑完回归不记种子,结果 bug 复现不了,只能重写激励,白白浪费一周时间。
好了,这一章就到这里。记住一句话:激励是验证的子弹,覆盖率是瞄准镜。子弹再好,瞄不准也打不中目标。