UVM 工厂(Factory)机制的核心是注册→创建→覆盖 ,用集中管控与动态绑定实现 "接口声明、实现可替换",是 UVM 实现高复用、易扩展验证环境的基石。下面从原理、核心组件、使用方法、典型场景与源码本质逐层详解。
一、核心设计思想
工厂本质是单例模式 + 依赖反转(IoC):
- 解耦创建与使用 :不硬编码
new(),而是通过工厂请求对象,创建逻辑由工厂统一管理。 - 运行时动态替换 :无需修改原有代码,用派生类替换基类实例,实现 "同一环境、不同行为"。
- 全局唯一管控 :整个验证环境只有一个
uvm_factory实例,集中管理所有注册类型与覆盖规则。
传统 new () 与工厂 create () 对比:
// 硬编码:写死类型,无法替换
my_driver drv = new("drv", this);
// 工厂方式:声明接口,实现由工厂决定
my_driver drv = my_driver::type_id::create("drv", this);
二、三大核心组件
1. 全局工厂单例:uvm_factory
- 全局唯一实例,通过
uvm_factory::get()获取。 - 维护两张表:类型注册表 (记录所有注册类)、覆盖映射表(记录类型 / 实例替换规则)。
2. 类型注册宏
UVM 通过宏自动注册类到工厂,分两类:
| 宏 | 用途 | 适用类 |
|---|---|---|
uvm_component_utils(T) |
注册组件(有层次、生命周期) | uvm_component派生类(driver/monitor/env) |
uvm_object_utils(T) |
注册对象(无层次、数据 / 配置) | uvm_object派生类(transaction/config) |
注册示例:
class my_driver extends uvm_driver#(my_transaction);
`uvm_component_utils(my_driver) // 注册到工厂
// ...
endclass
宏展开后会:
- 定义
type_id(uvm_object_registry单例)。 - 实现
get_type()/create()等方法,供工厂查找与创建实例。
3. 类型代理:uvm_object_registry#(T)
- 每个注册类对应一个
type_id,是工厂与类之间的代理接口。 - 核心方法:
create()(触发工厂创建)、set_type_override()(设置类型覆盖)。
三、工厂工作全流程(注册→覆盖→创建)
1. 注册(Registration)
- 编译期:
uvm_*_utils宏将类信息(类型名、创建函数)存入uvm_factory的类型表。 - 关键:只有注册过的类,工厂才能创建或替换。
2. 覆盖(Override):动态替换规则
覆盖分两种,均在创建前 设置(通常在build_phase)。
(1)类型覆盖(Type Override):全局替换所有实例
// 所有base_driver实例 → 替换为enhanced_driver
base_driver::type_id::set_type_override(enhanced_driver::get_type());
// 或全局工厂调用
uvm_factory::get().set_type_override_by_type(
base_driver::get_type(),
enhanced_driver::get_type()
);
(2)实例覆盖(Instance Override):仅替换特定路径实例
// 仅替换env.agent.drv这一个实例
uvm_factory::get().set_inst_override_by_type(
base_driver::get_type(),
debug_driver::get_type(),
"env.agent.drv" // 实例路径(通配符*支持模糊匹配)
);
3. 创建(Creation):工厂按规则实例化
调用type_id::create()时,工厂执行:
- 查覆盖表:是否有当前类型 / 实例的替换规则。
- 选实际类型:有覆盖则用替换类 ,无则用原类。
- 实例化:调用替换类 / 原类的
new(),返回句柄。
创建示例:
// 工厂创建:若有base_driver→enhanced_driver覆盖,实际返回enhanced_driver实例
my_driver drv = my_driver::type_id::create("drv", this);
四、关键使用规则与注意事项
- 继承要求 :替换类必须是基类的派生类(满足多态)。
- 宏一致性 :基类与派生类都必须用
uvm_*_utils注册。 - 覆盖时机 :覆盖必须在创建前 设置(
build_phase早于connect_phase)。 - 路径匹配 :实例覆盖路径需与
get_full_name()完全一致,支持*通配符。 - 覆盖优先级 :实例覆盖 > 类型覆盖(局部规则优先于全局)。
五、典型应用场景
1. 功能扩展:用增强驱动替换基础驱动
- 基类
base_driver(基础功能)。 - 派生类
perf_driver(增加性能统计)、debug_driver(增加日志)。 - 测试中通过覆盖切换,同一环境跑不同功能。
2. 环境复用:同一 ENV 适配不同 DUT
- 基类
base_transaction(通用激励)。 - 派生类
dut1_transaction/dut2_transaction(适配不同 DUT 时序)。 - 工厂覆盖动态切换激励类型,ENV 无需修改。
3. 调试与错误注入:替换正常组件为故障组件
- 用
error_inject_driver替换正常driver,无需修改原有代码即可注入错误,验证 DUT 容错性。
六、源码本质(简化理解)
1. uvm_factory核心逻辑
class uvm_factory;
static uvm_factory inst; // 单例
uvm_type_info type_table[string]; // 类型注册表
uvm_override_info type_override_table[uvm_type_info]; // 类型覆盖表
uvm_override_info inst_override_table[string]; // 实例覆盖表
virtual function uvm_object create_object(uvm_type_info type, string name, string inst_path);
// 1. 查实例覆盖
if (inst_override_table.exists(inst_path))
type = inst_override_table[inst_path].new_type;
// 2. 查类型覆盖
else if (type_override_table.exists(type))
type = type_override_table[type].new_type;
// 3. 创建实例
return type.create(name);
endfunction
endclass
2. uvm_object_registry代理
class uvm_object_registry#(T) extends uvm_type_info;
static uvm_object_registry#(T) inst; // 单例type_id
virtual function uvm_object create(string name);
return new T(name); // 实际创建
endfunction
endclass
七、总结
UVM 工厂机制是 **"接口抽象 + 动态绑定"** 的典范:
- 注册:让工厂 "认识" 类,纳入统一管理。
- 覆盖:运行时动态调整类型映射,实现无代码修改的功能切换。
- 创建:工厂按规则实例化,解耦创建与使用,提升环境复用性。
掌握工厂机制,是写出高复用、易维护、可扩展UVM 验证环境的核心。