第三章:验证计划——如何制定一份可执行的VPlan

说实话,我刚入行那会儿,觉得验证计划就是走个过场。

项目经理催着要,我就随便列几个测试用例,写个覆盖率目标,交差了事。结果呢?项目后期天天加班,不是漏场景就是测不全,最后还得靠老员工救火。

后来我才明白——一份好的VPlan,是整个验证工程的蓝图。它不光是文档,更是你和设计、架构、后端沟通的桥梁。

3.1 验证计划到底长什么样?

我习惯把VPlan分成三个层次:

  • 策略层:回答“测什么、怎么测、测到什么程度”
  • 执行层:列出具体的测试用例、检查点、覆盖率目标
  • 管理层:时间节点、资源分配、风险预案

你想想看,如果连测什么都不清楚,那后面写testbench、跑仿真,不就成了无头苍蝇?

核心原则:VPlan不是写给别人看的,是写给自己和团队用的。它必须可执行、可追踪、可度量。

3.2 第一步:吃透设计规格

我见过太多人,拿到设计文档扫两眼就开始写计划。结果呢?漏掉关键功能,或者理解错了协议。

我个人习惯,先花一天时间通读设计规格,然后做三件事:

  1. 画功能框图:把模块的输入输出、内部状态机、数据通路画出来
  2. 列接口清单:所有协议接口、配置寄存器、中断信号
  3. 找边界条件:FIFO满空、超时处理、异常复位、跨时钟域

举个例子,我之前做DMA控制器验证。设计文档说“支持链式描述符”,但没提描述符指针为NULL时怎么办。我追问了架构师,才发现这是个未定义行为——最后我们决定在验证计划里加一个“空指针异常处理”的测试用例。

小技巧:把设计文档里的“Note”、“Remark”、“Assumption”全部标红。这些地方往往是坑。

3.3 第二步:分解功能点

功能点分解,说白了就是把“这个模块要干啥”拆成“每个场景怎么测”。

我常用的方法是功能覆盖组(Functional Coverage Group)的思路:

功能点ID 功能描述 验证方法 优先级
F1 正常写操作:地址对齐、数据宽度匹配 定向测试 + 随机测试 P0
F2 写操作地址未对齐 错误注入测试 P1
F3 写操作时总线超时 时序反压测试 P1
F4 写操作与读操作重叠 并发场景测试 P0

嗯,这里要注意:优先级P0是必须测的,P1是尽量测,P2是时间允许再测。别一上来就想覆盖所有,那不现实。

3.4 第三步:设计测试用例

有了功能点,接下来就是写具体的测试用例。我建议每个功能点至少对应一个定向测试和一个随机测试

定向测试用来验证基本功能,随机测试用来踩边界和组合场景。

// 定向测试示例:验证写操作地址对齐
task test_write_aligned();
    logic [31:0] addr = 32'h1000;
    logic [31:0] data = 32'hA5A5A5A5;
    // 发起一次32位对齐写
    bus_write(addr, data, 4'b1111);
    // 检查写响应
    wait(bus_resp == OK);
    // 读回验证
    bus_read(addr, 4'b1111);
    assert(bus_rdata == data);
endtask

// 随机测试示例:随机地址、随机数据、随机字节使能
task test_write_random();
    repeat (1000) begin
        rand_addr = $urandom_range(0, 32'hFFFF);
        rand_data = $urandom;
        rand_be   = $urandom & 4'hF;
        bus_write(rand_addr, rand_data, rand_be);
        // 检查响应
        ...
    end
endtask

我曾经踩过的坑:随机测试的种子没固定。结果回归时同一个用例每次跑的结果都不一样,根本没法复现bug。后来我强制每个随机用例都记录种子,并在日志里打印出来。

3.5 第四步:定义覆盖率目标

覆盖率不是越高越好,而是够用就好

我一般这样定目标:

  • 代码覆盖率:行覆盖≥90%,条件覆盖≥85%,状态机覆盖100%
  • 功能覆盖率:所有P0功能点100%,P1功能点≥90%
  • 断言覆盖率:所有协议断言100%触发过

为什么状态机要100%?因为状态机漏掉一个状态,很可能就是死锁或者跑飞。我在一个项目里就遇到过,状态机有个“IDLE→WAIT”的跳转从来没被触发过,结果芯片在特定条件下直接卡死。

3.6 第五步:制定时间线和里程碑

VPlan里必须包含时间规划。我习惯用倒推法

  1. 先定死芯片tape-out日期
  2. 往前推验证冻结日期(一般提前2周)
  3. 再推回归测试完成日期
  4. 最后推测试用例开发完成日期

举个例子:

里程碑 时间 交付物
VPlan评审 第1周 验证计划文档
Testbench搭建 第2-3周 可运行的仿真环境
定向测试完成 第4-5周 所有P0用例通过
随机测试+回归 第6-8周 覆盖率达标
验证冻结 第9周 验证报告+覆盖率报告

我的习惯:每周五下午开30分钟验证站会,只看三件事——本周完成了什么、下周要做什么、有没有阻塞项。别搞成汇报大会,那没用。

3.7 第六步:风险识别与预案

做验证的都知道,计划永远赶不上变化。

我一般会在VPlan里专门列一个风险清单

  • 设计延迟:RTL交付晚了,验证时间被压缩 → 预案:先测核心功能,边缘功能后补
  • 工具问题:仿真器bug或者license不够 → 预案:准备备用工具链,提前申请额外license
  • 需求变更:架构师临时加功能 → 预案:评估影响范围,和项目经理协商延期或者砍需求

说白了,VPlan不是死文档。它要随着项目推进不断更新。我见过最离谱的项目,VPlan写完就没人管了,最后验证结束才发现覆盖率只有60%。

3.8 总结:一份好VPlan的检查清单

最后,我分享一个自检清单。每次写完VPlan,我都会过一遍:

  1. 所有功能点是否都覆盖到了?有没有遗漏的边界?
  2. 每个测试用例是否有明确的通过/失败标准?
  3. 覆盖率目标是否可量化、可追踪?
  4. 时间规划是否留了缓冲?
  5. 风险是否都识别了?预案是否可行?

嗯,做到这五点,你的VPlan基本就及格了。剩下的,就是在执行中不断迭代优化。

记住一句话:验证计划的质量,决定了验证项目的成败。别把它当成负担,它其实是帮你省时间的利器。


公众号:蓝海资料掘金营,微信deep3321