uvm_factory——我们的工厂(二)
上节我们说到uvm_object_registry #(T),uvm_object_reistry 又继承自uvm_object_wrapper,所以首先,让我们先看看它爹是啥样子的:
//------------------------------------------------------------------------------ // // CLASS: uvm_object_wrapper // // The uvm_object_wrapper provides an abstract interface for creating object and // component proxies. Instances of these lightweight proxies, representing every // <uvm_object>-based and <uvm_component>-based object available in the test // environment, are registered with the <uvm_factory>. When the factory is // called upon to create an object or component, it finds and delegates the // request to the appropriate proxy. // //------------------------------------------------------------------------------ virtual class uvm_object_wrapper; // Function: create_object // // Creates a new object with the optional ~name~. // An object proxy (e.g., <uvm_object_registry #(T,Tname)>) implements this // method to create an object of a specific type, T. virtual function uvm_object create_object (string name=""); return null; endfunction // Function: create_component // // Creates a new component, passing to its constructor the given ~name~ and // ~parent~. A component proxy (e.g. <uvm_component_registry #(T,Tname)>) // implements this method to create a component of a specific type, T. virtual function uvm_component create_component (string name, uvm_component parent); return null; endfunction // Function: get_type_name // // Derived classes implement this method to return the type name of the object // created by <create_component> or <create_object>. The factory uses this // name when matching against the requested type in name-based lookups. pure virtual function string get_type_name(); endclass
从代码注释来看,都是虚类,这只是轻量级的代理proxy, 它只负责搭台,具体实现让子类去实现,也就是所在uvm中create class,无非就两种uvm_object 和uvm_componet. 它只有这两个儿子,古人云:儿孙自有儿孙福,莫为儿孙做远忧。所以,具体的实现还是让我们进一步去看uvm_object_registry(uvm_register.svh中).
首先来看用法:
// Group: Usage // // This section describes usage for the uvm_*_registry classes. // // The wrapper classes are used to register lightweight proxies of objects and // components. // // To register a particular component type, you need only typedef a // specialization of its proxy class, which is typically done inside the class. // // For example, to register a UVM component of type ~mycomp~ // //| class mycomp extends uvm_component; //| typedef uvm_component_registry #(mycomp,"mycomp") type_id; //| endclass // // However, because of differences between simulators, it is necessary to use a // macro to ensure vendor interoperability with factory registration. To // register a UVM component of type ~mycomp~ in a vendor-independent way, you // would write instead: // //| class mycomp extends uvm_component; //| `uvm_component_utils(mycomp); //| ... //| endclass // // The <`uvm_component_utils> macro is for non-parameterized classes. In this // example, the typedef underlying the macro specifies the ~Tname~ // parameter as "mycomp", and ~mycomp~'s get_type_name() is defined to return // the same. With ~Tname~ defined, you can use the factory's name-based methods to // set overrides and create objects and components of non-parameterized types. // // For parameterized types, the type name changes with each specialization, so // you cannot specify a ~Tname~ inside a parameterized class and get the behavior // you want; the same type name string would be registered for all // specializations of the class! (The factory would produce warnings for each // specialization beyond the first.) To avoid the warnings and simulator // interoperability issues with parameterized classes, you must register // parameterized classes with a different macro. // // For example, to register a UVM component of type driver #(T), you // would write: // //| class driver #(type T=int) extends uvm_component; //| `uvm_component_param_utils(driver #(T)); //| ... //| endclass // // The <`uvm_component_param_utils> and <`uvm_object_param_utils> macros are used // to register parameterized classes with the factory. Unlike the non-param // versions, these macros do not specify the ~Tname~ parameter in the underlying // uvm_component_registry typedef, and they do not define the get_type_name // method for the user class. Consequently, you will not be able to use the // factory's name-based methods for parameterized classes. // // The primary purpose for adding the factory's type-based methods was to // accommodate registration of parameterized types and eliminate the many sources // of errors associated with string-based factory usage. Thus, use of name-based // lookup in <uvm_factory> is no longer recommended.
uvm_object_register的定义如下:
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;
type::id::create()
// Function: create // // Returns an instance of the object 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, supersedes the // ~parent~'s context. The new instance will have the given leaf ~name~, // if provided. 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
create() 调用factory.create_object_by_type()函数,该函数又调用create_object()
// 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
所以tpye::id::create()本质上就是调用该class的new()函数。