3. UVM中的工厂机制应用
任务目标
本案例演示UVM工厂机制的核心用法:通过uvm_component_utils和uvm_object_utils宏注册类,使用create()代替直接构造,并分别实现类型覆盖(type override)与实例覆盖(instance override),验证覆盖后实际创建的对象类型。
环境依赖
需要UVM库(推荐UVM-1.2或IEEE 1800.2),仿真器支持SystemVerilog(如VCS、QuestaSim、Xcelium)。以下代码在单个SV文件中即可编译运行。
关键完整代码
// file: factory_demo.sv
`include "uvm_macros.svh"
import uvm_pkg::*;
// 1. 注册一个uvm_object派生类
class packet extends uvm_object;
`uvm_object_utils(packet)
function new(string name = "packet");
super.new(name);
endfunction
virtual function string get_type_name();
return "packet";
endfunction
endclass
// 2. 注册一个派生object类,用于类型覆盖
class packet_ext extends packet;
`uvm_object_utils(packet_ext)
function new(string name = "packet_ext");
super.new(name);
endfunction
virtual function string get_type_name();
return "packet_ext";
endfunction
endclass
// 3. 注册一个uvm_component派生类
class driver extends uvm_component;
`uvm_component_utils(driver)
function new(string name = "driver", uvm_component parent = null);
super.new(name, parent);
endfunction
virtual function string get_type_name();
return "driver";
endfunction
endclass
// 4. 注册一个派生component类,用于实例覆盖
class driver_ext extends driver;
`uvm_component_utils(driver_ext)
function new(string name = "driver_ext", uvm_component parent = null);
super.new(name, parent);
endfunction
virtual function string get_type_name();
return "driver_ext";
endfunction
endclass
// 5. 测试顶层模块
module test_top;
initial begin
packet p1, p2;
driver d1, d2;
string msg;
// 5.1 类型覆盖:所有packet的create都返回packet_ext
set_type_override_by_type(packet::get_type(), packet_ext::get_type());
p1 = packet::type_id::create("p1");
$sformat(msg, "type override: p1 actual type = %s", p1.get_type_name());
$display("%s", msg);
// 5.2 实例覆盖:仅对路径为"uvm_test_top.d1"的driver实例生效
set_inst_override_by_type("uvm_test_top.d1", driver::get_type(), driver_ext::get_type());
d1 = driver::type_id::create("d1", null);
d2 = driver::type_id::create("d2", null);
$sformat(msg, "instance override: d1 actual type = %s", d1.get_type_name());
$display("%s", msg);
$sformat(msg, "instance override: d2 actual type = %s", d2.get_type_name());
$display("%s", msg);
// 5.3 验证未受覆盖影响的普通创建
p2 = packet::type_id::create("p2");
$sformat(msg, "no override: p2 actual type = %s", p2.get_type_name());
$display("%s", msg);
end
endmodule
运行方式
# 使用VCS示例
vcs -sverilog +incdir+$UVM_HOME/src $UVM_HOME/src/uvm_pkg.sv factory_demo.sv -o simv
./simv
# 使用QuestaSim示例
vlog +incdir+$UVM_HOME/src $UVM_HOME/src/uvm_pkg.sv factory_demo.sv
vsim -c work.test_top -do "run -all; quit"
验证方法与判定标准
仿真输出应包含以下三行关键信息,且类型名称与代码逻辑严格一致:
type override: p1 actual type = packet_ext
instance override: d1 actual type = driver_ext
instance override: d2 actual type = driver
no override: p2 actual type = packet
判定通过条件:p1被类型覆盖为packet_ext;d1因实例覆盖路径匹配而变为driver_ext;d2路径不匹配保持driver;p2未受任何覆盖影响仍为packet。若输出与上述一致,则工厂机制的类型覆盖和实例覆盖均验证成功。
常见问题
- 覆盖不生效:检查覆盖调用是否在
create()之前执行;实例覆盖的路径必须与组件在UVM树中的完整层次路径完全一致(本案例中d1的父节点为null,因此路径为uvm_test_top.d1)。 - 编译报错找不到
uvm_pkg:确认UVM_HOME环境变量已设置,且编译命令中正确包含UVM源码路径。