// //------------------------------------------------------------------------------ // Copyright 2007-2010 Mentor Graphics Corporation // Copyright 2007-2010 Cadence Design Systems, Inc. // Copyright 2010 Synopsys, Inc. // All Rights Reserved Worldwide // // Licensed under the Apache License, Version 2.0 (the // "License"); you may not use this file except in // compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in // writing, software distributed under the License is // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See // the License for the specific language governing // permissions and limitations under the License. //------------------------------------------------------------------------------ `ifndef UVM_REGISTRY_SVH `define UVM_REGISTRY_SVH //------------------------------------------------------------------------------ // Title: Factory Component and Object Wrappers // // Topic: Intro // // This section defines the proxy component and object classes used by the // factory. 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. //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ // // CLASS: 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. The proxy enables efficient // registration with the . Without it, registration would // require an instance of the component itself. // // See section below for information on using uvm_component_registry. // //------------------------------------------------------------------------------ class uvm_component_registry #(type T=uvm_component, string Tname="") extends uvm_object_wrapper; typedef uvm_component_registry #(T,Tname) this_type; // Function: create_component // // Creates a component of type T having the provided ~name~ and ~parent~. // This is an override of the method in . It is // called by the factory after determining the type of object to create. // You should not call this method directly. Call instead. virtual function uvm_component create_component (string name, uvm_component parent); T obj; obj = new(name, parent); return obj; endfunction const static string type_name = Tname; // Function: get_type_name // // Returns the value given by the string parameter, ~Tname~. This method // overrides the method in . virtual function string get_type_name(); return type_name; endfunction local static this_type me = get(); // Function: get // // Returns the singleton instance of this type. Type-based factory operation // depends on there being a single proxy instance for each registered type. static function this_type get(); if (me == null) begin uvm_factory f = uvm_factory::get(); me = new; f.register(me); end return me; endfunction // Function: create // // 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(); if (contxt == "" && parent != null) contxt = parent.get_full_name(); obj = f.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 // Function: set_type_override // // Configures the factory to create an object of the type represented by // ~override_type~ whenever a request is made to create an object of the type, // ~T~, represented by this proxy, provided no instance override applies. The // original type, ~T~, is typically a super class of the override type. static function void set_type_override (uvm_object_wrapper override_type, bit replace=1); factory.set_type_override_by_type(get(),override_type,replace); endfunction // Function: set_inst_override // // Configures the factory to create a component of the type represented by // ~override_type~ whenever a request is made to create an object of the type, // ~T~, represented by this proxy, with matching instance paths. The original // type, ~T~, is typically a super class of the override type. // // 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. static function void set_inst_override(uvm_object_wrapper override_type, string inst_path, uvm_component parent=null); string full_inst_path; if (parent != null) begin if (inst_path == "") inst_path = parent.get_full_name(); else inst_path = {parent.get_full_name(),".",inst_path}; end factory.set_inst_override_by_type(get(),override_type,inst_path); endfunction endclass //------------------------------------------------------------------------------ // // CLASS: uvm_object_registry #(T,Tname) // // The uvm_object_registry serves as a lightweight proxy for an of // type ~T~ and type name ~Tname~, a string. The proxy enables efficient // registration with the . Without it, registration would // require an instance of the object itself. // // See section below for information on using uvm_component_registry. // //------------------------------------------------------------------------------ class uvm_object_registry #(type T=uvm_object, string Tname="") 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 an // . This is an override of the method in . // It is called by the factory after determining the type of object to create. // You should not call this method directly. Call instead. virtual function uvm_object create_object(string name=""); T obj; `ifdef UVM_OBJECT_MUST_HAVE_CONSTRUCTOR if (name=="") obj = new(); else obj = new(name); `else obj = new(); if (name!="") obj.set_name(name); `endif return obj; endfunction const static string type_name = Tname; // Function: get_type_name // // Returns the value given by the string parameter, ~Tname~. This method // overrides the method in . virtual function string get_type_name(); return type_name; endfunction local static this_type me = get(); // Function: get // // Returns the singleton instance of this type. Type-based factory operation // depends on there being a single proxy instance for each registered type. static function this_type get(); if (me == null) begin uvm_factory f = uvm_factory::get(); me = new; f.register(me); end return me; endfunction // 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, supercedes 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_factory f = uvm_factory::get(); if (contxt == "" && parent != null) contxt = parent.get_full_name(); obj = f.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 // Function: set_type_override // // Configures the factory to create an object of the type represented by // ~override_type~ whenever a request is made to create an object of the type // represented by this proxy, provided no instance override applies. The // original type, ~T~, is typically a super class of the override type. static function void set_type_override (uvm_object_wrapper override_type, bit replace=1); factory.set_type_override_by_type(get(),override_type,replace); endfunction // Function: set_inst_override // // Configures the factory to create an object of the type represented by // ~override_type~ whenever a request is made to create an object of the type // represented by this proxy, with matching instance paths. The original // type, ~T~, is typically a super class of the override type. // // 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. static function void set_inst_override(uvm_object_wrapper override_type, string inst_path, uvm_component parent=null); string full_inst_path; if (parent != null) begin if (inst_path == "") inst_path = parent.get_full_name(); else inst_path = {parent.get_full_name(),".",inst_path}; end factory.set_inst_override_by_type(get(),override_type,inst_path); endfunction endclass // 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 an 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 an 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 can not 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 an 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 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 is no longer recommended. `endif // UVM_REGISTRY_SVH