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_process_handle.h -- Process access support.
23
24  Original Author: Andy Goodrich, Forte Design Systems, 17 June 2003
25
26
27  CHANGE LOG AT THE END OF THE FILE
28 *****************************************************************************/
29
30// $Log: sc_process_handle.h,v $
31// Revision 1.21  2011/08/26 21:54:04  acg
32//  Torsten Maehne: Simplify use of dynamic_cast<> for initializing m_target.
33//
34// Revision 1.20  2011/08/26 20:46:10  acg
35//  Andy Goodrich: moved the modification log to the end of the file to
36//  eliminate source line number skew when check-ins are done.
37//
38
39#if !defined(sc_process_handle_h_INCLUDED)
40#define sc_process_handle_h_INCLUDED
41
42#include "sysc/kernel/sc_module.h"
43
44namespace sc_core {
45
46// forward operator declarations:
47
48class sc_process_handle;
49bool
50operator == ( const sc_process_handle& left, const sc_process_handle& right );
51bool
52operator != ( const sc_process_handle& left, const sc_process_handle& right );
53bool
54operator < ( const sc_process_handle& left, const sc_process_handle& right );
55
56
57
58//=============================================================================
59// CLASS sc_process_handle
60//
61// This class provides access to an sc_process_b object instance in a
62// manner which allows some persistence after the deletion of the actual
63// process.
64//=============================================================================
65class sc_simcontext;
66class sc_process_handle {
67    typedef sc_process_handle this_type;
68
69    friend bool operator == ( const this_type& left, const this_type& right );
70    friend bool operator != ( const this_type& left, const this_type& right );
71    friend bool operator < ( const this_type& left, const this_type& right );
72    friend class sc_object;
73    friend class sc_join;
74    friend class sc_module;
75    friend class sc_reset;
76    friend class sc_sensitive;
77    friend class sc_sensitive_pos;
78    friend class sc_sensitive_neg;
79    friend class sc_thread_process;
80
81  public:
82    inline sc_process_handle();
83    inline explicit sc_process_handle( sc_object* object_p );
84    inline explicit sc_process_handle( sc_process_b* process_p );
85    inline sc_process_handle( const sc_process_handle& orig );
86    inline ~sc_process_handle();
87    inline sc_process_handle& operator = ( sc_process_handle src );
88    inline void swap( sc_process_handle& other );
89
90  public:
91    inline void disable(
92        sc_descendant_inclusion_info descendants=SC_NO_DESCENDANTS );
93    inline bool dynamic() const;
94    inline void enable(
95        sc_descendant_inclusion_info descendants=SC_NO_DESCENDANTS );
96    inline const std::vector<sc_event*>& get_child_events() const;
97    inline const std::vector<sc_object*>& get_child_objects() const;
98    inline sc_object* get_parent_object() const;
99    inline sc_object* get_process_object() const;
100    inline bool is_unwinding() const;
101    inline void kill(
102        sc_descendant_inclusion_info descendants=SC_NO_DESCENDANTS );
103    inline const char* name() const;
104    inline sc_curr_proc_kind proc_kind() const;
105    inline void reset(
106        sc_descendant_inclusion_info descendants=SC_NO_DESCENDANTS );
107    inline sc_event& reset_event() const;
108    inline void resume(
109        sc_descendant_inclusion_info descendants=SC_NO_DESCENDANTS );
110    inline void suspend(
111        sc_descendant_inclusion_info descendants=SC_NO_DESCENDANTS );
112    inline void sync_reset_off(
113        sc_descendant_inclusion_info descendants=SC_NO_DESCENDANTS );
114    inline void sync_reset_on(
115        sc_descendant_inclusion_info descendants=SC_NO_DESCENDANTS );
116    inline sc_event& terminated_event();
117    inline bool terminated() const;
118    template<typename EXCEPT>
119    inline void throw_it( const EXCEPT& exception,
120        sc_descendant_inclusion_info descendants=SC_NO_DESCENDANTS );
121    inline bool valid() const;
122
123  public: // implementation specific methods:
124    inline std::string dump_state() const;
125
126  protected:
127    inline bool dont_initialize() const
128        { return m_target_p ? m_target_p->dont_initialize() : false; }
129    inline void dont_initialize( bool dont );
130
131  public:
132    operator sc_process_b* ()
133        { return m_target_p; }
134    operator sc_cthread_handle ();
135    operator sc_method_handle ();
136    operator sc_thread_handle ();
137
138  protected:
139    sc_process_b* m_target_p;   // Target for this object instance.
140
141  protected:
142    static std::vector<sc_event*>  empty_event_vector;  // If m_target_p == 0.
143    static std::vector<sc_object*> empty_object_vector; // If m_target_p == 0.
144    static sc_event                non_event;           // If m_target_p == 0.
145};
146
147inline bool operator == (
148    const sc_process_handle& left, const sc_process_handle& right )
149{
150    return (left.m_target_p != 0) && (right.m_target_p != 0) &&
151        (left.m_target_p == right.m_target_p);
152}
153
154inline bool operator != (
155    const sc_process_handle& left, const sc_process_handle& right )
156{
157    return (left.m_target_p == 0) || (right.m_target_p == 0) ||
158        (left.m_target_p != right.m_target_p);
159}
160
161inline bool operator < (
162    const sc_process_handle& left, const sc_process_handle& right )
163{
164    return left.m_target_p < right.m_target_p;
165}
166
167//------------------------------------------------------------------------------
168//"sc_process_handle::sc_process_handle - non-pointer constructor"
169//
170// This version of the object instance constructor for this class creates
171// an object instance whose target needs to be supplied via an assignment.
172//------------------------------------------------------------------------------
173inline sc_process_handle::sc_process_handle() : m_target_p(0)
174{
175}
176
177//------------------------------------------------------------------------------
178//"sc_process_handle::sc_process_handle - pointer constructor"
179//
180// This version of the object instance constructor for this class creates
181// an object instance whose target is the supplied sc_object instance.
182// The supplied sc_object must in fact be an sc_process_b instance.
183//     object_p -> sc_object instance this is handle for.
184//------------------------------------------------------------------------------
185inline sc_process_handle::sc_process_handle( sc_object* object_p ) :
186    m_target_p(DCAST<sc_process_b*>(object_p))
187{
188    if ( m_target_p ) m_target_p->reference_increment();
189}
190
191//------------------------------------------------------------------------------
192//"sc_process_handle::sc_process_handle - pointer constructor"
193//
194// This version of the object instance constructor for this class creates
195// an object instance whose target is the supplied sc_process_b instance.
196// This saves a dynamic cast compared to the sc_object* case.
197//     process_p -> process instance this is handle for.
198//------------------------------------------------------------------------------
199inline sc_process_handle::sc_process_handle( sc_process_b* process_p ) :
200  m_target_p(process_p)
201{
202  if ( m_target_p ) m_target_p->reference_increment();
203}
204
205//------------------------------------------------------------------------------
206//"sc_process_handle::sc_process_handle - copy constructor"
207//
208// This version of the object instance constructor for this class provides
209// the copy constructor for the class. It clones the supplied original
210// handle and increments the references to its target.
211//     orig = sc_process_handle object instance to be copied from.
212//------------------------------------------------------------------------------
213inline sc_process_handle::sc_process_handle( const sc_process_handle& orig ) :
214    m_target_p(orig.m_target_p)
215{
216    if ( m_target_p ) m_target_p->reference_increment();
217}
218
219
220//------------------------------------------------------------------------------
221//"sc_process_handle::operator ="
222//
223// This assignment operator signature is call by value rather than reference.
224// This means that an sc_process_handle instance will be created and the
225// target for that instance will be incremented before the assignment is done.
226// The assignment is done using the swap() method, which simply swaps the
227// targets of 'orig' and this object instance. We don't need to increment
228// the reference count for our new target since that was done when 'orig'
229// was created. Our old target's reference count will be decremented when
230// 'orig' is deleted.
231//     orig = sc_process_handle object instance to be copied from.
232// Result is a reference for this object instance.
233//------------------------------------------------------------------------------
234inline sc_process_handle&
235sc_process_handle::operator = ( sc_process_handle orig )
236{
237    swap( orig );
238    return *this;
239}
240
241
242//------------------------------------------------------------------------------
243//"sc_process_handle::~sc_process_handle"
244//
245// This is the object instance destructor for this class. It decrements
246// the reference count for its target.
247//------------------------------------------------------------------------------
248inline sc_process_handle::~sc_process_handle()
249{
250    if ( m_target_p ) m_target_p->reference_decrement();
251}
252
253//------------------------------------------------------------------------------
254//"sc_process_handle::inline methods"
255//
256// These are short inline methods.
257//------------------------------------------------------------------------------
258
259// disable this object instance's target.
260
261inline void sc_process_handle::disable(sc_descendant_inclusion_info descendants)
262{
263    if ( m_target_p )
264        m_target_p->disable_process(descendants);
265    else
266        SC_REPORT_WARNING( SC_ID_EMPTY_PROCESS_HANDLE_, "disable()");
267}
268
269// call dont_initialize() on this object instance's target.
270
271inline void sc_process_handle::dont_initialize( bool dont )
272{
273    if ( m_target_p )
274        m_target_p->dont_initialize( dont );
275    else
276        SC_REPORT_WARNING( SC_ID_EMPTY_PROCESS_HANDLE_, "dont_initialize()");
277}
278
279// dump the status of this object instance's target:
280
281inline std::string sc_process_handle::dump_state() const
282{
283    return m_target_p ? m_target_p->dump_state() : std::string("NO TARGET");
284}
285
286// return whether this object instance's target is dynamic or not.
287
288inline bool sc_process_handle::dynamic() const
289{
290    return  m_target_p ?  m_target_p->dynamic() : false;
291}
292
293// enable this object instance's target.
294
295inline void sc_process_handle::enable(sc_descendant_inclusion_info descendants)
296{
297    if ( m_target_p )
298        m_target_p->enable_process(descendants);
299    else
300        SC_REPORT_WARNING( SC_ID_EMPTY_PROCESS_HANDLE_, "enable()");
301}
302
303// return the child objects for this object instance's target.
304
305inline
306const std::vector<sc_event*>& sc_process_handle::get_child_events() const
307{
308    return m_target_p ?  m_target_p->get_child_events() : empty_event_vector;
309}
310
311// return the child objects for this object instance's target.
312
313inline
314const std::vector<sc_object*>& sc_process_handle::get_child_objects() const
315{
316    return m_target_p ?  m_target_p->get_child_objects() : empty_object_vector;
317}
318
319// return the parent object for this object instance's target.
320
321inline sc_object* sc_process_handle::get_parent_object() const
322{
323    return m_target_p ?  m_target_p->get_parent_object() : NULL;
324}
325
326// return this object instance's target.
327
328inline sc_object* sc_process_handle::get_process_object() const
329{
330    return m_target_p;
331}
332
333// return whether this object instance is unwinding or not.
334
335inline bool sc_process_handle::is_unwinding() const
336{
337    if ( m_target_p )
338        return m_target_p->is_unwinding();
339    else {
340        SC_REPORT_WARNING( SC_ID_EMPTY_PROCESS_HANDLE_, "is_unwinding()");
341        return false;
342    }
343}
344
345// kill this object instance's target.
346
347inline void sc_process_handle::kill( sc_descendant_inclusion_info descendants )
348{
349    if ( m_target_p )
350        m_target_p->kill_process( descendants );
351    else
352        SC_REPORT_WARNING( SC_ID_EMPTY_PROCESS_HANDLE_, "kill()");
353}
354
355// return the name of this object instance's target.
356
357inline const char* sc_process_handle::name() const
358{
359    return  m_target_p ? m_target_p->name() : "";
360}
361
362// return the process kind for this object instance's target.
363
364inline sc_curr_proc_kind sc_process_handle::proc_kind() const
365{
366    return m_target_p ?  m_target_p->proc_kind() : SC_NO_PROC_;
367}
368
369// reset this object instance's target.
370
371inline void sc_process_handle::reset( sc_descendant_inclusion_info descendants )
372{
373    if ( m_target_p )
374        m_target_p->reset_process( sc_process_b::reset_asynchronous,
375	                           descendants );
376    else
377        SC_REPORT_WARNING( SC_ID_EMPTY_PROCESS_HANDLE_, "reset()");
378}
379
380// return the reset event for this object instance's target.
381
382inline sc_event& sc_process_handle::reset_event() const
383{
384    if ( m_target_p )
385        return m_target_p->reset_event();
386    else
387    {
388        SC_REPORT_WARNING( SC_ID_EMPTY_PROCESS_HANDLE_, "reset()");
389        return sc_process_handle::non_event;
390    }
391}
392
393// resume this object instance's target.
394
395inline void sc_process_handle::resume(sc_descendant_inclusion_info descendants)
396{
397    if ( m_target_p )
398        m_target_p->resume_process(descendants);
399    else
400        SC_REPORT_WARNING( SC_ID_EMPTY_PROCESS_HANDLE_, "resume()");
401}
402
403// suspend this object instance's target.
404
405inline void sc_process_handle::suspend(sc_descendant_inclusion_info descendants)
406{
407    if ( m_target_p )
408        m_target_p->suspend_process(descendants);
409    else
410        SC_REPORT_WARNING( SC_ID_EMPTY_PROCESS_HANDLE_, "suspend()");
411}
412
413// swap targets of this process handle with the supplied one.
414
415inline void sc_process_handle::swap( sc_process_handle& other )
416{
417    sc_process_b* tmp = m_target_p;
418    m_target_p = other.m_target_p;
419    other.m_target_p = tmp;
420}
421
422// turn sync_reset off for this object instance's target.
423
424inline void sc_process_handle::sync_reset_off(
425    sc_descendant_inclusion_info descendants)
426{
427    if ( m_target_p )
428        m_target_p->reset_process( sc_process_b::reset_synchronous_off,
429	                           descendants);
430    else
431        SC_REPORT_WARNING( SC_ID_EMPTY_PROCESS_HANDLE_, "sync_reset_off()");
432}
433
434// turn sync_reset on for this object instance's target.
435
436inline void sc_process_handle::sync_reset_on(
437    sc_descendant_inclusion_info descendants)
438{
439    if ( m_target_p )
440    {
441        m_target_p->reset_process(sc_process_b::reset_synchronous_on,
442            descendants);
443    }
444    else
445    {
446        SC_REPORT_WARNING( SC_ID_EMPTY_PROCESS_HANDLE_, "sync_reset_on()");
447    }
448}
449
450// terminate this object instance's target.
451
452inline bool sc_process_handle::terminated() const
453{
454    return m_target_p ?  m_target_p->terminated() : false;
455}
456
457// return the termination event for this object instance's target.
458
459inline sc_event& sc_process_handle::terminated_event()
460{
461    if ( m_target_p )
462        return m_target_p->terminated_event();
463    else
464    {
465        SC_REPORT_WARNING( SC_ID_EMPTY_PROCESS_HANDLE_, "terminated_event()");
466        return sc_process_handle::non_event;
467    }
468}
469
470// return true if this object instance has a target, false it not.
471
472inline bool sc_process_handle::valid() const
473{
474    return m_target_p ? true : false;
475}
476
477//------------------------------------------------------------------------------
478//"sc_process_handle::sc_throw_it"
479//
480// This method throws the supplied exception to the process whose handle this
481// object instance is, and optionally to the process' descendants. Once the
482// exception is thrown the currently executed process will suspend to allow
483// the exception to be propagated. Once the propagation has occurred the
484// current process will be resumed.
485//
486// Notes:
487//   (1) We allocate the helper function on the stack, see the description of
488//       sc_throw_it<EXCEPT>, in sc_process.h, for why.
489//
490// Arguments:
491//    exception = exception to be thrown
492//    descendants = indication of whether descendant processes should also
493//                  receive the throw.
494//------------------------------------------------------------------------------
495template<typename EXCEPT>
496inline void sc_process_handle::throw_it( const EXCEPT& exception,
497    sc_descendant_inclusion_info descendants)
498{
499    sc_throw_it<EXCEPT> helper(exception);  // helper to throw the exception.
500
501    if ( !m_target_p )
502    {
503        SC_REPORT_WARNING( SC_ID_EMPTY_PROCESS_HANDLE_, "throw_it()");
504	return;
505    }
506    m_target_p->throw_user(helper, descendants);
507}
508
509
510//------------------------------------------------------------------------------
511//"sc_process_b::last_created_process_handle"
512//
513// This method returns the kind of this process.
514//------------------------------------------------------------------------------
515inline sc_process_handle sc_process_b::last_created_process_handle()
516{
517    return sc_process_handle(m_last_created_process_p);
518}
519
520inline sc_process_handle sc_get_last_created_process_handle()
521{
522    return sc_process_b::last_created_process_handle();
523}
524
525} // namespace sc_core
526
527// Revision 1.19  2011/08/24 22:05:51  acg
528//  Torsten Maehne: initialization changes to remove warnings.
529//
530// Revision 1.18  2011/04/01 22:08:26  acg
531//  Andy Goodrich: remove unused variable.
532//
533// Revision 1.17  2011/03/12 21:07:51  acg
534//  Andy Goodrich: changes to kernel generated event support.
535//
536// Revision 1.16  2011/02/18 20:27:14  acg
537//  Andy Goodrich: Updated Copyrights.
538//
539// Revision 1.15  2011/02/17 19:53:03  acg
540//  Andy Goodrich: changed dump_status() to dump_state() with new signature.
541//
542// Revision 1.14  2011/02/13 21:47:37  acg
543//  Andy Goodrich: update copyright notice.
544//
545// Revision 1.13  2011/02/13 21:33:30  acg
546//  Andy Goodrich: added dump_status() to allow the dumping of the status
547//  of a process handle's target.
548//
549// Revision 1.12  2011/02/01 23:01:53  acg
550//  Andy Goodrich: removed dead code.
551//
552// Revision 1.11  2011/02/01 21:07:36  acg
553//  Andy Goodrich: defering of run queue manipulations to the
554//  sc_thread_process::throw_it() method.
555//
556// Revision 1.10  2011/01/25 20:50:37  acg
557//  Andy Goodrich: changes for IEEE 1666 2011.
558//
559// Revision 1.9  2011/01/20 16:52:20  acg
560//  Andy Goodrich: changes for IEEE 1666 2011.
561//
562// Revision 1.8  2011/01/19 23:21:50  acg
563//  Andy Goodrich: changes for IEEE 1666 2011
564//
565// Revision 1.7  2011/01/18 20:10:45  acg
566//  Andy Goodrich: changes for IEEE1666_2011 semantics.
567//
568// Revision 1.6  2010/07/30 05:21:22  acg
569//  Andy Goodrich: release 2.3 fixes.
570//
571// Revision 1.5  2010/07/22 20:02:33  acg
572//  Andy Goodrich: bug fixes.
573//
574// Revision 1.4  2009/05/22 16:06:29  acg
575//  Andy Goodrich: process control updates.
576//
577// Revision 1.3  2008/05/22 17:06:26  acg
578//  Andy Goodrich: updated copyright notice to include 2008.
579//
580// Revision 1.2  2007/09/20 20:32:35  acg
581//  Andy Goodrich: changes to the semantics of throw_it() to match the
582//  specification. A call to throw_it() will immediately suspend the calling
583//  thread until all the throwees have executed. At that point the calling
584//  thread will be restarted before the execution of any other threads.
585//
586// Revision 1.1.1.1  2006/12/15 20:20:05  acg
587// SystemC 2.3
588//
589// Revision 1.7  2006/05/08 17:58:24  acg
590// Andy Goodrich: added David Long's forward declarations for friend
591//   functions, methods, and operators to keep the Microsoft compiler happy.
592//
593// Revision 1.6  2006/04/20 17:08:17  acg
594//  Andy Goodrich: 3.0 style process changes.
595//
596// Revision 1.5  2006/04/11 23:13:21  acg
597//   Andy Goodrich: Changes for reduced reset support that only includes
598//   sc_cthread, but has preliminary hooks for expanding to method and thread
599//   processes also.
600//
601// Revision 1.4  2006/01/24 20:49:05  acg
602// Andy Goodrich: changes to remove the use of deprecated features within the
603// simulator, and to issue warning messages when deprecated features are used.
604//
605// Revision 1.3  2006/01/13 18:44:30  acg
606// Added $Log to record CVS changes into the source.
607
608#endif // !defined(sc_spawn_h_INCLUDED)
609