summaryrefslogtreecommitdiff
path: root/ext/systemc/src/sysc/kernel/sc_simcontext.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ext/systemc/src/sysc/kernel/sc_simcontext.cpp')
-rw-r--r--ext/systemc/src/sysc/kernel/sc_simcontext.cpp2284
1 files changed, 2284 insertions, 0 deletions
diff --git a/ext/systemc/src/sysc/kernel/sc_simcontext.cpp b/ext/systemc/src/sysc/kernel/sc_simcontext.cpp
new file mode 100644
index 000000000..104f7c984
--- /dev/null
+++ b/ext/systemc/src/sysc/kernel/sc_simcontext.cpp
@@ -0,0 +1,2284 @@
+/*****************************************************************************
+
+ Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
+ more contributor license agreements. See the NOTICE file distributed
+ with this work for additional information regarding copyright ownership.
+ Accellera licenses this file to you under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with the
+ License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ permissions and limitations under the License.
+
+ *****************************************************************************/
+
+/*****************************************************************************
+
+ sc_simcontext.cpp -- Provides a simulation context for use with multiple
+ simulations.
+
+ Original Author: Stan Y. Liao, Synopsys, Inc.
+ Martin Janssen, Synopsys, Inc.
+
+ CHANGE LOG AT THE END OF THE FILE
+ *****************************************************************************/
+
+#include <algorithm>
+
+#define SC_DISABLE_API_VERSION_CHECK // for in-library sc_ver.h inclusion
+
+#include "sysc/kernel/sc_cor_fiber.h"
+#include "sysc/kernel/sc_cor_pthread.h"
+#include "sysc/kernel/sc_cor_qt.h"
+#include "sysc/kernel/sc_event.h"
+#include "sysc/kernel/sc_kernel_ids.h"
+#include "sysc/kernel/sc_module.h"
+#include "sysc/kernel/sc_module_registry.h"
+#include "sysc/kernel/sc_name_gen.h"
+#include "sysc/kernel/sc_object_manager.h"
+#include "sysc/kernel/sc_cthread_process.h"
+#include "sysc/kernel/sc_method_process.h"
+#include "sysc/kernel/sc_thread_process.h"
+#include "sysc/kernel/sc_process_handle.h"
+#include "sysc/kernel/sc_simcontext.h"
+#include "sysc/kernel/sc_simcontext_int.h"
+#include "sysc/kernel/sc_reset.h"
+#include "sysc/kernel/sc_ver.h"
+#include "sysc/kernel/sc_boost.h"
+#include "sysc/kernel/sc_spawn.h"
+#include "sysc/kernel/sc_phase_callback_registry.h"
+#include "sysc/communication/sc_port.h"
+#include "sysc/communication/sc_export.h"
+#include "sysc/communication/sc_prim_channel.h"
+#include "sysc/tracing/sc_trace.h"
+#include "sysc/utils/sc_mempool.h"
+#include "sysc/utils/sc_list.h"
+#include "sysc/utils/sc_utils_ids.h"
+
+// DEBUGGING MACROS:
+//
+// DEBUG_MSG(NAME,P,MSG)
+// MSG = message to print
+// NAME = name that must match the process for the message to print, or
+// null if the message should be printed unconditionally.
+// P = pointer to process message is for, or NULL in which case the
+// message will not print.
+#if 0
+# define DEBUG_NAME ""
+# define DEBUG_MSG(NAME,P,MSG) \
+ { \
+ if ( P && ( (strlen(NAME)==0) || !strcmp(NAME,P->name())) ) \
+ std::cout << "**** " << sc_time_stamp() << " (" \
+ << sc_get_current_process_name() << "): " << MSG \
+ << " - " << P->name() << std::endl; \
+ }
+#else
+# define DEBUG_MSG(NAME,P,MSG)
+#endif
+
+#if SC_HAS_PHASE_CALLBACKS_
+# define SC_DO_PHASE_CALLBACK_( Kind ) \
+ m_phase_cb_registry->Kind()
+#else
+# define SC_DO_PHASE_CALLBACK_( Kind ) \
+ ((void)0) /* do nothing */
+#endif
+
+#if defined( SC_ENABLE_SIMULATION_PHASE_CALLBACKS_TRACING )
+// use callback based tracing
+# define SC_SIMCONTEXT_TRACING_ 0
+#else
+// enable tracing via explicit trace_cycle calls from simulator loop
+# define SC_SIMCONTEXT_TRACING_ 1
+#endif
+
+namespace sc_core {
+
+sc_stop_mode stop_mode = SC_STOP_FINISH_DELTA;
+
+// ----------------------------------------------------------------------------
+// CLASS : sc_process_table
+//
+// Container class that keeps track of all method processes,
+// (c)thread processes.
+// ----------------------------------------------------------------------------
+
+class sc_process_table
+{
+ public:
+
+ sc_process_table();
+ ~sc_process_table();
+ void push_front( sc_method_handle );
+ void push_front( sc_thread_handle );
+ sc_method_handle method_q_head();
+ sc_method_handle remove( sc_method_handle );
+ sc_thread_handle thread_q_head();
+ sc_thread_handle remove( sc_thread_handle );
+
+
+ private:
+
+ sc_method_handle m_method_q; // Queue of existing method processes.
+ sc_thread_handle m_thread_q; // Queue of existing thread processes.
+};
+
+
+// IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
+
+sc_process_table::sc_process_table() : m_method_q(0), m_thread_q(0)
+{}
+
+sc_process_table::~sc_process_table()
+{
+
+ sc_method_handle method_next_p; // Next method to delete.
+ sc_method_handle method_now_p; // Method now deleting.
+
+ for( method_now_p = m_method_q; method_now_p; method_now_p = method_next_p )
+ {
+ method_next_p = method_now_p->next_exist();
+ delete method_now_p;
+ }
+
+ if ( m_thread_q )
+ {
+ ::std::cout << ::std::endl
+ << "WATCH OUT!! In sc_process_table destructor. "
+ << "Threads and cthreads are not actually getting deleted here. "
+ << "Some memory may leak. Look at the comments here in "
+ << "kernel/sc_simcontext.cpp for more details."
+ << ::std::endl;
+ }
+
+ // don't delete threads and cthreads. If a (c)thread
+ // has died, then it has already been deleted. Only (c)threads created
+ // before simulation-start are in this table. Due to performance
+ // reasons, we don't look up the dying thread in the process table
+ // and remove it from there. simcontext::reset and ~simcontext invoke this
+ // destructor. At present none of these routines are ever invoked.
+ // We can delete threads and cthreads here if a dying thread figured out
+ // it was created before simulation-start and took itself off the
+ // process_table.
+
+#if 0
+ sc_thread_handle thread_next_p; // Next thread to delete.
+ sc_thread_handle thread_now_p; // Thread now deleting.
+
+ for( thread_now_p=m_thread_q; thread_now_p; thread_now_p=thread_next_p )
+ {
+ thread_next_p = thread_now_p->next_exist();
+ delete thread_now_p;
+ }
+#endif // 0
+}
+
+inline
+sc_method_handle
+sc_process_table::method_q_head()
+{
+ return m_method_q;
+}
+
+inline
+void
+sc_process_table::push_front( sc_method_handle handle_ )
+{
+ handle_->set_next_exist(m_method_q);
+ m_method_q = handle_;
+}
+
+inline
+void
+sc_process_table::push_front( sc_thread_handle handle_ )
+{
+ handle_->set_next_exist(m_thread_q);
+ m_thread_q = handle_;
+}
+
+sc_method_handle
+sc_process_table::remove( sc_method_handle handle_ )
+{
+ sc_method_handle now_p; // Entry now examining.
+ sc_method_handle prior_p; // Entry prior to one now examining.
+
+ prior_p = 0;
+ for ( now_p = m_method_q; now_p; now_p = now_p->next_exist() )
+ {
+ if ( now_p == handle_ )
+ {
+ if ( prior_p )
+ prior_p->set_next_exist( now_p->next_exist() );
+ else
+ m_method_q = now_p->next_exist();
+ return handle_;
+ }
+ }
+ return 0;
+}
+
+sc_thread_handle
+sc_process_table::remove( sc_thread_handle handle_ )
+{
+ sc_thread_handle now_p; // Entry now examining.
+ sc_thread_handle prior_p; // Entry prior to one now examining.
+
+ prior_p = 0;
+ for ( now_p = m_thread_q; now_p; now_p = now_p->next_exist() )
+ {
+ if ( now_p == handle_ )
+ {
+ if ( prior_p )
+ prior_p->set_next_exist( now_p->next_exist() );
+ else
+ m_thread_q = now_p->next_exist();
+ return handle_;
+ }
+ }
+ return 0;
+}
+
+inline
+sc_thread_handle
+sc_process_table::thread_q_head()
+{
+ return m_thread_q;
+}
+
+int
+sc_notify_time_compare( const void* p1, const void* p2 )
+{
+ const sc_event_timed* et1 = static_cast<const sc_event_timed*>( p1 );
+ const sc_event_timed* et2 = static_cast<const sc_event_timed*>( p2 );
+
+ const sc_time& t1 = et1->notify_time();
+ const sc_time& t2 = et2->notify_time();
+
+ if( t1 < t2 ) {
+ return 1;
+ } else if( t1 > t2 ) {
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+
+// +============================================================================
+// | CLASS sc_invoke_method - class to invoke sc_method's to support
+// | sc_simcontext::preempt_with().
+// +============================================================================
+SC_MODULE(sc_invoke_method)
+{
+ SC_CTOR(sc_invoke_method)
+ {
+ // remove from object hierarchy
+ detach();
+ }
+
+ virtual ~sc_invoke_method()
+ {
+ m_invokers.resize(0);
+ }
+
+ // Method to call to execute a method's semantics.
+
+ void invoke_method( sc_method_handle method_h )
+ {
+ sc_process_handle invoker_h; // handle for invocation thread to use.
+ std::vector<sc_process_handle>::size_type invokers_n; // number of invocation threads available.
+
+ m_method = method_h;
+
+ // There is not an invocation thread to use, so allocate one.
+
+ invokers_n = m_invokers.size();
+ if ( invokers_n == 0 )
+ {
+ sc_spawn_options options;
+ options.dont_initialize();
+ options.set_stack_size(0x100000);
+ options.set_sensitivity(&m_dummy);
+ invoker_h = sc_spawn(sc_bind(&sc_invoke_method::invoker,this),
+ sc_gen_unique_name("invoker"), &options);
+ ((sc_process_b*)invoker_h)->detach();
+ }
+
+ // There is an invocation thread to use, use the last one on the list.
+
+ else
+ {
+ invoker_h = m_invokers[invokers_n-1];
+ m_invokers.pop_back();
+ }
+
+ // Fire off the invocation thread to invoke the method's semantics,
+ // When it blocks put it onto the list of invocation threads that
+ // are available.
+
+ sc_get_curr_simcontext()->preempt_with( (sc_thread_handle)invoker_h );
+ DEBUG_MSG( DEBUG_NAME, m_method, "back from preemption" );
+ m_invokers.push_back(invoker_h);
+ }
+
+ // Thread to call method from:
+
+ void invoker()
+ {
+ sc_simcontext* csc_p = sc_get_curr_simcontext();
+ sc_process_b* me = sc_get_current_process_b();
+
+ DEBUG_MSG( DEBUG_NAME, me, "invoker initialization" );
+ for (;; )
+ {
+ DEBUG_MSG( DEBUG_NAME, m_method, "invoker executing method" );
+ csc_p->set_curr_proc( (sc_process_b*)m_method );
+ csc_p->get_active_invokers().push_back((sc_thread_handle)me);
+ m_method->run_process();
+ csc_p->set_curr_proc( me );
+ csc_p->get_active_invokers().pop_back();
+ DEBUG_MSG( DEBUG_NAME, m_method, "back from executing method" );
+ wait();
+ }
+ }
+
+ sc_event m_dummy; // dummy event to wait on.
+ sc_method_handle m_method; // method to be invoked.
+ std::vector<sc_process_handle> m_invokers; // list of invoking threads.
+};
+
+// ----------------------------------------------------------------------------
+// CLASS : sc_simcontext
+//
+// The simulation context.
+// ----------------------------------------------------------------------------
+
+void
+sc_simcontext::init()
+{
+
+ // ALLOCATE VARIOUS MANAGERS AND REGISTRIES:
+
+ m_object_manager = new sc_object_manager;
+ m_module_registry = new sc_module_registry( *this );
+ m_port_registry = new sc_port_registry( *this );
+ m_export_registry = new sc_export_registry( *this );
+ m_prim_channel_registry = new sc_prim_channel_registry( *this );
+ m_phase_cb_registry = new sc_phase_callback_registry( *this );
+ m_name_gen = new sc_name_gen;
+ m_process_table = new sc_process_table;
+ m_current_writer = 0;
+
+
+ // CHECK FOR ENVIRONMENT VARIABLES THAT MODIFY SIMULATOR EXECUTION:
+
+ const char* write_check = std::getenv("SC_SIGNAL_WRITE_CHECK");
+ m_write_check = ( (write_check==0) || strcmp(write_check,"DISABLE") ) ?
+ true : false;
+
+
+ // FINISH INITIALIZATIONS:
+
+ reset_curr_proc();
+ m_next_proc_id = -1;
+ m_timed_events = new sc_ppq<sc_event_timed*>( 128, sc_notify_time_compare );
+ m_something_to_trace = false;
+ m_runnable = new sc_runnable;
+ m_collectable = new sc_process_list;
+ m_time_params = new sc_time_params;
+ m_curr_time = SC_ZERO_TIME;
+ m_max_time = SC_ZERO_TIME;
+ m_change_stamp = 0;
+ m_delta_count = 0;
+ m_forced_stop = false;
+ m_paused = false;
+ m_ready_to_simulate = false;
+ m_elaboration_done = false;
+ m_execution_phase = phase_initialize;
+ m_error = NULL;
+ m_cor_pkg = 0;
+ m_method_invoker_p = NULL;
+ m_cor = 0;
+ m_in_simulator_control = false;
+ m_start_of_simulation_called = false;
+ m_end_of_simulation_called = false;
+ m_simulation_status = SC_ELABORATION;
+}
+
+void
+sc_simcontext::clean()
+{
+ delete m_object_manager;
+ delete m_module_registry;
+ delete m_port_registry;
+ delete m_export_registry;
+ delete m_prim_channel_registry;
+ delete m_phase_cb_registry;
+ delete m_name_gen;
+ delete m_process_table;
+ m_child_objects.resize(0);
+ m_delta_events.resize(0);
+ delete m_timed_events;
+ for( int i = m_trace_files.size() - 1; i >= 0; -- i ) {
+ delete m_trace_files[i];
+ }
+ m_trace_files.resize(0);
+ delete m_runnable;
+ delete m_collectable;
+ delete m_time_params;
+ delete m_cor_pkg;
+ delete m_error;
+}
+
+
+sc_simcontext::sc_simcontext() :
+ m_object_manager(0), m_module_registry(0), m_port_registry(0),
+ m_export_registry(0), m_prim_channel_registry(0),
+ m_phase_cb_registry(0), m_name_gen(0),
+ m_process_table(0), m_curr_proc_info(), m_current_writer(0),
+ m_write_check(false), m_next_proc_id(-1), m_child_events(),
+ m_child_objects(), m_delta_events(), m_timed_events(0), m_trace_files(),
+ m_something_to_trace(false), m_runnable(0), m_collectable(0),
+ m_time_params(), m_curr_time(SC_ZERO_TIME), m_max_time(SC_ZERO_TIME),
+ m_change_stamp(0), m_delta_count(0), m_forced_stop(false), m_paused(false),
+ m_ready_to_simulate(false), m_elaboration_done(false),
+ m_execution_phase(phase_initialize), m_error(0),
+ m_in_simulator_control(false), m_end_of_simulation_called(false),
+ m_simulation_status(SC_ELABORATION), m_start_of_simulation_called(false),
+ m_cor_pkg(0), m_cor(0)
+{
+ init();
+}
+
+sc_simcontext::~sc_simcontext()
+{
+ clean();
+}
+
+// +----------------------------------------------------------------------------
+// |"sc_simcontext::active_object"
+// |
+// | This method returns the currently active object with respect to
+// | additions to the hierarchy. It will be the top of the object hierarchy
+// | stack if it is non-empty, or it will be the active process, or NULL
+// | if there is no active process.
+// +----------------------------------------------------------------------------
+sc_object*
+sc_simcontext::active_object()
+{
+ sc_object* result_p; // pointer to return.
+
+ result_p = m_object_manager->hierarchy_curr();
+ if ( !result_p )
+ result_p = (sc_object*)get_curr_proc_info()->process_handle;
+ return result_p;
+}
+
+// +----------------------------------------------------------------------------
+// |"sc_simcontext::crunch"
+// |
+// | This method implements the simulator's execution of processes. It performs
+// | one or more "delta" cycles. Each delta cycle consists of an evaluation,
+// | an update phase, and a notification phase. During the evaluation phase any
+// | processes that are ready to run are executed. After all the processes have
+// | been executed the update phase is entered. During the update phase the
+// | values of any signals that have changed are updated. After the updates
+// | have been performed the notification phase is entered. During that phase
+// | any notifications that need to occur because of of signal values changes
+// | are performed. This will result in the queueing of processes for execution
+// | that are sensitive to those notifications. At that point a delta cycle
+// | is complete, and the process is started again unless 'once' is true.
+// |
+// | Arguments:
+// | once = true if only one delta cycle is to be performed.
+// +----------------------------------------------------------------------------
+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;
+ bool empty_eval_phase = true;
+ while( true )
+ {
+
+ // execute method processes
+
+ m_runnable->toggle_methods();
+ sc_method_handle method_h = pop_runnable_method();
+ while( method_h != 0 ) {
+ empty_eval_phase = false;
+ if ( !method_h->run_process() )
+ {
+ goto out;
+ }
+ method_h = pop_runnable_method();
+ }
+
+ // execute (c)thread processes
+
+ m_runnable->toggle_threads();
+ sc_thread_handle thread_h = pop_runnable_thread();
+ while( thread_h != 0 ) {
+ if ( thread_h->m_cor_p != NULL ) break;
+ thread_h = pop_runnable_thread();
+ }
+
+ if( thread_h != 0 ) {
+ empty_eval_phase = false;
+ m_cor_pkg->yield( thread_h->m_cor_p );
+ }
+ if( m_error ) {
+ goto out;
+ }
+
+ // check for call(s) to sc_stop
+ if( m_forced_stop ) {
+ if ( stop_mode == SC_STOP_IMMEDIATE ) goto out;
+ }
+
+ // no more runnable processes
+
+ if( m_runnable->is_empty() ) {
+ break;
+ }
+ }
+
+ // remove finally dead zombies:
+
+ while( ! m_collectable->empty() )
+ {
+ sc_process_b* del_p = m_collectable->front();
+ m_collectable->pop_front();
+ del_p->reference_decrement();
+ }
+
+
+ // UPDATE PHASE
+ //
+ // The change stamp must be updated first so that event_occurred()
+ // will work.
+
+ m_execution_phase = phase_update;
+ if ( !empty_eval_phase )
+ {
+// SC_DO_PHASE_CALLBACK_(evaluation_done);
+ m_change_stamp++;
+ m_delta_count ++;
+ }
+ m_prim_channel_registry->perform_update();
+ SC_DO_PHASE_CALLBACK_(update_done);
+ m_execution_phase = phase_notify;
+
+#if SC_SIMCONTEXT_TRACING_
+ if( m_something_to_trace ) {
+ trace_cycle( /* delta cycle? */ true );
+ }
+#endif
+
+ // 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
+
+ // NOTIFICATION PHASE:
+ //
+ // Process delta notifications which will queue processes for
+ // subsequent execution.
+
+ 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 sc_pause() was called we are done.
+
+ if ( m_paused ) break;
+
+ // IF ONLY DOING ONE CYCLE, WE ARE DONE. OTHERWISE EXECUTE NEW CALLBACKS
+
+ if ( once ) break;
+ }
+
+ // When this point is reached the processing of delta cycles is complete,
+ // if the completion was because of an error throw the exception specified
+ // by '*m_error'.
+out:
+ this->reset_curr_proc();
+ if( m_error ) throw *m_error; // re-throw propagated error
+}
+
+inline
+void
+sc_simcontext::cycle( const sc_time& t)
+{
+ sc_time next_event_time;
+
+ m_in_simulator_control = true;
+ crunch();
+ SC_DO_PHASE_CALLBACK_(before_timestep);
+#if SC_SIMCONTEXT_TRACING_
+ if( m_something_to_trace ) {
+ trace_cycle( /* delta cycle? */ false );
+ }
+#endif
+ m_curr_time += t;
+ if ( next_time(next_event_time) && next_event_time <= m_curr_time) {
+ SC_REPORT_WARNING(SC_ID_CYCLE_MISSES_EVENTS_, "");
+ }
+ m_in_simulator_control = false;
+ SC_DO_PHASE_CALLBACK_(simulation_paused);
+}
+
+void
+sc_simcontext::elaborate()
+{
+ if( m_elaboration_done || sim_status() != SC_SIM_OK ) {
+ return;
+ }
+
+ // Instantiate the method invocation module
+ // (not added to public object hierarchy)
+
+ m_method_invoker_p =
+ new sc_invoke_method("$$$$kernel_module$$$$_invoke_method" );
+
+ m_simulation_status = SC_BEFORE_END_OF_ELABORATION;
+ for( int cd = 0; cd != 4; /* empty */ )
+ {
+ cd = m_port_registry->construction_done();
+ cd += m_export_registry->construction_done();
+ cd += m_prim_channel_registry->construction_done();
+ cd += m_module_registry->construction_done();
+
+ // check for call(s) to sc_stop
+ if( m_forced_stop ) {
+ do_sc_stop_action();
+ return;
+ }
+
+ }
+ SC_DO_PHASE_CALLBACK_(construction_done);
+
+ // 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_simulation_status = SC_END_OF_ELABORATION;
+
+ m_port_registry->elaboration_done();
+ m_export_registry->elaboration_done();
+ m_prim_channel_registry->elaboration_done();
+ m_module_registry->elaboration_done();
+ SC_DO_PHASE_CALLBACK_(elaboration_done);
+ sc_reset::reconcile_resets();
+
+ // check for call(s) to sc_stop
+ if( m_forced_stop ) {
+ do_sc_stop_action();
+ return;
+ }
+}
+
+void
+sc_simcontext::prepare_to_simulate()
+{
+ 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
+ m_cor_pkg = new sc_cor_pkg_t( this );
+ m_cor = m_cor_pkg->get_main();
+
+ // NOTIFY ALL OBJECTS THAT SIMULATION IS ABOUT TO START:
+
+ m_simulation_status = SC_START_OF_SIMULATION;
+ m_port_registry->start_simulation();
+ m_export_registry->start_simulation();
+ m_prim_channel_registry->start_simulation();
+ m_module_registry->start_simulation();
+ SC_DO_PHASE_CALLBACK_(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();
+ }
+
+ m_simulation_status = SC_RUNNING;
+ 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->m_state & sc_process_b::ps_bit_disabled) != 0) ||
+ method_p->dont_initialize() )
+ {
+ if ( method_p->m_static_events.size() == 0 )
+ {
+ SC_REPORT_WARNING( SC_ID_DISABLE_WILL_ORPHAN_PROCESS_,
+ method_p->name() );
+ }
+ }
+ else if ( (method_p->m_state & sc_process_b::ps_bit_suspended) == 0)
+ {
+ push_runnable_method_front( method_p );
+ }
+ else
+ {
+ method_p->m_state |= sc_process_b::ps_bit_ready_to_run;
+ }
+ }
+
+ // make thread processes runnable
+ // (cthread processes always have the dont_initialize flag set)
+
+ for ( thread_p = m_process_table->thread_q_head();
+ thread_p; thread_p = thread_p->next_exist() )
+ {
+ if ( ((thread_p->m_state & sc_process_b::ps_bit_disabled) != 0) ||
+ thread_p->dont_initialize() )
+ {
+ if ( thread_p->m_static_events.size() == 0 )
+ {
+ SC_REPORT_WARNING( SC_ID_DISABLE_WILL_ORPHAN_PROCESS_,
+ thread_p->name() );
+ }
+ }
+ else if ( (thread_p->m_state & sc_process_b::ps_bit_suspended) == 0)
+ {
+ push_runnable_thread_front( thread_p );
+ }
+ else
+ {
+ thread_p->m_state |= sc_process_b::ps_bit_ready_to_run;
+ }
+ }
+
+
+ // 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);
+ }
+
+ SC_DO_PHASE_CALLBACK_(initialization_done);
+}
+
+void
+sc_simcontext::initial_crunch( bool no_crunch )
+{
+ if( no_crunch || m_runnable->is_empty() ) {
+ return;
+ }
+
+ // run the delta cycle loop
+
+ crunch();
+ if( m_error ) {
+ return;
+ }
+
+#if SC_SIMCONTEXT_TRACING_
+ if( m_something_to_trace ) {
+ trace_cycle( false );
+ }
+#endif
+
+ // check for call(s) to sc_stop
+ if( m_forced_stop ) {
+ do_sc_stop_action();
+ }
+}
+
+void
+sc_simcontext::initialize( bool no_crunch )
+{
+ m_in_simulator_control = true;
+ elaborate();
+
+ prepare_to_simulate();
+ initial_crunch(no_crunch);
+ m_in_simulator_control = false;
+}
+
+// +----------------------------------------------------------------------------
+// |"sc_simcontext::simulate"
+// |
+// | This method runs the simulation for the specified amount of time.
+// |
+// | Notes:
+// | (1) This code always run with an SC_EXIT_ON_STARVATION starvation policy,
+// | so the simulation time on return will be the minimum of the
+// | simulation on entry plus the duration, and the maximum time of any
+// | event present in the simulation. If the simulation policy is
+// | SC_RUN_TO_TIME starvation it is implemented by the caller of this
+// | method, e.g., sc_start(), by artificially setting the simulation
+// | time forward after this method completes.
+// |
+// | Arguments:
+// | duration = amount of time to simulate.
+// +----------------------------------------------------------------------------
+void
+sc_simcontext::simulate( const sc_time& duration )
+{
+ initialize( true );
+
+ if (sim_status() != SC_SIM_OK) {
+ return;
+ }
+
+ sc_time non_overflow_time = sc_max_time() - 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;
+ m_paused = false;
+
+ sc_time until_t = m_curr_time + duration;
+ sc_time t; // current simulaton time.
+
+ // IF DURATION WAS ZERO WE ONLY CRUNCH ONCE:
+ //
+ // 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_in_simulator_control = true;
+ crunch( true );
+ if( m_error ) {
+ m_in_simulator_control = false;
+ return;
+ }
+#if SC_SIMCONTEXT_TRACING_
+ if( m_something_to_trace )
+ trace_cycle( /* delta cycle? */ false );
+#endif
+ if( m_forced_stop ) {
+ do_sc_stop_action();
+ return;
+ }
+ // return via implicit pause
+ goto exit_pause;
+ }
+
+ // NON-ZERO DURATION: EXECUTE UP TO THAT TIME, OR UNTIL EVENT STARVATION:
+
+ do {
+
+ crunch();
+ if( m_error ) {
+ m_in_simulator_control = false;
+ return;
+ }
+#if SC_SIMCONTEXT_TRACING_
+ if( m_something_to_trace ) {
+ trace_cycle( false );
+ }
+#endif
+ // check for call(s) to sc_stop() or sc_pause().
+ if( m_forced_stop ) {
+ do_sc_stop_action();
+ return;
+ }
+ if( m_paused ) goto exit_pause; // return explicit pause
+
+ t = m_curr_time;
+
+ do {
+ // See note 1 above:
+
+ if ( !next_time(t) || (t > until_t ) ) goto exit_time;
+ if ( t > m_curr_time )
+ {
+ SC_DO_PHASE_CALLBACK_(before_timestep);
+ m_curr_time = t;
+ m_change_stamp++;
+ }
+
+ // PROCESS TIMED NOTIFICATIONS AT THE CURRENT TIME
+
+ 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() );
+ } while ( t < until_t ); // hold off on the delta for the until_t time.
+
+exit_time: // final simulation time update, if needed
+ if ( t > m_curr_time && t <= until_t )
+ {
+ SC_DO_PHASE_CALLBACK_(before_timestep);
+ m_curr_time = t;
+ m_change_stamp++;
+ }
+exit_pause: // call pause callback upon implicit or explicit pause
+ m_execution_phase = phase_evaluate;
+ m_in_simulator_control = false;
+ SC_DO_PHASE_CALLBACK_(simulation_paused);
+}
+
+void
+sc_simcontext::do_sc_stop_action()
+{
+ SC_REPORT_INFO("/OSCI/SystemC","Simulation stopped by user.");
+ if (m_start_of_simulation_called) {
+ end();
+ m_in_simulator_control = false;
+ }
+ m_simulation_status = SC_STOPPED;
+ SC_DO_PHASE_CALLBACK_(simulation_stopped);
+}
+
+void
+sc_simcontext::mark_to_collect_process( sc_process_b* zombie )
+{
+ m_collectable->push_back( zombie );
+}
+
+
+//------------------------------------------------------------------------------
+//"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.
+//------------------------------------------------------------------------------
+
+void
+sc_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();
+ }
+}
+
+void
+sc_simcontext::reset()
+{
+ clean();
+ init();
+}
+
+void
+sc_simcontext::end()
+{
+ m_simulation_status = SC_END_OF_SIMULATION;
+ 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();
+ SC_DO_PHASE_CALLBACK_(simulation_done);
+ m_end_of_simulation_called = true;
+}
+
+void
+sc_simcontext::hierarchy_push( sc_module* mod )
+{
+ m_object_manager->hierarchy_push( mod );
+}
+
+sc_module*
+sc_simcontext::hierarchy_pop()
+{
+ return static_cast<sc_module*>( m_object_manager->hierarchy_pop() );
+}
+
+sc_module*
+sc_simcontext::hierarchy_curr() const
+{
+ return static_cast<sc_module*>( m_object_manager->hierarchy_curr() );
+}
+
+sc_object*
+sc_simcontext::first_object()
+{
+ return m_object_manager->first_object();
+}
+
+sc_object*
+sc_simcontext::next_object()
+{
+ return m_object_manager->next_object();
+}
+
+sc_object*
+sc_simcontext::find_object( const char* name )
+{
+ static bool warn_find_object=true;
+ if ( warn_find_object )
+ {
+ warn_find_object = false;
+ SC_REPORT_INFO(SC_ID_IEEE_1666_DEPRECATION_,
+ "sc_simcontext::find_object() is deprecated,\n" \
+ " use sc_find_object()" );
+ }
+ return m_object_manager->find_object( name );
+}
+
+// to generate unique names for objects in an MT-Safe way
+
+const char*
+sc_simcontext::gen_unique_name( const char* basename_, bool preserve_first )
+{
+ return m_name_gen->gen_unique_name( basename_, preserve_first );
+}
+
+
+sc_process_handle
+sc_simcontext::create_cthread_process(
+ const char* name_p, bool free_host, SC_ENTRY_FUNC method_p,
+ sc_process_host* host_p, const sc_spawn_options* opt_p )
+{
+ sc_thread_handle handle =
+ new sc_cthread_process(name_p, free_host, method_p, host_p, opt_p);
+ if ( m_ready_to_simulate )
+ {
+ handle->prepare_for_simulation();
+ } else {
+ m_process_table->push_front( handle );
+ }
+ return sc_process_handle(handle);
+}
+
+
+sc_process_handle
+sc_simcontext::create_method_process(
+ const char* name_p, bool free_host, SC_ENTRY_FUNC method_p,
+ sc_process_host* host_p, const sc_spawn_options* opt_p )
+{
+ sc_method_handle handle =
+ new sc_method_process(name_p, free_host, method_p, host_p, opt_p);
+ if ( m_ready_to_simulate ) { // dynamic process
+ if ( !handle->dont_initialize() )
+ {
+#ifdef SC_HAS_PHASE_CALLBACKS_
+ if( SC_UNLIKELY_( m_simulation_status
+ & (SC_END_OF_UPDATE|SC_BEFORE_TIMESTEP) ) )
+ {
+ std::stringstream msg;
+ msg << m_simulation_status
+ << ":\n\t immediate method spawning of "
+ "`" << handle->name() << "' ignored";
+ SC_REPORT_WARNING( SC_ID_PHASE_CALLBACK_FORBIDDEN_
+ , msg.str().c_str() );
+ }
+ else
+#endif // SC_HAS_PHASE_CALLBACKS_
+ {
+ push_runnable_method( handle );
+ }
+ }
+ else if ( handle->m_static_events.size() == 0 )
+ {
+ SC_REPORT_WARNING( SC_ID_DISABLE_WILL_ORPHAN_PROCESS_,
+ handle->name() );
+ }
+
+ } else {
+ m_process_table->push_front( handle );
+ }
+ return sc_process_handle(handle);
+}
+
+
+sc_process_handle
+sc_simcontext::create_thread_process(
+ const char* name_p, bool free_host, SC_ENTRY_FUNC method_p,
+ sc_process_host* host_p, const sc_spawn_options* opt_p )
+{
+ sc_thread_handle handle =
+ new sc_thread_process(name_p, free_host, method_p, host_p, opt_p);
+ if ( m_ready_to_simulate ) { // dynamic process
+ handle->prepare_for_simulation();
+ if ( !handle->dont_initialize() )
+ {
+#ifdef SC_HAS_PHASE_CALLBACKS_
+ if( SC_UNLIKELY_( m_simulation_status
+ & (SC_END_OF_UPDATE|SC_BEFORE_TIMESTEP) ) )
+ {
+ std::stringstream msg;
+ msg << m_simulation_status
+ << ":\n\t immediate thread spawning of "
+ "`" << handle->name() << "' ignored";
+ SC_REPORT_WARNING( SC_ID_PHASE_CALLBACK_FORBIDDEN_
+ , msg.str().c_str() );
+ }
+ else
+#endif // SC_HAS_PHASE_CALLBACKS_
+ {
+ push_runnable_thread( handle );
+ }
+ }
+ else if ( handle->m_static_events.size() == 0 )
+ {
+ SC_REPORT_WARNING( SC_ID_DISABLE_WILL_ORPHAN_PROCESS_,
+ handle->name() );
+ }
+
+ } else {
+ m_process_table->push_front( handle );
+ }
+ return sc_process_handle(handle);
+}
+
+void
+sc_simcontext::add_trace_file( sc_trace_file* tf )
+{
+ m_trace_files.push_back( tf );
+ m_something_to_trace = true;
+}
+
+void
+sc_simcontext::remove_trace_file( sc_trace_file* tf )
+{
+ m_trace_files.erase(
+ std::remove( m_trace_files.begin(), m_trace_files.end(), tf )
+ );
+ m_something_to_trace = ( m_trace_files.size() > 0 );
+}
+
+sc_cor*
+sc_simcontext::next_cor()
+{
+ if( m_error ) {
+ return m_cor;
+ }
+
+ sc_thread_handle thread_h = pop_runnable_thread();
+ while( thread_h != 0 ) {
+ if ( thread_h->m_cor_p != NULL ) break;
+ thread_h = pop_runnable_thread();
+ }
+
+ if( thread_h != 0 ) {
+ return thread_h->m_cor_p;
+ } else {
+ return m_cor;
+ }
+}
+
+const ::std::vector<sc_object*>&
+sc_simcontext::get_child_objects() const
+{
+ static bool warn_get_child_objects=true;
+ if ( warn_get_child_objects )
+ {
+ warn_get_child_objects = false;
+ SC_REPORT_INFO(SC_ID_IEEE_1666_DEPRECATION_,
+ "sc_simcontext::get_child_objects() is deprecated,\n" \
+ " use sc_get_top_level_objects()" );
+ }
+ return m_child_objects;
+}
+
+void
+sc_simcontext::add_child_event( sc_event* event_ )
+{
+ // no check if object_ is already in the set
+ m_child_events.push_back( event_ );
+}
+
+void
+sc_simcontext::add_child_object( sc_object* object_ )
+{
+ // no check if object_ is already in the set
+ m_child_objects.push_back( object_ );
+}
+
+void
+sc_simcontext::remove_child_event( sc_event* event_ )
+{
+ int size = m_child_events.size();
+ for( int i = 0; i < size; ++ i ) {
+ if( event_ == m_child_events[i] ) {
+ m_child_events[i] = m_child_events[size - 1];
+ m_child_events.resize(size-1);
+ return;
+ }
+ }
+ // no check if event_ is really in the set
+}
+
+void
+sc_simcontext::remove_child_object( sc_object* object_ )
+{
+ int size = m_child_objects.size();
+ for( int i = 0; i < size; ++ i ) {
+ if( object_ == m_child_objects[i] ) {
+ m_child_objects[i] = m_child_objects[size - 1];
+ m_child_objects.resize(size-1);
+ return;
+ }
+ }
+ // no check if object_ is really in the set
+}
+
+sc_dt::uint64
+sc_simcontext::delta_count() const
+{
+ static bool warn_delta_count=true;
+ if ( warn_delta_count )
+ {
+ warn_delta_count = false;
+ SC_REPORT_INFO(SC_ID_IEEE_1666_DEPRECATION_,
+ "sc_simcontext::delta_count() is deprecated, use sc_delta_count()" );
+ }
+ return m_delta_count;
+}
+
+bool
+sc_simcontext::is_running() const
+{
+ static bool warn_is_running=true;
+ if ( warn_is_running )
+ {
+ warn_is_running = false;
+ SC_REPORT_INFO(SC_ID_IEEE_1666_DEPRECATION_,
+ "sc_simcontext::is_running() is deprecated, use sc_is_running()" );
+ }
+ return m_ready_to_simulate;
+}
+
+// +----------------------------------------------------------------------------
+// |"sc_simcontext::next_time"
+// |
+// | This method returns the time of the next event. If there are no events
+// | it returns false.
+// |
+// | Arguments:
+// | result = where to place time of the next event, if no event is
+// | found this value will not be changed.
+// | Result is true if an event is found, false if not.
+// +----------------------------------------------------------------------------
+bool
+sc_simcontext::next_time( sc_time& result ) const
+{
+ while( m_timed_events->size() ) {
+ sc_event_timed* et = m_timed_events->top();
+ if( et->event() != 0 ) {
+ result = et->notify_time();
+ return true;
+ }
+ delete m_timed_events->extract_top();
+ }
+ return false;
+}
+
+void
+sc_simcontext::remove_delta_event( sc_event* e )
+{
+ int i = e->m_delta_event_index;
+ int j = m_delta_events.size() - 1;
+ assert( i >= 0 && i <= j );
+ if( i != j ) {
+ sc_event** l_delta_events = &m_delta_events[0];
+ l_delta_events[i] = l_delta_events[j];
+ l_delta_events[i]->m_delta_event_index = i;
+ }
+ m_delta_events.resize(m_delta_events.size()-1);
+ e->m_delta_event_index = -1;
+}
+
+// +----------------------------------------------------------------------------
+// |"sc_simcontext::preempt_with"
+// |
+// | This method executes the supplied method immediately, suspending the
+// | caller. After executing the supplied method the caller's execution will
+// | be restored. It is used to allow a method to immediately throw an
+// | exception, e.g., when the method's kill_process() method was called.
+// | There are three cases to consider:
+// | (1) The caller is a method, e.g., murder by method.
+// | (2) The caller is a thread instance, e.g., murder by thread.
+// | (3) The caller is this method instance, e.g., suicide.
+// |
+// | Arguments:
+// | method_h -> method to be executed.
+// +----------------------------------------------------------------------------
+void
+sc_simcontext::preempt_with( sc_method_handle method_h )
+{
+ sc_curr_proc_info caller_info; // process info for caller.
+ sc_method_handle active_method_h; // active method or null.
+ sc_thread_handle active_thread_h; // active thread or null.
+
+ // Determine the active process and take the thread to be run off the
+ // run queue, if its there, since we will be explicitly causing its
+ // execution.
+
+ active_method_h = DCAST<sc_method_handle>(sc_get_current_process_b());
+ active_thread_h = DCAST<sc_thread_handle>(sc_get_current_process_b());
+ if ( method_h->next_runnable() != NULL )
+ remove_runnable_method( method_h );
+
+ // CALLER IS THE METHOD TO BE RUN:
+ //
+ // Should never get here, ignore it unless we are debugging.
+
+ if ( method_h == active_method_h )
+ {
+ DEBUG_MSG(DEBUG_NAME,method_h,"self preemption of active method");
+ }
+
+ // THE CALLER IS A METHOD:
+ //
+ // (a) Set the current process information to our method.
+ // (b) Invoke our method directly by-passing the run queue.
+ // (c) Restore the process info to the caller.
+ // (d) Check to see if the calling method should throw an exception
+ // because of activity that occurred during the preemption.
+
+ else if ( active_method_h != NULL )
+ {
+ caller_info = m_curr_proc_info;
+ DEBUG_MSG( DEBUG_NAME, method_h,
+ "preempting active method with method" );
+ sc_get_curr_simcontext()->set_curr_proc( (sc_process_b*)method_h );
+ method_h->run_process();
+ sc_get_curr_simcontext()->set_curr_proc((sc_process_b*)active_method_h);
+ active_method_h->check_for_throws();
+ }
+
+ // CALLER IS A THREAD:
+ //
+ // (a) Use an invocation thread to execute the method.
+
+ else if ( active_thread_h != NULL )
+ {
+ DEBUG_MSG( DEBUG_NAME, method_h,
+ "preempting active thread with method" );
+ m_method_invoker_p->invoke_method(method_h);
+ }
+
+ // CALLER IS THE SIMULATOR:
+ //
+ // That is not allowed.
+
+ else
+ {
+ caller_info = m_curr_proc_info;
+ DEBUG_MSG( DEBUG_NAME, method_h,
+ "preempting no active process with method" );
+ sc_get_curr_simcontext()->set_curr_proc( (sc_process_b*)method_h );
+ method_h->run_process();
+ m_curr_proc_info = caller_info;
+ }
+}
+
+//------------------------------------------------------------------------------
+//"sc_simcontext::requeue_current_process"
+//
+// This method requeues the current process at the beginning of the run queue
+// if it is a thread. This is called by sc_process_handle::throw_it() to assure
+// that a thread that is issuing a throw will execute immediately after the
+// processes it notifies via the throw.
+//------------------------------------------------------------------------------
+void sc_simcontext::requeue_current_process()
+{
+ sc_thread_handle thread_p;
+ thread_p = DCAST<sc_thread_handle>(get_curr_proc_info()->process_handle);
+ if ( thread_p )
+ {
+ execute_thread_next( thread_p );
+ }
+}
+
+//------------------------------------------------------------------------------
+//"sc_simcontext::suspend_current_process"
+//
+// This method suspends the current process if it is a thread. This is called
+// by sc_process_handle::throw_it() to allow the processes that have received
+// a throw to execute.
+//------------------------------------------------------------------------------
+void sc_simcontext::suspend_current_process()
+{
+ sc_thread_handle thread_p;
+ thread_p = DCAST<sc_thread_handle>(get_curr_proc_info()->process_handle);
+ if ( thread_p )
+ {
+ thread_p->suspend_me();
+ }
+}
+
+void
+sc_simcontext::trace_cycle( bool delta_cycle )
+{
+ int size;
+ if( ( size = m_trace_files.size() ) != 0 ) {
+ sc_trace_file** l_trace_files = &m_trace_files[0];
+ int i = size - 1;
+ do {
+ l_trace_files[i]->cycle( delta_cycle );
+ } while( -- i >= 0 );
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+#if 1
+#ifdef PURIFY
+ static sc_simcontext sc_default_global_context;
+ sc_simcontext* sc_curr_simcontext = &sc_default_global_context;
+#else
+ sc_simcontext* sc_curr_simcontext = 0;
+ sc_simcontext* sc_default_global_context = 0;
+#endif
+#else
+// Not MT-safe!
+static sc_simcontext* sc_curr_simcontext = 0;
+
+
+sc_simcontext*
+sc_get_curr_simcontext()
+{
+ if( sc_curr_simcontext == 0 ) {
+#ifdef PURIFY
+ static sc_simcontext sc_default_global_context;
+ sc_curr_simcontext = &sc_default_global_context;
+#else
+ static sc_simcontext* sc_default_global_context = new sc_simcontext;
+ sc_curr_simcontext = sc_default_global_context;
+#endif
+ }
+ return sc_curr_simcontext;
+}
+#endif // 0
+
+// Generates unique names within each module.
+
+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 );
+ }
+ }
+}
+
+// Get a handle for the current process
+//
+// Note that this method should not be called if the current process is
+// in the act of being deleted, it will mess up the reference count management
+// of sc_process_b instance the handle represents. Instead, use the a
+// pointer to the raw sc_process_b instance, which may be acquired via
+// sc_get_current_process_b().
+
+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();
+}
+
+// THE FOLLOWING FUNCTION IS DEPRECATED IN 2.1
+sc_process_b*
+sc_get_curr_process_handle()
+{
+ static bool warn=true;
+ if ( warn )
+ {
+ warn = false;
+ SC_REPORT_INFO(SC_ID_IEEE_1666_DEPRECATION_,
+ "sc_get_curr_process_handle deprecated use sc_get_current_process_handle"
+ );
+ }
+
+ return sc_get_curr_simcontext()->get_curr_proc_info()->process_handle;
+}
+
+// Return indication if there are more processes to execute in this delta phase
+
+bool
+sc_simcontext::pending_activity_at_current_time() const
+{
+ return ( m_delta_events.size() != 0) ||
+ ( m_runnable->is_initialized() && !m_runnable->is_empty() ) ||
+ m_prim_channel_registry->pending_updates();
+}
+
+// Return time of next activity.
+
+sc_time sc_time_to_pending_activity( const sc_simcontext* simc_p )
+{
+ // If there is an activity pending at the current time
+ // return a delta of zero.
+
+ sc_time result=SC_ZERO_TIME; // time of pending activity.
+
+ if ( simc_p->pending_activity_at_current_time() )
+ {
+ return result;
+ }
+
+ // Any activity will take place in the future pick up the next event's time.
+
+ else
+ {
+ result = simc_p->max_time();
+ simc_p->next_time(result);
+ result -= sc_time_stamp();
+ }
+ return result;
+}
+
+// Set the random seed for controlled randomization -- not yet implemented
+
+void
+sc_set_random_seed( unsigned int )
+{
+ SC_REPORT_WARNING( SC_ID_NOT_IMPLEMENTED_,
+ "void sc_set_random_seed( unsigned int )" );
+}
+
+
+// +----------------------------------------------------------------------------
+// |"sc_start"
+// |
+// | This function starts, or restarts, the execution of the simulator.
+// |
+// | Arguments:
+// | duration = the amount of time the simulator should execute.
+// | p = event starvation policy.
+// +----------------------------------------------------------------------------
+void
+sc_start( const sc_time& duration, sc_starvation_policy p )
+{
+ sc_simcontext* context_p; // current simulation context.
+ sc_time entry_time; // simulation time upon entry.
+ sc_time exit_time; // simulation time to set upon exit.
+ sc_dt::uint64 starting_delta; // delta count upon entry.
+ int status; // current simulation status.
+
+ // Set up based on the arguments passed to us:
+
+ context_p = sc_get_curr_simcontext();
+ starting_delta = sc_delta_count();
+ entry_time = context_p->m_curr_time;
+ if ( p == SC_RUN_TO_TIME )
+ exit_time = context_p->m_curr_time + duration;
+
+ // called with duration = SC_ZERO_TIME for the first time
+ static bool init_delta_or_pending_updates =
+ ( starting_delta == 0 && exit_time == SC_ZERO_TIME );
+
+ // If the simulation status is bad issue the appropriate message:
+
+ status = context_p->sim_status();
+ if( status != SC_SIM_OK )
+ {
+ if ( status == SC_SIM_USER_STOP )
+ SC_REPORT_ERROR(SC_ID_SIMULATION_START_AFTER_STOP_, "");
+ if ( status == SC_SIM_ERROR )
+ SC_REPORT_ERROR(SC_ID_SIMULATION_START_AFTER_ERROR_, "");
+ return;
+ }
+
+ if ( context_p->m_prim_channel_registry->pending_updates() )
+ init_delta_or_pending_updates = true;
+
+ // If the simulation status is good perform the simulation:
+
+ context_p->simulate( duration );
+
+ // Re-check the status:
+
+ status = context_p->sim_status();
+
+ // Update the current time to the exit time if that is the starvation
+ // policy:
+
+ if ( p == SC_RUN_TO_TIME && !context_p->m_paused && status == SC_SIM_OK )
+ {
+ context_p->m_curr_time = exit_time;
+ }
+
+ // If there was no activity and the simulation clock did not move warn
+ // the user, except if we're in a first sc_start(SC_ZERO_TIME) for
+ // initialisation (only) or there have been pending updates:
+
+ if ( !init_delta_or_pending_updates &&
+ starting_delta == sc_delta_count() &&
+ context_p->m_curr_time == entry_time &&
+ status == SC_SIM_OK )
+ {
+ SC_REPORT_WARNING(SC_ID_NO_SC_START_ACTIVITY_, "");
+ }
+
+ // reset init/update flag for subsequent calls
+ init_delta_or_pending_updates = false;
+}
+
+void
+sc_start()
+{
+ sc_start( sc_max_time() - sc_time_stamp(),
+ SC_EXIT_ON_STARVATION );
+}
+
+// for backward compatibility with 1.0
+#if 0
+void
+sc_start( double duration ) // in default time units
+{
+ static bool warn_sc_start=true;
+ if ( warn_sc_start )
+ {
+ warn_sc_start = false;
+ SC_REPORT_INFO(SC_ID_IEEE_1666_DEPRECATION_,
+ "sc_start(double) deprecated, use sc_start(sc_time) or sc_start()");
+ }
+
+ if( duration == -1 ) // simulate forever
+ {
+ sc_start(
+ sc_time(~sc_dt::UINT64_ZERO, false) - sc_time_stamp() );
+ }
+ else
+ {
+ sc_start( sc_time( duration, true ) );
+ }
+}
+#endif //
+
+void
+sc_stop()
+{
+ sc_get_curr_simcontext()->stop();
+}
+
+
+// The following function is deprecated in favor of sc_start(SC_ZERO_TIME):
+
+void
+sc_initialize()
+{
+ static bool warning_initialize = true;
+
+ if ( warning_initialize )
+ {
+ warning_initialize = false;
+ SC_REPORT_INFO(SC_ID_IEEE_1666_DEPRECATION_,
+ "sc_initialize() is deprecated: use sc_start(SC_ZERO_TIME)" );
+ }
+ sc_get_curr_simcontext()->initialize();
+}
+
+// The following function has been deprecated in favor of sc_start(duration):
+
+void
+sc_cycle( const sc_time& duration )
+{
+ static bool warning_cycle = true;
+
+ if ( warning_cycle )
+ {
+ warning_cycle = false;
+ SC_REPORT_INFO(SC_ID_IEEE_1666_DEPRECATION_,
+ "sc_cycle is deprecated: use sc_start(sc_time)" );
+ }
+ sc_get_curr_simcontext()->cycle( duration );
+}
+
+sc_event* sc_find_event( const char* name )
+{
+ return sc_get_curr_simcontext()->get_object_manager()->find_event( name );
+}
+
+sc_object* sc_find_object( const char* name )
+{
+ return sc_get_curr_simcontext()->get_object_manager()->find_object( name );
+}
+
+
+const sc_time&
+sc_max_time()
+{
+ return sc_get_curr_simcontext()->max_time();
+}
+
+const sc_time&
+sc_time_stamp()
+{
+ return sc_get_curr_simcontext()->time_stamp();
+}
+
+double
+sc_simulation_time()
+{
+ static bool warn_simulation_time=true;
+ if ( warn_simulation_time )
+ {
+ warn_simulation_time=false;
+ SC_REPORT_INFO(SC_ID_IEEE_1666_DEPRECATION_,
+ "sc_simulation_time() is deprecated use sc_time_stamp()" );
+ }
+ return sc_get_curr_simcontext()->time_stamp().to_default_time_units();
+}
+
+void
+sc_defunct_process_function( sc_module* )
+{
+ // This function is pointed to by defunct sc_thread_process'es and
+ // sc_cthread_process'es. In a correctly constructed world, this
+ // function should never be called; hence the assert.
+ assert( false );
+}
+
+//------------------------------------------------------------------------------
+//"sc_set_stop_mode"
+//
+// This function sets the mode of operation when sc_stop() is called.
+// mode = SC_STOP_IMMEDIATE or SC_STOP_FINISH_DELTA.
+//------------------------------------------------------------------------------
+void sc_set_stop_mode(sc_stop_mode mode)
+{
+ if ( sc_is_running() )
+ {
+ SC_REPORT_ERROR(SC_ID_STOP_MODE_AFTER_START_,"");
+ }
+ else
+ {
+ switch( mode )
+ {
+ case SC_STOP_IMMEDIATE:
+ case SC_STOP_FINISH_DELTA:
+ stop_mode = mode;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+sc_stop_mode
+sc_get_stop_mode()
+{
+ return stop_mode;
+}
+
+bool sc_is_unwinding()
+{
+ return sc_get_current_process_handle().is_unwinding();
+}
+
+// The IEEE 1666 Standard for 2011 designates that the treatment of
+// certain process control interactions as being "implementation dependent".
+// These interactions are:
+// (1) What happens when a resume() call is performed on a disabled,
+// suspended process.
+// (2) What happens when sync_reset_on() or sync_reset_off() is called
+// on a suspended process.
+// (3) What happens when the value specified in a reset_signal_is()
+// call changes value while a process is suspended.
+//
+// By default this Proof of Concept implementation reports an error
+// for these interactions. However, the implementation also provides
+// a non-error treatment. The non-error treatment for the interactions is:
+// (1) A resume() call performed on a disabled, suspended process will
+// mark the process as no longer suspended, and if it is capable
+// of execution (not waiting on any events) it will be placed on
+// the queue of runnable processes. See the state diagram below.
+// (2) A call to sync_reset_on() or sync_reset_off() will set or clear
+// the synchronous reset flag. Whether the process is in reset or
+// not will be determined when the process actually executes by
+// looking at the flag's value at that time.
+// (3) If a suspended process has a reset_signal_is() specification
+// the value of the reset variable at the time of its next execution
+// will determine whether it is in reset or not.
+//
+// TO GET THE NON-ERROR BEHAVIOR SET THE VARIABLE BELOW TO TRUE.
+//
+// This can be done in this source before you build the library, or you
+// can use an assignment as the first statement in your sc_main() function:
+// sc_core::sc_allow_process_control_corners = true;
+
+bool sc_allow_process_control_corners = false;
+
+// The state transition diagram for the interaction of disable and suspend
+// when sc_allow_process_control_corners is true is shown below:
+//
+// ......................................................................
+// . ENABLED . DISABLED .
+// . . .
+// . +----------+ disable +----------+ .
+// . +------------>| |-------.-------->| | .
+// . | | runnable | . | runnable | .
+// . | +-------| |<------.---------| |------+ .
+// . | | +----------+ enable +----------+ | .
+// . | | | ^ . | ^ | .
+// . | | suspend | | resume . suspend | | resume | .
+// . | | V | . V | | .
+// . | | +----------+ disable +----------+ | .
+// . | | | suspend |-------.-------->| suspend | | .
+// . t | r | | | . | | | r .
+// . r | u | | ready |<------.---------| ready | | u .
+// . i | n | +----------+ enable +----------+ | n .
+// . g | / | ^ . | / .
+// . g | w | trigger| . | w .
+// . e | a | | . | a .
+// . r | i | +----------+ disable +----------+ | i .
+// . | t | | suspend |-------.-------->| suspend | | t .
+// . | | | | . | | | .
+// . | | | waiting |<------.---------| waiting | | .
+// . | | +----------+ enable +----------+ | .
+// . | | | ^ . | ^ | .
+// . | | suspend | | resume . suspend | | resume | .
+// . | | V | . V | | .
+// . | | +----------+ disable +----------+ | .
+// . | +------>| |-------.-------->| | | .
+// . | | waiting | . | waiting | | .
+// . +-------------| |<------.---------| |<-----+ .
+// . +----------+ enable +----------+ .
+// . . .
+// ......................................................................
+
+// ----------------------------------------------------------------------------
+
+static std::ostream&
+print_status_expression( std::ostream& os, sc_status s );
+
+// utility helper to print a simulation status
+std::ostream& operator << ( std::ostream& os, sc_status s )
+{
+ // print primitive values
+ switch(s)
+ {
+# define PRINT_STATUS( Status ) \
+ case Status: { os << #Status; } break
+
+ PRINT_STATUS( SC_UNITIALIZED );
+ PRINT_STATUS( SC_ELABORATION );
+ PRINT_STATUS( SC_BEFORE_END_OF_ELABORATION );
+ PRINT_STATUS( SC_END_OF_ELABORATION );
+ PRINT_STATUS( SC_START_OF_SIMULATION );
+
+ PRINT_STATUS( SC_RUNNING );
+ PRINT_STATUS( SC_PAUSED );
+ PRINT_STATUS( SC_STOPPED );
+ PRINT_STATUS( SC_END_OF_SIMULATION );
+
+ PRINT_STATUS( SC_END_OF_INITIALIZATION );
+// PRINT_STATUS( SC_END_OF_EVALUATION );
+ PRINT_STATUS( SC_END_OF_UPDATE );
+ PRINT_STATUS( SC_BEFORE_TIMESTEP );
+
+ PRINT_STATUS( SC_STATUS_ANY );
+
+# undef PRINT_STATUS
+ default:
+
+ if( s & SC_STATUS_ANY ) // combination of status bits
+ print_status_expression( os, s );
+ else // invalid number, print hex value
+ os << "0x" << std::hex << +s;
+ }
+
+ return os;
+}
+
+// pretty-print a combination of sc_status bits (i.e. a callback mask)
+static std::ostream&
+print_status_expression( std::ostream& os, sc_status s )
+{
+ std::vector<sc_status> bits;
+ unsigned is_set = SC_ELABORATION;
+
+ // collect bits
+ while( is_set <= SC_STATUS_LAST )
+ {
+ if( s & is_set )
+ bits.push_back( (sc_status)is_set );
+ is_set <<= 1;
+ }
+ if( s & ~SC_STATUS_ANY ) // remaining bits
+ bits.push_back( (sc_status)( s & ~SC_STATUS_ANY ) );
+
+ // print expression
+ std::vector<sc_status>::size_type i=0, n=bits.size();
+ if ( n>1 )
+ os << "(";
+ for( ; i<n-1; ++i )
+ os << bits[i] << "|";
+ os << bits[i];
+ if ( n>1 )
+ os << ")";
+ return os;
+}
+
+} // namespace sc_core
+
+/*****************************************************************************
+
+ MODIFICATION LOG - modifiers, enter your name, affiliation, date and
+ changes you are making here.
+
+ Name, Affiliation, Date: Ali Dasdan, Synopsys, Inc.
+ Description of Modification: - Added sc_stop() detection into initial_crunch
+ and crunch. This makes it possible to exit out
+ of a combinational loop using sc_stop().
+
+ Name, Affiliation, Date: Andy Goodrich, Forte Design Systems 20 May 2003
+ Description of Modification: - sc_stop mode
+ - phase callbacks
+
+ Name, Affiliation, Date: Bishnupriya Bhattacharya, Cadence Design Systems,
+ 25 August 2003
+ Description of Modification: - support for dynamic process
+ - support for sc export registry
+ - new member methods elaborate(),
+ prepare_to_simulate(), and initial_crunch()
+ that are invoked by initialize() in that order
+ - implement sc_get_last_created_process_handle() for use
+ before simulation starts
+ - remove "set_curr_proc(handle)" from
+ register_method_process and
+ register_thread_process - led to bugs
+
+ Name, Affiliation, Date: Andy Goodrich, Forte Design Systems 04 Sep 2003
+ Description of Modification: - changed process existence structures to
+ linked lists to eliminate exponential
+ execution problem with using sc_pvector.
+ *****************************************************************************/
+// $Log: sc_simcontext.cpp,v $
+// Revision 1.37 2011/08/29 18:04:32 acg
+// Philipp A. Hartmann: miscellaneous clean ups.
+//
+// Revision 1.36 2011/08/26 20:46:10 acg
+// Andy Goodrich: moved the modification log to the end of the file to
+// eliminate source line number skew when check-ins are done.
+//
+// Revision 1.35 2011/08/24 22:05:51 acg
+// Torsten Maehne: initialization changes to remove warnings.
+//
+// Revision 1.34 2011/08/04 17:15:28 acg
+// Andy Goodrich: added documentation to crunch() routine.
+//
+// Revision 1.32 2011/07/24 11:16:36 acg
+// Philipp A. Hartmann: fix reference counting on deferred deletions of
+// processes.
+//
+// Revision 1.31 2011/07/01 18:49:07 acg
+// Andy Goodrich: moved pln() from sc_simcontext.cpp to sc_ver.cpp.
+//
+// Revision 1.30 2011/05/09 04:07:49 acg
+// Philipp A. Hartmann:
+// (1) Restore hierarchy in all phase callbacks.
+// (2) Ensure calls to before_end_of_elaboration.
+//
+// Revision 1.29 2011/04/08 22:39:09 acg
+// Andy Goodrich: moved method invocation code to sc_method.h so that the
+// details are hidden from sc_simcontext.
+//
+// Revision 1.28 2011/04/05 20:50:57 acg
+// Andy Goodrich:
+// (1) changes to make sure that event(), posedge() and negedge() only
+// return true if the clock has not moved.
+// (2) fixes for method self-resumes.
+// (3) added SC_PRERELEASE_VERSION
+// (4) removed kernel events from the object hierarchy, added
+// sc_hierarchy_name_exists().
+//
+// Revision 1.27 2011/04/05 06:14:15 acg
+// Andy Goodrich: fix typo.
+//
+// Revision 1.26 2011/04/05 06:03:32 acg
+// Philipp A. Hartmann: added code to set ready to run bit for a suspended
+// process that does not have dont_initialize specified at simulation
+// start up.
+//
+// Revision 1.25 2011/04/01 21:31:55 acg
+// Andy Goodrich: make sure processes suspended before the start of execution
+// don't get scheduled for initial execution.
+//
+// Revision 1.24 2011/03/28 13:02:52 acg
+// Andy Goodrich: Changes for disable() interactions.
+//
+// Revision 1.23 2011/03/12 21:07:51 acg
+// Andy Goodrich: changes to kernel generated event support.
+//
+// Revision 1.22 2011/03/07 17:38:43 acg
+// Andy Goodrich: tightening up of checks for undefined interaction between
+// synchronous reset and suspend.
+//
+// Revision 1.21 2011/03/06 19:57:11 acg
+// Andy Goodrich: refinements for the illegal suspend - synchronous reset
+// interaction.
+//
+// Revision 1.20 2011/03/06 15:58:50 acg
+// Andy Goodrich: added escape to turn off process control corner case
+// checks.
+//
+// Revision 1.19 2011/03/05 04:45:16 acg
+// Andy Goodrich: moved active process calculation to the sc_simcontext class.
+//
+// Revision 1.18 2011/03/05 01:39:21 acg
+// Andy Goodrich: changes for named events.
+//
+// Revision 1.17 2011/02/18 20:27:14 acg
+// Andy Goodrich: Updated Copyrights.
+//
+// Revision 1.16 2011/02/17 19:53:28 acg
+// Andy Goodrich: eliminated use of ready_to_run() as part of process control
+// simplification.
+//
+// Revision 1.15 2011/02/13 21:47:38 acg
+// Andy Goodrich: update copyright notice.
+//
+// Revision 1.14 2011/02/11 13:25:24 acg
+// Andy Goodrich: Philipp A. Hartmann's changes:
+// (1) Removal of SC_CTHREAD method overloads.
+// (2) New exception processing code.
+//
+// Revision 1.13 2011/02/08 08:42:50 acg
+// Andy Goodrich: fix ordering of check for stopped versus paused.
+//
+// Revision 1.12 2011/02/07 19:17:20 acg
+// Andy Goodrich: changes for IEEE 1666 compatibility.
+//
+// Revision 1.11 2011/02/02 07:18:11 acg
+// Andy Goodrich: removed toggle() calls for the new crunch() toggle usage.
+//
+// Revision 1.10 2011/02/01 23:01:53 acg
+// Andy Goodrich: removed dead code.
+//
+// Revision 1.9 2011/02/01 21:11:59 acg
+// Andy Goodrich:
+// (1) Use of new toggle_methods() and toggle_threads() run queue methods
+// to make sure the thread run queue does not execute when allow preempt_me()
+// is called from an SC_METHOD.
+// (2) Use of execute_thread_next() to allow thread execution in the current
+// delta cycle() rather than push_runnable_thread_front which executed
+// in the following cycle.
+//
+// Revision 1.8 2011/01/25 20:50:37 acg
+// Andy Goodrich: changes for IEEE 1666 2011.
+//
+// Revision 1.7 2011/01/19 23:21:50 acg
+// Andy Goodrich: changes for IEEE 1666 2011
+//
+// Revision 1.6 2011/01/18 20:10:45 acg
+// Andy Goodrich: changes for IEEE1666_2011 semantics.
+//
+// Revision 1.5 2010/11/20 17:10:57 acg
+// Andy Goodrich: reset processing changes for new IEEE 1666 standard.
+//
+// Revision 1.4 2010/07/22 20:02:33 acg
+// Andy Goodrich: bug fixes.
+//
+// Revision 1.3 2008/05/22 17:06:26 acg
+// Andy Goodrich: updated copyright notice to include 2008.
+//
+// Revision 1.2 2007/09/20 20:32:35 acg
+// Andy Goodrich: changes to the semantics of throw_it() to match the
+// specification. A call to throw_it() will immediately suspend the calling
+// thread until all the throwees have executed. At that point the calling
+// thread will be restarted before the execution of any other threads.
+//
+// Revision 1.1.1.1 2006/12/15 20:20:05 acg
+// SystemC 2.3
+//
+// Revision 1.21 2006/08/29 23:37:13 acg
+// Andy Goodrich: Added check for negative time.
+//
+// Revision 1.20 2006/05/26 20:33:16 acg
+// Andy Goodrich: changes required by additional platform compilers (i.e.,
+// Microsoft VC++, Sun Forte, HP aCC).
+//
+// Revision 1.19 2006/05/08 17:59:52 acg
+// Andy Goodrich: added a check before m_curr_time is set to make sure it
+// is not set to a time before its current value. This will treat
+// sc_event.notify( ) calls with negative times as calls with a zero time.
+//
+// Revision 1.18 2006/04/20 17:08:17 acg
+// Andy Goodrich: 3.0 style process changes.
+//
+// Revision 1.17 2006/04/11 23:13:21 acg
+// Andy Goodrich: Changes for reduced reset support that only includes
+// sc_cthread, but has preliminary hooks for expanding to method and thread
+// processes also.
+//
+// Revision 1.16 2006/03/21 00:00:34 acg
+// Andy Goodrich: changed name of sc_get_current_process_base() to be
+// sc_get_current_process_b() since its returning an sc_process_b instance.
+//
+// Revision 1.15 2006/03/13 20:26:50 acg
+// Andy Goodrich: Addition of forward class declarations, e.g.,
+// sc_reset, to keep gcc 4.x happy.
+//
+// Revision 1.14 2006/02/02 23:42:41 acg
+// Andy Goodrich: implemented a much better fix to the sc_event_finder
+// proliferation problem. This new version allocates only a single event
+// finder for each port for each type of event, e.g., pos(), neg(), and
+// value_change(). The event finder persists as long as the port does,
+// which is what the LRM dictates. Because only a single instance is
+// allocated for each event type per port there is not a potential
+// explosion of storage as was true in the 2.0.1/2.1 versions.
+//
+// Revision 1.13 2006/02/02 21:29:10 acg
+// Andy Goodrich: removed the call to sc_event_finder::free_instances() that
+// was in end_of_elaboration(), leaving only the call in clean(). This is
+// because the LRM states that sc_event_finder instances are persistent as
+// long as the sc_module hierarchy is valid.
+//
+// Revision 1.12 2006/02/02 21:09:50 acg
+// Andy Goodrich: added call to sc_event_finder::free_instances in the clean()
+// method.
+//
+// Revision 1.11 2006/02/02 20:43:14 acg
+// Andy Goodrich: Added an existence linked list to sc_event_finder so that
+// the dynamically allocated instances can be freed after port binding
+// completes. This replaces the individual deletions in ~sc_bind_ef, as these
+// caused an exception if an sc_event_finder instance was used more than
+// once, due to a double freeing of the instance.
+//
+// Revision 1.10 2006/01/31 21:43:26 acg
+// Andy Goodrich: added comments in constructor to highlight environmental
+// overrides section.
+//
+// Revision 1.9 2006/01/26 21:04:54 acg
+// Andy Goodrich: deprecation message changes and additional messages.
+//
+// Revision 1.8 2006/01/25 00:31:19 acg
+// Andy Goodrich: Changed over to use a standard message id of
+// SC_ID_IEEE_1666_DEPRECATION for all deprecation messages.
+//
+// Revision 1.7 2006/01/24 20:49:05 acg
+// Andy Goodrich: changes to remove the use of deprecated features within the
+// simulator, and to issue warning messages when deprecated features are used.
+//
+// Revision 1.6 2006/01/19 00:29:52 acg
+// Andy Goodrich: Yet another implementation for signal write checking. This
+// one uses an environment variable SC_SIGNAL_WRITE_CHECK, that when set to
+// DISABLE will disable write checking on signals.
+//
+// Revision 1.5 2006/01/13 18:44:30 acg
+// Added $Log to record CVS changes into the source.
+//
+// Revision 1.4 2006/01/03 23:18:44 acg
+// Changed copyright to include 2006.
+//
+// Revision 1.3 2005/12/20 22:11:10 acg
+// Fixed $Log lines.
+//
+// Revision 1.2 2005/12/20 22:02:30 acg
+// Changed where delta cycles are incremented to match IEEE 1666. Added the
+// event_occurred() method to hide how delta cycle comparisions are done within
+// sc_simcontext. Changed the boolean update_phase to an enum that shows all
+// the phases.
+// Taf!