通常情况下我们会使用factory机制如下:(这里我们以object为例,component的原理是类似的)
class my_seq extends uvm_seqeuence_item;
`uvm_object_utils(my_seq)
...
endclass:my_seq
然后我们就可以create:
class my_test extends uvm_test;
...
task main_phase(uvm_phase phase);
my_seq seq0;
seq0 = my_seq::type_id::create("seq0");
endtask:main_phase
endclass:my_test
为什么create就可以直接生成seq0这个object呢? sv中只有new的方式可以生成新的object
其背后的操作如下:
`define uvm_object_utils(T) \
`uvm_object_utils_begin(T) \
`uvm_object_utils_end
===================================================
`define uvm_object_utils_begin(T) \
`m_uvm_object_registry_internal(T,T) \
`m_uvm_object_create_func(T) \
`m_uvm_get_type_name_func(T) \
`uvm_field_utils_begin(T)
===================================================
`define m_uvm_object_registry_internal(T,S) \
typedef uvm_object_registry#(T,`"S`") type_id; \
static function type_id get_type(); \
return type_id::get(); \
endfunction \
virtual function uvm_object_wrapper get_object_type(); \
return type_id::get(); \
endfunction
line1-> lines2->line6->line12,注意line12中的type_id, 其实际上是一个参数类:
uvm_object_registry#(T, `"S`")
那么我们定义的`uvm_object_utils(my_seq),在背后的代码中体现为(这里只说明uvm如何认识我们定义的新的class: my_seq)
type_def uvm_object_regsitery#(my_seq,"my_seq") type_id
同时声明了一个以my_seq作为class 和class-name作为为参数的类成员:type_id
而uvm_object_register这个参数类的定义如下,其中定义了static 函数成员create,get:
class uvm_object_registry #(type T=uvm_object, string Tname="<unknown>")
extends uvm_object_wrapper;
typedef uvm_object_registry #(T,Tname) this_type;
。。。
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
...
static function T create (string name="", uvm_component parent=null,
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_object_by_type(get(),contxt,name);
if (!$cast(create, obj)) begin
string msg;
msg = {"Factory did not return an object 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
注意其中的第23行,
obj = factory.create_object_by_type(get(),contxt,name);(方便引用,记为--1--)
其中,
get()中包含两个操作:
1.1. new me(即为object);
1.2. factory.register(me);
factory的register操作的定义如下:
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;
// If a named override happens before the type is registered, need to copy
// the override queue.
// Note:Registration occurs via static initialization, which occurs ahead of
// procedural (e.g. initial) blocks. There should not be any preexisting overrides.
if(m_inst_override_name_queues.exists(obj.get_type_name())) begin
m_inst_override_queues[obj] = new;
m_inst_override_queues[obj].queue = m_inst_override_name_queues[obj.get_type_name()].queue;
m_inst_override_name_queues.delete(obj.get_type_name());
end
if(m_wildcard_inst_overrides.size()) begin
if(! m_inst_override_queues.exists(obj))
m_inst_override_queues[obj] = new;
foreach (m_wildcard_inst_overrides[i]) begin
if(uvm_is_match( m_wildcard_inst_overrides[i].orig_type_name, obj.get_type_name()))
m_inst_override_queues[obj].queue.push_back(m_wildcard_inst_overrides[i]);
end
end
end
endfunction
注意其中的第12行,会把obj和get_type_name()作为key-value存入关联数组m_type_names中。
而--1--的create_object_by_type的定义如下
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
这里第18行,还是调用create_object,不过这个函数应该是隶属于requested_type的成员,requested_type即为我们所指定的type_id,(即uvm_object_registry),故其最终调用的是
class uvm_object_registry #(type T=uvm_object, string Tname="<unknown>")
extends uvm_object_wrapper;
typedef uvm_object_registry #(T,Tname) this_type;
// Function: create_object
//
// Creates an object of type ~T~ and returns it as a handle to a
// <uvm_object>. This is an override of the method in <uvm_object_wrapper>.
// It is called by the factory after determining the type of object to create.
// You should not call this method directly. Call <create> instead.
virtual function uvm_object create_object(string name="");
T obj;
`ifdef UVM_OBJECT_DO_NOT_NEED_CONSTRUCTOR
obj = new();
if (name!="")
obj.set_name(name);
`else
if (name=="") obj = new();
else obj = new(name);
`endif
return obj;
endfunction
const static string type_name = Tname;
。。。
endclass
其中地15行 最终new 产生了所需要的seq0.
其完整的调用逻辑如下
完毕
此处提出一个疑问, 如上图所示,uvm好像调用了两次new,是否多余了呢?