// 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(); }
void sc_module::start_simulation() { simcontext()->hierarchy_push( this ); start_of_simulation(); simcontext()->hierarchy_pop(); }
void sc_module::simulation_done() { simcontext()->hierarchy_push( this ); end_of_simulation(); simcontext()->hierarchy_pop(); }
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() ); }
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. }
// 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); } }
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; }
sc_port_base::~sc_port_base() { simcontext()->get_port_registry()->remove( this ); if ( m_bind_info != 0 ) { delete m_bind_info; } }
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 ); }
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 ); }
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 ); } }
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 ); }