UVM_FATAL :: " Attempting to register a null object with the Factory "

I am trying to understand output of following code ::


`include "uvm_macros.svh"
`include "uvm_pkg.sv"
 
 import uvm_pkg::* ;

  class user_seq_item  extends uvm_sequence_item ;
   
      localparam  string  TYPE_NAME  =  "user_seq_item" ;

     `uvm_object_utils(user_seq_item)

     //  Std  3  line  Constructor

  endclass 
  
  class  my_driver #( type T = user_seq_item )  extends  uvm_driver #( T ) ; 

	typedef   uvm_component_registry  #( my_driver#( T ) , $sformatf("my_driver#(%0s)" , T::TYPE_NAME )  )   type_id  ;

        //  Std  3  line  Constructor 

  task   main_phase(  uvm_phase phase ) ;

  `uvm_info(get_name() , $sformatf(" Within  driver of  Tname : %0s " , type_id::type_name ) , UVM_NONE )  //  'Tname'  of  uvm_component_registry  !!

  `uvm_info(get_name() , $sformatf(" Received request is  of  type_name : %0s " , req.get_type_name() ) , UVM_NONE )


   endtask

  endclass
  
   class  ext_driver #( type T = user_seq_item )  extends  my_driver #( T )  ;

        typedef   uvm_component_registry  #( ext_driver#( T ) , $sformatf("ext_driver#(%0s)" , T::TYPE_NAME )  )   type_id  ;

        //  Std  3  line  Constructor 

        //   main_phase()  Inherited  !!
      
   endclass


 class  env  extends  uvm_env  ;
  
      `uvm_component_utils( env ) 
  
      //  Std  3  line  Constructor

   my_driver #( user_seq_item )       drvr_h  ;

   function  void  build_phase ( uvm_phase phase ) ;
     
          drvr_h  =  my_driver #( user_seq_item ) :: type_id :: create( "drvr_h" , this ) ;

   endfunction
   

 endclass

 class  my_test  extends  uvm_test  ;
  
   `uvm_component_utils( my_test ) 
  
   //  Std  3  line  Constructor

   env  env_h  ;

   function  void  build_phase ( uvm_phase phase ) ;
     
        my_driver #( user_seq_item ) ::type_id :: set_type_override( ext_driver #( user_seq_item ) :: get_type() ) ;

        env_h  =  env  :: type_id  ::  create( "env_h" , this ) ;

   endfunction

 endclass


  module  TOP  ;
  
      initial  
         run_test("my_test") ;
  
  endmodule

The Output I observe ::

UVM_INFO @ 0: reporter [RNTST] Running test my_test…
UVM_ERROR @ 0: reporter [NOTYPID] get_type not implemented in derived class.
UVM_FATAL @ 0: reporter [NULLWR] Attempting to register a null object with the factory

The UVM_ERROR occurs since implementation of static function get_type() isn’t provided .
Hence get_type() function in uvm_object gets called which throws the error .

[Q1] Why do I Observe the Fatal Error ?

[Q2] I simply need to run the main_phase() in driver .
So is it alright if I raise and drop objection in main_phase() of driver ?

[Q3] Any suggestions for an alternative way to provide the actual to ‘Tname’
during specialization of uvm_component_registry ?

In reply to MICRO_91:

(A1): Because your driver is parameterized twice you need an individual get_type function, returning the type of the 1st parameter.
(A2) Instead of running main_phase you should run run_phase. You can implement there the objection mechanism. But it is not he best place. The recommeded implementation is in the test.
(A3) why do you need a 2nd parameter in your driver implementation. What you are doing with it?

See the solution below:

`include "uvm_macros.svh"
`include "uvm_pkg.sv"
 
 import uvm_pkg::* ;
 
  class user_seq_item  extends uvm_sequence_item ;
 
      localparam  string  TYPE_NAME  =  "user_seq_item" ;
 
     `uvm_object_utils(user_seq_item)
 
     //  Std  3  line  Constructor
   function new(string name = "user_seq_item");
     super.new(name);
   endfunction : new
 
  endclass 
 
  class  my_driver #( type T = user_seq_item )  extends  uvm_driver #( T ) ; 
 
	typedef   uvm_component_registry  #( my_driver#( T ) , $sformatf("my_driver#(%0s)" , T::TYPE_NAME )  )   type_id  ;
 
        //  Std  3  line  Constructor 
 
   function new(string name = "my_driver", uvm_component parent = null);
     super.new(name, parent);
   endfunction : new
        task   run_phase(  uvm_phase phase ) ;
 
            `uvm_info(get_name() , $sformatf(" Within  driver of  Tname : %0s " , type_id::type_name ) , UVM_NONE )  //  'Tname'  of  uvm_component_registry  !!
 
            `uvm_info(get_name() , $sformatf(" Received request is  of  type_name : %0p " , req.get_type() ) , UVM_NONE )
 
 
       endtask
 
   endclass
 
   class  ext_driver #( type T = user_seq_item )  extends  my_driver #( T )  ;
 
        typedef   uvm_component_registry  #( ext_driver#( T ) , $sformatf("ext_driver#(%0s)" , T::TYPE_NAME )  )   type_id  ;
 
        //  Std  3  line  Constructor 
 
        //   main_phase()  Inherited  !!
   function new(string name = "ext_driver", uvm_component parent = null);
     super.new(name, parent);
   endfunction : new

   static function type_id get_type();
    return type_id::get();
  endfunction

   endclass
 
 
 class  env  extends  uvm_env  ;
 
      `uvm_component_utils( env ) 
 
   function new(string name = "env", uvm_component parent = null);
     super.new(name, parent);
   endfunction : new
 
   my_driver #( user_seq_item )       drvr_h  ;
 
   function  void  build_phase ( uvm_phase phase ) ;
 
          drvr_h  =  my_driver #( user_seq_item ) :: type_id :: create( "drvr_h" , this ) ;
 
   endfunction
 
 
 endclass
 
 class  my_test  extends  uvm_test  ;
 
   `uvm_component_utils( my_test ) 
 
   function new(string name = "my_test", uvm_component parent = null);
     super.new(name, parent);
   endfunction : new
 
   env  env_h  ;
 
   function  void  build_phase ( uvm_phase phase ) ;
 
        my_driver #( user_seq_item ) ::type_id :: set_type_override( ext_driver #( user_seq_item ) :: get_type() ) ;
 
        env_h  =  env  :: type_id  ::  create( "env_h" , this ) ;
 
   endfunction
 
 endclass
 
 
  module  TOP  ;
 
      initial  
         run_test("my_test") ;
 
  endmodule

