第三章:验证计划——如何制定验证计划、验证范围定义、功能覆盖点提取、验证矩阵
说实话,很多刚入行的朋友觉得验证计划就是写个文档应付一下。我当年也这么想过。直到有一次,一个项目做到一半,才发现有个关键功能点根本没覆盖到。那叫一个惨。从那以后,我每次做项目,第一件事就是老老实实把验证计划写好。
验证计划是什么?说白了,它就是一张地图。告诉你从哪出发,要去哪,路上会经过哪些坑。没有它,你就是在黑夜里乱撞。
一、验证范围定义——先搞清楚你要测什么
我见过最离谱的事,是有人花了两周时间测了一个根本不会用到的功能。为什么会这样?因为一开始就没把范围划清楚。
验证范围定义,核心就三件事:
- 功能边界:芯片到底支持哪些功能?不支持哪些?
- 接口协议:走的是AXI还是AHB?有没有自定义协议?
- 工作模式:正常模式、低功耗模式、测试模式……每种模式都要测吗?
我个人习惯,先拉一张表格,把模块的输入输出信号全部列出来。然后问自己一个问题:“如果这个信号错了,系统会怎样?” 能回答上来的,就是需要验证的范围。回答不上来的,嗯,那更要测。
避坑指南:我曾经在一个项目中,忽略了复位信号的异步处理。结果仿真怎么跑都对,上板就挂。后来查了三天,才发现复位域没处理好。所以,复位、时钟、电源这些“基础设施”,一定要划进验证范围。
二、功能覆盖点提取——把需求翻译成可测的指标
功能覆盖点,听起来高大上。其实很简单:就是把设计规格书里的“人话”,翻译成验证工具能理解的“机器语言”。
举个例子:规格书上写“FIFO不能溢出”。你总不能直接测“不能溢出”吧?你得把它拆成:
- 写指针追上读指针时,full信号拉高
- full拉高后,写操作被阻塞
- 读走一个数据后,full信号拉低
你看,一个“不能溢出”,拆成了三个覆盖点。每个覆盖点都是一个具体的、可仿真的场景。
我一般用SystemVerilog的covergroup来写覆盖点。举个例子:
covergroup fifo_cg @(posedge clk);
// 覆盖FIFO满的情况
full_cp: coverpoint fifo_full {
bins full_asserted = {1};
bins full_deasserted = {0};
}
// 覆盖写使能与满信号的关系
wr_full_cross: cross wr_en, fifo_full {
bins wr_when_full = binsof(wr_en) intersect {1} &&
binsof(fifo_full) intersect {1};
}
endgroup
你想想看,如果没有这些覆盖点,你怎么知道你的测试用例到底测没测到“满”的情况?靠猜吗?
小技巧:提取覆盖点时,我习惯先画一个状态机。每个状态、每个跳转,都是一个潜在的覆盖点。尤其是那些“异常跳转”,比如从A状态直接跳到C状态,这种最容易漏掉。
三、验证矩阵——把计划变成可执行的清单
验证矩阵,也叫追溯矩阵。它的作用就一个:确保每个功能点都有对应的测试用例。
我见过最标准的验证矩阵,长这样:
| 功能ID | 功能描述 | 覆盖点 | 测试用例 | 验证方法 | 状态 |
|---|---|---|---|---|---|
| FIFO_001 | FIFO满信号正确拉高 | full_cp | test_fifo_full | 定向测试 | 通过 |
| FIFO_002 | FIFO满时写操作被阻塞 | wr_full_cross | test_fifo_wr_when_full | 随机测试 | 待验证 |
| FIFO_003 | FIFO空信号正确拉高 | empty_cp | test_fifo_empty | 定向测试 | 通过 |
这张表,就是你的作战地图。每天打开它,看看哪些还没测,哪些测了没过。一目了然。
我个人习惯,在项目初期就把矩阵搭好。然后每周更新一次状态。这样到了项目后期,就不会出现“哎呀,这个功能好像没测过”的尴尬。
注意:验证矩阵不是写一次就完事了。设计改版、需求变更,矩阵都要跟着更新。我曾经吃过这个亏——设计改了FIFO深度,我忘了更新矩阵,结果用旧的测试用例去测,白白浪费了两天时间。
四、验证计划的落地——别让计划变成废纸
很多团队的验证计划写得漂漂亮亮,最后却成了摆设。为什么?因为计划太死板了。
我建议,验证计划要包含这四部分:
- 时间节点:什么时候出第一版测试用例?什么时候跑完回归?
- 资源分配:谁负责哪个模块?用多少台服务器跑仿真?
- 风险预案:如果某个模块延期了,怎么调整优先级?
- 验收标准:覆盖率达到多少才算通过?100%?别天真了,有些场景根本覆盖不到。
说到验收标准,我一般定两个指标:
- 代码覆盖率:行覆盖、条件覆盖、跳转覆盖,至少95%以上
- 功能覆盖率:所有定义的覆盖点,至少90%被命中
剩下的那5%和10%,要么是冗余代码,要么是根本不可能出现的场景。没必要死磕。
总结一下:验证计划不是写给别人看的,是给自己用的。范围定义清楚,覆盖点提取到位,矩阵维护及时,这三点做到了,你的验证工作就成功了一半。另一半?嗯,那是执行的事了。
好了,这一章就聊到这。下一章我们讲讲测试用例怎么写,才能既快又准地命中那些覆盖点。