factory机制的一大特点就是根据类的名字来创建类的实例。
factory 机制中根据类名来创建类的实例所用到的技术:一是参数化的类,二是静态变量和静态函数。这两者是factory机制实现的根本所在。
UVM 中有两大关键类,uvm_object 和 uvm_component。一个 uvm_object 在定义时一般要调用 uvm_object_utils 宏,而一个 uvm_component 在定义时要调用uvm_component_utils宏。factory所有的操作都通过这两个宏来完成。
factory 机制的核心就是一个联合数组,m_type_names。这个联合数组的索引是string 类型的,其存储的内容是uvm_object_wrapper类型的
通过展开uvm_object_utils宏,我们发现这里面有一个m_uvm_object_registry_internal
407 `define m_uvm_object_registry_internal(T,S)
408 typedef uvm_object_registry#(T,`"S`") type_id; //每个object都有一个属于自己的代理类,这个type_id就是对应object的代理
409 static function type_id get_type(); //uvm_object_registry针对每个object都是一个单态类,也就是一个object,有只有一个代理
410 return type_id::get(); //拿到这个代理的
411 endfunction
412 virtual function uvm_object_wrapper get_object_type();
413 return type_id::get();
414 endfunction
这个宏里面定义一个static的function get_type,我们知道,所有static的function和property在elaborate结束之前存在,所以这里面很巧妙地利用了类的静态成员变量。简单看一下这个type_id::get()执行什么东西:
182 class uvm_object_registry #(type T=uvm_object, string Tname="<unknown>")
183 extends uvm_object_wrapper;
184 typedef uvm_object_registry #(T,Tname) this_type;
…
212 local static this_type me = get();//me在定义的时候就通过get初始化了,。get首先检查 me 是否为 null,如果不为 null,说明 me 已经是非空了,因此直接返回me 的值。如果为 null的话,则创建一个 me的实例,然后通过factory的register 函数注册到factory中。
…
219 static function this_type get();
220 if (me == null) begin
221 uvm_factory f = uvm_factory::get();
222 me = new;
223 f.register(me);
224 end
225 return me;
226 endfunction
…
296 endclass
我们先不管这里面register的具体实现,在这个点做一个总结,之后我们具体分析一下这些类里面的具体实现。
首先,我们定义了一个类(component类或者object类),然后再这个类里面调用uvm_*_utils的宏,在这个宏里面typedef uvm_object_registry#(T,`"S`") type_id;定义了type_id这个变量,每个参数化的类都是不同的类,因此,每一个component类都有与之对应的一个uvm_object_registry类。而这个uvm_object_registry里面有个me的静态成员变量,这个静态成员变量在elaborate结束的时候就被创建出来。在创建这个me的时候调用get()的function,在这个function里面调用factory的register,将对应类的uvm_object_registry类注册到factory里面。
这一部分定义了factory使用的代理组件和代理object类。To avoid the overhead of creating an instance of every component and object that get registered, the factory holds lightweight wrappers, or proxies. When a request for a new object is made, the factory calls upon the proxy to create the object it represents.
采用了singleton模式,每种uvm_object对应一个注册器,该注册器被自动注册到singleton模式的工厂,被注册到工厂后工厂可以识别这种注册器产生的uvm_object对象。
1. uvm_component_registry #(T,Tname) The uvm_component_registry serves as a lightweight proxy for a component of type T and type name Tname, a string.
2. uvm_object_registry #(T,Tname) The uvm_object_registry serves as a lightweight proxy for an uvm_object of type T and type name Tname, a string.
uvm_component_registry #(T,Tname):
Note: Without it, registration would require an instance of the component itself.
主要的方法:
1. virtual function uvm_component create_component ( string name, uvm_component parent )
1. 根据提供的name和parent创建一个T的组件。
2. 这个函数重写了uvm_object_wrapper的方法。
3. 这个方法不会被直接调用,在create中间接调用。
2. virtual function string get_type_name():
3. static function this_type get() //拿到本type的一个单态实例,
Type-based factory 操作依赖于对于每个寄存的type,只有一个代理例化
1. Returns an instance of the component type, T, represented by this proxy, subject to any factory overrides based on the context provided by the parent’s full name. The contxt argument, if supplied, supercedes the parent’s context. The new instance will have the given leaf name and parent.
static function T create(string name, uvm_component parent, string contxt="");
uvm_object obj;
uvm_factory f = uvm_factory::get(); //拿到整个环境中factory
if (contxt == "" && parent != null) //判断contxt
contxt = parent.get_full_name();
obj = f.create_component_by_type(get(),contxt,name,parent); //调用factory中的create_component_by_type(get(),contxt,name,parent);创建T的例化
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 5. static function void set_type_override ( uvm_object_wrapper override_type, bit replace =1);//在factory的m_type_overrides[$]数组中通过一个factory_override类记录把一个wrapper用另外一个wrapper替代
1. factory.set_type_override_by_type(get(),override_type,replace);
6. static function void set_inst_override( uvm_object_wrapper override_type, string inst_path, uvm_component parent = null )//在factory的m_inst_override_queues[uvm_object_wrapper]数组中通过一个uvm_factory_queue_class 的成员factory_override记录把一个wrapper用另外一个wrapper替代
1. 配置factory去创建一个被override_type里面type代表的组件,当有创建对象的请求发生。
2. If parent is not specified, inst_path is interpreted as an absolute instance path, which enables instance overrides to be set from outside component classes. If parent is specified, inst_path is interpreted as being relative to the parent’s hierarchical instance path, i.e. {parent.get_full_name(),”.”,inst_path} is the instance path that is registered with the override. The inst_path may contain wildcards for matching against multiple contexts.
3. factory.set_inst_override_by_type(get(),override_type,inst_path);
uvm_object_registry #(T,Tname):的作用和实现跟uvm_component_registry #(T,Tname)类似
USAGE:
1. The wrapper classes are used to register lightweight proxies of objects and components.
2. class mycomp extends uvm_component; //每个组建类都有一个代理类,名字叫做 type_id,这个type_id对每个组建类都是唯一的,使用这个type_id.create创建一个组件的例化。
typedef uvm_component_registry #(mycomp,"mycomp") type_id;
endclass
UVM Factory:
首先factory是一个单态类,整个仿真环境中只有一个factory。
1. uvm_factory As the name implies, uvm_factory is used to manufacture (create) UVM objects and components.
2. uvm_object_wrapper The uvm_object_wrapper provides an abstract interface for creating object and component proxies.
在factory中注册的是的实际的objects和component的创建的轻量级代理:
1. The uvm_object_registry #(T,Tname) and uvm_component_registry #(T,Tname) class are used to proxy uvm_objects and uvm_components.
2. factory提供 name-based和 type-based 接口
type-based The type-based interface is far less prone to errors in usage. When errors do occur, they are caught at compile-time.
name-based The name-based interface is dominated by string arguments that can be misspelled and provided in the wrong order. Errors in name-based requests might only be caught at the time of the call, if at all. Further, the name-based interface is not portable across simulators when used with parameterized classes.
Register:
function void register ( uvm_object_wrapper obj )
1. 在Factory中Registers那些提供代理的object。proxy object是它所表示的对象的一个轻量级代理,When the factory needs to create an object of a given type, it calls the proxy’s create_object or create_component method to do so.
2. When doing name-based operations, the factory calls the proxy’s get_type_name method to match against the requested_type_name argument in subsequent calls to create_component_by_name and create_object_by_name. If the proxy object’s get_type_name method returns the empty string, name-based lookup is effectively disabled.
3. 这是factory最主要实现的function,完成一个wrapper在factory中的注册,该注册函数将wrapper的名字和inst分别记录在m_types[uvm_object_wrapper]和m_type_names[string]中,注册wrapper的同时,如果在m_inst_override_name_queues中记录了该名字的wrapper则声称一个override记录该override并写入 m_inst_override_queues中,同时在m_inst_override_name_queues中删除对应的override的记录;此外,还要检查_wildcard_inst_overrides查找其中记录的override和注册的wrapper的名字的匹配情况,如果匹配则将对应的override录入m_inst_override_queues队列。
function void uvm_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 //检查object的get_type_name是否为空
if (m_type_names.exists(obj.get_type_name())) //如果在m_type_names中存在这个名字,则报告一个warning
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中用这个名字作为key指向这个对象的句柄
m_type_names[obj.get_type_name()] = obj; //指向某个实例的指针放入 m_type_names中,在放入之前先检查一下m_type_names中是否已经有了这条记录,索引是string类型,其存储的内容是 uvm_object_wrapper 类型的
end
if (m_types.exists(obj)) begin //如果在m_types中存在obj的句柄
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; //在m_types以这个对象句柄为key,并置为1,表示这个obj已经在factory里面注册过
// 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.//后面的代码主要用于override
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
总结一下如上所谓的注册,其实质就是把 uvm_object_registry#(T1,"S1")的 me放入 m_type_names 中,并把"S1"作为索引;把 me 作为 m_types 的索引,其内容为1。
主要的属性:
static local uvm_factory m_inst; //factory是要一个单态类
protected bit m_types[uvm_object_wrapper]; //按类型记录注册的wrapper
protected bit m_lookup_strs[string];
protected uvm_object_wrapper m_type_names[string]; //按类型的名字记录注册的wrapper