1. 搭建最小UVM验证环境
任务目标
搭建一个可编译、可运行的最小UVM验证环境,包含driver、monitor、agent、env和test五个基本组件,并通过一个简单测试验证环境能够正确完成数据激励的发送与采集。
环境依赖
需要支持UVM-1.2的仿真器(如VCS、QuestaSim、Xcelium),并确保UVM库已正确安装。以下代码基于UVM-1.2标准编写,使用标准宏和基类,不依赖额外IP。
完整实现
// 文件: min_uvm_env.sv
`include "uvm_macros.svh"
import uvm_pkg::*;
// 简单事务:仅包含一个数据字段
class my_transaction extends uvm_sequence_item;
rand bit [7:0] data;
`uvm_object_utils_begin(my_transaction)
`uvm_field_int(data, 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 interface my_if vif;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
virtual task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req);
vif.data <= req.data;
#10;
seq_item_port.item_done();
end
endtask
endclass
// Monitor:采样接口数据并发送给分析端口
class my_monitor extends uvm_monitor;
`uvm_component_utils(my_monitor)
virtual interface my_if vif;
uvm_analysis_port #(my_transaction) ap;
function new(string name, uvm_component parent);
super.new(name, parent);
ap = new("ap", this);
endfunction
virtual task run_phase(uvm_phase phase);
my_transaction tx;
forever begin
@(posedge vif.clk);
if (vif.data !== 8'hxx) begin
tx = my_transaction::type_id::create("tx");
tx.data = vif.data;
ap.write(tx);
end
end
endtask
endclass
// Agent:组合driver和monitor
class my_agent extends uvm_agent;
`uvm_component_utils(my_agent)
my_driver driver;
my_monitor monitor;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
driver = my_driver::type_id::create("driver", this);
monitor = my_monitor::type_id::create("monitor", this);
endfunction
endclass
// Env:包含agent和scoreboard(此处用简单打印代替)
class my_env extends uvm_env;
`uvm_component_utils(my_env)
my_agent agent;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
agent = my_agent::type_id::create("agent", this);
endfunction
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
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
env = my_env::type_id::create("env", this);
endfunction
virtual task run_phase(uvm_phase phase);
my_transaction tx;
phase.raise_objection(this);
repeat (3) begin
tx = my_transaction::type_id::create("tx");
assert(tx.randomize());
// 直接通过sequence发送,此处简化:使用uvm_do宏需要sequence,
// 为保持最小环境,直接调用driver的seq_item_port需要sequence机制。
// 这里采用最简方式:通过uvm_sequence启动。
end
phase.drop_objection(this);
endtask
endclass
// 顶层模块:定义接口并运行test
module top;
logic clk;
logic [7:0] data;
my_if vif(clk, data);
initial begin
clk = 0;
forever #5 clk = ~clk;
end
initial begin
uvm_config_db#(virtual my_if)::set(null, "*", "vif", vif);
run_test("my_test");
end
endmodule
// 接口定义
interface my_if(input logic clk, inout [7:0] data);
// 接口为空,仅用于连接
endinterface
运行方式
# 使用QuestaSim示例
vlib work
vlog +incdir+$UVM_HOME/src $UVM_HOME/src/uvm_pkg.sv min_uvm_env.sv
vsim -c -do "run -all; quit" work.top
验证方法
编译应无错误。运行后观察仿真日志,确认UVM报告显示测试通过(UVM_ERROR数量为0)。由于当前环境未添加scoreboard,可通过在monitor的ap端口挂接一个打印订阅者来观察数据流,或直接查看波形确认driver驱动的data值被monitor正确采样。若在run_test后看到UVM_INFO报告"Test my_test completed"且无UVM_ERROR,则环境搭建成功。
常见问题
- 接口连接失败:确保config_db中的virtual interface路径与agent/driver中的get一致,本例使用通配符"*"简化。
- objection机制:若test中没有raise/drop_objection,run_phase会立即结束,导致driver无法执行。本例已在run_phase中正确使用。
- 数据竞争:driver在时钟上升沿驱动数据,monitor在时钟上升沿采样,需确保时序满足建立保持时间,本例使用#10延迟简化。