1/*****************************************************************************
2
3  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
4  more contributor license agreements.  See the NOTICE file distributed
5  with this work for additional information regarding copyright ownership.
6  Accellera licenses this file to you under the Apache License, Version 2.0
7  (the "License"); you may not use this file except in compliance with the
8  License.  You may obtain a copy of the License at
9
10    http://www.apache.org/licenses/LICENSE-2.0
11
12  Unless required by applicable law or agreed to in writing, software
13  distributed under the License is distributed on an "AS IS" BASIS,
14  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
15  implied.  See the License for the specific language governing
16  permissions and limitations under the License.
17
18 *****************************************************************************/
19
20/*****************************************************************************
21
22  sc_thread_process.h -- Thread process declarations
23
24  Original Author: Andy Goodrich, Forte Design Systems, 4 August 2005
25
26
27  CHANGE LOG AT THE END OF THE FILE
28 *****************************************************************************/
29
30
31#if !defined(sc_thread_process_h_INCLUDED)
32#define sc_thread_process_h_INCLUDED
33
34#include "sysc/kernel/sc_spawn_options.h"
35#include "sysc/kernel/sc_process.h"
36#include "sysc/kernel/sc_cor.h"
37#include "sysc/kernel/sc_event.h"
38#include "sysc/kernel/sc_except.h"
39#include "sysc/kernel/sc_reset.h"
40
41// DEBUGGING MACROS:
42//
43// DEBUG_MSG(NAME,P,MSG)
44//     MSG  = message to print
45//     NAME = name that must match the process for the message to print, or
46//            null if the message should be printed unconditionally.
47//     P    = pointer to process message is for, or NULL in which case the
48//            message will not print.
49#if 0
50#   define DEBUG_NAME ""
51#   define DEBUG_MSG(NAME,P,MSG) \
52    { \
53        if ( P && ( (strlen(NAME)==0) || !strcmp(NAME,P->name())) ) \
54          std::cout << "**** " << sc_time_stamp() << " ("  \
55	            << sc_get_current_process_name() << "): " << MSG \
56		    << " - " << P->name() << std::endl; \
57    }
58#else
59#   define DEBUG_MSG(NAME,P,MSG)
60#endif
61
62
63namespace sc_core {
64
65// forward references:
66class sc_event_and_list;
67class sc_event_or_list;
68class sc_reset;
69void sc_thread_cor_fn( void* );
70void sc_set_stack_size( sc_thread_handle, std::size_t );
71class sc_event;
72class sc_join;
73class sc_module;
74class sc_process_handle;
75class sc_process_table;
76class sc_simcontext;
77class sc_runnable;
78
79sc_cor* get_cor_pointer( sc_process_b* process_p );
80void sc_set_stack_size( sc_thread_handle thread_h, std::size_t size );
81void wait( sc_simcontext* );
82void wait( const sc_event&, sc_simcontext* );
83void wait( const sc_event_or_list&, sc_simcontext* );
84void wait( const sc_event_and_list&, sc_simcontext* );
85void wait( const sc_time&, sc_simcontext* );
86void wait( const sc_time&, const sc_event&, sc_simcontext* );
87void wait( const sc_time&, const sc_event_or_list&, sc_simcontext* );
88void wait( const sc_time&, const sc_event_and_list&, sc_simcontext* );
89
90//==============================================================================
91// sc_thread_process -
92//
93//==============================================================================
94class sc_thread_process : public sc_process_b {
95    friend void sc_thread_cor_fn( void* );
96    friend void sc_set_stack_size( sc_thread_handle, std::size_t );
97    friend class sc_event;
98    friend class sc_join;
99    friend class sc_module;
100    friend class sc_process_b;
101    friend class sc_process_handle;
102    friend class sc_process_table;
103    friend class sc_simcontext;
104    friend class sc_runnable;
105    friend sc_cor* get_cor_pointer( sc_process_b* process_p );
106
107    friend void wait( sc_simcontext* );
108    friend void wait( const sc_event&, sc_simcontext* );
109    friend void wait( const sc_event_or_list&, sc_simcontext* );
110    friend void wait( const sc_event_and_list&, sc_simcontext* );
111    friend void wait( const sc_time&, sc_simcontext* );
112    friend void wait( const sc_time&, const sc_event&, sc_simcontext* );
113    friend void wait( const sc_time&, const sc_event_or_list&, sc_simcontext* );
114    friend void wait( const sc_time&, const sc_event_and_list&, sc_simcontext*);
115  public:
116    sc_thread_process( const char* name_p, bool free_host,
117        SC_ENTRY_FUNC method_p, sc_process_host* host_p,
118        const sc_spawn_options* opt_p );
119
120    virtual const char* kind() const
121        { return "sc_thread_process"; }
122
123  protected:
124    // may not be deleted manually (called from sc_process_b)
125    virtual ~sc_thread_process();
126
127    virtual void disable_process(
128        sc_descendant_inclusion_info descendants = SC_NO_DESCENDANTS );
129    virtual void enable_process(
130        sc_descendant_inclusion_info descendants = SC_NO_DESCENDANTS );
131    virtual void kill_process(
132        sc_descendant_inclusion_info descendants = SC_NO_DESCENDANTS );
133    sc_thread_handle next_exist();
134    sc_thread_handle next_runnable();
135    virtual void prepare_for_simulation();
136    virtual void resume_process(
137        sc_descendant_inclusion_info descendants = SC_NO_DESCENDANTS );
138    void set_next_exist( sc_thread_handle next_p );
139    void set_next_runnable( sc_thread_handle next_p );
140
141    void set_stack_size( std::size_t size );
142    inline void suspend_me();
143    virtual void suspend_process(
144        sc_descendant_inclusion_info descendants = SC_NO_DESCENDANTS );
145    virtual void throw_reset( bool async );
146    virtual void throw_user( const sc_throw_it_helper& helper,
147        sc_descendant_inclusion_info descendants = SC_NO_DESCENDANTS );
148
149    bool trigger_dynamic( sc_event* );
150    inline void trigger_static();
151
152    void wait( const sc_event& );
153    void wait( const sc_event_or_list& );
154    void wait( const sc_event_and_list& );
155    void wait( const sc_time& );
156    void wait( const sc_time&, const sc_event& );
157    void wait( const sc_time&, const sc_event_or_list& );
158    void wait( const sc_time&, const sc_event_and_list& );
159    void wait_cycles( int n=1 );
160
161  protected:
162    void add_monitor( sc_process_monitor* monitor_p );
163    void remove_monitor( sc_process_monitor* monitor_p);
164    void signal_monitors( int type = 0 );
165
166  protected:
167    sc_cor*                          m_cor_p;        // Thread's coroutine.
168    std::vector<sc_process_monitor*> m_monitor_q;    // Thread monitors.
169    std::size_t                      m_stack_size;   // Thread stack size.
170    int                              m_wait_cycle_n; // # of waits to be done.
171
172  private: // disabled
173    sc_thread_process( const sc_thread_process& );
174    const sc_thread_process& operator = ( const sc_thread_process& );
175
176};
177
178//------------------------------------------------------------------------------
179//"sc_thread_process::set_stack_size"
180//
181//------------------------------------------------------------------------------
182inline void sc_thread_process::set_stack_size( std::size_t size )
183{
184    assert( size );
185    m_stack_size = size;
186}
187
188//------------------------------------------------------------------------------
189//"sc_thread_process::suspend_me"
190//
191// This method suspends this object instance in favor of the next runnable
192// process. Upon awakening we check to see if an exception should be thrown.
193// There are two types of exceptions that can be thrown, synchronous reset
194// and asynchronous reset. At a future time there may be more asynchronous
195// exceptions.  If an asynchronous reset is seen and there is not static reset
196// specified, or the static reset is not active then clear the throw
197// type for the next time this method is called.
198//
199// Notes:
200//   (1) For an explanation of how the reset mechanism works see the top of
201//       the file sc_reset.cpp.
202//   (2) The m_sticky_reset field is used to handle synchronous resets that
203//       are enabled via the sc_process_handle::sync_reset_on() method. These
204//       resets are not generated by a signal, but rather are modal by
205//       method call: sync_reset_on() - sync_reset_off().
206//------------------------------------------------------------------------------
207inline void sc_thread_process::suspend_me()
208{
209    // remember, if we're currently unwinding
210
211    bool unwinding_preempted = m_unwinding;
212
213    sc_simcontext* simc_p = simcontext();
214    sc_cor*         cor_p = simc_p->next_cor();
215
216    // do not switch, if we're about to execute next (e.g. suicide)
217
218    if( m_cor_p != cor_p )
219    {
220        DEBUG_MSG( DEBUG_NAME , this, "suspending thread");
221        simc_p->cor_pkg()->yield( cor_p );
222        DEBUG_MSG( DEBUG_NAME , this, "resuming thread");
223    }
224
225    // IF THERE IS A THROW TO BE DONE FOR THIS PROCESS DO IT NOW:
226    //
227    // (1) Optimize THROW_NONE for speed as it is the normal case.
228    // (2) If this thread is already unwinding then suspend_me() was
229    //     called from the catch clause to throw an exception on another
230    //     process, so just go back to the catch clause.
231
232    if ( m_throw_status == THROW_NONE ) return;
233
234    if ( m_unwinding ) return;
235
236    switch( m_throw_status )
237    {
238      case THROW_ASYNC_RESET:
239      case THROW_SYNC_RESET:
240        DEBUG_MSG( DEBUG_NAME , this, "throwing reset for");
241	if ( m_reset_event_p ) m_reset_event_p->notify();
242        throw sc_unwind_exception( this, true );
243
244      case THROW_USER:
245        DEBUG_MSG( DEBUG_NAME, this, "invoking throw_it for");
246	m_throw_status = m_active_areset_n ? THROW_ASYNC_RESET :
247	                                  (m_active_reset_n ? THROW_SYNC_RESET :
248			                  THROW_NONE);
249        m_throw_helper_p->throw_it();
250	break;
251
252      case THROW_KILL:
253        DEBUG_MSG( DEBUG_NAME, this, "throwing kill for");
254	throw sc_unwind_exception( this, false );
255
256      default: // THROWING_NOW
257        sc_assert( unwinding_preempted );
258        DEBUG_MSG( DEBUG_NAME, this, "restarting thread");
259        break;
260    }
261}
262
263
264//------------------------------------------------------------------------------
265//"sc_thread_process::wait"
266//
267//------------------------------------------------------------------------------
268inline
269void
270sc_thread_process::wait( const sc_event& e )
271{
272    if( m_unwinding )
273        SC_REPORT_ERROR( SC_ID_WAIT_DURING_UNWINDING_, name() );
274
275    m_event_p = &e; // for cleanup.
276    e.add_dynamic( this );
277    m_trigger_type = EVENT;
278    suspend_me();
279}
280
281inline
282void
283sc_thread_process::wait( const sc_event_or_list& el )
284{
285    if( m_unwinding )
286        SC_REPORT_ERROR( SC_ID_WAIT_DURING_UNWINDING_, name() );
287
288    el.add_dynamic( this );
289    m_event_list_p = &el;
290    m_trigger_type = OR_LIST;
291    suspend_me();
292}
293
294inline
295void
296sc_thread_process::wait( const sc_event_and_list& el )
297{
298    if( m_unwinding )
299        SC_REPORT_ERROR( SC_ID_WAIT_DURING_UNWINDING_, name() );
300
301    el.add_dynamic( this );
302    m_event_list_p = &el;
303    m_event_count = el.size();
304    m_trigger_type = AND_LIST;
305    suspend_me();
306}
307
308inline
309void
310sc_thread_process::wait( const sc_time& t )
311{
312    if( m_unwinding )
313        SC_REPORT_ERROR( SC_ID_WAIT_DURING_UNWINDING_, name() );
314
315    m_timeout_event_p->notify_internal( t );
316    m_timeout_event_p->add_dynamic( this );
317    m_trigger_type = TIMEOUT;
318    suspend_me();
319}
320
321inline
322void
323sc_thread_process::wait( const sc_time& t, const sc_event& e )
324{
325    if( m_unwinding )
326        SC_REPORT_ERROR( SC_ID_WAIT_DURING_UNWINDING_, name() );
327
328    m_timeout_event_p->notify_internal( t );
329    m_timeout_event_p->add_dynamic( this );
330    e.add_dynamic( this );
331    m_event_p = &e;
332    m_trigger_type = EVENT_TIMEOUT;
333    suspend_me();
334}
335
336inline
337void
338sc_thread_process::wait( const sc_time& t, const sc_event_or_list& el )
339{
340    if( m_unwinding )
341        SC_REPORT_ERROR( SC_ID_WAIT_DURING_UNWINDING_, name() );
342
343    m_timeout_event_p->notify_internal( t );
344    m_timeout_event_p->add_dynamic( this );
345    el.add_dynamic( this );
346    m_event_list_p = &el;
347    m_trigger_type = OR_LIST_TIMEOUT;
348    suspend_me();
349}
350
351inline
352void
353sc_thread_process::wait( const sc_time& t, const sc_event_and_list& el )
354{
355    if( m_unwinding )
356        SC_REPORT_ERROR( SC_ID_WAIT_DURING_UNWINDING_, name() );
357
358    m_timeout_event_p->notify_internal( t );
359    m_timeout_event_p->add_dynamic( this );
360    el.add_dynamic( this );
361    m_event_list_p = &el;
362    m_event_count = el.size();
363    m_trigger_type = AND_LIST_TIMEOUT;
364    suspend_me();
365}
366
367//------------------------------------------------------------------------------
368//"sc_thread_process::wait_cycles"
369//
370// This method suspends this object instance for the specified number of cycles.
371// A cycle is defined as the event the thread is set up to staticly wait on.
372// The field m_wait_cycle_n is set to one less than the number of cycles to
373// be waited for, since the value is tested before being decremented in
374// the simulation kernel.
375//------------------------------------------------------------------------------
376inline
377void
378sc_thread_process::wait_cycles( int n )
379{
380    if( m_unwinding )
381        SC_REPORT_ERROR( SC_ID_WAIT_DURING_UNWINDING_, name() );
382
383    m_wait_cycle_n = n-1;
384    suspend_me();
385}
386
387//------------------------------------------------------------------------------
388//"sc_thread_process::miscellaneous support"
389//
390//------------------------------------------------------------------------------
391inline
392void sc_thread_process::add_monitor(sc_process_monitor* monitor_p)
393{
394    m_monitor_q.push_back(monitor_p);
395}
396
397
398inline
399void sc_thread_process::remove_monitor(sc_process_monitor* monitor_p)
400{
401    int mon_n = m_monitor_q.size();
402
403    for ( int mon_i = 0; mon_i < mon_n; mon_i++ )
404    {
405    if  ( m_monitor_q[mon_i] == monitor_p )
406        {
407            m_monitor_q[mon_i] = m_monitor_q[mon_n-1];
408            m_monitor_q.resize(mon_n-1);
409        }
410    }
411}
412
413inline
414void sc_thread_process::set_next_exist(sc_thread_handle next_p)
415{
416    m_exist_p = next_p;
417}
418
419inline
420sc_thread_handle sc_thread_process::next_exist()
421{
422    return (sc_thread_handle)m_exist_p;
423}
424
425inline
426void sc_thread_process::set_next_runnable(sc_thread_handle next_p)
427{
428    m_runnable_p = next_p;
429}
430
431inline
432sc_thread_handle sc_thread_process::next_runnable()
433{
434    return (sc_thread_handle)m_runnable_p;
435}
436
437inline sc_cor* get_cor_pointer( sc_process_b* process_p )
438{
439    sc_thread_handle thread_p = DCAST<sc_thread_handle>(process_p);
440    return thread_p->m_cor_p;
441}
442
443//------------------------------------------------------------------------------
444//"sc_thread_process::trigger_static"
445//
446// This inline method adds the current thread to the queue of runnable
447// processes, if required.  This is the case if the following criteria
448// are met:
449//   (1) The process is in a runnable state.
450//   (2) The process is not already on the run queue.
451//   (3) The process is expecting a static trigger,
452//       dynamic event waits take priority.
453//   (4) The process' static wait count is zero.
454//
455// If the triggering process is the same process, the trigger is
456// ignored as well, unless SC_ENABLE_IMMEDIATE_SELF_NOTIFICATIONS
457// is defined.
458//------------------------------------------------------------------------------
459inline
460void
461sc_thread_process::trigger_static()
462{
463    // No need to try queueing this thread if one of the following is true:
464    //    (a) its disabled
465    //    (b) its already queued for execution
466    //    (c) its waiting on a dynamic event
467    //    (d) its wait count is not satisfied
468
469    if ( (m_state & ps_bit_disabled) || is_runnable() ||
470          m_trigger_type != STATIC )
471        return;
472
473#if ! defined( SC_ENABLE_IMMEDIATE_SELF_NOTIFICATIONS )
474    if( SC_UNLIKELY_( sc_get_current_process_b() == this ) )
475    {
476        report_immediate_self_notification();
477        return;
478    }
479#endif // SC_ENABLE_IMMEDIATE_SELF_NOTIFICATIONS
480
481    if ( m_wait_cycle_n > 0 )
482    {
483        --m_wait_cycle_n;
484        return;
485    }
486
487    // If we get here then the thread is has satisfied its wait criteria, if
488    // its suspended mark its state as ready to run. If its not suspended then
489    // push it onto the runnable queue.
490
491    if ( m_state & ps_bit_suspended )
492    {
493        m_state = m_state | ps_bit_ready_to_run;
494    }
495    else
496    {
497	simcontext()->push_runnable_thread(this);
498    }
499}
500
501#undef DEBUG_MSG
502#undef DEBUG_NAME
503
504} // namespace sc_core
505
506// $Log: sc_thread_process.h,v $
507// Revision 1.30  2011/08/26 20:46:11  acg
508//  Andy Goodrich: moved the modification log to the end of the file to
509//  eliminate source line number skew when check-ins are done.
510//
511// Revision 1.29  2011/08/24 23:36:12  acg
512//  Andy Goodrich: removed break statements that can never be reached and
513//  which causes warnings in the Greenhills C++ compiler.
514//
515// Revision 1.28  2011/04/14 22:34:27  acg
516//  Andy Goodrich: removed dead code.
517//
518// Revision 1.27  2011/04/13 05:02:18  acg
519//  Andy Goodrich: added missing check to the wake up code in suspend_me()
520//  so that we just return if the call to suspend_me() was issued from a
521//  stack unwinding.
522//
523// Revision 1.26  2011/04/13 02:44:26  acg
524//  Andy Goodrich: added m_unwinding flag in place of THROW_NOW because the
525//  throw status will be set back to THROW_*_RESET if reset is active and
526//  the check for an unwind being complete was expecting THROW_NONE as the
527//  clearing of THROW_NOW.
528//
529// Revision 1.25  2011/04/11 22:05:14  acg
530//  Andy Goodrich: use the DEBUG_NAME macro in DEBUG_MSG invocations.
531//
532// Revision 1.24  2011/04/10 22:12:32  acg
533//  Andy Goodrich: adding debugging macros.
534//
535// Revision 1.23  2011/04/08 22:41:28  acg
536//  Andy Goodrich: added comment pointing to the description of the reset
537//  mechanism in sc_reset.cpp.
538//
539// Revision 1.22  2011/04/08 18:27:33  acg
540//  Andy Goodrich: added check to make sure we don't schedule a running process
541//  because of it issues a notify() it is sensitive to.
542//
543// Revision 1.21  2011/04/05 06:22:38  acg
544//  Andy Goodrich: expanded comment for trigger_static() initial vetting.
545//
546// Revision 1.20  2011/04/01 21:24:57  acg
547//  Andy Goodrich: removed unused code.
548//
549// Revision 1.19  2011/02/19 08:30:53  acg
550//  Andy Goodrich: Moved process queueing into trigger_static from
551//  sc_event::notify.
552//
553// Revision 1.18  2011/02/18 20:27:14  acg
554//  Andy Goodrich: Updated Copyrights.
555//
556// Revision 1.17  2011/02/17 19:55:58  acg
557//  Andy Goodrich:
558//    (1) Changed signature of trigger_dynamic() back to a bool.
559//    (2) Simplified process control usage.
560//    (3) Changed trigger_static() to recognize process controls and to
561//        do the down-count on wait(N), allowing the elimination of
562//        ready_to_run().
563//
564// Revision 1.16  2011/02/16 22:37:31  acg
565//  Andy Goodrich: clean up to remove need for ps_disable_pending.
566//
567// Revision 1.15  2011/02/13 21:47:38  acg
568//  Andy Goodrich: update copyright notice.
569//
570// Revision 1.14  2011/02/13 21:35:54  acg
571//  Andy Goodrich: added error for performing a wait() during unwinding.
572//
573// Revision 1.13  2011/02/11 13:25:24  acg
574//  Andy Goodrich: Philipp A. Hartmann's changes:
575//    (1) Removal of SC_CTHREAD method overloads.
576//    (2) New exception processing code.
577//
578// Revision 1.12  2011/02/01 23:01:53  acg
579//  Andy Goodrich: removed dead code.
580//
581// Revision 1.11  2011/02/01 21:18:01  acg
582//  Andy Goodrich:
583//  (1) Changes in throw processing for new process control rules.
584//  (2) Support of new process_state enum values.
585//
586// Revision 1.10  2011/01/25 20:50:37  acg
587//  Andy Goodrich: changes for IEEE 1666 2011.
588//
589// Revision 1.9  2011/01/19 23:21:50  acg
590//  Andy Goodrich: changes for IEEE 1666 2011
591//
592// Revision 1.8  2011/01/18 20:10:45  acg
593//  Andy Goodrich: changes for IEEE1666_2011 semantics.
594//
595// Revision 1.7  2011/01/06 17:59:58  acg
596//  Andy Goodrich: removed debugging output.
597//
598// Revision 1.6  2010/07/22 20:02:33  acg
599//  Andy Goodrich: bug fixes.
600//
601// Revision 1.5  2009/07/28 01:10:53  acg
602//  Andy Goodrich: updates for 2.3 release candidate.
603//
604// Revision 1.4  2009/05/22 16:06:29  acg
605//  Andy Goodrich: process control updates.
606//
607// Revision 1.3  2009/03/12 22:59:58  acg
608//  Andy Goodrich: updates for 2.4 stuff.
609//
610// Revision 1.2  2008/05/22 17:06:06  acg
611//  Andy Goodrich: formatting and comments.
612//
613// Revision 1.1.1.1  2006/12/15 20:20:05  acg
614// SystemC 2.3
615//
616// Revision 1.7  2006/05/08 17:57:13  acg
617//  Andy Goodrich: Added David Long's forward declarations for friend functions
618//  to keep the Microsoft C++ compiler happy.
619//
620// Revision 1.6  2006/04/20 17:08:17  acg
621//  Andy Goodrich: 3.0 style process changes.
622//
623// Revision 1.5  2006/04/11 23:13:21  acg
624//   Andy Goodrich: Changes for reduced reset support that only includes
625//   sc_cthread, but has preliminary hooks for expanding to method and thread
626//   processes also.
627//
628// Revision 1.4  2006/01/24 20:49:05  acg
629// Andy Goodrich: changes to remove the use of deprecated features within the
630// simulator, and to issue warning messages when deprecated features are used.
631//
632// Revision 1.3  2006/01/13 18:44:30  acg
633// Added $Log to record CVS changes into the source.
634
635#endif // !defined(sc_thread_process_h_INCLUDED)
636