第三章 验证计划制定:如何编写验证计划、验证点分解、功能覆盖率定义、验证计划模板

说实话,很多刚入行的朋友问我:「验证计划不就是写个文档吗?随便写写就行了。」

嗯,我当年也这么想过。直到有一次,我负责一个USB3.0的IP验证,计划写得潦草,结果验证点漏了十几个,最后不得不加班补测。从那以后,我再也不敢小看验证计划了。

3.1 验证计划的核心价值

验证计划是什么?说白了,它就是一张地图。告诉你从哪里出发,走哪条路,最终要到达哪里。

我个人习惯把验证计划分成三个层次:

  • 策略层:验证什么?用什么方法?
  • 执行层:谁来做?什么时候做?
  • 度量层:怎么算做完?覆盖率多少才算够?

核心观点:验证计划不是写给别人看的,是写给自己用的。你想想看,一个项目动辄几百万门电路,没有计划,你怎么保证不漏测?

3.2 验证点分解方法论

验证点分解,我把它叫做「庖丁解牛」。把一个大IP拆成一个个小功能点,每个点都能独立验证。

我在项目中常用的分解步骤:

  1. 读规格书:把Specification吃透,每个功能特性都标出来
  2. 画功能树:用思维导图把功能分层,顶层是模块级,底层是寄存器级
  3. 找边界:每个功能点的边界条件是什么?正常值、异常值、极限值
  4. 列场景:功能之间怎么交互?有没有竞态条件?

我的小技巧:分解验证点时,我习惯用Excel表格。每一行是一个验证点,列分别是:功能描述、输入条件、预期输出、优先级、负责人。这样一目了然。

3.3 功能覆盖率定义

功能覆盖率,很多人觉得就是写几个covergroup完事。其实没那么简单。

我曾经在一个项目中,写了200多个coverpoint,结果仿真跑完,覆盖率100%。但功能还是漏了。为什么?因为覆盖率点没覆盖到关键场景。

定义功能覆盖率时,我建议遵循「三覆盖」原则:

  • 数据覆盖:输入数据的取值范围、边界值、特殊值
  • 时序覆盖:信号之间的时序关系、延迟、握手协议
  • 状态覆盖:状态机的跳转、状态组合、非法状态

举个例子,一个简单的FIFO验证:

// 功能覆盖率定义示例
covergroup fifo_cg @(posedge clk);
  // 数据覆盖:写数据取值范围
  wr_data_cp : coverpoint wr_data {
    bins low = {[0:63]};
    bins mid = {[64:191]};
    bins high = {[192:255]};
    bins max = {255};
  }
  
  // 时序覆盖:读写同时发生
  wr_rd_cp : coverpoint {wr_en, rd_en} {
    bins write_only = {2'b10};
    bins read_only  = {2'b01};
    bins both       = {2'b11};
    bins none       = {2'b00};
  }
  
  // 状态覆盖:FIFO满/空状态
  fifo_status_cp : coverpoint fifo_level {
    bins empty = {0};
    bins full  = {DEPTH};
    bins mid   = {[1:DEPTH-1]};
  }
endgroup

避坑指南:我曾经犯过一个错误——只关注正常路径的覆盖率,忽略了异常路径。比如FIFO写满后继续写、读空后继续读。这些场景的覆盖率一定要单独定义。

3.4 验证计划模板

下面是我用了多年的验证计划模板,分享给大家。这个模板经过十几个项目的打磨,比较实用。

章节 内容 说明
1. 概述 IP功能简介、验证范围、验证目标 一句话说清楚要验证什么
2. 验证策略 验证方法(定向测试/随机测试)、工具链、环境架构 用什么方法验证
3. 验证点列表 功能分解表、每个验证点的详细描述 核心内容,要详细
4. 覆盖率计划 功能覆盖率定义、代码覆盖率目标、覆盖率收敛策略 怎么算验证完
5. 测试用例清单 每个验证点对应的测试用例、优先级、预计仿真时间 可执行计划
6. 里程碑计划 各阶段交付物、时间节点、评审计划 项目管理用
7. 风险与缓解 已知风险、应对措施、备选方案 提前想好退路

我的经验:验证计划不是一成不变的。项目进行中,你会发现新的验证点,或者某些验证点不需要了。我建议每两周更新一次计划,保持它和实际工作同步。

3.5 实战案例:一个简单的SPI验证计划

拿SPI Master IP举个例子,看看验证计划怎么写:

验证点:SPI Master 数据传输功能
- 验证点ID:SPI_001
- 功能描述:验证SPI Master能够正确发送和接收数据
- 输入条件:时钟频率1MHz,CPOL=0,CPHA=0,数据长度8位
- 预期输出:发送数据0xA5,接收数据0x5A
- 覆盖率要求:数据覆盖所有8位组合,时序覆盖所有4种模式
- 测试用例:spi_basic_test, spi_all_modes_test
- 优先级:P0(必须通过)

你看,一个验证点写清楚,测试的人拿到就能干活。不会出现「这个场景测了没?」「那个边界测了没?」的扯皮。

最后说一句:验证计划的质量,直接决定了验证工作的质量。花一周时间写好计划,能省下一个月返工的时间。这笔账,你算算看。