One of the main features of UVM is the factory mechanism, and we already know how to use
`uvm_component_utils () and
`uvm_object_utils () within user-defined component and object classes. It's a way of registering our new component with the factory so that we can request the factory to return an object of some other type later on via
type_id::create () method. Let's see what happens behind the scene when the code is elaborated and compiled for the example that follows.
class my_env extends uvm_env; `uvm_component_utils (my_env) ... endclass
`uvm_component_utils () is a UVM macro, and will be substituted with the following code when its compiled.
uvm_component_registry serves as a lightweight proxy for a component of type T and type name Tname. The proxy enables efficient registration with the
uvm_factory, and without it, registration would require an instance of the component itself.
typedef uvm_component_registry #(T, "Tname") type_id; // Note this important re-definition of the type where T = my_env ...
uvm_component_registry has an internal static function to create and return an object of type T.
static function T create (string name, uvm_component parent, string cntxt = ""); // Create a local object of type uvm_object // Get instance of the factory // Use factory method create_component_by_type () endfunction
The static method
create (), will return an object of type T, where T = my_env in our case, and will be assigned to the handle m_top_env.
class my_test extends uvm_test; `uvm_component_utils (uvm_test) my_env m_top_env; virtual function void build_phase (); super.build_phase (phase); m_top_env = my_env :: type_id :: create ("m_top_env", this); endfunction endclass
Note that you'll get an error if you forget to include
`uvm_component_utils () and try to use create( ), because
type_id will then be undefined.