int
sc_mutex::trylock()
{
    if ( m_owner == sc_get_current_process_b()) return 0;
    if( in_use() ) {
	return -1;
    }
    m_owner = sc_get_current_process_b();
    return 0;
}
int
sc_mutex::lock()
{
    if ( m_owner == sc_get_current_process_b()) return 0;
    while( in_use() ) {
	sc_core::wait( m_free, sc_get_curr_simcontext() );
    }
    m_owner = sc_get_current_process_b();
    return 0;
}
//------------------------------------------------------------------------------
//"sc_method_process::throw_reset"
//
// This virtual method is invoked to "throw" a reset. 
//
// If the reset is synchronous this is a no-op, except for triggering the
// reset event if it is present.
//
// If the reset is asynchronous we:
//   (a) cancel any dynamic waits 
//   (b) if it is the active process actually throw a reset exception.
//   (c) if it was not the active process and does not have a static
//       sensitivity emit an error if corner cases are to be considered
//       errors.
//
// Notes:
//   (1) If the process had a reset event it will have been triggered in 
//       sc_process_b::semantics()
//
// Arguments:
//   async = true if this is an asynchronous reset.
//------------------------------------------------------------------------------
void sc_method_process::throw_reset( bool async )
{
    // IF THE PROCESS IS CURRENTLY UNWINDING OR IS ALREADY A ZOMBIE
    // IGNORE THE RESET:

    if ( m_unwinding )
    {
        SC_REPORT_WARNING( SC_ID_PROCESS_ALREADY_UNWINDING_, name() );
        return;
    }

    if ( m_state & ps_bit_zombie )
        return;

    // Set the throw status and if its an asynchronous reset throw an
    // exception:

    m_throw_status = async ? THROW_ASYNC_RESET : THROW_SYNC_RESET;
    if ( async )
    {
        remove_dynamic_events();
	if ( sc_get_current_process_b() == this )
	{
	    DEBUG_MSG(DEBUG_NAME,this,"throw_reset: throwing exception");
	    m_throw_status = THROW_ASYNC_RESET;
	    throw sc_unwind_exception( this, true );
	}
	else 
	{
	    DEBUG_MSG(DEBUG_NAME,this,
	              "throw_reset: queueing this method for execution");
	    simcontext()->preempt_with(this);
	}
    }
}
void sc_report_handler::default_handler(const sc_report& rep,
					const sc_actions& actions)
{
    if ( actions & SC_DISPLAY )
	::std::cout << ::std::endl << sc_report_compose_message(rep) << 
		::std::endl;

    if ( (actions & SC_LOG) && get_log_file_name() )
    {
	if ( !log_stream )
	    log_stream = new ::std::ofstream(get_log_file_name()); // ios::trunc

	*log_stream << rep.get_time() << ": "
	    << sc_report_compose_message(rep) << ::std::endl;
    }
    if ( actions & SC_STOP )
    {
	sc_stop_here(rep.get_msg_type(), rep.get_severity());
	sc_stop();
    }
    if ( actions & SC_INTERRUPT )
	sc_interrupt_here(rep.get_msg_type(), rep.get_severity());

    if ( actions & SC_ABORT )
	abort();

    if ( actions & SC_THROW ) {
        sc_process_b* proc_p = sc_get_current_process_b();
        if( proc_p && proc_p->is_unwinding() )
            proc_p->clear_unwinding();
        throw rep; 
    }
}
Beispiel #5
0
sc_process_handle
sc_get_current_process_handle()
{
    return ( sc_is_running() ) ?
           sc_process_handle(sc_get_current_process_b()) :
           sc_get_last_created_process_handle();
}
Beispiel #6
0
sc_report* sc_report_handler::get_cached_report()
{
    sc_process_b * proc = sc_get_current_process_b();

    if ( proc )
        return proc->get_last_report();

    return last_global_report;
}
int
sc_mutex::unlock()
{
    if( m_owner != sc_get_current_process_b() ) {
	return -1;
    }
    m_owner = 0;
    m_free.notify();
    return 0;
}
//------------------------------------------------------------------------------
//"sc_method_process::kill_process"
//
// This method removes throws a kill for this object instance. It calls the
// sc_process_b::kill_process() method to perform low level clean up. 
//------------------------------------------------------------------------------
void sc_method_process::kill_process(sc_descendant_inclusion_info descendants)
{

    // IF THE SIMULATION HAS NOT BEEN INITIALIZED YET THAT IS AN ERROR:

    if ( sc_get_status() == SC_ELABORATION )
    {
        report_error( SC_ID_KILL_PROCESS_WHILE_UNITIALIZED_ );
    }

    // IF NEEDED, PROPOGATE THE KILL REQUEST THROUGH OUR DESCENDANTS:

    if ( descendants == SC_INCLUDE_DESCENDANTS )
    {
        const std::vector<sc_object*> children = get_child_objects();
        int                           child_n  = children.size();

        for ( int child_i = 0; child_i < child_n; child_i++ )
        {
            sc_process_b* child_p = DCAST<sc_process_b*>(children[child_i]);
            if ( child_p ) child_p->kill_process(descendants);
        }
    }

    // IF THE PROCESS IS CURRENTLY UNWINDING OR IS ALREADY A ZOMBIE
    // IGNORE THE KILL:

    if ( m_unwinding )
    {
        SC_REPORT_WARNING( SC_ID_PROCESS_ALREADY_UNWINDING_, name() );
        return;
    }

    if ( m_state & ps_bit_zombie )
        return;


    // REMOVE OUR PROCESS FROM EVENTS, ETC., AND IF ITS THE ACTIVE PROCESS
    // THROW ITS KILL. 
    // 
    // Note we set the throw status to kill regardless if we throw or not.
    // That lets check_for_throws stumble across it if we were in the call
    // chain when the kill call occurred.

    if ( next_runnable() != 0 )
        simcontext()->remove_runnable_method( this );
    disconnect_process();

    m_throw_status = THROW_KILL; 
    if ( sc_get_current_process_b() == this )
    {
        throw sc_unwind_exception( this, false );
    }
}
void sc_report_handler::cache_report(const sc_report& rep)
{
    sc_process_b * proc = sc_get_current_process_b();
    if ( proc )
	proc->set_last_report(new sc_report(rep));
    else
    {
	delete last_global_report;
	last_global_report = new sc_report(rep);
    }
}
void sc_report_handler::clear_cached_report()
{
    sc_process_b * proc = sc_get_current_process_b();

    if ( proc )
	proc->set_last_report(0);
    else
    {
	delete last_global_report;
	last_global_report = 0;
    }
}
//------------------------------------------------------------------------------
//"sc_method_process::suspend_process"
//
// This virtual method suspends this process and its children if requested to.
//     descendants = indicator of whether this process' children should also
//                   be suspended
//------------------------------------------------------------------------------
void sc_method_process::suspend_process(
    sc_descendant_inclusion_info descendants )
{     

    // IF NEEDED PROPOGATE THE SUSPEND REQUEST THROUGH OUR DESCENDANTS:

    if ( descendants == SC_INCLUDE_DESCENDANTS )
    {
        const std::vector<sc_object*>& children = get_child_objects();
        int                            child_n  = children.size();

        for ( int child_i = 0; child_i < child_n; child_i++ )
        {
            sc_process_b* child_p = DCAST<sc_process_b*>(children[child_i]);
            if ( child_p ) child_p->suspend_process(descendants);
        }
    }

    // CORNER CASE CHECKS, THE FOLLOWING ARE ERRORS:
    //   (a) if this method has a reset_signal_is specification 
    //   (b) if this method is in synchronous reset

    if ( !sc_allow_process_control_corners && m_has_reset_signal )
    {
	report_error(SC_ID_PROCESS_CONTROL_CORNER_CASE_,
		     "attempt to suspend a method that has a reset signal");
    }
    else if ( !sc_allow_process_control_corners && m_sticky_reset )
    {
	report_error(SC_ID_PROCESS_CONTROL_CORNER_CASE_,
		     "attempt to suspend a method in synchronous reset");
    }

    // SUSPEND OUR OBJECT INSTANCE:
    //
    // (1) If we are on the runnable queue then set suspended and ready_to_run,
    //     and remove ourselves from the run queue.
    // (2) If this is a self-suspension then a resume should cause immediate
    //     scheduling of the process.

    m_state = m_state | ps_bit_suspended;
    if ( next_runnable() != 0 ) 
    {
	m_state = m_state | ps_bit_ready_to_run;
	simcontext()->remove_runnable_method( this );
    }
    if ( sc_get_current_process_b() == DCAST<sc_process_b*>(this)  )
    {
	m_state = m_state | ps_bit_ready_to_run;
    }
}
//------------------------------------------------------------------------------
//"sc_method_process::throw_user"
//
// This virtual method is invoked when a user exception is to be thrown.
// If requested it will also throw the exception to the children of this 
// object instance. Since this is a method no throw will occur for this
// object instance. The children will be awakened from youngest child to
// eldest.
//     helper_p    -> object to use to throw the exception.
//     descendants =  indicator of whether this process' children should also
//                    be suspended
//------------------------------------------------------------------------------
void sc_method_process::throw_user( const sc_throw_it_helper& helper,
    sc_descendant_inclusion_info descendants )
{     

    // IF THE SIMULATION IS NOT ACTUALLY RUNNING THIS IS AN ERROR:

    if (  sc_get_status() != SC_RUNNING )
    {
        report_error( SC_ID_THROW_IT_WHILE_NOT_RUNNING_ );
    }

    // IF NEEDED PROPOGATE THE THROW REQUEST THROUGH OUR DESCENDANTS:

    if ( descendants == SC_INCLUDE_DESCENDANTS )
    {
        const std::vector<sc_object*> children = get_child_objects();
        int                           child_n  = children.size();

        for ( int child_i = 0; child_i < child_n; child_i++ )
        {
            sc_process_b* child_p = DCAST<sc_process_b*>(children[child_i]);
            if ( child_p ) 
	    {
	        DEBUG_MSG(DEBUG_NAME,child_p,"about to throw user on");
	        child_p->throw_user(helper, descendants);
	    }
        }
    }

#if 0 // shouldn't we throw, if we're currently running?

    if ( sc_get_current_process_b() == (sc_process_b*)this )
    {
        remove_dynamic_events();
        m_throw_status = THROW_USER;
        if ( m_throw_helper_p != 0 ) delete m_throw_helper_p;
        m_throw_helper_p = helper.clone();
        m_throw_helper_p->throw_it();
    }

    // throw_it HAS NO EFFECT ON A METHOD, ISSUE A WARNING:

    else

#endif
   {
        SC_REPORT_WARNING( SC_ID_THROW_IT_IGNORED_, name() );
   }


}
//------------------------------------------------------------------------------
//"sc_method_process::resume_process"
//
// This method resumes the execution of this process, and if requested, its
// descendants. If the process was suspended and has a resumption pending it 
// will be dispatched in the next delta cycle. Otherwise the state will be
// adjusted to indicate it is no longer suspended, but no immediate execution
// will occur.
//------------------------------------------------------------------------------
void sc_method_process::resume_process(
    sc_descendant_inclusion_info descendants )
{

    // IF NEEDED PROPOGATE THE RESUME REQUEST THROUGH OUR DESCENDANTS:

    if ( descendants == SC_INCLUDE_DESCENDANTS )
    {
        const std::vector<sc_object*>& children = get_child_objects();
        int                            child_n  = children.size();

        for ( int child_i = 0; child_i < child_n; child_i++ )
        {
            sc_process_b* child_p = DCAST<sc_process_b*>(children[child_i]);
            if ( child_p ) child_p->resume_process(descendants);
        }
    }


    // BY DEFAULT THE CORNER CASE IS AN ERROR:

    if ( !sc_allow_process_control_corners && (m_state & ps_bit_disabled) &&
         (m_state & ps_bit_suspended) )
    {
	m_state = m_state & ~ps_bit_suspended;
        report_error( SC_ID_PROCESS_CONTROL_CORNER_CASE_, 
	              "call to resume() on a disabled suspended method");
    }

    // CLEAR THE SUSPENDED BIT:

    m_state = m_state & ~ps_bit_suspended;

    // RESUME OBJECT INSTANCE:
    //
    // If this is not a self-resume and the method is ready to run then
    // put it on the runnable queue.

    if ( m_state & ps_bit_ready_to_run )
    {
	m_state = m_state & ~ps_bit_ready_to_run;
	if ( next_runnable() == 0 && 
	   ( sc_get_current_process_b() != DCAST<sc_process_b*>(this) ) )
        {
	    simcontext()->push_runnable_method(this);
	    remove_dynamic_events();  
	}
    }
}
Beispiel #14
0
sc_report::sc_report(sc_severity severity_,
                     const sc_msg_def* md_,
                     const char* msg_,
                     const char* file_,
                     int line_)
        : severity(severity_),
        md(md_),
        msg(empty_dup(msg_)),
        file(empty_dup(file_)),
        line(line_),
        timestamp(new sc_time(sc_time_stamp())),
        process(sc_get_current_process_b()),
        m_what(strdup(sc_report_compose_message(*this).c_str()))
{
}
const char*
sc_gen_unique_name( const char* basename_, bool preserve_first )
{
    sc_simcontext* simc = sc_get_curr_simcontext();
    sc_module* curr_module = simc->hierarchy_curr();
    if( curr_module != 0 ) {
	return curr_module->gen_unique_name( basename_, preserve_first );
    } else {
        sc_process_b* curr_proc_p = sc_get_current_process_b();
	if ( curr_proc_p )
	{
	    return curr_proc_p->gen_unique_name( basename_, preserve_first );
	}
	else
	{
	    return simc->gen_unique_name( basename_, preserve_first );
	}
    }
}
//------------------------------------------------------------------------------
//"sc_process_b::delete_process"
//
// This method deletes the current instance, if it is not the running
// process. Otherwise, it is put in the simcontext's process deletion
// queue.
//
// The reason for the two step deletion process is that the process from which
// reference_decrement() is called may be the running process, so we may need
// to wait until it goes idle.
//------------------------------------------------------------------------------
void sc_process_b::delete_process()
{
    assert( m_references_n == 0 );

    // Immediate deletion:

    if ( this != sc_get_current_process_b() )
    {
        delete this;
    }

    // Deferred deletion: note we set the reference count to one  for the call
    // to reference_decrement that occurs in sc_simcontext::crunch().

    else
    {
        m_references_n = 1;
        detach();
        simcontext()->mark_to_collect_process( this );
    }
}
bool
sc_vector_base::check_init( size_type n ) const
{
  if ( !n )
    return false;

  if( size() ) // already filled
  {
    std::stringstream str;
    str << name()
        << ", size=" << size()
        << ", requested size=" << n;
    SC_REPORT_ERROR( SC_ID_VECTOR_INIT_CALLED_TWICE_
                   , str.str().c_str() );
    return false;
  }

  sc_simcontext* simc = simcontext();
  sc_assert( simc == sc_get_curr_simcontext() );

  sc_object* parent_p = simc->get_object_manager()->hierarchy_curr();
  if ( !parent_p )
        parent_p = static_cast<sc_object*>( sc_get_current_process_b() );

  if( parent_p != get_parent_object() )
  {
    std::stringstream str;
    str << name() << ": expected "
        << ( get_parent_object()
              ? get_parent_object()->name() : "<top-level>" )
        << ", got "
        << ( parent_p ? parent_p->name() : "<top-level>" );

    SC_REPORT_ERROR( SC_ID_VECTOR_INIT_INVALID_CONTEXT_
                   , str.str().c_str() );
    return false;
  }

  return true;
}
Beispiel #18
0
//------------------------------------------------------------------------------
//"sc_thread_process::kill_process"
//
// This method removes this object instance from use. It calls the
// sc_process_b::kill_process() method to perform low level clean up. Then
// it aborts this process if it is the active process.
//------------------------------------------------------------------------------
void sc_thread_process::kill_process()
{
    // SIGNAL ANY MONITORS WAITING FOR THIS THREAD TO EXIT:

    int mon_n = m_monitor_q.size();
    if ( mon_n )
    {
        for ( int mon_i = 0; mon_i < mon_n; mon_i++ )
            m_monitor_q[mon_i]->signal( this, sc_process_monitor::spm_exit);
    }

    // CLEAN UP THE LOW LEVEL STUFF ASSOCIATED WITH THIS DATA STRUCTURE:

    sc_process_b::kill_process();


    // IF THIS IS THE ACTIVE PROCESS THEN ABORT IT AND SWITCH TO A NEW ONE:
    //
    // Note we do not use an sc_process_handle, by making a call to
    // sc_get_current_process_handle(), since we don't want to increment the
    // usage count in case it is already zero. (We are being deleted, and this
    // call to kill_process() may have been the result of the usage count going
    // to zero.) So we get a raw sc_process_b pointer instead.

    sc_process_b* active_p = sc_get_current_process_b();
    sc_simcontext*    simc_p = simcontext();
    if ( active_p == (sc_process_b*)this )
    {
        simc_p->cor_pkg()->abort( simc_p->next_cor() );
    }

    // IF THIS WAS NOT THE ACTIVE PROCESS REMOVE IT FROM ANY RUN QUEUES:

    else
    {
        simc_p->remove_runnable_thread( this );
    }
}
//------------------------------------------------------------------------------
//"sc_method_process::trigger_dynamic"
//
// This method sets up a dynamic trigger on an event.
//
// Notes:
//   (1) This method is identical to sc_thread_process::trigger_dynamic(), 
//       but they cannot be combined as sc_process_b::trigger_dynamic() 
//       because the signatures things like sc_event::remove_dynamic()
//       have different overloads for sc_method_process* and sc_thread_process*.
//       So if you change code here you'll also need to change it in 
//       sc_thread_process.cpp.
//
// Result is true if this process should be removed from the event's list,
// false if not.
//
// If the triggering process is the same process, the trigger is
// ignored as well, unless SC_ENABLE_IMMEDIATE_SELF_NOTIFICATIONS
// is defined.
//------------------------------------------------------------------------------
bool sc_method_process::trigger_dynamic( sc_event* e )
{
    // No time outs yet, and keep gcc happy.

    m_timed_out = false;

    // Escape cases:
    //   (a) If this method issued the notify() don't schedule it for
    //       execution, but leave the sensitivity in place.
    //   (b) If this method is already runnable can't trigger an event.

#if ! defined( SC_ENABLE_IMMEDIATE_SELF_NOTIFICATIONS )
    if( SC_UNLIKELY_( sc_get_current_process_b() == this ) )
    {
        report_immediate_self_notification();
        return false;
    }
#endif // SC_ENABLE_IMMEDIATE_SELF_NOTIFICATIONS

    if( is_runnable() ) 
        return true;

    // If a process is disabled then we ignore any events, leaving them enabled:
    //
    // But if this is a time out event we need to remove both it and the
    // event that was being waited for.

    if ( m_state & ps_bit_disabled )
    {
        if ( e == m_timeout_event_p )
	{
	    remove_dynamic_events( true );  
	    return true;
	}
	else
	{
	    return false;
	}
    }


    // Process based on the event type and current process state:
    //
    // Every case needs to set 'rc' and continue on to the end of
    // this method to allow suspend processing to work correctly.

    switch( m_trigger_type ) 
    {
      case EVENT: 
	m_event_p = 0;
	m_trigger_type = STATIC;
	break;

      case AND_LIST:
        -- m_event_count;
	if ( m_event_count == 0 )
	{
	    m_event_list_p->auto_delete();
	    m_event_list_p = 0;
	    m_trigger_type = STATIC;
	}
	else
	{
	    return true;
	}
	break;

      case OR_LIST:
	m_event_list_p->remove_dynamic( this, e );
	m_event_list_p->auto_delete();
	m_event_list_p = 0;
	m_trigger_type = STATIC;
	break;

      case TIMEOUT: 
	m_trigger_type = STATIC;
	break;

      case EVENT_TIMEOUT: 
        if ( e == m_timeout_event_p )
	{
	    m_timed_out = true;
	    m_event_p->remove_dynamic( this );
	    m_event_p = 0;
	    m_trigger_type = STATIC;
	}
	else
	{
	    m_timeout_event_p->cancel();
	    m_timeout_event_p->reset();
	    m_event_p = 0;
	    m_trigger_type = STATIC;
	}
	break;

      case OR_LIST_TIMEOUT:
        if ( e == m_timeout_event_p )
	{
            m_timed_out = true;
            m_event_list_p->remove_dynamic( this, e ); 
            m_event_list_p->auto_delete();
            m_event_list_p = 0; 
            m_trigger_type = STATIC;
	}

	else
	{
            m_timeout_event_p->cancel();
            m_timeout_event_p->reset();
	    m_event_list_p->remove_dynamic( this, e ); 
	    m_event_list_p->auto_delete();
	    m_event_list_p = 0; 
	    m_trigger_type = STATIC;
	}
	break;
      
      case AND_LIST_TIMEOUT:
        if ( e == m_timeout_event_p )
	{
            m_timed_out = true;
            m_event_list_p->remove_dynamic( this, e ); 
            m_event_list_p->auto_delete();
            m_event_list_p = 0; 
            m_trigger_type = STATIC;
	}

	else
	{
	    -- m_event_count;
	    if ( m_event_count == 0 )
	    {
		m_timeout_event_p->cancel();
		m_timeout_event_p->reset();
		// no need to remove_dynamic
		m_event_list_p->auto_delete();
		m_event_list_p = 0; 
		m_trigger_type = STATIC;
	    }
	    else
	    {
	        return true;
	    }
	}
	break;

      case STATIC: {
        // we should never get here, but throw_it() can make it happen.
	SC_REPORT_WARNING(SC_ID_NOT_EXPECTING_DYNAMIC_EVENT_NOTIFY_, name());
        return true;
      }
    }

    // If we get here then the method has satisfied its next_trigger, if its 
    // suspended mark its state as ready to run. If its not suspended then push
    // it onto the runnable queue.

    if ( (m_state & ps_bit_suspended) )
    {
	m_state = m_state | ps_bit_ready_to_run;
    }
    else
    {
        simcontext()->push_runnable_method(this);
    }

    return true;
}
void 
sc_object::sc_object_init(const char* nm) 
{ 
    bool        clash;                  // True if path name exists in obj table
    const char* leafname_p;             // Leaf name (this object) 
    char        pathname[BUFSIZ];       // Path name 
    char        pathname_orig[BUFSIZ];  // Original path name which may clash 
    const char* parentname_p;           // Parent path name 
    bool        put_in_table;           // True if should put in object table 
 
    // SET UP POINTERS TO OBJECT MANAGER, PARENT, AND SIMULATION CONTEXT: 
	//
    // Make the current simcontext the simcontext for this object 

    m_simc = sc_get_curr_simcontext(); 
    m_attr_cltn_p = 0; 
    sc_object_manager* object_manager = m_simc->get_object_manager(); 
    sc_object*         parent_p = object_manager->hierarchy_curr(); 
    if (!parent_p) { 
        sc_object* proc = (sc_object*)sc_get_current_process_b();
        parent_p = proc; 
    } 
    m_parent = parent_p; 


    // CONSTRUCT PATHNAME TO OBJECT BEING CREATED: 
    // 
    // If there is not a leaf name generate one. 

    parentname_p = parent_p ? parent_p->name() : ""; 
    if (nm && nm[0] ) 
    { 
        leafname_p = nm; 
        put_in_table = true; 
    } 
    else 
    { 
        leafname_p = sc_object_newname(pathname_orig); 
        put_in_table = false; 
    } 
    if (parent_p) { 
        std::sprintf(pathname, "%s%c%s", parentname_p, 
                SC_HIERARCHY_CHAR, leafname_p 
        ); 
    } else { 
        strcpy(pathname, leafname_p); 
    } 

    // SAVE the original path name 
    // 
    strcpy(pathname_orig, pathname); 

    // MAKE SURE THE OBJECT NAME IS UNIQUE 
    // 
    // If not use unique name generator to make it unique. 

    clash = false; 
    while (object_manager->find_object(pathname)) { 
        clash = true; 
        leafname_p = sc_gen_unique_name(leafname_p); 
        if (parent_p) { 
            std::sprintf(pathname, "%s%c%s", parentname_p, 
                    SC_HIERARCHY_CHAR, leafname_p 
            ); 
        } else { 
            strcpy(pathname, leafname_p); 
        } 
    } 
    if (clash) { 
	std::string message = pathname_orig;
	message += ". Latter declaration will be renamed to ";
	message += pathname;
        SC_REPORT_WARNING( SC_ID_OBJECT_EXISTS_, message.c_str());
    } 


    // MOVE OBJECT NAME TO PERMANENT STORAGE 
    // 
    // Note here we pull a little trick -- use the first byte to store 
    // information about whether to put the object in the object table in the 
    // object manager 

    char* ptr = new char[strlen( pathname ) + 2]; 
    ptr[0] = put_in_table; 
    m_name = ptr + 1; 
    strcpy(m_name, pathname); 

    if (put_in_table) { 
        object_manager->insert_object(m_name, this); 
        sc_module* curr_module = m_simc->hierarchy_curr(); 
        if( curr_module != 0 ) { 
            curr_module->add_child_object( this ); 
        } else { 
            sc_process_b* curr_proc = sc_get_current_process_b();
            if (curr_proc) { 
                curr_proc->add_child_object( this ); 
            } else { 
                m_simc->add_child_object( this ); 
            } 
        } 
    } 
}