一、典型模块化验证框架
模块化的验证思想是:分层次、分模块
包括以下组件:
1.被测模块(DUT)
待测verilog(vhdl)模块
2.测试平台(testbench)
(1)激励生成器(driver):生成输入信号激励。
(2)监视器(Monitor):捕获DUT输出信号。
(3)参考模型(reference model):提供预期结果的黄金模型。
(4)比较器(scoreboard):对DUT输出与参考模型结果进行比较。
(5)覆盖率收集器(coverage collector):统计功能覆盖率和代码覆盖率。
3.验证环境
支持随机化测试、断言(assertions)和自动化回归测试。
二、验证步骤流程
1.验证计划
(1)目标:明确待验证功能点(如fifo的读写,ALU的运算)
(2)策略:确定测试类型(定向测试、随机测试),覆盖率目标(功能覆盖率100%,代码覆盖率95%)
(3)工具链:选择仿真工具(如modelsim/VCS)、脚本语言(python/perl)
2.测试平台开发
(1)接口定义:定义DUT输入输出信号的时序和协议。
(2)模块化设计:将driver、monitor等组件独立开发、支持复用。
(3)自动化脚本:编写脚本自动编译、运行仿真并生成报告。
3.测试用例编写
(1)定向测试:针对特定功能的手动测试(如复位信号测试)
(2)随机测试:通过约束随机生成输入激励(如随机数据、地址)
(3)边界测试:覆盖极端情况(如计数器溢出、fifo满/空状态)
4.仿真与调试
(1)波形分析:使用仿真工具查看信号时序。
(2)断言检查:插入assert语句实时验证协议或数据有效性。
(3)日志记录:记录错误信息及仿真上下文
5.覆盖率分析
(1)代码覆盖率:检查所有代码行是否被执行(line/branch coverage)
(2)功能覆盖率:验证所有功能点是否覆盖(通过覆盖组covergroup定义)
6.回归测试
自动化运行所有测试用例,确保代码修改未引入新错误
三、实例:
实例1:
fifo模块验证
1.DUT功能
模块:深度为8的同步fifo,支持读写操作和满/空状态标志。
2.验证计划
(1)功能点:正常读写、满、空标志、溢出处理、复位功能
(2)覆盖率目标:100%功能覆盖,95%代码覆盖。
3.测试平台结构
module fifo_tb;
// 接口声明
reg clk, rst, wr_en, rd_en;
reg [7:0] data_in;
wire [7:0] data_out;
wire full, empty;
// 实例化DUT
fifo #(.DEPTH(8)) dut (.*);
// 时钟生成
initial begin
clk = 0;
forever #5 clk = ~clk;
end
// 参考模型(行为级FIFO)
reg [7:0] ref_mem[0:7];
int ref_wptr = 0, ref_rptr = 0;
// 比较器
always @(posedge clk) begin
if (rd_en && !empty) begin
assert(data_out === ref_mem[ref_rptr]) else $error("Data mismatch!");
ref_rptr = (ref_rptr + 1) % 8;
end
end
endmodule
4.测试用例示例
// 测试1:正常写入和读取
initial begin
rst = 1;
#10 rst = 0;
repeat(10) begin
@(negedge clk);
wr_en = 1;
data_in = $random;
ref_mem[ref_wptr] = data_in; // 更新参考模型
ref_wptr = (ref_wptr + 1) % 8;
end
// 读取并验证数据...
end
// 测试2:溢出测试
initial begin
rst = 1;
#10 rst = 0;
repeat(9) begin // 写入9次,触发溢出
@(negedge clk);
wr_en = 1;
data_in = $random;
end
assert(full) else $error("FIFO未满!");
end
5.覆盖率收集
定义覆盖率组:
covergroup fifo_cov;
coverpoint dut.wptr { bins wptr = {[0:7]}; }
coverpoint dut.rptr { bins rptr = {[0:7]}; }
cross dut.wptr, dut.rptr; // 覆盖读写指针组合
endgroup
6.回归测试
使用makefile自动化运行所有测试
sim:
vlib work
vlog fifo.v fifo_tb.v
vsim -c fifo_tb -do "run -all; quit"
实例2:
AXI4-Lite总线接口验证
1. 设计概述
- DUT: AXI4-Lite 从设备接口,支持寄存器读写,包含以下功能:
- 支持32位地址和数据总线。
- 支持单次读写操作(无Burst传输)。
- 错误处理:解码错误(访问未映射地址时返回SLVERR响应)。
- 应用场景: SoC中外设寄存器配置(如GPIO、UART控制器)。
2. 验证计划
- 功能点:
- 正常读写:验证地址对齐、数据正确性。
- 错误注入:访问未映射地址时返回SLVERR。
- 协议合规性:检查AXI信号时序(如VALID先于READY)。
- 覆盖率目标:
- 代码覆盖率 > 98%(Line + Branch + FSM)。
- 功能覆盖率:地址范围、读写操作组合、错误响应覆盖。
3. 验证环境(基于UVM框架)
systemverilog
// UVM Testbench 架构
class axi_lite_env extends uvm_env;
// 组件实例化
axi_lite_agent agent; // 驱动和监控AXI信号
reg_block reg_model; // 寄存器模型(参考模型)
axi_lite_scoreboard scoreboard; // 数据比对器
coverage_collector coverage; // 覆盖率收集
// UVM Phase 初始化
function void build_phase(uvm_phase phase);
agent = axi_lite_agent::type_id::create("agent", this);
reg_model = reg_block::type_id::create("reg_model", this);
scoreboard = axi_lite_scoreboard::type_id::create("scoreboard", this);
coverage = coverage_collector::type_id::create("coverage", this);
endfunction
endclass
关键组件说明:
- AXI Agent:
- Driver: 生成符合AXI协议的读写操作(支持随机化地址和数据)。
- Monitor: 捕获总线上的实际传输,发送至Scoreboard和Coverage。
- 寄存器模型 (Register Model):
- 镜像DUT内部寄存器状态,预测读写结果。
- Scoreboard:
- 比较DUT输出与寄存器模型的预测值(如读数据、SLVERR响应)。
- Coverage Collector:
- 收集以下覆盖率:
systemverilog
covergroup axi_cov; // 地址范围:覆盖所有可访问寄存器地址 address_cp: coverpoint addr { bins reg0 = {32'h0000_0000}; bins reg1 = {32'h0000_0004}; bins invalid = {[32'h0000_0008:32'hFFFF_FFFF]}; } // 操作类型:读写组合 op_cp: coverpoint {read, write} { bins read_op = {1}; bins write_op = {2}; } // 错误响应覆盖率 error_cp: coverpoint resp { bins ok = {AXI_OKAY}; bins slverr = {AXI_SLVERR}; } endgroup
- 收集以下覆盖率:
4. 测试用例设计
用例1:基础寄存器读写
systemverilog
class basic_rw_test extends uvm_test;
virtual task run_phase(uvm_phase phase);
// 写入寄存器0,数据为0xA5A5_A5A5
axi_lite_seq::start(agent.seqr, .addr(32'h0000_0000), .data(32'hA5A5_A5A5), .is_write(1));
// 读取寄存器0,验证数据
axi_lite_seq::start(agent.seqr, .addr(32'h0000_0000), .is_write(0));
assert (scoreboard.last_rd_data == 32'hA5A5_A5A5) else uvm_error("DATA_MISMATCH");
endtask
endclass
用例2:错误注入测试
systemverilog
class error_test extends uvm_test;
virtual task run_phase(uvm_phase phase);
// 尝试访问未映射地址0xFFFF_0000
axi_lite_seq::start(agent.seqr, .addr(32'hFFFF_0000), .is_write(0));
// 验证响应为SLVERR
assert (scoreboard.last_resp == AXI_SLVERR) else uvm_error("SLVERR_NOT_RECEIVED");
endtask
endclass
用例3:随机化测试
systemverilog
class random_test extends uvm_test;
virtual task run_phase(uvm_phase phase);
repeat(1000) begin
// 随机生成地址(覆盖合法和非法范围)、操作类型(读/写)
axi_lite_seq::start(agent.seqr, .addr($urandom_range(0, 32'hFFFF_FFFF)), .is_write($urandom%2));
end
endtask
endclass
5. 仿真与调试
- 波形调试: 使用Verdi或SimVision查看AXI信号时序(如VALID/READY握手)。
- 断言检查: 插入协议断言确保设计符合AXI规范:
systemverilog
// 断言:VALID信号一旦置高,必须保持到READY置高 property valid_hold; @(posedge clk) disable iff (rst) $rose(axi_valid) |-> axi_valid throughout axi_ready [->1]; endproperty assert_valid_hold: assert property (valid_hold);
6. 覆盖率分析与改进
- 覆盖率报告:
- 代码覆盖率: 通过VCS或Questa生成,确保所有代码分支(如错误处理逻辑)被覆盖。
- 功能覆盖率: 通过回归测试迭代补充用例,例如:
- 若发现“连续写后读”场景未覆盖,增加对应测试序列。
7. 回归测试自动化
- 脚本示例 (Makefile):
makefile
run_tests: for test in basic_rw_test error_test random_test; do \ vcs -sverilog axi_lite_dut.sv axi_lite_tb.sv +define+UVM_NO_RELNOTES; \ ./simv +UVM_TESTNAME=$$test; \ urg -format both -dir simv.vdb; \ done
- CI/CD集成: 通过Jenkins/GitLab CI自动运行回归测试并生成覆盖率报告。
8. 工业实践关键点
- 模块化与复用:
- AXI Agent可封装为通用组件,复用于其他AXI接口验证。
- 随机约束:
- 使用
rand
变量和constraint
控制随机化范围,例如限制90%的操作为合法地址。
- 使用
- 性能测试:
- 添加吞吐量测试(如连续1000次读写的延迟统计)。
- 门级仿真:
- 在综合后网表上重跑测试用例,验证时序收敛性。
总结
通过以上流程,一个工业级AXI4-Lite接口的验证可实现:
- 高可靠性: 协议断言和随机测试覆盖极端场景。
- 高效率: UVM框架支持测试用例快速迭代。
- 可追溯性: 覆盖率报告与回归测试确保需求完全覆盖。
四、关键点总结
- 模块化:Testbench组件需解耦,便于复用。
- 自动化:通过脚本实现编译、仿真、覆盖率分析全流程。
- 覆盖率驱动:以覆盖率为导向迭代补充测试用例。
- 断言与参考模型:实时验证协议正确性,避免后处理分析延迟。
通过以上流程,可系统性地完成Verilog模块的验证,确保设计符合功能需求且鲁棒性达标。