Exemple #1
0
// We push the sc_module instance onto the stack of open objects so 
// that any objects that are created in before_end_of_elaboration have
// the proper parent. After the call we pop the hierarchy.
void
sc_module::construction_done()
{
    simcontext()->hierarchy_push( this );
    before_end_of_elaboration();
    simcontext()->hierarchy_pop();
}
Exemple #2
0
void
sc_module::start_simulation()
{
    simcontext()->hierarchy_push( this );
    start_of_simulation();
    simcontext()->hierarchy_pop();
}
Exemple #3
0
void
sc_module::simulation_done()
{
    simcontext()->hierarchy_push( this );
    end_of_simulation();
    simcontext()->hierarchy_pop();
}
Exemple #4
0
void
sc_module::sc_module_init()
{
    simcontext()->get_module_registry()->insert( *this );
    simcontext()->hierarchy_push( this );
    m_end_module_called = false;
    m_module_name_p = 0;
    m_port_vec = new std::vector<sc_port_base*>;
    m_port_index = 0;
    m_name_gen = new sc_name_gen;
}
//------------------------------------------------------------------------------
//"sc_process_b::sc_process_b"
//
// This is the object instance constructor for this class.
//------------------------------------------------------------------------------
sc_process_b::sc_process_b( const char* name_p, bool is_thread, bool free_host,
                            SC_ENTRY_FUNC method_p, sc_process_host* host_p,
                            const sc_spawn_options* /* opt_p  */
                          ) :
    sc_object( name_p ),
    file(0),
    lineno(0),
    proc_id( simcontext()->next_proc_id()),
    m_active_areset_n(0),
    m_active_reset_n(0),
    m_dont_init( false ),
    m_dynamic_proc( simcontext()->elaboration_done() ),
    m_event_p(0),
    m_event_count(0),
    m_event_list_p(0),
    m_exist_p(0),
    m_free_host( free_host ),
    m_has_reset_signal( false ),
    m_has_stack(false),
    m_is_thread(is_thread),
    m_last_report_p(0),
    m_name_gen_p(0),
    m_process_kind(SC_NO_PROC_),
    m_references_n(1),
    m_resets(),
    m_reset_event_p(0),
    m_resume_event_p(0),
    m_runnable_p(0),
    m_semantics_host_p( host_p ),
    m_semantics_method_p ( method_p ),
    m_state(ps_normal),
    m_static_events(),
    m_sticky_reset(false),
    m_term_event_p(0),
    m_throw_helper_p(0),
    m_throw_status( THROW_NONE ),
    m_timed_out(false),
    m_timeout_event_p(0),
    m_trigger_type(STATIC),
    m_unwinding(false)
{

    // THIS OBJECT INSTANCE IS NOW THE LAST CREATED PROCESS:

    m_last_created_process_p = this;
    m_timeout_event_p = new sc_event(
        (std::string(SC_KERNEL_EVENT_PREFIX)+"_free_event").c_str() );
}
Exemple #6
0
sc_module::sc_module( const sc_module_name& )
: sc_object(::sc_core::sc_get_curr_simcontext()
                  ->get_object_manager()
                  ->top_of_module_name_stack()
                  ->operator const char*()),
  sensitive(this),
  sensitive_pos(this),
  sensitive_neg(this),
  m_end_module_called(false),
  m_port_vec(),
  m_port_index(0),
  m_name_gen(0),
  m_module_name_p(0)
{
    /* For those used to the old style of passing a name to sc_module,
       this constructor will reduce the chance of making a mistake */

    /* When this form is used, we better have a fresh sc_module_name
       on the top of the stack */
    sc_module_name* mod_name = 
        simcontext()->get_object_manager()->top_of_module_name_stack();
    if (0 == mod_name || 0 != mod_name->m_module_p)
      SC_REPORT_ERROR( SC_ID_SC_MODULE_NAME_REQUIRED_, 0 );
    sc_module_init();
    mod_name->set_module( this );
    m_module_name_p = mod_name; // must come after sc_module_init call.
}
Exemple #7
0
// We push the sc_module instance onto the stack of open objects so 
// that any objects that are created in end_of_elaboration have
// the proper parent. After the call we pop the hierarchy.
void
sc_module::elaboration_done( bool& error_ )
{
    if( ! m_end_module_called ) {
	char msg[BUFSIZ];
	std::sprintf( msg, "module '%s'", name() );
	SC_REPORT_WARNING( SC_ID_END_MODULE_NOT_CALLED_, msg );
	if( error_ ) {
	    SC_REPORT_WARNING( SC_ID_HIER_NAME_INCORRECT_, 0 );
	}
	error_ = true;
    }
    simcontext()->hierarchy_push( this );
    end_of_elaboration();
    simcontext()->hierarchy_pop();
}
//------------------------------------------------------------------------------
//"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);
	}
    }
}
//------------------------------------------------------------------------------
//"sc_method_process::enable_process"
//
// This method enables 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::enable_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->enable_process(descendants);
        }
    }

    // ENABLE THIS OBJECT INSTANCE:
    //
    // If it was disabled and ready to run then put it on the run queue.

    m_state = m_state & ~ps_bit_disabled;
    if ( m_state == ps_bit_ready_to_run )
    {
        m_state = ps_normal;
	if ( next_runnable() == 0 )
	    simcontext()->push_runnable_method(this);
    }
}
Exemple #10
0
sc_object::phase_cb_mask
sc_object::unregister_simulation_phase_callback( phase_cb_mask mask )
{
    mask = simcontext()->m_phase_cb_registry
                       ->unregister_callback(*this, mask);
    return mask;
}
Exemple #11
0
sc_port_base::~sc_port_base()
{
    simcontext()->get_port_registry()->remove( this );
    if ( m_bind_info != 0 )
    {
        delete m_bind_info;
    }
}
Exemple #12
0
sc_port_base::sc_port_base(
    const char* name_, int max_size_, sc_port_policy policy
) :
        sc_object( name_ ),
        m_bind_info( new sc_bind_info( max_size_, policy ) )
{
    simcontext()->get_port_registry()->insert( this );
}
Exemple #13
0
sc_port_base::sc_port_base(
    int max_size_, sc_port_policy policy
) :
        sc_object( sc_gen_unique_name( "port" ) ),
        m_bind_info( new sc_bind_info( max_size_, policy ) )
{
    simcontext()->get_port_registry()->insert( this );
}
void sc_event_queue::notify (const sc_time& when)
{
    m_change_stamp = simcontext()->change_stamp();
    sc_time* t = new sc_time( when+sc_time_stamp() );
    if ( m_ppq.size()==0 || *t < *m_ppq.top() ) {
	m_e.notify( when );
    }
    m_ppq.insert( t );
}
//------------------------------------------------------------------------------
//"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 );
    }
}
//------------------------------------------------------------------------------
//"sc_method_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_method_process::kill_process()
{
    // CLEAN UP THE LOW LEVEL STUFF ASSOCIATED WITH THIS DATA STRUCTURE:

    sc_process_b::kill_process();


    // REMOVE METHOD FROM RUN QUEUE:

    simcontext()->remove_runnable_method( this );

}
Exemple #17
0
sc_module::~sc_module()
{
    delete m_port_vec;
    delete m_name_gen;
    orphan_child_objects();
    if ( m_module_name_p )
    {
	m_module_name_p->clear_module( this ); // must be before end_module()
    	end_module();
    }
    simcontext()->get_module_registry()->remove( *this );
}
sc_clock::sc_clock( const char* name_,
		    double         period_v_,
		    sc_time_unit   period_tu_,
		    double         duty_cycle_,
		    double         start_time_v_,
		    sc_time_unit   start_time_tu_,
		    bool           posedge_first_ )
