第4章 验证计划(Verification Plan)
验证计划(Verification Plan, VPlan)是原型验证阶段的技术蓝图,它定义了“验证什么”和“如何验证”。在DVT(Design Verification & Test)阶段的原型验证中,一份结构化的VPlan能够将设计规范中的功能点转化为可执行的测试用例和可量化的覆盖率目标。本章围绕功能点分解、测试用例矩阵和覆盖率目标三个核心要素,阐述其原理、实现流程及工程化落地方法。
4.1 功能点分解
功能点分解是从设计规格文档(如体系结构规范、微架构文档)中提取原子化验证对象的过程。每个功能点应满足以下特征:可观测、可激励、可量化。例如,对于一个AXI总线接口,功能点可能包括:突发传输、未对齐地址、窄传输(2/4/8字节)、写响应、读数据交织等。
功能点分解的典型步骤:
- 梳理设计模块的所有输入输出接口、内部状态机、配置寄存器及异常路径。
- 按功能域分组,如“数据通路”、“控制逻辑”、“中断处理”、“电源管理”。
- 为每个功能点分配唯一ID(如FP_001),并标注预期行为及参考文档章节。
| ID | 功能域 | 功能描述 | 优先级 |
|---|---|---|---|
| FP_001 | AXI写通道 | 单次写突发(长度1~16,大小1~8字节) | 高 |
| FP_002 | AXI写通道 | 写地址与写数据分离握手 | 高 |
| FP_003 | AXI读通道 | 读请求后接收乱序读数据 | 中 |
| FP_004 | 寄存器配置 | 所有可读寄存器回读值与写入值一致 | 高 |
| FP_005 | 中断 | 多个中断源同时触发,仲裁优先级 | 中 |
4.2 测试用例矩阵
测试用例矩阵将功能点映射到具体的激励场景和仿真场景。矩阵列通常包含:测试用例名称、关联功能点ID、激励描述、覆盖率收集方法、预期结果。行则按测试类型分组(直接测试、随机测试、定向边界测试、错误注入测试)。
| 测试用例 | 功能点ID | 激励描述 | 覆盖率组 |
|---|---|---|---|
| axi_wr_single_burst | FP_001 | 单次写突发,长度=8,大小=4,地址对齐 | axi_write_cg |
| axi_wr_unaligned | FP_001, FP_002 | 写地址未对齐,长度=4,大小=2 | axi_write_cg |
| axi_rd_reorder | FP_003 | 发送两个读请求,使响应乱序返回 | axi_read_cg |
| reg_rw_all | FP_004 | 遍历所有可读寄存器写入并回读 | reg_covergroup |
| intr_multi | FP_005 | 同时触发3个中断源,检查仲裁结果 | intr_cg |
矩阵中每个测试用例应与至少一个功能点关联,确保验证的完备性。在原型验证中,建议为每个测试用例指定仿真平台(如VCS、Xcelium)和运行时间预算。
4.3 覆盖率目标
覆盖率目标定义了验证完成的量化门限。典型类型包括:
- 代码覆盖率:语句、分支、条件、翻转、有限状态机(FSM)。行业内成熟设计通常要求语句覆盖 ≥ 95%,分支覆盖 ≥ 90%。
- 功能覆盖率:通过SystemVerilog covergroup/cross定义的功能点覆盖。目标应基于功能点矩阵,通常设为目标≥90%(含cross覆盖率)。
- 断言覆盖率:显式断言(assert/property)的触发次数及通过率。要求所有关键断言在仿真中被激活至少一次。
- 覆盖率合并:多个仿真运行(回归测试)的覆盖率需合并,合并后满足总目标。
| 覆盖率类型 | DVT阶段建议目标 | 备注 |
|---|---|---|
| 语句覆盖 | ≥95% | 不含仿真环境代码 |
| 分支覆盖 | ≥90% | 含所有条件分支 |
| 功能覆盖(含cross) | ≥90% | 每个covergroup及其cross |
| 断言覆盖 | 100%触发至少一次 | 通过率无要求,但触发必须发生 |
4.4 实现流程与工具
验证计划落地需要结合脚本和覆盖率定义。以下是一个典型流程:
- 从功能点矩阵生成SystemVerilog covergroup骨架。
- 在UVM环境中实例化covergroup,绑定信号。
- 编写回归Makefile,启用覆盖率收集并指定覆盖率数据库。
- 仿真结束后执行覆盖率合并及报告。
SystemVerilog covergroup代码示例:
// axi_write_cg.sv
covergroup axi_write_cg with function sample(input bit [1:0] burst_type,
input bit [3:0] burst_len,
input bit [2:0] burst_size);
option.per_instance = 1;
burst_type_cp : coverpoint burst_type {
bins fixed = {2'b00};
bins incr = {2'b01};
bins wrap = {2'b10};
}
burst_len_cp : coverpoint burst_len {
bins len_1 = {4'd0};
bins len_2_4 = {[4'd1:4'd3]};
bins len_5_8 = {[4'd4:4'd7]};
bins len_9_16 = {[4'd8:4'd15]};
}
burst_size_cp : coverpoint burst_size {
bins size_1 = {3'd0};
bins size_2 = {3'd1};
bins size_4 = {3'd2};
bins size_8 = {3'd3};
}
type_len : cross burst_type_cp, burst_len_cp;
endgroup : axi_write_cg
Makefile覆盖率集成片段:
# Makefile excerpt
VCS_OPTS = -sverilog +vcs+lic+wait \
-cm line+cond+fsm+tgl \
-cm_dir $(COV_DIR)
SIM_OPTS = +UVM_TESTNAME=$(TEST_NAME) \
-cm_name $(TEST_NAME) \
-cm_log /dev/stdout
run:
mkdir -p $(COV_DIR)
vcs -R $(VCS_OPTS) $(SIM_OPTS) -l sim_$(TEST_NAME).log
merge:
urg -dir $(COV_DIR) -dbname merged.vdb -report coverage_report
clean:
rm -rf simv* csrc *.log $(COV_DIR)
部署时,应将验证计划文档(包含矩阵和目标)纳入版本控制(如Git),并在每次回归后自动检查覆盖率是否达标,若不达标则标记失败。
4.5 调试与常见错误
覆盖率调试方法:
- 使用覆盖率浏览器(verdi -cov -dir merged.vdb)检查未覆盖的bin和cross。
- 针对未覆盖点,回放对应测试用例的波形,分析激励是否到达目标状态机或接口。
- 若功能覆盖长期停滞,检查covergroup采样条件(clocking block或@posedge)是否与设计同步。
常见错误:
| 错误类型 | 表现 | 解决方案 |
|---|---|---|
| 功能点遗漏 | 覆盖率始终无法达到目标,但设计行为无异常 | 重新审查设计规范,补充功能点及对应covergroup |
| 覆盖率目标过高 | 仿真回归时间过长,却无法收敛 | 根据项目节点调整目标,优先保证关键路径100%覆盖 |
| 矩阵与测试用例脱节 | 新增测试用例未在矩阵中注册 | 建立矩阵维护流程,测试用例入库前必须更新矩阵 |
| 覆盖率合并错误 | urg合并后数据库尺寸异常小或统计值不合理 | 检查各仿真运行的-cm_dir路径是否不同,确保使用-cm_name区分 |
4.6 性能与稳定性优化
验证计划中的覆盖收集会显著影响仿真性能。优化策略:
- 采样优化:避免在covergroup中使用过于密集的时钟采样(如每拍采样改为在事务完成后采样一次)。
- 选择性启用:在参数回归时关闭部分低频覆盖组(如仅保留功能覆盖),仅在每周全量回归中全开覆盖率收集。
- 稳定断言:在覆盖率驱动阶段将断言检查放在第二位,优先保证功能覆盖收集完毕,防止断言失败导致仿真提前终止而丢失覆盖率数据。
- 增量合并:使用
urg -full64 -dir iter1.vdb -dir iter2.vdb -dbname merged.vdb合并增量结果,避免每次从头合并全部数据库。
通过严格遵循本章所述的功能点分解、测试用例矩阵及覆盖率目标制定方法,DVT阶段的原型验证能够从“定性”走向“定量”,确保验证收敛的可视化与可审计性。