一、激励生成概述
什么是测试激励
测试激励,说白了就是喂给DUT(待测设计)的输入信号。
你想想看,验证一个芯片模块,总得给它一些输入吧?
比如一个加法器,你得给它两个加数。一个FIFO,你得给它写数据和写使能。这些输入信号,就是测试激励。
我个人习惯把测试激励分成三类:
- 合法激励:符合协议规范的正常输入
- 边界激励:刚好在合法范围边缘的输入
- 异常激励:故意构造的非法或极端输入
我在项目中遇到过最典型的例子——一个AHB总线桥,正常读写都没问题。但当我构造了一个「地址刚好对齐、长度刚好4字节、burst类型为INCR4」的激励时,竟然触发了内部状态机死锁。这就是边界激励的价值。
核心要点:测试激励不是随便给几个波形就完事了。好的激励,要能覆盖功能点、触发边界条件、暴露设计缺陷。
为什么需要自动生成
手动写激励?我刚开始做验证时就是这么干的。
一个简单的UART模块,手动写了200多个测试用例。结果呢?
- 花了整整两周时间
- 漏掉了两个关键边界场景
- 回归测试时改一个参数,所有用例都要手动调
为什么会这样?因为手动激励有几个硬伤:
| 痛点 | 手动方式 | 自动生成 |
|---|---|---|
| 覆盖率 | 依赖工程师经验,容易遗漏 | 可系统化覆盖所有组合 |
| 效率 | 一个复杂场景写半天 | 几秒钟生成上千条 |
| 可维护性 | 改需求等于重写 | 改约束即可 |
| 随机性 | 基本固定套路 | 可引入随机,发现意外bug |
嗯,这里要注意——自动生成不是要完全替代手动。而是把工程师从重复劳动中解放出来,去关注更复杂的验证策略。
自动生成的核心挑战
自动生成听起来很美好,但做起来坑不少。
我曾经在一个PCIe项目里,写了一个自动激励生成器。结果跑了一晚上,生成了100万条激励。第二天一看——90%都是重复场景,真正的边界情况一个都没覆盖到。
这就是第一个挑战:有效覆盖率。
自动生成容易陷入「量大但无用」的陷阱。你想想看,如果生成器只是机械地组合所有输入,那大概率会产出大量无意义的激励。
第二个挑战:约束的准确性。
我记得有一次,一个同事写的约束里有个笔误——地址范围写反了。结果生成的所有激励都是非法的,跑了一周仿真全白费。约束错了,生成的东西就是垃圾。
第三个挑战:可复现性。
随机生成好是好,但出了问题怎么复现?我习惯的做法是:每次生成时记录随机种子。这样即使生成了100万条,也能精确回放某一条出错的激励。
避坑指南:我曾经在一个项目里,自动生成器跑出来的激励在仿真器里通过率只有60%。排查了两天才发现——生成器没有考虑时序窗口。有些激励在功能上合法,但时序上根本不可能出现。所以,自动生成一定要加上时序合理性检查。
自动生成的收益
说了这么多挑战,那自动生成到底值不值得做?
我的答案是:值得,但要有策略。
收益主要体现在三个方面:
- 人力解放:一个需要3人周的激励编写工作,自动生成可能只需要1人天来配置约束
- 覆盖深度:手动很难想到的极端组合,自动生成可以系统化探索
- 回归效率:设计改了,只需要重新生成一次,不用手动改几百个用例
我参与过一个SoC项目,验证周期原本计划6个月。后来我们搭建了一套自动激励生成框架,把常规激励的编写时间压缩了80%。最终验证周期缩短到4个月,还多覆盖了30%的边界场景。
个人经验:自动生成不是银弹。我建议从最耗时的模块开始试点,比如协议类模块(AHB、AXI、PCIe),这类模块激励模式固定但组合爆炸,自动生成收益最明显。
知识体系总览
下面这张图,是我对激励生成整体知识结构的理解:
这张图展示了我对激励自动生成的整体理解。从核心目标出发,三大支柱支撑起整个方法论,最终落到具体的输出产物和收益上。
嗯,这一章就到这里。记住一句话:自动生成不是目的,高效发现bug才是。