📄 sc_simcontext.cpp
字号:
sc_simcontext::sc_simcontext(){ init();}sc_simcontext::~sc_simcontext(){ clean();}inline voidsc_simcontext::crunch( bool once ){#ifdef DEBUG_SYSTEMC int num_deltas = 0; // number of delta cycles#endif while ( true ) { // EVALUATE PHASE m_execution_phase = phase_evaluate; while( true ) { // execute method processes sc_method_handle method_h = pop_runnable_method(); while( method_h != 0 ) { try { method_h->semantics(); } catch( const sc_report& ex ) { ::std::cout << "\n" << ex.what() << ::std::endl; m_error = true; return; } method_h = pop_runnable_method(); } // execute (c)thread processes sc_thread_handle thread_h = pop_runnable_thread(); while( thread_h != 0 ) { if ( thread_h->ready_to_run() ) break; thread_h = pop_runnable_thread(); } if( thread_h != 0 ) { m_cor_pkg->yield( thread_h->m_cor_p ); } if( m_error ) { return; } // check for call(s) to sc_stop if( m_forced_stop ) { if ( stop_mode == SC_STOP_IMMEDIATE ) return; } if( m_runnable->is_empty() ) { // no more runnable processes break; } m_runnable->toggle(); } // UPDATE PHASE // // The delta count must be updated first so that event_occurred() // will work. m_execution_phase = phase_update; m_delta_count ++; m_prim_channel_registry->perform_update(); m_execution_phase = phase_notify; if( m_something_to_trace ) { trace_cycle( /* delta cycle? */ true ); } // m_delta_count ++; // check for call(s) to sc_stop if( m_forced_stop ) { break; }#ifdef DEBUG_SYSTEMC // check for possible infinite loops if( ++ num_deltas > SC_MAX_NUM_DELTA_CYCLES ) { ::std::cerr << "SystemC warning: " << "the number of delta cycles exceeds the limit of " << SC_MAX_NUM_DELTA_CYCLES << ", defined in sc_constants.h.\n" << "This is a possible sign of an infinite loop.\n" << "Increase the limit if this warning is invalid.\n"; break; }#endif // PROCESS DELTA NOTIFICATIONS: int size = m_delta_events.size(); if ( size != 0 ) { sc_event** l_events = &m_delta_events[0]; int i = size - 1; do { l_events[i]->trigger(); } while( -- i >= 0 ); m_delta_events.resize(0); } if( m_runnable->is_empty() ) { // no more runnable processes break; } // IF ONLY DOING ONE CYCLE, WE ARE DONE. OTHERWISE GET NEW CALLBACKS if ( once ) break; m_runnable->toggle(); } }inlinevoidsc_simcontext::cycle( const sc_time& t){ sc_time next_event_time; m_in_simulator_control = true; m_runnable->toggle(); crunch(); trace_cycle( /* delta cycle? */ false ); m_curr_time += t; next_event_time = next_time(); if ( next_event_time != SC_ZERO_TIME && next_event_time <= m_curr_time) { SC_REPORT_WARNING(SC_ID_CYCLE_MISSES_EVENTS_, ""); } m_in_simulator_control = false;}voidsc_simcontext::elaborate(){ if( m_elaboration_done || sim_status() != SC_SIM_OK ) { return; } m_port_registry->construction_done(); m_export_registry->construction_done(); m_prim_channel_registry->construction_done(); m_module_registry->construction_done(); // check for call(s) to sc_stop if( m_forced_stop ) { do_sc_stop_action(); return; } // SIGNAL THAT ELABORATION IS DONE // // We set the switch before the calls in case someone creates a process // in an end_of_elaboration callback. We need the information to flag // the process as being dynamic. m_elaboration_done = true; m_port_registry->elaboration_done(); m_export_registry->elaboration_done(); m_prim_channel_registry->elaboration_done(); m_module_registry->elaboration_done(); sc_reset::reconcile_resets(); // check for call(s) to sc_stop if( m_forced_stop ) { do_sc_stop_action(); return; }}voidsc_simcontext::prepare_to_simulate(){ sc_cthread_handle cthread_p; // Pointer to cthread process accessing. sc_method_handle method_p; // Pointer to method process accessing. sc_thread_handle thread_p; // Pointer to thread process accessing. if( m_ready_to_simulate || sim_status() != SC_SIM_OK ) { return; } // instantiate the coroutine package# if defined(WIN32) m_cor_pkg = new sc_cor_pkg_fiber( this );# else# if defined(SC_USE_PTHREADS) m_cor_pkg = new sc_cor_pkg_pthread( this );# else m_cor_pkg = new sc_cor_pkg_qt( this );# endif# endif m_cor = m_cor_pkg->get_main(); // NOTIFY ALL OBJECTS THAT SIMULATION IS ABOUT TO START: m_port_registry->start_simulation(); m_export_registry->start_simulation(); m_prim_channel_registry->start_simulation(); m_module_registry->start_simulation(); m_start_of_simulation_called = true; // CHECK FOR CALL(S) TO sc_stop if( m_forced_stop ) { do_sc_stop_action(); return; } // PREPARE ALL (C)THREAD PROCESSES FOR SIMULATION: for ( thread_p = m_process_table->thread_q_head(); thread_p; thread_p = thread_p->next_exist() ) { thread_p->prepare_for_simulation(); } for ( cthread_p = m_process_table->cthread_q_head(); cthread_p; cthread_p = cthread_p->next_exist() ) { cthread_p->prepare_for_simulation(); } m_ready_to_simulate = true; m_runnable->init(); // update phase m_execution_phase = phase_update; m_prim_channel_registry->perform_update(); m_execution_phase = phase_notify; int size; // make all method processes runnable for ( method_p = m_process_table->method_q_head(); method_p; method_p = method_p->next_exist() ) { if( !method_p->dont_initialize() ) { push_runnable_method_front( method_p ); } } // make all thread processes runnable for ( thread_p = m_process_table->thread_q_head(); thread_p; thread_p = thread_p->next_exist() ) { if( !thread_p->dont_initialize() ) { push_runnable_thread_front( thread_p ); } } // process delta notifications if( ( size = m_delta_events.size() ) != 0 ) { sc_event** l_delta_events = &m_delta_events[0]; int i = size - 1; do { l_delta_events[i]->trigger(); } while( -- i >= 0 ); m_delta_events.resize(0); } // used in 'simulate()' m_until_event = new sc_event; if( m_runnable->is_empty() ) { m_delta_count++; }}voidsc_simcontext::initial_crunch( bool no_crunch ){ if( no_crunch || m_runnable->is_empty() ) { return; } m_runnable->toggle(); // run the delta cycle loop crunch(); if( m_error ) { return; } if( m_something_to_trace ) { trace_cycle( false ); } // check for call(s) to sc_stop if( m_forced_stop ) { do_sc_stop_action(); }}voidsc_simcontext::initialize( bool no_crunch ){ m_in_simulator_control = true; elaborate(); prepare_to_simulate(); initial_crunch(no_crunch); m_in_simulator_control = false;}voidsc_simcontext::simulate( const sc_time& duration ){ initialize( true ); if (sim_status() != SC_SIM_OK) { return; } sc_time non_overflow_time = sc_time(~sc_dt::UINT64_ZERO, false) - m_curr_time; if ( duration > non_overflow_time ) { SC_REPORT_ERROR(SC_ID_SIMULATION_TIME_OVERFLOW_, ""); return; } else if ( duration < SC_ZERO_TIME ) { SC_REPORT_ERROR(SC_ID_NEGATIVE_SIMULATION_TIME_,""); } m_in_simulator_control = true; sc_time until_t = m_curr_time + duration; m_until_event->cancel(); // to be on the safe side m_until_event->notify_internal( duration ); sc_time t; // IF DURATION WAS ZERO WE ONLY CRUNCH: // // We duplicate the code so that we don't add the overhead of the // check to each loop in the do below. if ( duration == SC_ZERO_TIME ) { m_runnable->toggle(); crunch( true ); if( m_error ) return; if( m_something_to_trace ) trace_cycle( /* delta cycle? */ false ); if( m_forced_stop ) do_sc_stop_action(); return; } // NON-ZERO DURATION: EXECUTE UP TO THAT TIME: do { m_runnable->toggle(); crunch(); if( m_error ) { m_in_simulator_control = false; return; } if( m_something_to_trace ) { trace_cycle( false ); } // check for call(s) to sc_stop if( m_forced_stop ) { do_sc_stop_action(); return; } do { t = next_time(); // PROCESS TIMED NOTIFICATIONS do { sc_event_timed* et = m_timed_events->extract_top(); sc_event* e = et->event(); delete et; if( e != 0 ) { e->trigger(); } } while( m_timed_events->size() && m_timed_events->top()->notify_time() == t ); } while( m_runnable->is_empty() && t != until_t ); if ( t > m_curr_time ) m_curr_time = t; } while( t != until_t ); m_in_simulator_control = false;}voidsc_simcontext::do_sc_stop_action(){ ::std::cout << "SystemC: simulation stopped by user." << ::std::endl; if (m_start_of_simulation_called) { end(); m_in_simulator_control = false; }}//------------------------------------------------------------------------------//"sc_simcontext::stop"//// This method stops the simulator after some amount of further processing.// How much processing is done depends upon the value of the global variable// stop_mode:// SC_STOP_IMMEDIATE - aborts the execution phase of the current delta// cycle and performs whatever updates are pending.// SC_STOP_FINISH_DELTA - finishes the current delta cycle - both execution// and updates.// If sc_stop is called outside of the purview of the simulator kernel // (e.g., directly from sc_main), the end of simulation notifications // are performed. From within the purview of the simulator kernel, these// will be performed at a later time.//------------------------------------------------------------------------------voidsc_simcontext::stop(){ static bool stop_warning_issued = false; if (m_forced_stop) { if ( !stop_warning_issued ) { stop_warning_issued = true; // This must be before the WARNING!!! SC_REPORT_WARNING(SC_ID_SIMULATION_STOP_CALLED_TWICE_, ""); } return; } if ( stop_mode == SC_STOP_IMMEDIATE ) m_runnable->init(); m_forced_stop = true; if ( !m_in_simulator_control ) { do_sc_stop_action(); } }voidsc_simcontext::reset(){ clean(); init();}voidsc_simcontext::end(){ m_ready_to_simulate = false; m_port_registry->simulation_done(); m_export_registry->simulation_done(); m_prim_channel_registry->simulation_done(); m_module_registry->simulation_done(); m_end_of_simulation_called = true;}voidsc_simcontext::hierarchy_push( sc_module* mod ){ m_object_manager->hierarchy_push( mod );}sc_module*sc_simcontext::hierarchy_pop(){ return DCAST<sc_module*>( m_object_manager->hierarchy_pop() );}sc_module*sc_simcontext::hierarchy_curr() const{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -