// //------------------------------------------------------------------------------ // Copyright 2007-2011 Mentor Graphics Corporation // Copyright 2007-2011 Cadence Design Systems, Inc. // Copyright 2010-2011 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. //------------------------------------------------------------------------------ typedef class uvm_object; typedef class uvm_component; typedef class uvm_object_wrapper; typedef class uvm_factory_override; //Instance overrides by requested type lookup class uvm_factory_queue_class; uvm_factory_override queue[$]; endclass //------------------------------------------------------------------------------ // Title: UVM Factory // // This page covers the classes that define the UVM factory facility. //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ // // CLASS: uvm_factory // //------------------------------------------------------------------------------ // // As the name implies, uvm_factory is used to manufacture (create) UVM objects // and components. Only one instance of the factory is present in a given // simulation (termed a singleton). Object and component types are registered // with the factory using lightweight proxies to the actual objects and // components being created. The and // class are used to proxy // and . // // The factory provides both name-based and type-based interfaces. // // 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. // // See section for details on configuring and using the factory. // class uvm_factory; extern protected function new (); // Function: get() // Get the factory singleton // extern static function uvm_factory get(); // Group: Registering Types // Function: register // // Registers the given proxy object, ~obj~, with the factory. The proxy object // is a lightweight substitute for the component or object it represents. 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. // // 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 and . // If the proxy object's get_type_name method returns the empty string, // name-based lookup is effectively disabled. extern function void register (uvm_object_wrapper obj); // Group: Type & Instance Overrides // Function: set_inst_override_by_type extern function void set_inst_override_by_type (uvm_object_wrapper original_type, uvm_object_wrapper override_type, string full_inst_path); // Function: set_inst_override_by_name // // Configures the factory to create an object of the override's type whenever // a request is made to create an object of the original type using a context // that matches ~full_inst_path~. The original type is typically a super class // of the override type. // // When overriding by type, the ~original_type~ and ~override_type~ are // handles to the types' proxy objects. Preregistration is not required. // // When overriding by name, the ~original_type_name~ typically refers to a // preregistered type in the factory. It may, however, be any arbitrary // string. Future calls to any of the create_* methods with the same string // and matching instance path will produce the type represented by // ~override_type_name~, which must be preregistered with the factory. // // The ~full_inst_path~ is matched against the contentation of // {~parent_inst_path~, ".", ~name~} provided in future create requests. The // ~full_inst_path~ may include wildcards (* and ?) such that a single // instance override can be applied in multiple contexts. A ~full_inst_path~ // of "*" is effectively a type override, as it will match all contexts. // // When the factory processes instance overrides, the instance queue is // processed in order of override registrations, and the first override // match prevails. Thus, more specific overrides should be registered // first, followed by more general overrides. extern function void set_inst_override_by_name (string original_type_name, string override_type_name, string full_inst_path); // Function: set_type_override_by_type extern function void set_type_override_by_type (uvm_object_wrapper original_type, uvm_object_wrapper override_type, bit replace=1); // Function: set_type_override_by_name // // Configures the factory to create an object of the override's type whenever // a request is made to create an object of the original type, provided no // instance override applies. The original type is typically a super class of // the override type. // // When overriding by type, the ~original_type~ and ~override_type~ are // handles to the types' proxy objects. Preregistration is not required. // // When overriding by name, the ~original_type_name~ typically refers to a // preregistered type in the factory. It may, however, be any arbitrary // string. Future calls to any of the create_* methods with the same string // and matching instance path will produce the type represented by // ~override_type_name~, which must be preregistered with the factory. // // When ~replace~ is 1, a previous override on ~original_type_name~ is // replaced, otherwise a previous override, if any, remains intact. extern function void set_type_override_by_name (string original_type_name, string override_type_name, bit replace=1); // Group: Creation // Function: create_object_by_type extern function uvm_object create_object_by_type (uvm_object_wrapper requested_type, string parent_inst_path="", string name=""); // Function: create_component_by_type extern function uvm_component create_component_by_type (uvm_object_wrapper requested_type, string parent_inst_path="", string name, uvm_component parent); // Function: create_object_by_name extern function uvm_object create_object_by_name (string requested_type_name, string parent_inst_path="", string name=""); // Function: create_component_by_name // // Creates and returns a component or object of the requested type, which may // be specified by type or by name. A requested component must be derived // from the base class, and a requested object must be derived // from the base class. // // When requesting by type, the ~requested_type~ is a handle to the type's // proxy object. Preregistration is not required. // // When requesting by name, the ~request_type_name~ is a string representing // the requested type, which must have been registered with the factory with // that name prior to the request. If the factory does not recognize the // ~requested_type_name~, an error is produced and a null handle returned. // // If the optional ~parent_inst_path~ is provided, then the concatenation, // {~parent_inst_path~, ".",~name~}, forms an instance path (context) that // is used to search for an instance override. The ~parent_inst_path~ is // typically obtained by calling the on the // parent. // // If no instance override is found, the factory then searches for a type // override. // // Once the final override is found, an instance of that component or object // is returned in place of the requested type. New components will have the // given ~name~ and ~parent~. New objects will have the given ~name~, if // provided. // // Override searches are recursively applied, with instance overrides taking // precedence over type overrides. If ~foo~ overrides ~bar~, and ~xyz~ // overrides ~foo~, then a request for ~bar~ will produce ~xyz~. Recursive // loops will result in an error, in which case the type returned will be // that which formed the loop. Using the previous example, if ~bar~ // overrides ~xyz~, then ~bar~ is returned after the error is issued. extern function uvm_component create_component_by_name (string requested_type_name, string parent_inst_path="", string name, uvm_component parent); // Group: Debug // Function: debug_create_by_type extern function void debug_create_by_type (uvm_object_wrapper requested_type, string parent_inst_path="", string name=""); // Function: debug_create_by_name // // These methods perform the same search algorithm as the create_* methods, // but they do not create new objects. Instead, they provide detailed // information about what type of object it would return, listing each // override that was applied to arrive at the result. Interpretation of the // arguments are exactly as with the create_* methods. extern function void debug_create_by_name (string requested_type_name, string parent_inst_path="", string name=""); // Function: find_override_by_type extern function uvm_object_wrapper find_override_by_type (uvm_object_wrapper requested_type, string full_inst_path); // Function: find_override_by_name // // These methods return the proxy to the object that would be created given // the arguments. The ~full_inst_path~ is typically derived from the parent's // instance path and the leaf name of the object to be created, i.e. // { parent.get_full_name(), ".", name }. extern function uvm_object_wrapper find_override_by_name (string requested_type_name, string full_inst_path); extern function uvm_object_wrapper find_by_name (string type_name); // Function: print // // Prints the state of the uvm_factory, including registered types, instance // overrides, and type overrides. // // When ~all_types~ is 0, only type and instance overrides are displayed. When // ~all_types~ is 1 (default), all registered user-defined types are printed as // well, provided they have names associated with them. When ~all_types~ is 2, // the UVM types (prefixed with uvm_) are included in the list of registered // types. extern function void print (int all_types=1); //---------------------------------------------------------------------------- // PRIVATE MEMBERS extern protected function void m_debug_create (string requested_type_name, uvm_object_wrapper requested_type, string parent_inst_path, string name); extern protected function void m_debug_display(string requested_type_name, uvm_object_wrapper result, string full_inst_path); static local uvm_factory m_inst; protected bit m_types[uvm_object_wrapper]; protected bit m_lookup_strs[string]; protected uvm_object_wrapper m_type_names[string]; protected uvm_factory_override m_type_overrides[$]; protected uvm_factory_queue_class m_inst_override_queues[uvm_object_wrapper]; protected uvm_factory_queue_class m_inst_override_name_queues[string]; protected uvm_factory_override m_wildcard_inst_overrides[$]; local uvm_factory_override m_override_info[$]; local static bit m_debug_pass; extern function bit m_has_wildcard(string nm); extern function bit check_inst_override_exists (uvm_object_wrapper original_type, uvm_object_wrapper override_type, string full_inst_path); endclass //------------------------------------------------------------------------------ // // Group: Usage // // Using the factory involves three basic operations // // 1 - Registering objects and components types with the factory // 2 - Designing components to use the factory to create objects or components // 3 - Configuring the factory with type and instance overrides, both within and // outside components // // We'll briefly cover each of these steps here. More reference information can // be found at , , // , . // // 1 -- Registering objects and component types with the factory: // // When defining and -based classes, simply invoke // the appropriate macro. Use of macros are required to ensure portability // across different vendors' simulators. // // Objects that are not parameterized are declared as // //| class packet extends uvm_object; //| `uvm_object_utils(packet) //| endclass //| //| class packetD extends packet; //| `uvm_object_utils(packetD) //| endclass // // Objects that are parameterized are declared as // //| class packet #(type T=int, int WIDTH=32) extends uvm_object; //| `uvm_object_param_utils(packet #(T,WIDTH)) //| endclass // // Components that are not parameterized are declared as // //| class comp extends uvm_component; //| `uvm_component_utils(comp) //| endclass // // Components that are parameterized are declared as // //| class comp #(type T=int, int WIDTH=32) extends uvm_component; //| `uvm_component_param_utils(comp #(T,WIDTH)) //| endclass // // The `uvm_*_utils macros for simple, non-parameterized classes will register // the type with the factory and define the get_type, get_type_name, and create // virtual methods inherited from . It will also define a static // type_name variable in the class, which will allow you to determine the type // without having to allocate an instance. // // The `uvm_*_param_utils macros for parameterized classes differ from // `uvm_*_utils classes in the following ways: // // - The get_type_name method and static type_name variable are not defined. You // will need to implement these manually. // // - A type name is not associated with the type when registeriing with the // factory, so the factory's *_by_name operations will not work with // parameterized classes. // // - The factory's , , and // methods, which depend on type names to convey information, will list // parameterized types as . // // It is worth noting that environments that exclusively use the type-based // factory methods (*_by_type) do not require type registration. The factory's // type-based methods will register the types involved "on the fly," when first // used. However, registering with the `uvm_*_utils macros enables name-based // factory usage and implements some useful utility functions. // // // 2 -- Designing components that defer creation to the factory: // // Having registered your objects and components with the factory, you can now // make requests for new objects and components via the factory. Using the factory // instead of allocating them directly (via new) allows different objects to be // substituted for the original without modifying the requesting class. The // following code defines a driver class that is parameterized. // //| class driverB #(type T=uvm_object) extends uvm_driver; //| //| // parameterized classes must use the _param_utils version //| `uvm_component_param_utils(driverB #(T)) //| //| // our packet type; this can be overridden via the factory //| T pkt; //| //| // standard component constructor //| function new(string name, uvm_component parent=null); //| super.new(name,parent); //| endfunction //| //| // get_type_name not implemented by macro for parameterized classes //| const static string type_name = {"driverB #(",T::type_name,")"}; //| virtual function string get_type_name(); //| return type_name; //| endfunction //| //| // using the factory allows pkt overrides from outside the class //| virtual function void build_phase(uvm_phase phase); //| pkt = packet::type_id::create("pkt",this); //| endfunction //| //| // print the packet so we can confirm its type when printing //| virtual function void do_print(uvm_printer printer); //| printer.print_object("pkt",pkt); //| endfunction //| //| endclass // // For purposes of illustrating type and instance overrides, we define two // subtypes of the ~driverB~ class. The subtypes are also parameterized, so // we must again provide an implementation for , // which we recommend writing in terms of a static string constant. // //| class driverD1 #(type T=uvm_object) extends driverB #(T); //| //| `uvm_component_param_utils(driverD1 #(T)) //| //| function new(string name, uvm_component parent=null); //| super.new(name,parent); //| endfunction //| //| const static string type_name = {"driverD1 #(",T::type_name,")"}; //| virtual function string get_type_name(); //| ...return type_name; //| endfunction //| //| endclass //| //| class driverD2 #(type T=uvm_object) extends driverB #(T); //| //| `uvm_component_param_utils(driverD2 #(T)) //| //| function new(string name, uvm_component parent=null); //| super.new(name,parent); //| endfunction //| //| const static string type_name = {"driverD2 #(",T::type_name,")"}; //| virtual function string get_type_name(); //| return type_name; //| endfunction //| //| endclass //| //| // typedef some specializations for convenience //| typedef driverB #(packet) B_driver; // the base driver //| typedef driverD1 #(packet) D1_driver; // a derived driver //| typedef driverD2 #(packet) D2_driver; // another derived driver // // Next, we'll define a agent component, which requires a utils macro for // non-parameterized types. Before creating the drivers using the factory, we // override ~driver0~'s packet type to be ~packetD~. // //| class agent extends uvm_agent; //| //| `uvm_component_utils(agent) //| ... //| B_driver driver0; //| B_driver driver1; //| //| function new(string name, uvm_component parent=null); //| super.new(name,parent); //| endfunction //| //| virtual function void build_phase(uvm_phase phase); //| //| // override the packet type for driver0 and below //| packet::type_id::set_inst_override(packetD::get_type(),"driver0.*"); //| //| // create using the factory; actual driver types may be different //| driver0 = B_driver::type_id::create("driver0",this); //| driver1 = B_driver::type_id::create("driver1",this); //| //| endfunction //| //| endclass // // Finally we define an environment class, also not parameterized. Its build // method shows three methods for setting an instance override on a grandchild // component with relative path name, ~agent1.driver1~, all equivalent. // //| class env extends uvm_env; //| //| `uvm_component_utils(env) //| //| agent agent0; //| agent agent1; //| //| function new(string name, uvm_component parent=null); //| super.new(name,parent); //| endfunction //| //| virtual function void build_phase(uvm_phase phase); //| //| // three methods to set an instance override for agent1.driver1 //| // - via component convenience method... //| set_inst_override_by_type("agent1.driver1", //| B_driver::get_type(), //| D2_driver::get_type()); //| //| // - via the component's proxy (same approach as create)... //| B_driver::type_id::set_inst_override(D2_driver::get_type(), //| "agent1.driver1",this); //| //| // - via a direct call to a factory method... //| factory.set_inst_override_by_type(B_driver::get_type(), //| D2_driver::get_type(), //| {get_full_name(),".agent1.driver1"}); //| //| // create agents using the factory; actual agent types may be different //| agent0 = agent::type_id::create("agent0",this); //| agent1 = agent::type_id::create("agent1",this); //| //| endfunction //| //| // at end_of_elaboration, print topology and factory state to verify //| virtual function void end_of_elaboration_phase(uvm_phase phase); //| uvm_top.print_topology(); //| endfunction //| //| virtual task run_phase(uvm_phase phase); //| #100 global_stop_request(); //| endfunction //| //| endclass // // // 3 -- Configuring the factory with type and instance overrides: // // In the previous step, we demonstrated setting instance overrides and creating // components using the factory within component classes. Here, we will // demonstrate setting overrides from outside components, as when initializing // the environment prior to running the test. // //| module top; //| //| env env0; //| //| initial begin //| //| // Being registered first, the following overrides take precedence //| // over any overrides made within env0's construction & build. //| //| // Replace all base drivers with derived drivers... //| B_driver::type_id::set_type_override(D_driver::get_type()); //| //| // ...except for agent0.driver0, whose type remains a base driver. //| // (Both methods below have the equivalent result.) //| //| // - via the component's proxy (preferred) //| B_driver::type_id::set_inst_override(B_driver::get_type(), //| "env0.agent0.driver0"); //| //| // - via a direct call to a factory method //| factory.set_inst_override_by_type(B_driver::get_type(), //| B_driver::get_type(), //| {get_full_name(),"env0.agent0.driver0"}); //| //| // now, create the environment; our factory configuration will //| // govern what topology gets created //| env0 = new("env0"); //| //| // run the test (will execute build phase) //| run_test(); //| //| end //| //| endmodule // // When the above example is run, the resulting topology (displayed via a call to // in env's method) // is similar to the following: // //| # UVM_INFO @ 0 [RNTST] Running test ... //| # UVM_INFO @ 0 [UVMTOP] UVM testbench topology: //| # ---------------------------------------------------------------------- //| # Name Type Size Value //| # ---------------------------------------------------------------------- //| # env0 env - env0@2 //| # agent0 agent - agent0@4 //| # driver0 driverB #(packet) - driver0@8 //| # pkt packet - pkt@21 //| # driver1 driverD #(packet) - driver1@14 //| # pkt packet - pkt@23 //| # agent1 agent - agent1@6 //| # driver0 driverD #(packet) - driver0@24 //| # pkt packet - pkt@37 //| # driver1 driverD2 #(packet) - driver1@30 //| # pkt packet - pkt@39 //| # ---------------------------------------------------------------------- // //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ // // 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 // -based and -based object available in the test // environment, are registered with the . 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., ) 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. ) // 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 or . The factory uses this // name when matching against the requested type in name-based lookups. pure virtual function string get_type_name(); endclass //------------------------------------------------------------------------------ // // CLASS- uvm_factory_override // // Internal class. //------------------------------------------------------------------------------ class uvm_factory_override; string full_inst_path; string orig_type_name; string ovrd_type_name; bit selected; uvm_object_wrapper orig_type; uvm_object_wrapper ovrd_type; function new (string full_inst_path="", string orig_type_name="", uvm_object_wrapper orig_type=null, uvm_object_wrapper ovrd_type); if (ovrd_type == null) begin uvm_report_fatal ("NULLWR", "Attempting to register a null override object with the factory", UVM_NONE); end this.full_inst_path= full_inst_path; this.orig_type_name = orig_type == null ? orig_type_name : orig_type.get_type_name(); this.orig_type = orig_type; this.ovrd_type_name = ovrd_type.get_type_name(); this.ovrd_type = ovrd_type; endfunction endclass //----------------------------------------------------------------------------- // our singleton factory; it is statically initialized //----------------------------------------------------------------------------- const uvm_factory factory = uvm_factory::get(); //----------------------------------------------------------------------------- // IMPLEMENTATION //----------------------------------------------------------------------------- // get // --- function uvm_factory uvm_factory::get(); if (m_inst == null) begin m_inst = new(); end return m_inst; endfunction // new // --- function uvm_factory::new (); endfunction // register // -------- 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() != "") 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() != "") 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 // set_type_override_by_type // ------------------------- function void uvm_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() == "") 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); return; 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); // 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 != "" && 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 // 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 endfunction // set_type_override_by_name // ------------------------- function void uvm_factory::set_type_override_by_name (string original_type_name, string override_type_name, bit replace=1); bit replaced; uvm_object_wrapper original_type; uvm_object_wrapper override_type; if(m_type_names.exists(original_type_name)) original_type = m_type_names[original_type_name]; if(m_type_names.exists(override_type_name)) override_type = m_type_names[override_type_name]; // check that type is registered with the factory if (override_type == null) begin uvm_report_error("TYPNTF", {"Cannot register override for original type '", original_type_name,"' because the override type '", override_type_name, "' is not registered with the factory."}, UVM_NONE); return; end // check that old and new are not the same if (original_type_name == override_type_name) begin uvm_report_warning("TYPDUP", {"Requested and actual type name ", " arguments are identical: ",original_type_name,". Ignoring this override."}, UVM_NONE); return; end foreach (m_type_overrides[index]) begin if (m_type_overrides[index].orig_type_name == original_type_name) begin if (!replace) begin uvm_report_info("TPREGD", {"Original type '",original_type_name, "' already registered to produce '",m_type_overrides[index].ovrd_type_name, "'. Set 'replace' argument to replace the existing entry."}, UVM_MEDIUM); return; end uvm_report_info("TPREGR", {"Original object type '",original_type_name, "' already registered to produce '",m_type_overrides[index].ovrd_type_name, "'. Replacing with override to produce type '",override_type_name,"'."}, UVM_MEDIUM); replaced = 1; m_type_overrides[index].ovrd_type = override_type; m_type_overrides[index].ovrd_type_name = override_type_name; end end if (original_type == null) m_lookup_strs[original_type_name] = 1; if (!replaced) begin uvm_factory_override override; override = new(.orig_type(original_type), .orig_type_name(original_type_name), .full_inst_path("*"), .ovrd_type(override_type)); m_type_overrides.push_back(override); // m_type_names[original_type_name] = override.ovrd_type; end endfunction // check_inst_override_exists // -------------------------- function bit uvm_factory::check_inst_override_exists (uvm_object_wrapper original_type, uvm_object_wrapper override_type, string full_inst_path); uvm_factory_override override; uvm_factory_queue_class qc; if (m_inst_override_queues.exists(original_type)) qc = m_inst_override_queues[original_type]; else return 0; for (int index=0; index max1) max1=qc.queue[i].orig_type_name.len(); if (qc.queue[i].full_inst_path.len() > max2) max2=qc.queue[i].full_inst_path.len(); if (qc.queue[i].ovrd_type_name.len() > max3) max3=qc.queue[i].ovrd_type_name.len(); end end if (max1 < 14) max1 = 14; if (max2 < 13) max2 = 13; if (max3 < 13) max3 = 13; $display("Instance Overrides:\n"); $display(" %0s%0s %0s%0s %0s%0s","Requested Type",space.substr(1,max1-14), "Override Path", space.substr(1,max2-13), "Override Type", space.substr(1,max3-13)); $display(" %0s %0s %0s",dash.substr(1,max1), dash.substr(1,max2), dash.substr(1,max3)); foreach(sorted_override_queues[j]) begin uvm_factory_queue_class qc = sorted_override_queues[j]; for (int i=0; i max1) max1=m_type_overrides[i].orig_type_name.len(); if (m_type_overrides[i].ovrd_type_name.len() > max2) max2=m_type_overrides[i].ovrd_type_name.len(); end if (max1 < 14) max1 = 14; if (max2 < 13) max2 = 13; $display("\nType Overrides:\n"); $display(" %0s%0s %0s%0s","Requested Type",space.substr(1,max1-14), "Override Type", space.substr(1,max2-13)); $display(" %0s %0s",dash.substr(1,max1), dash.substr(1,max2)); foreach (m_type_overrides[index]) $display(" %0s%0s %0s", m_type_overrides[index].orig_type_name, space.substr(1,max1-m_type_overrides[index].orig_type_name.len()), m_type_overrides[index].ovrd_type_name); end end // print all registered types, if all_types >= 1 if (all_types >= 1 && m_type_names.first(key)) begin bit banner; $display("\nAll types registered with the factory: %0d total",m_types.num()); $display("(types without type names will not be printed)\n"); do begin // filter out uvm_ classes (if all_types<2) and non-types (lookup strings) if (!(all_types < 2 && uvm_is_match("uvm_*", m_type_names[key].get_type_name())) && key == m_type_names[key].get_type_name()) begin if (!banner) begin $display(" Type Name"); $display(" ---------"); banner=1; end $display(" ", m_type_names[key].get_type_name()); end end while(m_type_names.next(key)); end $display("(*) Types with no associated type name will be printed as "); $display("\n####\n"); endfunction // debug_create_by_name // -------------------- function void uvm_factory::debug_create_by_name (string requested_type_name, string parent_inst_path="", string name=""); m_debug_create(requested_type_name, null, parent_inst_path, name); endfunction // debug_create_by_type // -------------------- function void uvm_factory::debug_create_by_type (uvm_object_wrapper requested_type, string parent_inst_path="", string name=""); m_debug_create("", requested_type, parent_inst_path, name); endfunction // m_debug_create // -------------- function void uvm_factory::m_debug_create (string requested_type_name, uvm_object_wrapper requested_type, string parent_inst_path, string name); string full_inst_path; uvm_object_wrapper result; 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(); if (requested_type == null) begin if (!m_type_names.exists(requested_type_name) && !m_lookup_strs.exists(requested_type_name)) begin uvm_report_warning("Factory Warning", {"The factory does not recognize '", requested_type_name,"' as a registered type."}, UVM_NONE); return; end m_debug_pass = 1; result = find_override_by_name(requested_type_name,full_inst_path); end else begin m_debug_pass = 1; if (!m_types.exists(requested_type)) register(requested_type); result = find_override_by_type(requested_type,full_inst_path); if (requested_type_name == "") requested_type_name = requested_type.get_type_name(); end m_debug_display(requested_type_name, result, full_inst_path); m_debug_pass = 0; foreach (m_override_info[index]) m_override_info[index].selected = 0; endfunction // m_debug_display // --------------- function void uvm_factory::m_debug_display (string requested_type_name, uvm_object_wrapper result, string full_inst_path); int max1,max2,max3; string dash = "---------------------------------------------------------------------------------------------------"; string space= " "; $display("\n#### Factory Override Information (*)\n"); $write("Given a request for an object of type '",requested_type_name, "' with an instance\npath of '",full_inst_path, "', the factory encountered\n"); if (m_override_info.size() == 0) $display("no relevant overrides.\n"); else begin $display("the following relevant overrides. An 'x' next to a match indicates a", "\nmatch that was ignored.\n"); foreach (m_override_info[i]) begin if (m_override_info[i].orig_type_name.len() > max1) max1=m_override_info[i].orig_type_name.len(); if (m_override_info[i].full_inst_path.len() > max2) max2=m_override_info[i].full_inst_path.len(); if (m_override_info[i].ovrd_type_name.len() > max3) max3=m_override_info[i].ovrd_type_name.len(); end if (max1 < 13) max1 = 13; if (max2 < 13) max2 = 13; if (max3 < 13) max3 = 13; $display(" %0s%0s", "Original Type", space.substr(1,max1-13), " %0s%0s", "Instance Path", space.substr(1,max2-13), " %0s%0s", "Override Type", space.substr(1,max3-13)); $display(" %0s %0s %0s",dash.substr(1,max1), dash.substr(1,max2), dash.substr(1,max3)); foreach (m_override_info[i]) begin $write("%s%0s%0s", m_override_info[i].selected ? " " : "x ", m_override_info[i].orig_type_name, space.substr(1,max1-m_override_info[i].orig_type_name.len())); $write(" %0s%0s", m_override_info[i].full_inst_path, space.substr(1,max2-m_override_info[i].full_inst_path.len())); $write(" %0s%0s", m_override_info[i].ovrd_type_name, space.substr(1,max3-m_override_info[i].ovrd_type_name.len())); if (m_override_info[i].full_inst_path == "*") $display(" "); else $display(); end $display(); end $display("Result:\n"); $display(" The factory will produce an object of type '%0s'", result == null ? requested_type_name : result.get_type_name()); $display("\n(*) Types with no associated type name will be printed as "); $display("\n####\n"); endfunction