void sc_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(); } }
inline void sc_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; }
void sc_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; }
inline void sc_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(); } }