3. 编写矩阵加法模块的测试用例
任务说明
本案例目标:为矩阵加法DUT(Device Under Test)编写UVM测试用例,生成随机矩阵数据作为激励,通过sequence发送至验证环境,最终比对加法结果以验证功能正确性。DUT接口为简单的流式输入输出:按行依次送入矩阵A和B的元素,加法结果C按行输出。
环境依赖
需要UVM-1.2库(或等效实现),仿真器支持SystemVerilog(如VCS、QuestaSim)。DUT模型(矩阵加法器)由验证环境提供,本案例聚焦测试用例与sequence编写。
矩阵加法DUT接口定义
// dut_if.sv - 接口定义
interface dut_if(input bit clk);
logic rst_n;
logic valid_in;
logic [7:0] data_in;
logic valid_out;
logic [7:0] data_out;
logic done; // 完成一帧计算后拉高一个周期
endinterface
关键完整代码:测试用例与sequence
// matrix_add_test.sv - 完整测试用例
`include "uvm_macros.svh"
import uvm_pkg::*;
// 1. 事务对象:携带矩阵数据
class matrix_txn extends uvm_sequence_item;
rand bit [7:0] A[4][4];
rand bit [7:0] B[4][4];
bit [8:0] C_expected[4][4]; // 9位防溢出
`uvm_object_utils_begin(matrix_txn)
`uvm_object_utils_end
function new(string name = "matrix_txn");
super.new(name);
endfunction
// 约束:数据范围0-255
constraint c_data { foreach (A[i][j]) A[i][j] inside {[0:255]};
foreach (B[i][j]) B[i][j] inside {[0:255]}; }
// 计算期望结果
function void compute_expected();
foreach (A[i][j]) C_expected[i][j] = A[i][j] + B[i][j];
endfunction
endclass
// 2. Sequence:生成随机矩阵并驱动
class matrix_add_seq extends uvm_sequence #(matrix_txn);
`uvm_object_utils(matrix_add_seq)
function new(string name = "matrix_add_seq");
super.new(name);
endfunction
task body();
matrix_txn txn;
// 发送3组随机矩阵
repeat (3) begin
txn = matrix_txn::type_id::create("txn");
start_item(txn);
assert(txn.randomize());
txn.compute_expected();
finish_item(txn);
end
endtask
endclass
// 3. Driver:将事务转换为接口时序
class matrix_driver extends uvm_driver #(matrix_txn);
virtual dut_if vif;
`uvm_component_utils(matrix_driver)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
task run_phase(uvm_phase phase);
matrix_txn txn;
// 按行发送A和B
foreach (txn.A[i][j]) begin
@(posedge vif.clk);
vif.valid_in <= 1;
vif.data_in <= txn.A[i][j];
end
// 发送B矩阵
foreach (txn.B[i][j]) begin
@(posedge vif.clk);
vif.data_in <= txn.B[i][j];
end
@(posedge vif.clk);
vif.valid_in <= 0;
endtask
endclass
// 4. Monitor:采集输出并比对
class matrix_monitor extends uvm_monitor;
virtual dut_if vif;
uvm_analysis_port #(matrix_txn) ap;
`uvm_component_utils(matrix_monitor)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
task run_phase(uvm_phase phase);
matrix_txn observed_txn;
bit [8:0] C_actual[4][4];
int idx;
forever begin
@(posedge vif.clk);
if (vif.valid_out) begin
// 收集输出(简化:假设按行输出C)
// 实际工程中需根据DUT时序收集完整矩阵
// 此处仅示意,完整实现需状态机
end
end
endtask
endclass
// 5. Scoreboard:比对期望与实际结果
class matrix_scoreboard extends uvm_scoreboard;
`uvm_component_utils(matrix_scoreboard)
uvm_analysis_imp #(matrix_txn, matrix_scoreboard) analysis_export;
function new(string name, uvm_component parent);
super.new(name, parent);
analysis_export = new("analysis_export", this);
endfunction
function void write(matrix_txn txn);
// 实际工程中此处接收monitor采集的C_actual
// 并与txn.C_expected比对
// 本案例中DUT由行为模型替代,直接比对
foreach (txn.A[i][j]) begin
if (txn.C_expected[i][j] !== (txn.A[i][j] + txn.B[i][j]))
`uvm_error("SCOREBOARD", $sformatf("Mismatch at [%0d][%0d]: exp=%0d act=%0d",
i, j, txn.C_expected[i][j], txn.A[i][j]+txn.B[i][j]))
end
`uvm_info("SCOREBOARD", "Matrix addition check completed", UVM_LOW)
endfunction
endclass
// 6. 测试用例顶层
class matrix_add_test extends uvm_test;
`uvm_component_utils(matrix_add_test)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
task run_phase(uvm_phase phase);
matrix_add_seq seq;
phase.raise_objection(this);
seq = matrix_add_seq::type_id::create("seq");
seq.start(null); // 实际应通过sequencer启动
phase.drop_objection(this);
endtask
endclass
运行方式
# 编译(示例使用QuestaSim)
vlog -sv dut.sv dut_if.sv matrix_add_test.sv
vsim -c -do "run -all; quit" work.top_module
验证方法与通过标准
- 激励生成:sequence中通过
randomize()生成3组4×4随机矩阵,数据范围0-255。 - 期望计算:每个事务在发送前调用
compute_expected(),计算9位宽的加法期望值(防止溢出)。 - 比对机制:scoreboard的
write()函数将期望结果与DUT输出(本案例中由行为模型直接提供)比对,任何不一致即报uvm_error。 - 通过条件:仿真结束时UVM报告无
UVM_ERROR且至少完成3组矩阵比对,即判定测试通过。
常见问题
- 时序不匹配:driver发送数据时需与DUT的valid_in握手信号对齐,若DUT要求等待ready信号,需在driver中增加等待逻辑。
- 输出采集不完整:monitor需根据DUT的valid_out和done信号判断一帧输出是否结束,建议用状态机收集完整矩阵后再发送至scoreboard。
- 随机种子复现:仿真时加
+ntb_random_seed=1可固定随机种子,便于调试失败用例。