1. 搭建UVM验证环境基本框架
任务目标
为矩阵加法模块(matrix_add)搭建一个最小可运行的UVM验证环境,包含driver、monitor、scoreboard三个基础组件,通过一个简单测试用例完成对加法功能的基本验证。本案例聚焦于UVM环境的结构搭建与数据流贯通,不涉及时序协议细节。
环境依赖
需要支持UVM-1.2的仿真器(如VCS、QuestaSim),并已配置UVM库路径。DUT为组合逻辑矩阵加法器,接口信号:clk、rst_n、valid_i、a[7:0]、b[7:0]、valid_o、sum[8:0](9位,防止溢出)。
UVM环境结构
环境采用标准UVM树形结构:test → env → agent(内含driver、monitor)→ scoreboard。driver负责驱动输入激励,monitor采样输出结果,scoreboard通过analysis端口接收driver的输入激励副本和monitor的输出结果,进行数据比对。
关键完整代码
// 文件: matrix_add_tb.sv
`include "uvm_macros.svh"
import uvm_pkg::*;
// 接口定义
interface matrix_add_if(input logic clk);
logic rst_n;
logic valid_i;
logic [7:0] a, b;
logic valid_o;
logic [8:0] sum;
endinterface
// 事务对象
class my_transaction extends uvm_sequence_item;
rand logic [7:0] a, b;
logic [8:0] expected_sum;
`uvm_object_utils_begin(my_transaction)
`uvm_field_int(a, UVM_ALL_ON)
`uvm_field_int(b, UVM_ALL_ON)
`uvm_object_utils_end
function new(string name = "my_transaction");
super.new(name);
endfunction
endclass
// Driver:驱动输入激励
class my_driver extends uvm_driver #(my_transaction);
`uvm_component_utils(my_driver)
virtual matrix_add_if vif;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if (!uvm_config_db#(virtual matrix_add_if)::get(this, "", "vif", vif))
`uvm_fatal("NOVIF", "virtual interface not found")
endfunction
task run_phase(uvm_phase phase);
my_transaction tx;
forever begin
seq_item_port.get_next_item(tx);
@(posedge vif.clk);
vif.a <= tx.a;
vif.b <= tx.b;
vif.valid_i <= 1;
@(posedge vif.clk);
vif.valid_i <= 0;
seq_item_port.item_done();
end
endtask
endclass
// Monitor:采样输出
class my_monitor extends uvm_monitor;
`uvm_component_utils(my_monitor)
virtual matrix_add_if vif;
uvm_analysis_port #(my_transaction) mon_ap;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if (!uvm_config_db#(virtual matrix_add_if)::get(this, "", "vif", vif))
`uvm_fatal("NOVIF", "virtual interface not found")
mon_ap = new("mon_ap", this);
endfunction
task run_phase(uvm_phase phase);
my_transaction tx;
forever begin
@(posedge vif.clk);
if (vif.valid_o) begin
tx = my_transaction::type_id::create("tx");
tx.a = vif.a; // 采样输入作为参考
tx.b = vif.b;
tx.expected_sum = vif.sum;
mon_ap.write(tx);
end
end
endtask
endclass
// Scoreboard:数据比对
class my_scoreboard extends uvm_scoreboard;
`uvm_component_utils(my_scoreboard)
uvm_analysis_imp #(my_transaction, my_scoreboard) sb_imp;
int match_count, mismatch_count;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
sb_imp = new("sb_imp", this);
endfunction
function void write(my_transaction tx);
logic [8:0] calc_sum;
calc_sum = tx.a + tx.b;
if (calc_sum == tx.expected_sum) begin
match_count++;
`uvm_info("SB_MATCH", $sformatf("a=%0d b=%0d sum=%0d PASS", tx.a, tx.b, tx.expected_sum), UVM_MEDIUM)
end else begin
mismatch_count++;
`uvm_error("SB_MISMATCH", $sformatf("a=%0d b=%0d exp=%0d got=%0d", tx.a, tx.b, calc_sum, tx.expected_sum))
end
endfunction
endclass
// Agent:封装driver和monitor
class my_agent extends uvm_agent;
`uvm_component_utils(my_agent)
my_driver drv;
my_monitor mon;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
drv = my_driver::type_id::create("drv", this);
mon = my_monitor::type_id::create("mon", this);
endfunction
endclass
// Env:顶层环境
class my_env extends uvm_env;
`uvm_component_utils(my_env)
my_agent agent;
my_scoreboard sb;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
agent = my_agent::type_id::create("agent", this);
sb = my_scoreboard::type_id::create("sb", this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
agent.mon.mon_ap.connect(sb.sb_imp);
endfunction
endclass
// 简单测试序列
class simple_seq extends uvm_sequence #(my_transaction);
`uvm_object_utils(simple_seq)
function new(string name = "simple_seq");
super.new(name);
endfunction
task body();
my_transaction tx;
repeat(10) begin
tx = my_transaction::type_id::create("tx");
start_item(tx);
assert(tx.randomize());
finish_item(tx);
end
endtask
endclass
// Test:顶层测试
class my_test extends uvm_test;
`uvm_component_utils(my_test)
my_env env;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
env = my_env::type_id::create("env", this);
endfunction
task run_phase(uvm_phase phase);
simple_seq seq;
phase.raise_objection(this);
seq = simple_seq::type_id::create("seq");
seq.start(env.agent.drv.seq_item_port);
#100;
phase.drop_objection(this);
endtask
function void report_phase(uvm_phase phase);
super.report_phase(phase);
`uvm_info("REPORT", $sformatf("match=%0d mismatch=%0d", env.sb.match_count, env.sb.mismatch_count), UVM_LOW)
endfunction
endclass
// DUT:矩阵加法模块(组合逻辑)
module matrix_add(
input logic clk,
input logic rst_n,
input logic valid_i,
input logic [7:0] a, b,
output logic valid_o,
output logic [8:0] sum
);
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
valid_o <= 0;
sum <= 0;
end else begin
valid_o <= valid_i;
sum <= a + b;
end
end
endmodule
// 顶层模块:连接DUT与接口
module top;
logic clk = 0;
always #5 clk = ~clk;
matrix_add_if mif(clk);
matrix_add dut(
.clk(clk), .rst_n(mif.rst_n), .valid_i(mif.valid_i),
.a(mif.a), .b(mif.b), .valid_o(mif.valid_o), .sum(mif.sum)
);
initial begin
mif.rst_n = 0;
#20 mif.rst_n = 1;
uvm_config_db#(virtual matrix_add_if)::set(null, "uvm_test_top.env.agent.drv", "vif", mif);
uvm_config_db#(virtual matrix_add_if)::set(null, "uvm_test_top.env.agent.mon", "vif", mif);
run_test("my_test");
end
endmodule
运行方式
# VCS编译运行示例
vcs -sverilog +incdir+$UVM_HOME/src matrix_add_tb.sv $UVM_HOME/src/uvm.sv -R -l run.log
验证方法与判定标准
运行仿真后,观察日志中的SB_MATCH信息。判定通过条件:mismatch=0且match=10(对应10个随机激励)。若出现SB_MISMATCH或UVM_ERROR,则说明环境数据通路或DUT功能存在错误。可通过修改simple_seq中的repeat次数来增加验证规模。
常见问题
- 接口未找到:检查
uvm_config_db的路径字符串是否与组件层次一致,特别是uvm_test_top前缀。 - 比对不通过:确认monitor采样时刻是否正确,DUT为时序输出,需在
valid_o拉高且数据稳定后采样。 - 仿真不结束:检查objection的raise/drop是否配对,确保run_phase能正常退出。