Why does Simulation hang in following code

Hi ,

I am confused as to why in the following code the simulation hangs .



`define COMP_NEW function new ( string name , uvm_component parent ) ; \
                  super.new(name,parent);\
                 endfunction

class trans ; 
   rand bit [2:0] addr ;
endclass

class Producer extends uvm_component ;

 `uvm_component_utils(Producer)
 
 uvm_blocking_put_port #(trans) put_port ;

 `COMP_NEW

  function void build_phase ( uvm_phase phase ) ;
     put_port = new("put_port",this);
  endfunction
  
  task main_phase ( uvm_phase phase ) ;
    trans txn ;
     
	 phase.raise_objection(this);

	 txn = new();
    
	for ( int i = 1 ; i< 3 ; i++ )
	 begin
       txn.randomize();
       put_port.put(txn);
	 end

	 phase.drop_objection(this);

  endtask

endclass

typedef class Consumer ;

class Consumer_child extends Consumer ;

 `uvm_component_utils(Consumer_child) 

 `COMP_NEW

task put ( trans t ) ;

 $display(" %0s Received %0p",get_name(),t);

endtask

endclass

class Consumer extends uvm_component ;

 `uvm_component_utils(Consumer)

  uvm_blocking_put_imp #(trans,Consumer ) put_imp ;
  Consumer_child                          child ;
 
 `COMP_NEW

  function void build_phase ( uvm_phase phase ) ;
     child   = new("child",this);
     put_imp = new("put_imp",child);
  endfunction
  
  task put ( trans t );

  endtask  


endclass

class env extends uvm_component ;

 `uvm_component_utils(env)
 
 `COMP_NEW
  
  Consumer  cons ;
  Producer  prod ;

  function void build_phase ( uvm_phase phase ) ;
     cons   = new("cons",this);
     prod   = new("prod",this);
  endfunction

 function void connect_phase ( uvm_phase phase ) ;

      prod.put_port.connect(cons.put_imp) ;

 endfunction

endclass 


initial begin

  run_test("env") ;

end



In reply to ABD_91:

You have recursive Consumer object construction. Use the factory to create the Consumer_child

class Consumer extends uvm_component ;
`uvm_component_utils(Consumer)
 
  uvm_blocking_put_imp #(trans,Consumer ) put_imp ;

 `COMP_NEW
 
  function void build_phase ( uvm_phase phase ) ;
    put_imp = new("put_imp",this);
  endfunction
 
  virtual task put ( trans t );
  endtask  
endclass
 
class env extends uvm_component ;
 
 `uvm_component_utils(env)
 
 `COMP_NEW
 
  Consumer  cons ;
  Producer  prod ;
 
  function void build_phase ( uvm_phase phase ) ;
     cons   = Consumer::type_id::create("cons",this);
     prod   = new("prod",this);
  endfunction
 
 function void connect_phase ( uvm_phase phase ) ;
    prod.put_port.connect(cons.put_imp) ;
 endfunction 
endclass 
initial begin
  Consumer::type_id::set_type_override(Consumer_child::type_id::get());
  run_test("env") ;
 
end
endmodule

In reply to dave_59:

Hi Dave ,

**Could you elaborate on “you have recursive Consumer object construction” .
**
Via my own abd_pkg [ Useful for Debugging purposes :) ] I see that ::

uvm_test_top.cons.child.put_imp
uvm_test_top.cons.child.child.put_imp
uvm_test_top.cons.child.child.childput_imp

Goes on being created ( Hence the Simulation Hang !! )


The intent behind the code was to see apart from typical 'this' ( in 2nd argument while calling new() of imp-port ) what if I delegate the component implementing the interface ( put() method ) to an extended type ( Consumer_child in my original code ) .

Here’s the code of blocking_put_imp class ::



class uvm_blocking_put_imp #(type T=int, type IMP=int) extends uvm_port_base #(uvm_tlm_if_base #(T,T) ) ;
  local IMP m_imp; 
  function new (string name, IMP imp); 
    super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); 
    m_imp = imp ; 
    m_if_mask = MASK ; 
  endfunction 
 `UVM_BLOCKING_PUT_IMP (m_imp, T, t)
endclass


So what leads to the simulation hanging ? Essentially 2nd arg. does is


m_imp = imp ;

Which is equivalent to assigning a base class handle to extended class object .

In reply to ABD_91:

You’ve extended Consumer_child from Consumer AND you’ve made Consumer_child a child instance of Consumer. I strongly recommend against using the term “child” when referring to inheritance. If you name the class Consumer_extended instead, it would avoid a lot of confusion.

In your orginal example, when exacute

  child   = new("child",this);

You are creating a child uvm_component whose build_phase will get called. Since Component_child has a build_phase that it inherited from Consumer, its build_phase gets called recursively.

Instead of used the factory override as I show, you could instead extend Consumer_child from uvm_component directly and change the declaration of put_imp. But then the put() task would not have access to anything in the Consumer object.

In reply to dave_59:

Thanks Dave ,

The above issue is resolved by adding following in Consumer_child ::



function void build_phase ( uvm_phase phase ) ;
     $display(" This should solve the issue !! "); // Indeed it does !!
endfunction



Also to call put() of Consumer_child ( Consumer_extended rather is a better name as you suggested ) one would have to simply declare put() task in Consumer class as virtual !!