: sc_signal<bool>( name_ )
{
    init( sc_time( period_v_, period_tu_, simcontext() ),
	  duty_cycle_,
	  sc_time( start_time_v_, start_time_tu_, simcontext() ),
	  posedge_first_ );

    if( posedge_first_ ) {
	// posedge first
	m_next_posedge_event.notify_internal( m_start_time );
    } else {
	// negedge first
	m_next_negedge_event.notify_internal( m_start_time );
    }
}
// +----------------------------------------------------------------------------
// |"sc_object::orphan_child_objects"
// | 
// | This method moves the children of this object instance to be children
// | of the simulator.
// +----------------------------------------------------------------------------
void sc_object::orphan_child_objects()
{
    std::vector< sc_object* > const & children = get_child_objects();

    std::vector< sc_object* >::const_iterator
            it  = children.begin(), end = children.end();

    for( ; it != end; ++it  )
    {
        (*it)->m_parent = NULL;
        simcontext()->add_child_object(*it);
    }
}
// +----------------------------------------------------------------------------
// |"sc_object::orphan_child_events"
// | 
// | This method moves the children of this object instance to be children
// | of the simulator.
// +----------------------------------------------------------------------------
void sc_object::orphan_child_events()
{
    std::vector< sc_event* > const & events = get_child_events();

    std::vector< sc_event* >::const_iterator
            it  = events.begin(), end = events.end();

    for( ; it != end; ++it  )
    {
        (*it)->m_parent_p = NULL;
        simcontext()->add_child_event(*it);
    }
}
//------------------------------------------------------------------------------
//"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_clock::sc_clock( const char* name_,
		    double         period_v_,
		    sc_time_unit   period_tu_,
		    double         duty_cycle_ )
