//
//------------------------------------------------------------------------------
// 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 <uvm_factory>. Without it, registration would
// require an instance of the component itself.
//
// See <Usage> section below for information on using uvm_component_registry.
//
//------------------------------------------------------------------------------
class [docs]uvm_component_registry #(type T=uvm_component, string Tname="<unknown>")
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 <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_component [docs]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 <uvm_object_wrapper>.
virtual function string [docs]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 [docs]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
// 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, supersedes the
// ~parent~'s context. The new instance will have the given leaf ~name~
// and ~parent~.
static function T [docs]create(string name, uvm_component parent, 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_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 [docs]set_type_override (uvm_object_wrapper override_type,
bit replace=1);
uvm_coreservice_t cs = uvm_coreservice_t::get();
uvm_factory factory=cs.get_factory();
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 [docs]set_inst_override(uvm_object_wrapper override_type,
string inst_path,
uvm_component parent=null);
string full_inst_path;
uvm_coreservice_t cs = uvm_coreservice_t::get();
uvm_factory factory=cs.get_factory();
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 a <uvm_object> of
// type ~T~ and type name ~Tname~, a string. The proxy enables efficient
// registration with the <uvm_factory>. Without it, registration would
// require an instance of the object itself.
//
// See <Usage> section below for information on using uvm_component_registry.
//
//------------------------------------------------------------------------------
class [docs]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 [docs]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;
// Function: get_type_name
//
// Returns the value given by the string parameter, ~Tname~. This method
// overrides the method in <uvm_object_wrapper>.
virtual function string [docs]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 [docs]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
// 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 [docs]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
// 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 [docs]set_type_override (uvm_object_wrapper override_type,
bit replace=1);
uvm_coreservice_t cs = uvm_coreservice_t::get();
uvm_factory factory=cs.get_factory();
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 [docs]set_inst_override(uvm_object_wrapper override_type,
string inst_path,
uvm_component parent=null);
string full_inst_path;
uvm_coreservice_t cs = uvm_coreservice_t::get();
uvm_factory factory=cs.get_factory();
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 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.
`endif // UVM_REGISTRY_SVH