UVM验证环境搭建:从base test到scoreboard的完整步骤
在ASIC/SoC验证中,UVM(Universal Verification Methodology) 提供标准化的component层次结构。本文按实战顺序,从agent、env、base_test到scoreboard,走完一个可编译、可扩展的最小UVM验证环境搭建流程(以DUT为简单寄存器型模块为例)。
一、Transaction(uvm_sequence_item)
所有component传递的“数据包”需继承uvm_sequence_item,并注册field宏:
class my_txn extends uvm_sequence_item;
`uvm_object_utils(my_txn)
rand bit [31:0] addr;
rand bit [31:0] wdata;
rand bit wr; // 1=写, 0=读
bit [31:0] rdata; // 读返回(仅用于scoreboard比对)
constraint c_addr { addr[31:28]==4'h0; } // 示例:低1GB空间
function new(string name="my_txn");
super.new(name);
endfunction
endclass
二、Driver + Monitor + Agent
2.1 Driver(驱动DUT接口)
class my_drv extends uvm_driver #(my_txn);
`uvm_component_utils(my_drv)
virtual bus_if vif; // 在env中通过config_db设置
task run_phase(uvm_phase phase);
my_txn tx;
forever begin
seq_item_port.get_next_item(tx);
// 简化:在posedge vif.clk 驱动地址/数据/we
@(posedge vif.clk);
vif.addr <= tx.addr;
vif.wdata <= tx.wdata;
vif.we <= tx.wr;
seq_item_port.item_done();
end
endtask
endclass
2.2 Monitor(采集并广播)
class my_mon extends uvm_monitor;
`uvm_component_utils(my_mon)
virtual bus_if vif;
uvm_analysis_port #(my_txn) ap;
function void build_phase(uvm_phase phase);
ap = new("ap",this);
endfunction
task run_phase(uvm_phase phase);
my_txn tx = my_txn::type_id::create("tx");
forever @(posedge vif.clk iff vif.we or posedge vif.clk iff !vif.we) begin
tx.addr = vif.addr;
tx.wdata = vif.wdata;
tx.wr = vif.we;
tx.rdata = vif.rdata; // 读时捕捉返回
ap.write(tx); // 广播给scoreboard
end
endtask
endclass
2.3 Agent封装
class my_agent extends uvm_agent;
`uvm_component_utils(my_agent)
my_drv drv;
my_mon mon;
uvm_sequencer #(my_txn) sqr;
function void build_phase(uvm_phase phase);
sqr = uvm_sequencer#(my_txn)::type_id::create("sqr",this);
drv = my_drv::type_id::create("drv",this);
mon = my_mon::type_id::create("mon",this);
endfunction
function void connect_phase(uvm_phase phase);
drv.seq_item_port.connect(sqr.seq_item_export);
endfunction
endclass
三、Scoreboard(比对期望vs实际)
最简scoreboard:维护参考模型(Reg File镜像)并比对读回数据。
class my_sb extends uvm_scoreboard;
`uvm_component_utils(my_sb)
uvm_analysis_imp #(my_txn, my_sb) imp;
bit [31:0] ref_mem [bit [31:0]]; // 简单参考模型
function void write(my_txn tx);
if (tx.wr) begin
ref_mem[tx.addr] = tx.wdata;
`uvm_info("SCOREBOARD",$sformatf("WRITE addr=%0h data=%0h",tx.addr,tx.wdata),UVM_LOW)
end else begin
if (ref_mem.exists(tx.addr)) begin
if (ref_mem[tx.addr] !== tx.rdata)
`uvm_error("SCOREBOARD",
$sformatf("READ MISMATCH addr=%0h EXP=%0h GOT=%0h",
tx.addr,ref_mem[tx.addr],tx.rdata))
else
`uvm_info("SCOREBOARD","READ MATCH",UVM_LOW)
end else
`uvm_warning("SCOREBOARD","Uninitialized addr read")
end
endfunction
endclass
四、Environment(env)
class my_env extends uvm_env;
`uvm_component_utils(my_env)
my_agent agt;
my_sb sb;
function void build_phase(uvm_phase phase);
agt = my_agent::type_id::create("agt",this);
sb = my_sb::type_id::create("sb",this);
endfunction
function void connect_phase(uvm_phase phase);
agt.mon.ap.connect(sb.imp); // Monitor → Scoreboard
endfunction
endclass
五、Base Test与Sequence
5.1 Base Test
class base_test extends uvm_test;
`uvm_component_utils(base_test)
my_env env;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
env = my_env::type_id::create("env",this);
// 配置virtual interface(在top_tb中set)
if (!uvm_config_db#(virtual bus_if)::get(this,"","vif",env.agt.drv.vif))
`uvm_fatal("CFG","vif not set")
uvm_config_db#(virtual bus_if)::set(this,"env.agt.mon","vif",env.agt.drv.vif);
endfunction
task run_phase(uvm_phase phase);
phase.raise_objection(this);
`uvm_info("TEST","Starting sequence",UVM_MEDIUM)
fork
begin
my_seq seq = my_seq::type_id::create("seq");
seq.start(env.agt.sqr);
end
join
phase.drop_objection(this);
endtask
endclass
5.2 简单Sequence
class my_seq extends uvm_sequence #(my_txn);
`uvm_object_utils(my_seq)
task body();
repeat(10) begin
req = my_txn::type_id::create("req");
start_item(req);
if (!req.randomize() with { wr==1; })
`uvm_error("SEQ","randomize fail")
finish_item(req);
end
endtask
endclass
六、Top TB中连接与运行
module top_tb;
bus_if bif(); // 定义 interface
dut dut_i (.clk(bif.clk), .addr(bif.addr), .wdata(bif.wdata),
.we(bif.we), .rdata(bif.rdata));
initial begin
uvm_config_db#(virtual bus_if)::set(null,"*","vif",bif);
run_test("base_test");
end
endmodule
七、编译与调试要点
现象 原因 解决
factory override fail 类名拼写错或忘记 uvm_component_utils 检查 type_id::create 名与 class 一致
Monitor不广播 ap.write()未调用或ap未connect 确认 connect_phase 中 mon.ap.connect(sb.imp)
Sequence不启动 未在test中 seq.start(sqr) 或 objection未raise 确认 raise_objection/drop_objection 配对
Scoreboard误报Mismatch DUT返回latency导致rdata未稳 确保Monitor采样在DUT输出稳定后(posedge + valid)
八、结语
UVM环境搭建的骨架是:transaction定义→agent(drv+mon)→env连接monitor到scoreboard→basetest启动sequence。按此模板扩展(添加coverage、register model、multi-agent),即可构建符合IEEE 1800 UVM标准的可复用验证平台。





