| /***************************************************************************** |
| |
| 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_runnable_int.h -- For inline definitions of some utility functions. |
| DO NOT EXPORT THIS INCLUDE FILE. Include this file |
| after "sc_process_int.h" so that we can get the base |
| class right. |
| |
| Original Author: Bishnupriya Bhattacharya , Cadence Design, 28th July, 2003 |
| |
| CHANGE LOG AT THE END OF THE FILE |
| ******************************************************************************/ |
| |
| #ifndef SC_RUNNABLE_INT_H |
| #define SC_RUNNABLE_INT_H |
| |
| |
| #include "sysc/kernel/sc_runnable.h" |
| #include "sysc/kernel/sc_method_process.h" |
| #include "sysc/kernel/sc_thread_process.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 |
| |
| namespace sc_core { |
| |
| // The values below are used to indicate when a queue is empty. A non-zero |
| // non-legal pointer value is used for this so that a zero value in the |
| // m_execute_p field of an sc_process_b instance can be used to indicate |
| // that is has not been queued for run. (If we did not use a non-zero |
| // queue empty indicator then a sc_process_b instance that was queued |
| // twice in a row might end up on the queue twice if it were the first |
| // one that was queued!) |
| |
| #define SC_NO_METHODS ((sc_method_handle)0xdb) |
| #define SC_NO_THREADS ((sc_thread_handle)0xdb) |
| |
| |
| //------------------------------------------------------------------------------ |
| //"sc_runnable::dump" |
| // |
| // This method dumps the contents of this object instance. |
| //------------------------------------------------------------------------------ |
| inline void sc_runnable::dump() const |
| { |
| // Dump the thread queues: |
| |
| std::cout << "thread pop queue: " << std::endl; |
| for ( sc_thread_handle p = m_threads_pop; p != SC_NO_THREADS; |
| p = p->next_runnable() ) |
| { |
| std::cout << " " << p << std::endl; |
| } |
| |
| std::cout << "thread push queue: " << std::endl; |
| for ( sc_thread_handle p = m_threads_push_head->next_runnable(); |
| p != SC_NO_THREADS; p = p->next_runnable() ) |
| { |
| std::cout << " " << p << std::endl; |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| //"sc_runnable::execute_method_next" |
| // |
| // This method pushes the the supplied method to execute as the next process. |
| // This is done by pushing it onto the front of the m_methods_pop. |
| // method_h -> method process to add to the queue. |
| //------------------------------------------------------------------------------ |
| inline void sc_runnable::execute_method_next( sc_method_handle method_h ) |
| { |
| DEBUG_MSG(DEBUG_NAME,method_h,"pushing this method to execute next"); |
| method_h->set_next_runnable( m_methods_pop ); |
| m_methods_pop = method_h; |
| } |
| |
| //------------------------------------------------------------------------------ |
| //"sc_runnable::execute_thread_next" |
| // |
| // This method pushes the the supplied thread to execute as the next process. |
| // This is done by pushing it onto the front of the m_threads_pop. |
| // thread_h -> thread process to add to the queue. |
| //------------------------------------------------------------------------------ |
| inline void sc_runnable::execute_thread_next( sc_thread_handle thread_h ) |
| { |
| DEBUG_MSG(DEBUG_NAME,thread_h,"pushing this thread to execute next"); |
| thread_h->set_next_runnable( m_threads_pop ); |
| m_threads_pop = thread_h; |
| } |
| |
| //------------------------------------------------------------------------------ |
| //"sc_runnable::init" |
| // |
| // This method initializes this object instance. Note we allocate the queue |
| // heads if necessary. This is done here rather than in the constructor for |
| // this class to eliminate CTOR processing errors with gcc. |
| //------------------------------------------------------------------------------ |
| inline void sc_runnable::init() |
| { |
| m_methods_pop = SC_NO_METHODS; |
| if ( !m_methods_push_head ) |
| { |
| m_methods_push_head = new sc_method_process("methods_push_head", true, |
| (SC_ENTRY_FUNC)0, 0, 0); |
| m_methods_push_head->dont_initialize(true); |
| m_methods_push_head->detach(); |
| } |
| m_methods_push_tail = m_methods_push_head; |
| m_methods_push_head->set_next_runnable(SC_NO_METHODS); |
| |
| m_threads_pop = SC_NO_THREADS; |
| if ( !m_threads_push_head ) |
| { |
| m_threads_push_head = new sc_thread_process("threads_push_head", true, |
| (SC_ENTRY_FUNC)0, 0, 0); |
| m_threads_push_head->dont_initialize(true); |
| m_threads_push_head->detach(); |
| } |
| m_threads_push_head->set_next_runnable(SC_NO_THREADS); |
| m_threads_push_tail = m_threads_push_head; |
| } |
| |
| |
| //------------------------------------------------------------------------------ |
| //"sc_runnable::is_empty" |
| // |
| // This method returns true if the push queue is empty, or false if not. |
| //------------------------------------------------------------------------------ |
| inline bool sc_runnable::is_empty() const |
| { |
| return m_methods_push_head->next_runnable() == SC_NO_METHODS && |
| m_methods_pop == SC_NO_METHODS && |
| m_threads_push_head->next_runnable() == SC_NO_THREADS && |
| m_threads_pop == SC_NO_THREADS; |
| } |
| |
| |
| //------------------------------------------------------------------------------ |
| //"sc_runnable::is_initialized" |
| // |
| // This method returns true if the push queue is already initialized. |
| //------------------------------------------------------------------------------ |
| inline bool sc_runnable::is_initialized() const |
| { |
| return m_methods_push_head && m_threads_push_head; |
| } |
| |
| |
| //------------------------------------------------------------------------------ |
| //"sc_runnable::push_back_method" |
| // |
| // This method pushes the supplied method process onto the back of the queue of |
| // runnable method processes. |
| // method_h -> method process to add to the queue. |
| //------------------------------------------------------------------------------ |
| inline void sc_runnable::push_back_method( sc_method_handle method_h ) |
| { |
| // assert( method_h->next_runnable() == 0 ); // Can't queue twice. |
| DEBUG_MSG(DEBUG_NAME,method_h,"pushing back method"); |
| method_h->set_next_runnable(SC_NO_METHODS); |
| m_methods_push_tail->set_next_runnable(method_h); |
| m_methods_push_tail = method_h; |
| } |
| |
| |
| //------------------------------------------------------------------------------ |
| //"sc_runnable::push_back_thread" |
| // |
| // This method pushes the supplied thread process onto the back of the queue of |
| // runnable thread processes. |
| // thread_h -> thread process to add to the queue. |
| //------------------------------------------------------------------------------ |
| inline void sc_runnable::push_back_thread( sc_thread_handle thread_h ) |
| { |
| // assert( thread_h->next_runnable() == 0 ); // Can't queue twice. |
| DEBUG_MSG(DEBUG_NAME,thread_h,"pushing back thread"); |
| thread_h->set_next_runnable(SC_NO_THREADS); |
| m_threads_push_tail->set_next_runnable(thread_h); |
| m_threads_push_tail = thread_h; |
| } |
| |
| |
| //------------------------------------------------------------------------------ |
| //"sc_runnable::push_front_method" |
| // |
| // This method pushes the supplied method process onto the front of the queue of |
| // runnable method processes. If the queue is empty the process is the tail |
| // also. |
| // method_h -> method process to add to the queue. |
| //------------------------------------------------------------------------------ |
| inline void sc_runnable::push_front_method( sc_method_handle method_h ) |
| { |
| // assert( method_h->next_runnable() == 0 ); // Can't queue twice. |
| DEBUG_MSG(DEBUG_NAME,method_h,"pushing front method"); |
| method_h->set_next_runnable(m_methods_push_head->next_runnable()); |
| if ( m_methods_push_tail == m_methods_push_head ) // Empty queue. |
| { |
| m_methods_push_tail->set_next_runnable(method_h); |
| m_methods_push_tail = method_h; |
| } |
| else // Non-empty queue. |
| { |
| m_methods_push_head->set_next_runnable(method_h); |
| } |
| } |
| |
| |
| //------------------------------------------------------------------------------ |
| //"sc_runnable::push_front_thread" |
| // |
| // This method pushes the supplied thread process onto the front of the queue of |
| // runnable thread processes. If the queue is empty the process is the tail |
| // also. |
| // thread_h -> thread process to add to the queue. |
| //------------------------------------------------------------------------------ |
| inline void sc_runnable::push_front_thread( sc_thread_handle thread_h ) |
| { |
| // assert( thread_h->next_runnable() == 0 ); // Can't queue twice. |
| DEBUG_MSG(DEBUG_NAME,thread_h,"pushing front thread"); |
| thread_h->set_next_runnable(m_threads_push_head->next_runnable()); |
| if ( m_threads_push_tail == m_threads_push_head ) // Empty queue. |
| { |
| m_threads_push_tail->set_next_runnable(thread_h); |
| m_threads_push_tail = thread_h; |
| } |
| else // Non-empty queue. |
| { |
| m_threads_push_head->set_next_runnable(thread_h); |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| //"sc_runnable::pop_method" |
| // |
| // This method pops the next method process to be executed, or returns a null |
| // if no method processes are available for execution. |
| //------------------------------------------------------------------------------ |
| inline sc_method_handle sc_runnable::pop_method() |
| { |
| sc_method_handle result_p; |
| |
| result_p = m_methods_pop; |
| if ( result_p != SC_NO_METHODS ) |
| { |
| m_methods_pop = result_p->next_runnable(); |
| result_p->set_next_runnable(0); |
| } |
| else |
| { |
| result_p = 0; |
| } |
| DEBUG_MSG(DEBUG_NAME,result_p,"popping method"); |
| return result_p; |
| |
| } |
| |
| //------------------------------------------------------------------------------ |
| //"sc_runnable::pop_thread" |
| // |
| // This method pops the next thread process to be executed, or returns a null |
| // if no thread processes are available for execution. |
| //------------------------------------------------------------------------------ |
| inline sc_thread_handle sc_runnable::pop_thread() |
| { |
| sc_thread_handle result_p; |
| |
| result_p = m_threads_pop; |
| if ( result_p != SC_NO_THREADS ) |
| { |
| m_threads_pop = result_p->next_runnable(); |
| result_p->set_next_runnable(0); |
| } |
| else |
| { |
| result_p = 0; |
| } |
| DEBUG_MSG(DEBUG_NAME,result_p,"popping thread for execution"); |
| return result_p; |
| } |
| |
| |
| //------------------------------------------------------------------------------ |
| //"sc_runnable::remove_method" |
| // |
| // This method removes the supplied method process from the push queue if it is |
| // present. Note we clear the method's next pointer so that it may be queued |
| // again. |
| // remove_p -> method process to remove from the run queue. |
| //------------------------------------------------------------------------------ |
| inline void sc_runnable::remove_method( sc_method_handle remove_p ) |
| { |
| sc_method_handle now_p; // Method now checking. |
| sc_method_handle prior_p; // Method prior to now_p. |
| |
| // Don't try to remove things if we have not been initialized. |
| |
| if ( !is_initialized() ) return; |
| |
| // Search the push queue: |
| |
| prior_p = m_methods_push_head; |
| for ( now_p = m_methods_push_head; now_p!= SC_NO_METHODS; |
| now_p = now_p->next_runnable() ) |
| { |
| if ( remove_p == now_p ) |
| { |
| prior_p->set_next_runnable( now_p->next_runnable() ); |
| if (now_p == m_methods_push_tail) { |
| m_methods_push_tail = prior_p; |
| } |
| now_p->set_next_runnable(0); |
| DEBUG_MSG(DEBUG_NAME,now_p,"removing method from push queue"); |
| return; |
| } |
| prior_p = now_p; |
| } |
| |
| // Search the pop queue: |
| |
| prior_p = NULL; |
| for ( now_p = m_methods_pop; now_p != SC_NO_METHODS; |
| now_p = now_p->next_runnable() ) |
| { |
| if ( remove_p == now_p ) |
| { |
| if ( prior_p ) |
| prior_p->set_next_runnable( now_p->next_runnable() ); |
| else |
| m_methods_pop = now_p->next_runnable(); |
| now_p->set_next_runnable(0); |
| DEBUG_MSG(DEBUG_NAME,now_p,"removing method from pop queue"); |
| return; |
| } |
| prior_p = now_p; |
| } |
| } |
| |
| |
| //------------------------------------------------------------------------------ |
| //"sc_runnable::remove_thread" |
| // |
| // This method removes the supplied thread process from the push or pop |
| // queue if it is present. Note we clear the thread's next pointer so that it |
| // may be queued again. |
| // remove_p -> thread process to remove from the run queue. |
| //------------------------------------------------------------------------------ |
| inline void sc_runnable::remove_thread( sc_thread_handle remove_p ) |
| { |
| sc_thread_handle now_p; // Thread now checking. |
| sc_thread_handle prior_p; // Thread prior to now_p. |
| |
| // Don't try to remove things if we have not been initialized. |
| |
| if ( !is_initialized() ) return; |
| |
| // Search the push queue: |
| |
| prior_p = m_threads_push_head; |
| for ( now_p = m_threads_push_head; now_p != SC_NO_THREADS; |
| now_p = now_p->next_runnable() ) |
| { |
| if ( remove_p == now_p ) |
| { |
| prior_p->set_next_runnable( now_p->next_runnable() ); |
| if (now_p == m_threads_push_tail) { |
| m_threads_push_tail = prior_p; |
| } |
| now_p->set_next_runnable(0); |
| DEBUG_MSG(DEBUG_NAME,now_p,"removing thread from push queue"); |
| return; |
| } |
| prior_p = now_p; |
| } |
| |
| // Search the pop queue: |
| |
| prior_p = NULL; |
| for ( now_p = m_threads_pop; now_p != SC_NO_THREADS; |
| now_p = now_p->next_runnable() ) |
| { |
| if ( remove_p == now_p ) |
| { |
| if ( prior_p ) |
| prior_p->set_next_runnable( now_p->next_runnable() ); |
| else |
| m_threads_pop = now_p->next_runnable(); |
| now_p->set_next_runnable(0); |
| DEBUG_MSG(DEBUG_NAME,now_p,"removing thread from pop queue"); |
| return; |
| } |
| prior_p = now_p; |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| //"sc_runnable::sc_runnable" |
| // |
| // This is the object instance constructor for this class. |
| //------------------------------------------------------------------------------ |
| inline sc_runnable::sc_runnable() : |
| m_methods_push_head(0), m_methods_push_tail(0), m_methods_pop(SC_NO_METHODS), |
| m_threads_push_head(0), m_threads_push_tail(0), m_threads_pop(SC_NO_THREADS) |
| {} |
| |
| //------------------------------------------------------------------------------ |
| //"sc_runnable::~sc_runnable" |
| // |
| // This is the object instance destructor for this class. |
| //------------------------------------------------------------------------------ |
| inline sc_runnable::~sc_runnable() |
| { |
| delete m_methods_push_head; |
| delete m_threads_push_head; |
| } |
| |
| |
| //------------------------------------------------------------------------------ |
| //"sc_runnable::toggle_methods" |
| // |
| // This method moves the methods push queue to the pop queue and zeros the push |
| // queue. This will only be done if the pop queue is presently empty. |
| //------------------------------------------------------------------------------ |
| inline void sc_runnable::toggle_methods() |
| { |
| if ( m_methods_pop == SC_NO_METHODS ) |
| { |
| m_methods_pop = m_methods_push_head->next_runnable(); |
| m_methods_push_head->set_next_runnable(SC_NO_METHODS); |
| m_methods_push_tail = m_methods_push_head; |
| } |
| } |
| |
| |
| //------------------------------------------------------------------------------ |
| //"sc_runnable::toggle_threads" |
| // |
| // This method moves the threads push queue to the pop queue and zeros the push |
| // queue. This will only be done if the pop queue is presently empty. |
| //------------------------------------------------------------------------------ |
| inline void sc_runnable::toggle_threads() |
| { |
| if ( m_threads_pop == SC_NO_THREADS ) |
| { |
| m_threads_pop = m_threads_push_head->next_runnable(); |
| m_threads_push_head->set_next_runnable(SC_NO_THREADS); |
| m_threads_push_tail = m_threads_push_head; |
| } |
| } |
| |
| #undef SC_NO_METHODS |
| #undef SC_NO_THREADS |
| #undef DEBUG_MSG |
| |
| } // namespace sc_core |
| |
| |
| /******************************************************************************* |
| |
| MODIFICATION LOG - modifiers, enter your name, affiliation, date and |
| changes you are making here. |
| Andy Goodrich, Forte Design Systems, 2 September 2003 |
| Changed queue heads to instances to eliminate the checks for null heads. |
| |
| ******************************************************************************/ |
| |
| // $Log: sc_runnable_int.h,v $ |
| // Revision 1.19 2011/08/24 22:05:51 acg |
| // Torsten Maehne: initialization changes to remove warnings. |
| // |
| // Revision 1.18 2011/08/07 19:08:04 acg |
| // Andy Goodrich: moved logs to end of file so line number synching works |
| // better between versions. |
| // |
| // Revision 1.17 2011/04/13 02:45:11 acg |
| // Andy Goodrich: eliminated warning message that occurred if the DEBUG_MSG |
| // macro was used. |
| // |
| // Revision 1.16 2011/04/10 22:18:23 acg |
| // Andy Goodrich: debugging message clean up. |
| // |
| // Revision 1.15 2011/04/08 18:26:07 acg |
| // Andy Goodrich: added execute_method_next() to handle method dispatch |
| // for asynchronous notifications that occur outside the evaluation phase. |
| // |
| // Revision 1.14 2011/04/01 21:31:10 acg |
| // Andy Goodrich: turn off diagnostic messages by default. |
| // |
| // Revision 1.13 2011/04/01 21:30:02 acg |
| // Andy Goodrich: inserted conditional displays for queue manipulations. |
| // |
| // Revision 1.12 2011/03/30 00:01:34 acg |
| // Philip A. Hartmann: change break to return in remove_method() to short |
| // circuit the search the way remove_thread() works. |
| // |
| // Revision 1.11 2011/03/28 13:02:52 acg |
| // Andy Goodrich: Changes for disable() interactions. |
| // |
| // Revision 1.10 2011/03/06 15:58:17 acg |
| // Andy Goodrich: formatting changes. |
| // |
| // Revision 1.9 2011/02/18 20:27:14 acg |
| // Andy Goodrich: Updated Copyrights. |
| // |
| // Revision 1.8 2011/02/13 21:47:38 acg |
| // Andy Goodrich: update copyright notice. |
| // |
| // Revision 1.7 2011/02/02 06:37:03 acg |
| // Andy Goodrich: removed toggle() method since it is no longer used. |
| // |
| // Revision 1.6 2011/02/01 21:09:13 acg |
| // Andy Goodrich: addition of toggle_methods() and toggle_threads() calls. |
| // |
| // Revision 1.5 2011/01/25 20:50:37 acg |
| // Andy Goodrich: changes for IEEE 1666 2011. |
| // |
| // Revision 1.4 2010/07/22 20:02:33 acg |
| // Andy Goodrich: bug fixes. |
| // |
| // Revision 1.3 2009/02/28 00:26:58 acg |
| // Andy Goodrich: changed boost name space to sc_boost to allow use with |
| // full boost library applications. |
| // |
| // Revision 1.2 2008/05/22 17:06:26 acg |
| // Andy Goodrich: updated copyright notice to include 2008. |
| // |
| // Revision 1.1.1.1 2006/12/15 20:20:05 acg |
| // SystemC 2.3 |
| // |
| // Revision 1.4 2006/04/20 17:08:17 acg |
| // Andy Goodrich: 3.0 style process changes. |
| // |
| // Revision 1.3 2006/01/13 18:44:30 acg |
| // Added $Log to record CVS changes into the source. |
| // |
| |
| #endif // SC_RUNNABLE_INT_H |
| |
| // Taf! |