1. 搭建UVM验证环境基础框架
任务说明
本案例目标为搭建一个最小化UVM验证环境基础框架,包含uvm_test、uvm_env、uvm_agent、uvm_driver、uvm_sequencer、uvm_monitor和uvm_scoreboard七个核心组件,并通过一个冒烟测试验证框架可正确编译与运行。该框架不针对特定DUT协议,仅验证UVM组件层次结构与phase机制工作正常。
环境依赖
- 支持UVM-1.2或IEEE 1800.2的仿真器(如VCS、Questa、Xcelium)
- UVM库已正确安装并可通过
+incdir+<uvm_home>/src引用
完整实现代码
// file: uvm_base_framework.sv
`include "uvm_macros.svh"
import uvm_pkg::*;
// 1. Transaction
class simple_trans extends uvm_sequence_item;
rand bit [7:0] data;
`uvm_object_utils_begin(simple_trans)
`uvm_field_int(data, UVM_ALL_ON)
`uvm_object_utils_end
function new(string name = "simple_trans");
super.new(name);
endfunction
endclass
// 2. Driver
class simple_driver extends uvm_driver #(simple_trans);
`uvm_component_utils(simple_driver)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
task run_phase(uvm_phase phase);
simple_trans req;
forever begin
seq_item_port.get_next_item(req);
`uvm_info("DRV", $sformatf("Driving data: %0d", req.data), UVM_LOW)
seq_item_port.item_done();
end
endtask
endclass
// 3. Sequencer
class simple_sequencer extends uvm_sequencer #(simple_trans);
`uvm_component_utils(simple_sequencer)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
endclass
// 4. Monitor
class simple_monitor extends uvm_monitor;
`uvm_component_utils(simple_monitor)
uvm_analysis_port #(simple_trans) mon_ap;
function new(string name, uvm_component parent);
super.new(name, parent);
mon_ap = new("mon_ap", this);
endfunction
task run_phase(uvm_phase phase);
simple_trans item;
forever begin
#10;
item = simple_trans::type_id::create("item");
item.randomize();
`uvm_info("MON", $sformatf("Observed data: %0d", item.data), UVM_LOW)
mon_ap.write(item);
end
endtask
endclass
// 5. Scoreboard
class simple_scoreboard extends uvm_scoreboard;
`uvm_component_utils(simple_scoreboard)
uvm_analysis_imp #(simple_trans, simple_scoreboard) sb_imp;
int unsigned count;
function new(string name, uvm_component parent);
super.new(name, parent);
sb_imp = new("sb_imp", this);
count = 0;
endfunction
function void write(simple_trans t);
count++;
`uvm_info("SCB", $sformatf("Received item #%0d, data=%0d", count, t.data), UVM_LOW)
endfunction
function void check_phase(uvm_phase phase);
if (count == 0)
`uvm_error("SCB", "No transaction received by scoreboard!")
endfunction
endclass
// 6. Agent
class simple_agent extends uvm_agent;
`uvm_component_utils(simple_agent)
simple_driver drv;
simple_sequencer seq;
simple_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 = simple_driver::type_id::create("drv", this);
seq = simple_sequencer::type_id::create("seq", this);
mon = simple_monitor::type_id::create("mon", this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
drv.seq_item_port.connect(seq.seq_item_export);
endfunction
endclass
// 7. Environment
class simple_env extends uvm_env;
`uvm_component_utils(simple_env)
simple_agent agt;
simple_scoreboard scb;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
agt = simple_agent::type_id::create("agt", this);
scb = simple_scoreboard::type_id::create("scb", this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
agt.mon.mon_ap.connect(scb.sb_imp);
endfunction
endclass
// 8. Sequence
class simple_seq extends uvm_sequence #(simple_trans);
`uvm_object_utils(simple_seq)
function new(string name = "simple_seq");
super.new(name);
endfunction
task body();
repeat (3) begin
simple_trans tr;
tr = simple_trans::type_id::create("tr");
start_item(tr);
tr.randomize();
finish_item(tr);
end
endtask
endclass
// 9. Test
class base_test extends uvm_test;
`uvm_component_utils(base_test)
simple_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 = simple_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.agt.seq);
#100;
phase.drop_objection(this);
endtask
endclass
// 10. Top module
module top;
initial begin
run_test("base_test");
end
endmodule
编译与运行
# VCS 示例
vcs -sverilog -ntb_opts uvm-1.2 -timescale=1ns/1ps \
+incdir+$UVM_HOME/src $UVM_HOME/src/uvm.sv \
uvm_base_framework.sv -o simv
./simv
# Questa 示例
vlog -sv +incdir+$UVM_HOME/src $UVM_HOME/src/uvm.sv uvm_base_framework.sv
vsim -c -do "run -all; quit" work.top
验证方法与通过标准
- 编译通过:仿真器无编译错误,UVM库正常链接。
- 运行日志:仿真运行后,UVM报告显示
UVM_INFO日志,包含来自driver的Driving data、monitor的Observed data以及scoreboard的Received item信息。 - 通过条件:UVM报告最终显示
UVM_ERROR : 0,且scoreboard的check_phase未报告错误(即收到至少1个transaction)。
预期输出(确定性部分)
由于sequence中固定发送3个transaction,scoreboard的count最终应为3。UVM报告应包含类似以下信息(具体时间戳与实例路径可能因仿真器而异):
UVM_INFO DRV: Driving data: <随机值>
UVM_INFO MON: Observed data: <随机值>
UVM_INFO SCB: Received item #3, data=<随机值>
UVM_ERROR: 0
常见问题
- 编译报错找不到uvm_pkg:确认
+incdir+路径指向UVM源码src目录,且编译命令中包含了uvm.sv文件。 - 仿真挂起不退出:检查test的run_phase中是否正确raise/drop objection;若sequence提前结束且无objection控制,仿真可能立即退出。
- scoreboard报错“No transaction”:确认agent中monitor的analysis_port已连接到scoreboard的analysis_imp,且monitor的run_phase确实在产生数据。