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_manager.cpp -- Manager of objects (naming, &c.)
23
24  Original Author: Stan Y. Liao, Synopsys, Inc.
25
26  CHANGE LOG AT THE END OF THE FILE
27 *****************************************************************************/
28
29
30#include <stdio.h>
31#include <cstdlib>
32#include <cassert>
33#include <ctype.h>
34#include <stddef.h>
35#include <algorithm> // pick up std::sort.
36
37#include "sysc/utils/sc_iostream.h"
38#include "sysc/kernel/sc_object.h"
39#include "sysc/utils/sc_hash.h"
40#include "sysc/utils/sc_list.h"
41#include "sysc/utils/sc_mempool.h"
42#include "sysc/kernel/sc_simcontext.h"
43#include "sysc/kernel/sc_object_manager.h"
44#include "sysc/kernel/sc_kernel_ids.h"
45#include "sysc/kernel/sc_process.h"
46#include "sysc/kernel/sc_module_name.h"
47
48namespace sc_core {
49
50// ----------------------------------------------------------------------------
51//  CLASS : sc_object_manager
52//
53//  Manager of objects.
54// ----------------------------------------------------------------------------
55
56sc_object_manager::sc_object_manager() :
57    m_event_it(),
58    m_event_walk_ok(0),
59    m_instance_table(),
60    m_module_name_stack(0),
61    m_object_it(),
62    m_object_stack(),
63    m_object_walk_ok()
64{
65}
66
67// +----------------------------------------------------------------------------
68// |"sc_object_manager::~sc_object_manager"
69// |
70// | This is the object instance destructor for this class. It goes through
71// | each sc_object instance in the instance table and sets its m_simc field
72// | to NULL.
73// +----------------------------------------------------------------------------
74sc_object_manager::~sc_object_manager()
75{
76    instance_table_t::iterator it;     // instance table iterator.
77
78    for ( it = m_instance_table.begin(); it != m_instance_table.end(); it++)
79    {
80        sc_object* obj_p = it->second.m_object_p;
81        if ( obj_p ) obj_p->m_simc = 0;
82    }
83}
84
85// +----------------------------------------------------------------------------
86// |"sc_object_manager::create_name"
87// |
88// | This method creates a hierarchical name based on the name of the active
89// | object and the supplied leaf name. If the resultant name is not unique it
90// | will be made unique and a warning message issued.
91// |
92// | Arguments:
93// |     leaf_name = name to use for the leaf of the hierarchy.
94// | Result is an std::string containing the name.
95// +----------------------------------------------------------------------------
96std::string sc_object_manager::create_name(const char* leaf_name)
97{
98    bool        clash;                  // true if path name exists in obj table
99    std::string leafname_string;        // string containing the leaf name.
100    std::string parentname_string;      // parent path name
101    sc_object*  parent_p;               // parent for this instance or NULL.
102    std::string result_orig_string;     // save for warning message.
103    std::string result_string;          // name to return.
104
105    // CONSTRUCT PATHNAME TO THE NAME TO BE RETURNED:
106    //
107    // If there is not a leaf name generate one.
108
109    parent_p = sc_get_curr_simcontext()->active_object();
110    parentname_string = parent_p ? parent_p->name() : "";
111    leafname_string = leaf_name;
112    if (parent_p) {
113        result_string = parentname_string;
114	result_string += SC_HIERARCHY_CHAR;
115	result_string += leafname_string;
116    } else {
117        result_string = leafname_string;
118    }
119
120    // SAVE the original path name
121
122    result_orig_string = result_string;
123
124    // MAKE SURE THE ENTITY NAME IS UNIQUE:
125    //
126    // If not use unique name generator to make it unique.
127
128    clash = false;
129    for (;;)
130    {
131	instance_table_t::iterator it = m_instance_table.find(result_string);
132	if ( it == m_instance_table.end() ||
133	     (it->second.m_event_p == NULL && it->second.m_object_p == NULL ) )
134	{
135	    break;
136	}
137        clash = true;
138        leafname_string = sc_gen_unique_name(leafname_string.c_str(), false);
139	if (parent_p) {
140	    result_string = parentname_string;
141	    result_string += SC_HIERARCHY_CHAR;
142	    result_string += leafname_string;
143	} else {
144	    result_string = leafname_string;
145	}
146    }
147    if (clash) {
148	std::string message = result_orig_string;
149	message += ". Latter declaration will be renamed to ";
150	message += result_string;
151        SC_REPORT_WARNING( SC_ID_INSTANCE_EXISTS_, message.c_str());
152    }
153
154    return result_string;
155}
156
157// +----------------------------------------------------------------------------
158// |"sc_object_manager::find_event"
159// |
160// | This method returns the sc_event with the supplied name, or a NULL if
161// | the event does not exist.
162// |
163// | Arguments:
164// |     name = name of the event
165// | Result is a pointer to the event or NULL if it does not exist.
166// +----------------------------------------------------------------------------
167sc_event*
168sc_object_manager::find_event(const char* name)
169{
170    instance_table_t::iterator it;
171    it = m_instance_table.find(name);
172    return it == m_instance_table.end() ? NULL : it->second.m_event_p;
173}
174
175// +----------------------------------------------------------------------------
176// |"sc_object_manager::find_object"
177// |
178// | This method returns the sc_object with the supplied name, or a NULL if
179// | the object does not exist.
180// |
181// | Arguments:
182// |     name = name of the object
183// | Result is a pointer to the object or NULL if it does not exist.
184// +----------------------------------------------------------------------------
185sc_object*
186sc_object_manager::find_object(const char* name)
187{
188    instance_table_t::iterator it;
189    it = m_instance_table.find(name);
190    return it == m_instance_table.end() ? NULL : it->second.m_object_p;
191}
192
193
194// +----------------------------------------------------------------------------
195// |"sc_object_manager::first_object"
196// |
197// | This method initializes the object iterator to point to the first object
198// | in the instance table, and returns its address. If there are no objects
199// | in the table a NULL value is returned.
200// +----------------------------------------------------------------------------
201sc_object*
202sc_object_manager::first_object()
203{
204    sc_object* result_p; // result to return.
205
206    m_object_walk_ok = true;
207    result_p = NULL;
208    for ( m_object_it = m_instance_table.begin();
209          m_object_it != m_instance_table.end();
210	  m_object_it++ )
211    {
212        result_p = m_object_it->second.m_object_p;
213	if ( result_p ) break;
214    }
215    return result_p;
216}
217
218// +----------------------------------------------------------------------------
219// |"sc_object_manager::hierarchy_curr"
220// |
221// | This method returns the current object in the object hierarchy or NULL
222// | if it does not exist.
223// +----------------------------------------------------------------------------
224sc_object*
225sc_object_manager::hierarchy_curr()
226{
227    size_t     hierarchy_n; // current size of the hierarchy.
228
229    hierarchy_n = m_object_stack.size();
230    return hierarchy_n ? m_object_stack[hierarchy_n-1] : 0;
231}
232
233// +----------------------------------------------------------------------------
234// |"sc_object_manager::hierarchy_pop"
235// |
236// | This method pops the current object off the object hierarchy and returns
237// | it.
238// +----------------------------------------------------------------------------
239sc_object*
240sc_object_manager::hierarchy_pop()
241{
242    size_t     hierarchy_n; // current size of the hierarchy.
243    sc_object* result_p;    // object to return.
244
245    hierarchy_n = m_object_stack.size();
246    if ( hierarchy_n == 0 ) return NULL;
247    hierarchy_n--;
248    result_p = m_object_stack[hierarchy_n];
249    m_object_stack.pop_back();
250    return result_p;
251}
252
253// +----------------------------------------------------------------------------
254// |"sc_object_manager::hierarchy_push"
255// |
256// | This method pushes down the sc_object hierarchy to make the supplied
257// | object the current object in the hierarchy.
258// |
259// | Arguments:
260// |     object_p -> object to become the new current object in the hierarchy.
261// +----------------------------------------------------------------------------
262void
263sc_object_manager::hierarchy_push(sc_object* object_p)
264{
265    m_object_stack.push_back(object_p);
266}
267
268
269// +----------------------------------------------------------------------------
270// |"sc_object_manager::hierarchy_size"
271// |
272// | This method returns the current size of the object hierarchy stack.
273// +----------------------------------------------------------------------------
274int
275sc_object_manager::hierarchy_size()
276{
277    return m_object_stack.size();
278}
279
280// +----------------------------------------------------------------------------
281// |"sc_object_manager::insert_event"
282// |
283// | This method inserts the supplied sc_event instance into the instance
284// | table using the supplied name.
285// |
286// | Arguments:
287// |     name    =  name of the event to be inserted.
288// |     event_p -> event to be inserted.
289// +----------------------------------------------------------------------------
290void
291sc_object_manager::insert_event(const std::string& name, sc_event* event_p)
292{
293    m_instance_table[name].m_event_p = event_p;
294}
295
296// +----------------------------------------------------------------------------
297// |"sc_object_manager::insert_object"
298// |
299// | This method inserts the supplied sc_object instance into the instance
300// | table using the supplied name.
301// |
302// | Arguments:
303// |     name     =  name of the event to be inserted.
304// |     object_p -> object to be inserted.
305// +----------------------------------------------------------------------------
306void
307sc_object_manager::insert_object(const std::string& name, sc_object* object_p)
308{
309    m_instance_table[name].m_object_p = object_p;
310}
311
312// +----------------------------------------------------------------------------
313// |"sc_object_manager::next_object"
314// |
315// | This method returns the next object pointed to by the instance iterator.
316// +----------------------------------------------------------------------------
317sc_object*
318sc_object_manager::next_object()
319{
320    sc_object* result_p; // result to return.
321
322    assert( m_object_walk_ok );
323
324    if ( m_object_it == m_instance_table.end() ) return NULL;
325    m_object_it++;
326
327    for ( result_p = NULL; m_object_it != m_instance_table.end();
328	  m_object_it++ )
329    {
330        result_p = m_object_it->second.m_object_p;
331	if ( result_p ) break;
332    }
333    return result_p;
334}
335
336// +----------------------------------------------------------------------------
337// |"sc_object_manager::pop_module_name"
338// |
339// | This method pops an entry off the module name stack and returns it.
340// +----------------------------------------------------------------------------
341sc_module_name*
342sc_object_manager::pop_module_name()
343{
344    sc_module_name* mod_name = m_module_name_stack;
345    m_module_name_stack = m_module_name_stack->m_next;
346    mod_name->m_next = 0;
347    return mod_name;
348}
349
350// +----------------------------------------------------------------------------
351// |"sc_object_manager::push_module_name"
352// |
353// | This method pushes the supplied entry onto the module name stack.
354// |
355// | Arguments:
356// |     mod_name_p -> entry to push onto the module name stack.
357// +----------------------------------------------------------------------------
358void
359sc_object_manager::push_module_name(sc_module_name* mod_name_p)
360{
361    mod_name_p->m_next = m_module_name_stack;
362    m_module_name_stack = mod_name_p;
363}
364
365// +----------------------------------------------------------------------------
366// |"sc_object_manager::top_of_module_name_stack"
367// |
368// | This method returns the module name that is on the top of the module
369// | name stack.
370// +----------------------------------------------------------------------------
371sc_module_name*
372sc_object_manager::top_of_module_name_stack()
373{
374    if( m_module_name_stack == 0 ) {
375	SC_REPORT_ERROR( SC_ID_MODULE_NAME_STACK_EMPTY_, 0 );
376    }
377    return m_module_name_stack;
378}
379
380// +----------------------------------------------------------------------------
381// |"sc_object_manager::remove_event"
382// |
383// | This method removes the sc_event instance with the supplied name from
384// | the table of instances. Note we just clear the pointer since if the name
385// | was for an sc_object the m_event_p pointer will be null anyway.
386// |
387// | Arguments:
388// |     name = name of the event to be removed.
389// +----------------------------------------------------------------------------
390void
391sc_object_manager::remove_event(const std::string& name)
392{
393    instance_table_t::iterator it;     // instance table iterator.
394    it = m_instance_table.find(name);
395    if ( it != m_instance_table.end() ) it->second.m_event_p = NULL;
396}
397
398// +----------------------------------------------------------------------------
399// |"sc_object_manager::remove_object"
400// |
401// | This method removes the sc_object instance with the supplied name from
402// | the table of instances. Note we just clear the pointer since if the name
403// | was for an sc_event the m_object_p pointer will be null anyway.
404// |
405// | Arguments:
406// |     name = name of the object to be removed.
407// +----------------------------------------------------------------------------
408void
409sc_object_manager::remove_object(const std::string& name)
410{
411    instance_table_t::iterator it;     // instance table iterator.
412    it = m_instance_table.find(name);
413    if ( it != m_instance_table.end() ) it->second.m_object_p = NULL;
414}
415
416} // namespace sc_core
417
418// $Log: sc_object_manager.cpp,v $
419// Revision 1.13  2011/08/26 20:46:10  acg
420//  Andy Goodrich: moved the modification log to the end of the file to
421//  eliminate source line number skew when check-ins are done.
422//
423// Revision 1.12  2011/08/24 22:05:51  acg
424//  Torsten Maehne: initialization changes to remove warnings.
425//
426// Revision 1.11  2011/06/25 17:08:39  acg
427//  Andy Goodrich: Jerome Cornet's changes to use libtool to build the
428//  library.
429//
430// Revision 1.10  2011/04/01 21:27:54  acg
431//  Andy Goodrich: documentation of event and object insertion methods.
432//
433// Revision 1.9  2011/03/06 15:55:11  acg
434//  Andy Goodrich: Changes for named events.
435//
436// Revision 1.8  2011/03/05 19:44:20  acg
437//  Andy Goodrich: changes for object and event naming and structures.
438//
439// Revision 1.7  2011/03/05 04:45:16  acg
440//  Andy Goodrich: moved active process calculation to the sc_simcontext class.
441//
442// Revision 1.6  2011/03/05 01:39:21  acg
443//  Andy Goodrich: changes for named events.
444//
445// Revision 1.5  2011/02/18 20:27:14  acg
446//  Andy Goodrich: Updated Copyrights.
447//
448// Revision 1.4  2011/02/13 21:47:37  acg
449//  Andy Goodrich: update copyright notice.
450//
451// Revision 1.3  2010/07/22 20:02:33  acg
452//  Andy Goodrich: bug fixes.
453//
454// Revision 1.2  2008/05/22 17:06:26  acg
455//  Andy Goodrich: updated copyright notice to include 2008.
456//
457// Revision 1.1.1.1  2006/12/15 20:20:05  acg
458// SystemC 2.3
459//
460// Revision 1.3  2006/01/13 18:44:30  acg
461// Added $Log to record CVS changes into the source.
462//
463