提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
一、工厂机制
工厂机制负责管理uvm世界中所有object、component的注册、覆盖以及create前覆盖类的查找。
二、相关类(uvm_default_factory、uvm_*_registry、uvm_factory_override)
uvm_default_factory :定义了注册、设置覆盖、创建、查找覆盖等方法。
protected uvm_object_wrapper m_type_names[string]:类似于哈希表,保存对象类型的名称和类型的映射关系。
protected bit m_types[uvm_object_wrapper]:1表示该类型已被注册。
protected uvm_factory_override m_type_overrides[$]:队列,用于存储对象类型的覆盖规则。
uvm_object_registry#(type T = uvm_object,string Tname=‘’):作为工厂注册的基本单元,可创建类型T的对象。
const static string type_name = Tname:每个代理类都有唯一的type_name。
function string get_type_name:返回唯一的名字type_name。
local static this_type me = get():每个代理类都只有唯一的实例me。
static function this_type get():返回唯一的实例me。
function uvm_object create_object (string name):创建名字为name的T的对象,用工厂机制创建对象的最后一步。
static function T create (string name=“”):使用工厂机制创建对象。
static function void set_type_override (uvm_object_wrapper override_type,bit replace=1):调用工厂机制进行类型覆盖
static function void set_inst_override:调用工厂机制进行实例覆盖
uvm_factory_override:
uvm_object_wrapper orig_type:源类型
uvm_object_wrapper ovrd_type:覆盖类型
string orig_type_name:源类型对应的type_name
string ovrd_type_name:覆盖类型对应的type_name
三、源代码分析
1.注册
放入m_type_name中,以提高类型查找的效率,避免重复注册。
a:在uvm_component_utils内声明了类型为uvm_component_registry的type_id,然后调用type_id内的get函数。
`define uvm_component_utils(T) \
`m_uvm_component_registry_internal(T,T) \
`m_uvm_get_type_name_func(T) \
`define m_uvm_component_registry_internal(T,S) \
// `m_uvm_component_registry_internal(T,T) \
typedef uvm_component_registry #(T,`"S`") type_id; \
static function type_id get_type(); \
return type_id::get(); \
endfunction \
virtual function uvm_object_wrapper get_object_type(); \
b:在type_id内的get函数中创建了uvm_component_registry的对象,调用register对其进行注册。
static function this_type get();
if (me == null) begin
uvm_coreservice_t cs = uvm_coreservice_t::get();
uvm_factory factory=cs.get_factory();
me = new;
factory.register(me);
end
return me;
endfunction
c:注册时,先检查是否已经注册过,有的话发出警告。如果没有则将registry放到m_type_name中,m_type设为1表明已经注册。
function void uvm_default_factory::register (uvm_object_wrapper obj);
if (obj == null) begin
uvm_report_fatal ("NULLWR", "Attempting to register a null object with the factory", UVM_NONE);
end
if (obj.get_type_name() != "" && obj.get_type_name() != "<unknown>") begin
if (m_type_names.exists(obj.get_type_name()))
uvm_report_warning("TPRGED", {"Type name '",obj.get_type_name(),
"' already registered with factory. No string-based lookup ",
"support for multiple types with the same type name."}, UVM_NONE);
else
m_type_names[obj.get_type_name()] = obj;
end
if (m_types.exists(obj)) begin
if (obj.get_type_name() != "" && obj.get_type_name() != "<unknown>")
uvm_report_warning("TPRGED", {"Object type '",obj.get_type_name(),
"' already registered with factory. "}, UVM_NONE);
end
else begin
m_types[obj] = 1;
2.覆盖
分为类型覆盖和实例覆盖,背后都由工厂完成。(以set_type_override_by_type为例)
a:先检查original_type 和 override_type是否相同,参数类type_name为‘’且没有get_type_name函数,所以这里进行了区分。
function void uvm_default_factory::set_type_override_by_type (uvm_object_wrapper original_type,
uvm_object_wrapper override_type,
bit replace=1);
bit replaced;
// check that old and new are not the same
if (original_type == override_type) begin
if (original_type.get_type_name() == "" || original_type.get_type_name() == "<unknown>")
uvm_report_warning("TYPDUP", {"Original and override type ",
"arguments are identical"}, UVM_NONE);
else
uvm_report_warning("TYPDUP", {"Original and override type ",
"arguments are identical: ",
original_type.get_type_name()}, UVM_NONE);
end
// register the types if not already done so, for the benefit of string-based lookup
if (!m_types.exists(original_type))
register(original_type);
if (!m_types.exists(override_type))
register(override_type);
b:看m_type_override中能否找到original_type,若能说明之前已经被替换过,将replaced赋值为1,将覆盖规则进行更新。
// check for existing type override
foreach (m_type_overrides[index]) begin
if (m_type_overrides[index].orig_type == original_type ||
(m_type_overrides[index].orig_type_name != "<unknown>" &&
m_type_overrides[index].orig_type_name != "" &&
m_type_overrides[index].orig_type_name == original_type.get_type_name())) begin
string msg;
msg = {"Original object type '",original_type.get_type_name(),
"' already registered to produce '",
m_type_overrides[index].ovrd_type_name,"'"};
if (!replace) begin
msg = {msg, ". Set 'replace' argument to replace the existing entry."};
uvm_report_info("TPREGD", msg, UVM_MEDIUM);
return;
end
msg = {msg, ". Replacing with override to produce type '",
override_type.get_type_name(),"'."};
uvm_report_info("TPREGR", msg, UVM_MEDIUM);
replaced = 1;
m_type_overrides[index].orig_type = original_type;
m_type_overrides[index].orig_type_name = original_type.get_type_name();
m_type_overrides[index].ovrd_type = override_type;
m_type_overrides[index].ovrd_type_name = override_type.get_type_name();
end
end
c:若replaced=0说明没有找到,该规则为新的,将其push_back到m_type_override。
// make a new entry
if (!replaced) begin
uvm_factory_override override;
override = new(.orig_type(original_type),
.orig_type_name(original_type.get_type_name()),
.full_inst_path("*"),
.ovrd_type(override_type));
m_type_overrides.push_back(override);
end
3.创建
由工厂机制进行创建(以create举例)
a:type_id中有create函数,通过调用factory的create_*_by_type来创建名字为‘name’的对象。
static function T create(string name, uvm_component parent, string contxt="");
uvm_object obj;
uvm_coreservice_t cs = uvm_coreservice_t::get();
uvm_factory factory=cs.get_factory();
if (contxt == "" && parent != null)
contxt = parent.get_full_name();
obj = factory.create_component_by_type(get(),contxt,name,parent);
if (!$cast(create, obj)) begin
string msg;
msg = {"Factory did not return a component of type '",type_name,
"'. A component of type '",obj == null ? "null" : obj.get_type_name(),
"' was returned instead. Name=",name," Parent=",
parent==null?"null":parent.get_type_name()," contxt=",contxt};
uvm_report_fatal("FCTTYP", msg, UVM_NONE);
end
endfunction
b:工厂中先调用find_override_by_type获取覆盖类,在调用覆盖类中的creat_*进行创建。
function uvm_object uvm_default_factory::create_object_by_type (uvm_object_wrapper requested_type,
string parent_inst_path="",
string name="");
string full_inst_path;
if (parent_inst_path == "")
full_inst_path = name;
else if (name != "")
full_inst_path = {parent_inst_path,".",name};
else
full_inst_path = parent_inst_path;
m_override_info.delete();
requested_type = find_override_by_type(requested_type, full_inst_path);
return requested_type.create_object(name);
endfunction
c:在find_override_by_type中,先遍历m_type_override看是否有覆盖规则。
如果有,递归调用find_override_by_type,直到找不到替代规则时返回当前request_type。(递归的原因是覆盖类可能也 会被其他类覆盖,所以递归到最上面一层)
如果没有,说明没有被覆盖,所以直接返回当前request_type。
# 总结
本文介绍了工厂机制管理uvm_*_registry的逻辑。
register是指将registry放入m_type_name中,一个类一个registry,防止多次注册。
override是指将覆盖规则override放入m_factory_override中,用于在create前检查。
create中new操作是在registry中完成,然而在new前需要在工厂内调用find_override_by_type寻找覆盖类,若找到则有覆盖registry创建。