一、验证计划的核心价值
验证计划,说白了就是一张作战地图。
我刚入行那会儿,总觉得写计划是浪费时间。心想:直接写测试用例不就完了?结果呢?项目做到一半,发现功能点漏了,覆盖率不达标,回头补用例,工期全乱套。嗯,从那以后,我再也不敢跳过验证计划这一步了。
验证计划要回答三个问题:
- 测什么?——功能点分解
- 怎么算测完?——覆盖率模型
- 怎么记录?——计划文档模板
今天我们就一个一个来拆解。
二、功能点分解方法
2.1 从规格书出发
功能点分解的源头,是芯片的规格书(Spec)。我个人习惯,拿到规格书先通读三遍:
- 第一遍:了解整体功能
- 第二遍:圈出所有"边界条件"
- 第三遍:标注所有"异常场景"
举个例子,存储控制器的写操作,规格书里可能只写了一句"支持4KB对齐写"。但实际分解时,你要考虑:
- 对齐写(地址4KB对齐)
- 非对齐写(地址偏移1字节、2字节...)
- 跨4KB边界的写
- 写后立即读(写读冲突)
- 写操作被中断
你看,一个功能点能拆出5-6个子场景。
2.2 功能点分解的"三刀法"
我在项目中总结了一套方法,叫"三刀法":
- 第一刀:按协议层切
- 事务层(Transaction Level)
- 传输层(Transfer Level)
- 物理层(PHY Level)
- 第二刀:按操作类型切
- 读操作、写操作、擦除操作
- 正常操作、异常操作
- 单次操作、连续操作
- 第三刀:按边界条件切
- 地址边界(0地址、最大地址、跨页地址)
- 数据边界(全0、全1、随机数据)
- 时序边界(最快时钟、最慢时钟、时钟抖动)
关键提醒:功能点分解不是一次完成的。我建议先粗分解,再细分解,最后做交叉检查。交叉检查时,把两个维度的功能点组合起来,往往能发现遗漏。
2.3 功能点分解示例
以NAND Flash控制器的"页读取"功能为例:
| 功能模块 | 功能点 | 子场景 |
|---|---|---|
| 页读取 | 正常读取 | 单页读取、多页连续读取 |
| 异常读取 | 读空页、读坏块、读ECC错误页 | |
| 边界读取 | 读第0页、读最后一页、跨plane读取 | |
| 并发读取 | 读与写并发、读与擦除并发 |
三、覆盖率模型设计
3.1 覆盖率不是数字游戏
我曾经见过一个项目,代码覆盖率99%,但芯片流片回来还是挂了。为什么?因为功能覆盖率只有30%。
覆盖率模型设计,核心是回答一个问题:"哪些场景必须被覆盖到?"
3.2 三种覆盖率的关系
- 代码覆盖率:检查代码有没有被执行到。这是基础,但不够。
- 功能覆盖率:检查功能点有没有被覆盖。这是核心。
- 断言覆盖率:检查协议时序有没有被验证。这是保障。
我的经验:功能覆盖率要优先于代码覆盖率。先把功能点列全,再考虑代码覆盖。代码覆盖率高但功能覆盖低,等于白干。
3.3 覆盖率模型设计步骤
- 定义覆盖组(covergroup)
- 每个功能模块一个覆盖组
- 每个覆盖组包含多个覆盖点(coverpoint)
- 定义覆盖点
- 地址范围、数据模式、操作类型
- 状态机状态、FIFO深度
- 错误类型、中断类型
- 定义交叉覆盖(cross coverage)
- 两个覆盖点的组合
- 例如:操作类型 × 地址范围
3.4 覆盖率模型代码示例
// 存储控制器写操作覆盖率模型
covergroup write_cg @(posedge clk);
// 覆盖点:写地址范围
addr_range: coverpoint wr_addr {
bins low = {[0:4KB]};
bins mid = {[4KB+1:8KB]};
bins high = {[8KB+1:16KB]};
bins max = {16KB};
}
// 覆盖点:写数据模式
data_pattern: coverpoint wr_data {
bins all_zero = {0};
bins all_one = {-1};
bins random = default;
}
// 覆盖点:写操作类型
op_type: coverpoint wr_type {
bins single = {SINGLE_WRITE};
bins burst = {BURST_WRITE};
bins atomic = {ATOMIC_WRITE};
}
// 交叉覆盖:操作类型 × 地址范围
cross op_type, addr_range;
// 交叉覆盖:数据模式 × 操作类型
cross data_pattern, op_type;
endgroup
注意:交叉覆盖不要滥用。两个覆盖点交叉,如果每个有10个bin,就是100个组合。三个交叉就是1000个。我曾经见过有人交叉了5个点,结果仿真跑了三天还没跑完。合理控制交叉覆盖的粒度。
四、验证计划文档模板
4.1 文档结构
我个人习惯用这个模板,用了七八年,改过很多版,现在分享给你:
| 章节 | 内容 | 说明 |
|---|---|---|
| 1. 概述 | 验证范围、验证目标 | 一句话说清楚要验证什么 |
| 2. 功能点列表 | 功能点分解表 | 每个功能点编号、描述、优先级 |
| 3. 验证环境架构 | 环境框图、组件说明 | 用SVG画清楚 |
| 4. 测试用例清单 | 用例名称、对应功能点 | 每个用例覆盖哪些功能点 |
| 5. 覆盖率模型 | 覆盖组定义、覆盖点说明 | 附上代码或伪代码 |
| 6. 回归策略 | 回归频率、种子数量 | 每天/每周回归 |
| 7. 风险与缓解 | 已知风险、应对方案 | 比如:某个场景仿真太慢 |
4.2 功能点列表模板
| 编号 | 功能模块 | 功能点 | 子场景 | 优先级 | 对应用例 |
|------|----------|--------|--------|--------|----------|
| F01 | 写操作 | 对齐写 | 4KB对齐 | P0 | TC_WR_01 |
| F02 | 写操作 | 非对齐写 | 偏移1B | P1 | TC_WR_02 |
| F03 | 写操作 | 跨页写 | 跨4KB边界 | P0 | TC_WR_03 |
| ... | ... | ... | ... | ... | ... |
4.3 验证计划的核心原则
- 可追溯:每个功能点都能追溯到用例和覆盖率
- 可量化:覆盖率目标明确(比如功能覆盖率达到95%)
- 可执行:计划要能落地,别写一堆做不到的
避坑指南:我曾经写过一个验证计划,功能点列了200多个,结果项目周期只有3个月。最后只跑了50%的用例,剩下的全废了。所以,优先级一定要分清楚。P0是必须覆盖的,P1是尽量覆盖的,P2是有时间再覆盖的。
五、本章知识体系
下面这张图,是我画的功能点分解与覆盖率模型的核心流程:
这张图展示了从规格书到验证计划文档的完整链路。你写计划的时候,就按这个流程走,基本不会漏东西。