1. 搭建最小UVM测试平台
任务目标
本案例将搭建一个最小可运行的UVM验证平台,用于验证一个8位加法器DUT。平台包含driver(驱动激励)、monitor(监测输出)和scoreboard(数据比对)三个核心组件,通过一个基础测试用例完成数据比对并报告结果。
环境依赖
需要支持UVM-1.2的仿真器(如VCS、QuestaSim),并确保UVM库已正确安装。以下代码基于UVM-1.2标准编写,使用SystemVerilog语言。
DUT设计(加法器)
// adder.sv - 8位加法器DUT
module adder(
input logic [7:0] a,
input logic [7:0] b,
input logic cin,
output logic [7:0] sum,
output logic cout
);
assign {cout, sum} = a + b + cin;
endmodule
UVM验证平台完整代码
// uvmt_adder_pkg.sv - 最小UVM测试平台(单文件完整实现)
package uvmt_adder_pkg;
import uvm_pkg::*;
`include "uvm_macros.svh"
// 事务对象
class adder_transaction extends uvm_sequence_item;
rand logic [7:0] a;
rand logic [7:0] b;
rand logic cin;
logic [7:0] sum;
logic cout;
`uvm_object_utils_begin(adder_transaction)
`uvm_field_int(a, UVM_ALL_ON)
`uvm_field_int(b, UVM_ALL_ON)
`uvm_field_int(cin, UVM_ALL_ON)
`uvm_field_int(sum, UVM_ALL_ON)
`uvm_field_int(cout, UVM_ALL_ON)
`uvm_object_utils_end
function new(string name = "adder_transaction");
super.new(name);
endfunction
endclass
// 序列:生成随机激励
class adder_sequence extends uvm_sequence #(adder_transaction);
`uvm_object_utils(adder_sequence)
function new(string name = "adder_sequence");
super.new(name);
endfunction
task body();
repeat(10) begin
adder_transaction tx = adder_transaction::type_id::create("tx");
start_item(tx);
assert(tx.randomize());
finish_item(tx);
end
endtask
endclass
// Driver:驱动激励到DUT
class adder_driver extends uvm_driver #(adder_transaction);
`uvm_component_utils(adder_driver)
virtual adder_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 adder_if)::get(this, "", "vif", vif))
`uvm_fatal("NOVIF", "virtual interface not found")
endfunction
task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req);
vif.a <= req.a;
vif.b <= req.b;
vif.cin <= req.cin;
@(posedge vif.clk);
seq_item_port.item_done();
end
endtask
endclass
// Monitor:采集DUT输出
class adder_monitor extends uvm_monitor;
`uvm_component_utils(adder_monitor)
virtual adder_if vif;
uvm_analysis_port #(adder_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 adder_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);
adder_transaction tx;
forever begin
@(posedge vif.clk);
tx = adder_transaction::type_id::create("tx");
tx.a = vif.a;
tx.b = vif.b;
tx.cin = vif.cin;
tx.sum = vif.sum;
tx.cout = vif.cout;
mon_ap.write(tx);
end
endtask
endclass
// Scoreboard:数据比对
class adder_scoreboard extends uvm_scoreboard;
`uvm_component_utils(adder_scoreboard)
uvm_analysis_imp #(adder_transaction, adder_scoreboard) analysis_imp;
int match_count;
int error_count;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
analysis_imp = new("analysis_imp", this);
match_count = 0;
error_count = 0;
endfunction
function void write(adder_transaction tx);
logic [8:0] expected;
expected = tx.a + tx.b + tx.cin;
if ({tx.cout, tx.sum} == expected) begin
match_count++;
`uvm_info("SCB", $sformatf("MATCH: a=%0d b=%0d cin=%0d sum=%0d cout=%0d",
tx.a, tx.b, tx.cin, tx.sum, tx.cout), UVM_MEDIUM)
end else begin
error_count++;
`uvm_error("SCB", $sformatf("MISMATCH: a=%0d b=%0d cin=%0d expected=%0d actual={%0d,%0d}",
tx.a, tx.b, tx.cin, expected, tx.cout, tx.sum))
end
endfunction
function void report_phase(uvm_phase phase);
`uvm_info("SCB", $sformatf("Scoreboard report: %0d matched, %0d errors",
match_count, error_count), UVM_LOW)
endfunction
endclass
// 环境
class adder_env extends uvm_env;
`uvm_component_utils(adder_env)
adder_driver driver;
adder_monitor monitor;
adder_scoreboard scoreboard;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
driver = adder_driver::type_id::create("driver", this);
monitor = adder_monitor::type_id::create("monitor", this);
scoreboard = adder_scoreboard::type_id::create("scoreboard", this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
driver.seq_item_port.connect(driver.seq_item_export); // 内部连接
monitor.mon_ap.connect(scoreboard.analysis_imp);
endfunction
endclass
// 测试基类
class adder_base_test extends uvm_test;
`uvm_component_utils(adder_base_test)
adder_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 = adder_env::type_id::create("env", this);
endfunction
task run_phase(uvm_phase phase);
adder_sequence seq = adder_sequence::type_id::create("seq");
phase.raise_objection(this);
seq.start(env.driver.seq_item_port);
#100;
phase.drop_objection(this);
endtask
function void report_phase(uvm_phase phase);
if (env.scoreboard.error_count == 0)
`uvm_info("TEST", "*** TEST PASSED ***", UVM_LOW)
else
`uvm_error("TEST", "*** TEST FAILED ***")
endfunction
endclass
// 具体测试用例
class adder_basic_test extends adder_base_test;
`uvm_component_utils(adder_basic_test)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
endclass
endpackage
接口定义与顶层模块
// adder_if.sv - 接口定义
interface adder_if(input logic clk);
logic [7:0] a;
logic [7:0] b;
logic cin;
logic [7:0] sum;
logic cout;
endinterface
// top.sv - 顶层模块,连接DUT与UVM平台
module top;
logic clk;
initial clk = 0;
always #5 clk = ~clk;
adder_if vif(clk);
adder dut(
.a(vif.a), .b(vif.b), .cin(vif.cin),
.sum(vif.sum), .cout(vif.cout)
);
initial begin
uvm_config_db#(virtual adder_if)::set(null, "uvm_test_top.env.driver", "vif", vif);
uvm_config_db#(virtual adder_if)::set(null, "uvm_test_top.env.monitor", "vif", vif);
run_test("adder_basic_test");
end
endmodule
编译与运行
# 使用QuestaSim示例(其他仿真器命令类似)
vlib work
vlog +incdir+$UVM_HOME/src $UVM_HOME/src/uvm_pkg.sv adder.sv adder_if.sv uvmt_adder_pkg.sv top.sv
vsim -c -do "run -all; quit" work.top
验证方法与通过标准
运行仿真后,观察UVM报告。通过标准为:
- scoreboard报告显示10次比对全部MATCH,error_count为0;
- 测试报告显示“TEST PASSED”;
- UVM无FATAL或ERROR级别的报错。
若出现MISMATCH,说明DUT逻辑或平台连接有误,需检查接口信号连接和driver时序。
预期输出(确定性结果)
由于激励为随机生成,具体数值不可预测,但scoreboard的比对逻辑是确定性的:对于任意输入a、b、cin,期望输出恒为{cout, sum} = a + b + cin。因此只要DUT功能正确,所有事务必然比对通过,最终报告必然显示10次MATCH、0 errors,并打印“TEST PASSED”。