In reply to chr_sue:

I finally got the exact reason ::

[1] The Fatal error is from factory::register() function .



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

  .......................

endfunction
     

[2] Since get_type() isn’t implemented in derived class , get_type() in class
uvm_object gets called which throws UVM_ERROR and returns null .



static function uvm_object_wrapper uvm_object::get_type();
  uvm_report_error("NOTYPID", "get_type not implemented in derived class.", UVM_NONE);
  return null;
endfunction

  

[3] Via source code ::



function void uvm_factory::set_type_override_by_type (uvm_object_wrapper original_type,
                                                      uvm_object_wrapper override_type,
                                                      bit replace=1);

//   original type  points  to  singleton  instance  
//  ( local  static  this_type me  within  uvm_component_registry  )  via 
//    my_driver #( user_seq_item )

//   override_type  points  to  null  via  uvm_object::get_type()

    .................

      // register the types if not already done so, for the benefit of string-based lookup

// Condition is  False  since  my_driver #( user_seq_item )  
//  already  registered at TIME:0  in  Type  Based  Factory
  if (!m_types.exists(original_type))   
    register(original_type); 
    
//  Condition  is  True  since  'null'  isn't  registered in  Type Base Factory
  if (!m_types.exists(override_type)) 
    register(override_type);   //  Cause  of  error
    
    ..............
   
    

Regarding [A3] , I observe Issues with Simulators during explicit specialization of
uvm_component_registry .



Eg ::    
localparam  string  TYPE_NAME  =   $sformatf("my_driver#(%0s)" , T::TYPE_NAME ) ; // Issue !!
typedef   uvm_component_registry  #( my_driver#( T ) ,  TYPE_NAME   )   type_id  ;

This doesn’t work across some Simulators ( Possibly Simulator Issue )

The code in original question works across all Simulators I tried .

Hence I was wondering if any alternate approach is possible for specialization of
uvm_component_registry .