: sc_signal<bool>( name_ )
{
    init( sc_time( period_v_, period_tu_, simcontext() ),
	  duty_cycle_,
	  SC_ZERO_TIME,
	  true );

    // posedge first
    m_next_posedge_event.notify_internal( m_start_time );
}
//------------------------------------------------------------------------------
//"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();  
	}
    }
}
// +----------------------------------------------------------------------------
// |"sc_method_process::check_for_throws"
// | 
// | This method checks to see if this method process should throw an exception
// | or not. It is called from sc_simcontext::preempt_with() to see if the
// | thread that was executed during the preemption did a kill or other 
// | manipulation on this object instance that requires it to throw an 
// | exception.
// +----------------------------------------------------------------------------
void sc_method_process::check_for_throws()
{
    if ( !m_unwinding )
    {
	switch( m_throw_status )
	{
	  case THROW_ASYNC_RESET:
	    simcontext()->preempt_with(this);
	    break;
          case THROW_KILL:
	    throw sc_unwind_exception( this, false );
	  default:
	    break;
	}
    }
}
//------------------------------------------------------------------------------
//"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;
}
//------------------------------------------------------------------------------
//"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 );
    }
}
Exemple #28
0
sc_module::sc_module()
: sc_object(::sc_core::sc_get_curr_simcontext()
                  ->get_object_manager()
                  ->top_of_module_name_stack()
                  ->operator const char*()),
  sensitive(this),
  sensitive_pos(this),
  sensitive_neg(this),
  m_end_module_called(false),
  m_port_vec(),
  m_port_index(0),
  m_name_gen(0),
  m_module_name_p(0)
{
    /* When this form is used, we better have a fresh sc_module_name
       on the top of the stack */
    sc_module_name* mod_name = 
        simcontext()->get_object_manager()->top_of_module_name_stack();
    if (0 == mod_name || 0 != mod_name->m_module_p)
        SC_REPORT_ERROR( SC_ID_SC_MODULE_NAME_REQUIRED_, 0 );
    sc_module_init();
    mod_name->set_module( this );
    m_module_name_p = mod_name; // must come after sc_module_init call.
}
void
sc_trace_file_base::simulation_phase_callback()
{
    // delta cycle is traced at the end of an update phase
    cycle( simcontext()->get_status() == SC_END_OF_UPDATE );
}
//------------------------------------------------------------------------------
//"sc_thread_process::prepare_for_simulation"
//
// This method prepares this object instance for simulation. It calls the
// coroutine package to create the actual thread.
//------------------------------------------------------------------------------
void sc_thread_process::prepare_for_simulation()
{
    m_cor_p = simcontext()->cor_pkg()->create( m_stack_size,
              sc_thread_cor_fn, this );
    m_cor_p->stack_protect( true );
}