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_object.cpp -- Abstract base class of all SystemC objects.
23
24  Original Author: Stan Y. Liao, Synopsys, Inc.
25
26  CHANGE LOG AT THE END OF THE FILE
27 *****************************************************************************/
28
29
30#include <cstdlib>
31#include <cassert>
32#include <stddef.h>
33#include <cstdio>
34#include <string.h>
35#include <ctype.h>
36
37#include "sysc/kernel/sc_externs.h"
38#include "sysc/kernel/sc_kernel_ids.h"
39#include "sysc/kernel/sc_module.h"
40#include "sysc/kernel/sc_object.h"
41#include "sysc/kernel/sc_object_manager.h"
42#include "sysc/kernel/sc_phase_callback_registry.h"
43#include "sysc/kernel/sc_process_handle.h"
44#include "sysc/kernel/sc_simcontext.h"
45#include "sysc/kernel/sc_event.h"
46#include "sysc/utils/sc_hash.h"
47#include "sysc/utils/sc_iostream.h"
48#include "sysc/utils/sc_list.h"
49#include "sysc/utils/sc_utils_ids.h"
50#include "sysc/utils/sc_mempool.h"
51
52namespace sc_core {
53
54typedef int (*STRCMP)(const void*, const void*);
55
56const char SC_HIERARCHY_CHAR = '.';
57
58/* This will be gotten rid after multiple-processes
59   are implemented.  This is to fix some regression
60   problems. */
61bool sc_enable_name_checking = true;
62
63
64// ----------------------------------------------------------------------------
65//  CLASS : sc_object
66//
67//  Abstract base class of all SystemC `simulation' objects.
68// ----------------------------------------------------------------------------
69
70void
71sc_object::add_child_event( sc_event* event_p )
72{
73    // no check if event_p is already in the set
74    m_child_events.push_back( event_p );
75}
76
77void
78sc_object::add_child_object( sc_object* object_ )
79{
80    // no check if object_ is already in the set
81    m_child_objects.push_back( object_ );
82}
83
84const char*
85sc_object::basename() const
86{
87    size_t pos; // position of last SC_HIERARCHY_CHAR.
88    pos = m_name.rfind( (char)SC_HIERARCHY_CHAR );
89    return ( pos == m_name.npos ) ? m_name.c_str() : &(m_name.c_str()[pos+1]);
90}
91
92void
93sc_object::print(::std::ostream& os) const
94{
95    os << name();
96}
97
98void
99sc_object::dump(::std::ostream& os) const
100{
101    os << "name = " << name() << "\n";
102    os << "kind = " << kind() << "\n";
103}
104
105static int sc_object_num = 0;
106
107static std::string
108sc_object_newname()
109{
110    char        buffer[64];
111    std::string result;
112
113    std::sprintf(buffer, "{%d}", sc_object_num);
114    sc_object_num++;
115    result = buffer;
116
117    return result;
118}
119
120// +----------------------------------------------------------------------------
121// |"sc_object::remove_child_event"
122// |
123// | This virtual method removes the supplied event from the list of child
124// | events if it is present.
125// |
126// | Arguments:
127// |     event_p -> event to be removed.
128// | Returns true if the event was present, false if not.
129// +----------------------------------------------------------------------------
130bool
131sc_object::remove_child_event( sc_event* event_p )
132{
133    int size = m_child_events.size();
134    for( int i = 0; i < size; ++ i ) {
135        if( event_p == m_child_events[i] ) {
136            m_child_events[i] = m_child_events[size - 1];
137            m_child_events.pop_back();
138            return true;
139        }
140    }
141    return false;
142}
143
144// +----------------------------------------------------------------------------
145// |"sc_object::remove_child_object"
146// |
147// | This virtual method removes the supplied object from the list of child
148// | objects if it is present.
149// |
150// | Arguments:
151// |     object_p -> object to be removed.
152// | Returns true if the object was present, false if not.
153// +----------------------------------------------------------------------------
154bool
155sc_object::remove_child_object( sc_object* object_p )
156{
157    int size = m_child_objects.size();
158    for( int i = 0; i < size; ++ i ) {
159        if( object_p == m_child_objects[i] ) {
160            m_child_objects[i] = m_child_objects[size - 1];
161            m_child_objects.pop_back();
162	    object_p->m_parent = NULL;
163            return true;
164        }
165    }
166    return false;
167}
168
169// +----------------------------------------------------------------------------
170// |"sc_object::sc_object_init"
171// |
172// | This method initializes this object instance and places it in to the
173// | object hierarchy if the supplied name is not NULL.
174// |
175// | Arguments:
176// |     nm = leaf name for the object.
177// +----------------------------------------------------------------------------
178void
179sc_object::sc_object_init(const char* nm)
180{
181    // SET UP POINTERS TO OBJECT MANAGER, PARENT, AND SIMULATION CONTEXT:
182    //
183    // Make the current simcontext the simcontext for this object
184
185    m_simc = sc_get_curr_simcontext();
186    m_attr_cltn_p = 0;
187    sc_object_manager* object_manager = m_simc->get_object_manager();
188    m_parent = m_simc->active_object();
189
190    // CONSTRUCT PATHNAME TO OBJECT BEING CREATED:
191    //
192    // If there is not a leaf name generate one.
193
194    m_name = object_manager->create_name(nm ? nm : sc_object_newname().c_str());
195
196
197    // PLACE THE OBJECT INTO THE HIERARCHY
198
199    object_manager->insert_object(m_name, this);
200    if ( m_parent )
201        m_parent->add_child_object( this );
202    else
203        m_simc->add_child_object( this );
204}
205
206sc_object::sc_object() :
207    m_attr_cltn_p(0), m_child_events(), m_child_objects(), m_name(),
208    m_parent(0), m_simc(0)
209{
210    sc_object_init( sc_gen_unique_name("object") );
211}
212
213sc_object::sc_object( const sc_object& that ) :
214    m_attr_cltn_p(0), m_child_events(), m_child_objects(), m_name(),
215    m_parent(0), m_simc(0)
216{
217    sc_object_init( sc_gen_unique_name( that.basename() ) );
218}
219
220
221static bool
222object_name_illegal_char(char ch)
223{
224    return (ch == SC_HIERARCHY_CHAR) || isspace(ch);
225}
226
227sc_object::sc_object(const char* nm) :
228    m_attr_cltn_p(0), m_child_events(), m_child_objects(), m_name(),
229    m_parent(0), m_simc(0)
230{
231    int namebuf_alloc = 0;
232    char* namebuf = 0;
233    const char* p;
234
235    // null name or "" uses machine generated name.
236
237    if ( !nm || !*nm )
238	nm = sc_gen_unique_name("object");
239    p = nm;
240
241    if (nm && sc_enable_name_checking) {
242        namebuf_alloc = 1 + strlen(nm);
243        namebuf = (char*) sc_mempool::allocate(namebuf_alloc);
244        char* q = namebuf;
245        const char* r = nm;
246        bool has_illegal_char = false;
247        while (*r) {
248            if (object_name_illegal_char(*r)) {
249                has_illegal_char = true;
250                *q = '_';
251            } else {
252                *q = *r;
253            }
254            r++;
255            q++;
256        }
257        *q = '\0';
258        p = namebuf;
259        if (has_illegal_char)
260	{
261	    std::string message = nm;
262	    message += " substituted by ";
263	    message += namebuf;
264            SC_REPORT_WARNING( SC_ID_ILLEGAL_CHARACTERS_, message.c_str());
265	}
266    }
267    sc_object_init(p);
268    sc_mempool::release( namebuf, namebuf_alloc );
269}
270
271sc_object::~sc_object()
272{
273#if SC_HAS_PHASE_CALLBACKS_
274    unregister_simulation_phase_callback( SC_STATUS_ANY );
275#endif
276    detach();
277    delete m_attr_cltn_p;
278}
279
280//------------------------------------------------------------------------------
281//"sc_object::detach"
282//
283// This method detaches this object instance from the object hierarchy.
284// It is called in two places: ~sc_object() and sc_process_b::kill_process().
285//------------------------------------------------------------------------------
286void sc_object::detach()
287{
288    if (m_simc) {
289
290        // REMOVE OBJECT FROM THE OBJECT MANAGER:
291
292        sc_object_manager* object_manager = m_simc->get_object_manager();
293        object_manager->remove_object(m_name);
294
295		// REMOVE OBJECT FROM PARENT'S LIST OF OBJECTS:
296
297        if ( m_parent )
298	    m_parent->remove_child_object( this );
299	else
300	    m_simc->remove_child_object( this );
301
302        // ORPHAN THIS OBJECT'S CHILDREN:
303
304#if 0 // ####
305	    ::std::<sc_object*> children_p = &get_child_objects();
306		int                 child_n = children_p->size();
307		sc_object*          parent_p;
308
309		for ( int child_i = 0; child_i < child_n; child_i++ )
310		{
311			(*children_p)[child_i]->m_parent = 0;
312		}
313#endif
314
315    }
316}
317
318// +----------------------------------------------------------------------------
319// |"sc_object::orphan_child_events"
320// |
321// | This method moves the children of this object instance to be children
322// | of the simulator.
323// +----------------------------------------------------------------------------
324void sc_object::orphan_child_events()
325{
326    std::vector< sc_event* > const & events = get_child_events();
327
328    std::vector< sc_event* >::const_iterator
329            it  = events.begin(), end = events.end();
330
331    for( ; it != end; ++it  )
332    {
333        (*it)->m_parent_p = NULL;
334        simcontext()->add_child_event(*it);
335    }
336}
337
338// +----------------------------------------------------------------------------
339// |"sc_object::orphan_child_objects"
340// |
341// | This method moves the children of this object instance to be children
342// | of the simulator.
343// +----------------------------------------------------------------------------
344void sc_object::orphan_child_objects()
345{
346    std::vector< sc_object* > const & children = get_child_objects();
347
348    std::vector< sc_object* >::const_iterator
349            it  = children.begin(), end = children.end();
350
351    for( ; it != end; ++it  )
352    {
353        (*it)->m_parent = NULL;
354        simcontext()->add_child_object(*it);
355    }
356}
357
358void
359sc_object::trace( sc_trace_file * /* unused */) const
360{
361    /* This space is intentionally left blank */
362}
363
364
365// add attribute
366
367bool
368sc_object::add_attribute( sc_attr_base& attribute_ )
369{
370    if ( !m_attr_cltn_p ) m_attr_cltn_p = new sc_attr_cltn;
371    return ( m_attr_cltn_p->push_back( &attribute_ ) );
372}
373
374
375// get attribute by name
376
377sc_attr_base*
378sc_object::get_attribute( const std::string& name_ )
379{
380    if ( !m_attr_cltn_p ) m_attr_cltn_p = new sc_attr_cltn;
381    return ( (*m_attr_cltn_p)[name_] );
382}
383
384const sc_attr_base*
385sc_object::get_attribute( const std::string& name_ ) const
386{
387    if ( !m_attr_cltn_p ) m_attr_cltn_p = new sc_attr_cltn;
388    return ( (*m_attr_cltn_p)[name_] );
389}
390
391
392// remove attribute by name
393
394sc_attr_base*
395sc_object::remove_attribute( const std::string& name_ )
396{
397    if ( m_attr_cltn_p )
398	return ( m_attr_cltn_p->remove( name_ ) );
399    else
400	return 0;
401}
402
403
404// remove all attributes
405
406void
407sc_object::remove_all_attributes()
408{
409    if ( m_attr_cltn_p )
410	m_attr_cltn_p->remove_all();
411}
412
413
414// get the number of attributes
415
416int
417sc_object::num_attributes() const
418{
419    if ( m_attr_cltn_p )
420	return ( m_attr_cltn_p->size() );
421    else
422	return 0;
423}
424
425
426// get the attribute collection
427
428sc_attr_cltn&
429sc_object::attr_cltn()
430{
431    if ( !m_attr_cltn_p ) m_attr_cltn_p = new sc_attr_cltn;
432    return *m_attr_cltn_p;
433}
434
435const sc_attr_cltn&
436sc_object::attr_cltn() const
437{
438    if ( !m_attr_cltn_p ) m_attr_cltn_p = new sc_attr_cltn;
439    return *m_attr_cltn_p;
440}
441
442sc_object*
443sc_object::get_parent() const
444{
445    static bool warn_sc_get_parent_deprecated=true;
446    if ( warn_sc_get_parent_deprecated )
447    {
448        warn_sc_get_parent_deprecated=false;
449        SC_REPORT_INFO(sc_core::SC_ID_IEEE_1666_DEPRECATION_,
450          "sc_object::get_parent() is deprecated, "
451          "use get_parent_object() instead");
452    }
453    return get_parent_object();
454}
455
456// ----------------------------------------------------------------------------
457// simulation phase callbacks
458
459
460sc_object::phase_cb_mask
461sc_object::register_simulation_phase_callback( phase_cb_mask mask )
462{
463    mask = simcontext()->m_phase_cb_registry
464                       ->register_callback(*this, mask);
465    return mask;
466}
467
468
469sc_object::phase_cb_mask
470sc_object::unregister_simulation_phase_callback( phase_cb_mask mask )
471{
472    mask = simcontext()->m_phase_cb_registry
473                       ->unregister_callback(*this, mask);
474    return mask;
475}
476
477
478void
479sc_object::simulation_phase_callback()
480{
481    SC_REPORT_WARNING( SC_ID_PHASE_CALLBACK_NOT_IMPLEMENTED_, name() );
482}
483
484
485} // namespace sc_core
486
487/*****************************************************************************
488
489  MODIFICATION LOG - modifiers, enter your name, affiliation, date and
490  changes you are making here.
491
492      Name, Affiliation, Date: Bishnupriya Bhattacharya, Cadence Design Systems,
493                               25 August, 2003
494  Description of Modification: if module name hierarchy is empty, sc_object
495                               ctor assumes the currently executing process
496                               as the parent object to support dynamic process
497                               creation similar to other sc_objects
498
499      Name, Affiliation, Date: Andy Goodrich, Forte Design Systems
500                               5 September 2003
501  Description of Modification: - Made creation of attributes structure
502                                 conditional on its being used. This eliminates
503                                 100 bytes of storage for each normal sc_object.
504
505 *****************************************************************************/
506
507
508// $Log: sc_object.cpp,v $
509// Revision 1.16  2011/08/29 18:04:32  acg
510//  Philipp A. Hartmann: miscellaneous clean ups.
511//
512// Revision 1.15  2011/08/26 20:46:10  acg
513//  Andy Goodrich: moved the modification log to the end of the file to
514//  eliminate source line number skew when check-ins are done.
515//
516// Revision 1.14  2011/08/24 22:05:51  acg
517//  Torsten Maehne: initialization changes to remove warnings.
518//
519// Revision 1.13  2011/04/01 21:24:57  acg
520//  Andy Goodrich: removed unused code.
521//
522// Revision 1.12  2011/03/06 15:55:11  acg
523//  Andy Goodrich: Changes for named events.
524//
525// Revision 1.11  2011/03/05 19:44:20  acg
526//  Andy Goodrich: changes for object and event naming and structures.
527//
528// Revision 1.10  2011/03/05 04:45:16  acg
529//  Andy Goodrich: moved active process calculation to the sc_simcontext class.
530//
531// Revision 1.9  2011/03/05 01:39:21  acg
532//  Andy Goodrich: changes for named events.
533//
534// Revision 1.8  2011/02/18 20:27:14  acg
535//  Andy Goodrich: Updated Copyrights.
536//
537// Revision 1.7  2011/02/13 21:47:37  acg
538//  Andy Goodrich: update copyright notice.
539//
540// Revision 1.6  2011/01/25 20:50:37  acg
541//  Andy Goodrich: changes for IEEE 1666 2011.
542//
543// Revision 1.5  2011/01/18 20:10:44  acg
544//  Andy Goodrich: changes for IEEE1666_2011 semantics.
545//
546// Revision 1.4  2010/08/03 17:02:39  acg
547//  Andy Goodrich: formatting changes.
548//
549// Revision 1.3  2009/02/28 00:26:58  acg
550//  Andy Goodrich: changed boost name space to sc_boost to allow use with
551//  full boost library applications.
552//
553// Revision 1.2  2008/05/22 17:06:26  acg
554//  Andy Goodrich: updated copyright notice to include 2008.
555//
556// Revision 1.1.1.1  2006/12/15 20:20:05  acg
557// SystemC 2.3
558//
559// Revision 1.5  2006/04/20 17:08:17  acg
560//  Andy Goodrich: 3.0 style process changes.
561//
562// Revision 1.4  2006/03/21 00:00:34  acg
563//   Andy Goodrich: changed name of sc_get_current_process_base() to be
564//   sc_get_current_process_b() since its returning an sc_process_b instance.
565//
566// Revision 1.3  2006/01/13 18:44:30  acg
567// Added $Log to record CVS changes into the source.
568//
569