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_prim_channel.cpp -- Abstract base class of all primitive channel
23                         classes.
24
25  Original Author: Martin Janssen, Synopsys, Inc., 2001-05-21
26
27  CHANGE LOG IS AT THE END OF THE FILE
28 *****************************************************************************/
29
30#include "sysc/communication/sc_prim_channel.h"
31#include "sysc/communication/sc_communication_ids.h"
32#include "sysc/kernel/sc_simcontext.h"
33#include "sysc/kernel/sc_module.h"
34#include "sysc/kernel/sc_object_int.h"
35
36#ifndef SC_DISABLE_ASYNC_UPDATES
37#  include "sysc/communication/sc_host_mutex.h"
38#endif
39
40namespace sc_core {
41
42// ----------------------------------------------------------------------------
43//  CLASS : sc_prim_channel
44//
45//  Abstract base class of all primitive channel classes.
46// ----------------------------------------------------------------------------
47
48// constructors
49
50sc_prim_channel::sc_prim_channel()
51: sc_object( 0 ),
52  m_registry( simcontext()->get_prim_channel_registry() ),
53  m_update_next_p( 0 )
54{
55    m_registry->insert( *this );
56}
57
58sc_prim_channel::sc_prim_channel( const char* name_ )
59: sc_object( name_ ),
60  m_registry( simcontext()->get_prim_channel_registry() ),
61  m_update_next_p( 0 )
62{
63    m_registry->insert( *this );
64}
65
66
67// destructor
68
69sc_prim_channel::~sc_prim_channel()
70{
71    m_registry->remove( *this );
72}
73
74
75// the update method (does nothing by default)
76
77void
78sc_prim_channel::update()
79{}
80
81
82// called by construction_done (does nothing by default)
83
84void sc_prim_channel::before_end_of_elaboration()
85{}
86
87// called when construction is done
88
89void
90sc_prim_channel::construction_done()
91{
92    sc_object::hierarchy_scope scope( get_parent_object() );
93    before_end_of_elaboration();
94}
95
96// called by elaboration_done (does nothing by default)
97
98void
99sc_prim_channel::end_of_elaboration()
100{}
101
102
103// called when elaboration is done
104
105void
106sc_prim_channel::elaboration_done()
107{
108    sc_object::hierarchy_scope scope( get_parent_object() );
109    end_of_elaboration();
110}
111
112// called by start_simulation (does nothing)
113
114void
115sc_prim_channel::start_of_simulation()
116{}
117
118// called before simulation begins
119
120void
121sc_prim_channel::start_simulation()
122{
123    sc_object::hierarchy_scope scope( get_parent_object() );
124    start_of_simulation();
125}
126
127// called by simulation_done (does nothing)
128
129void
130sc_prim_channel::end_of_simulation()
131{}
132
133// called after simulation ends
134
135void
136sc_prim_channel::simulation_done()
137{
138    sc_object::hierarchy_scope scope( get_parent_object() );
139    end_of_simulation();
140}
141
142// ----------------------------------------------------------------------------
143//  CLASS : sc_prim_channel_registry::async_update_list
144//
145//  Thread-safe list of pending external updates
146//  FOR INTERNAL USE ONLY!
147// ----------------------------------------------------------------------------
148
149class sc_prim_channel_registry::async_update_list
150{
151#ifndef SC_DISABLE_ASYNC_UPDATES
152public:
153
154    bool pending() const
155    {
156	return m_push_queue.size() != 0;
157    }
158
159    void append( sc_prim_channel& prim_channel_ )
160    {
161	sc_scoped_lock lock( m_mutex );
162	m_push_queue.push_back( &prim_channel_ );
163	// return releases the mutex
164    }
165
166    void accept_updates()
167    {
168	sc_assert( ! m_pop_queue.size() );
169	{
170	    sc_scoped_lock lock( m_mutex );
171	    m_push_queue.swap( m_pop_queue );
172	    // leaving the block releases the mutex
173	}
174
175	std::vector< sc_prim_channel* >::const_iterator
176	    it = m_pop_queue.begin(), end = m_pop_queue.end();
177	while( it!= end )
178	{
179	    // we use request_update instead of perform_update
180	    // to skip duplicates
181	    (*it++)->request_update();
182	}
183	m_pop_queue.clear();
184    }
185
186private:
187    sc_host_mutex                   m_mutex;
188    std::vector< sc_prim_channel* > m_push_queue;
189    std::vector< sc_prim_channel* > m_pop_queue;
190
191#endif // ! SC_DISABLE_ASYNC_UPDATES
192};
193
194// ----------------------------------------------------------------------------
195//  CLASS : sc_prim_channel_registry
196//
197//  Registry for all primitive channels.
198//  FOR INTERNAL USE ONLY!
199// ----------------------------------------------------------------------------
200
201void
202sc_prim_channel_registry::insert( sc_prim_channel& prim_channel_ )
203{
204    if( sc_is_running() ) {
205       SC_REPORT_ERROR( SC_ID_INSERT_PRIM_CHANNEL_, "simulation running" );
206    }
207
208    if( m_simc->elaboration_done() ) {
209
210	SC_REPORT_ERROR( SC_ID_INSERT_PRIM_CHANNEL_, "elaboration done" );
211    }
212
213#ifdef DEBUG_SYSTEMC
214    // check if prim_channel_ is already inserted
215    for( int i = 0; i < size(); ++ i ) {
216	if( &prim_channel_ == m_prim_channel_vec[i] ) {
217	    SC_REPORT_ERROR( SC_ID_INSERT_PRIM_CHANNEL_, "already inserted" );
218	}
219    }
220#endif
221
222    // insert
223    m_prim_channel_vec.push_back( &prim_channel_ );
224
225}
226
227void
228sc_prim_channel_registry::remove( sc_prim_channel& prim_channel_ )
229{
230    int i;
231    for( i = 0; i < size(); ++ i ) {
232	if( &prim_channel_ == m_prim_channel_vec[i] ) {
233	    break;
234	}
235    }
236    if( i == size() ) {
237	SC_REPORT_ERROR( SC_ID_REMOVE_PRIM_CHANNEL_, 0 );
238    }
239
240    // remove
241    m_prim_channel_vec[i] = m_prim_channel_vec[size() - 1];
242    m_prim_channel_vec.resize(size()-1);
243}
244
245bool
246sc_prim_channel_registry::pending_async_updates() const
247{
248#ifndef SC_DISABLE_ASYNC_UPDATES
249    return m_async_update_list_p->pending();
250#else
251    return false;
252#endif
253}
254
255void
256sc_prim_channel_registry::async_request_update( sc_prim_channel& prim_channel_ )
257{
258#ifndef SC_DISABLE_ASYNC_UPDATES
259    m_async_update_list_p->append( prim_channel_ );
260#else
261    SC_REPORT_ERROR( SC_ID_NO_ASYNC_UPDATE_, prim_channel_.name() );
262#endif
263}
264
265// +----------------------------------------------------------------------------
266// |"sc_prim_channel_registry::perform_update"
267// |
268// | This method updates the values of the primitive channels in its update
269// | lists.
270// +----------------------------------------------------------------------------
271void
272sc_prim_channel_registry::perform_update()
273{
274    // Update the values for the primitive channels set external to the
275    // simulator.
276
277#ifndef SC_DISABLE_ASYNC_UPDATES
278    if( m_async_update_list_p->pending() )
279	m_async_update_list_p->accept_updates();
280#endif
281
282    sc_prim_channel* next_p; // Next update to perform.
283    sc_prim_channel* now_p;  // Update now performing.
284
285    // Update the values for the primitive channels in the simulator's list.
286
287    now_p = m_update_list_p;
288    m_update_list_p = (sc_prim_channel*)sc_prim_channel::list_end;
289    for ( ; now_p != (sc_prim_channel*)sc_prim_channel::list_end;
290	now_p = next_p )
291    {
292	next_p = now_p->m_update_next_p;
293	now_p->perform_update();
294    }
295}
296
297// constructor
298
299sc_prim_channel_registry::sc_prim_channel_registry( sc_simcontext& simc_ )
300  :  m_async_update_list_p(0)
301  ,  m_construction_done(0)
302  ,  m_prim_channel_vec()
303  ,  m_simc( &simc_ )
304  ,  m_update_list_p((sc_prim_channel*)sc_prim_channel::list_end)
305{
306#   ifndef SC_DISABLE_ASYNC_UPDATES
307        m_async_update_list_p = new async_update_list();
308#   endif
309}
310
311
312// destructor
313
314sc_prim_channel_registry::~sc_prim_channel_registry()
315{
316    delete m_async_update_list_p;
317}
318
319// called when construction is done
320
321bool
322sc_prim_channel_registry::construction_done()
323{
324    if( size() == m_construction_done )
325        // nothing has been updated
326        return true;
327
328    for( ; m_construction_done < size(); ++m_construction_done ) {
329        m_prim_channel_vec[m_construction_done]->construction_done();
330    }
331
332    return false;
333}
334
335
336// called when elaboration is done
337
338void
339sc_prim_channel_registry::elaboration_done()
340{
341    for( int i = 0; i < size(); ++ i ) {
342	m_prim_channel_vec[i]->elaboration_done();
343    }
344}
345
346// called before simulation begins
347
348void
349sc_prim_channel_registry::start_simulation()
350{
351    for( int i = 0; i < size(); ++ i ) {
352	m_prim_channel_vec[i]->start_simulation();
353    }
354}
355
356// called after simulation ends
357
358void
359sc_prim_channel_registry::simulation_done()
360{
361    for( int i = 0; i < size(); ++ i ) {
362	m_prim_channel_vec[i]->simulation_done();
363    }
364}
365
366} // namespace sc_core
367
368/*****************************************************************************
369
370  MODIFICATION LOG - modifiers, enter your name, affiliation, date and
371  changes you are making here.
372
373      Name, Affiliation, Date: Andy Goodrich, Forte,
374                               Bishnupriya Bhattacharya, Cadence Design Systems,
375                               25 August, 2003
376
377  Description of Modification: phase callbacks
378
379 *****************************************************************************/
380
381
382// $Log: sc_prim_channel.cpp,v $
383// Revision 1.11  2011/08/26 21:38:32  acg
384//  Philipp A. Hartmann: removed unused switch m_construction_done.
385//
386// Revision 1.10  2011/08/26 20:45:41  acg
387//  Andy Goodrich: moved the modification log to the end of the file to
388//  eliminate source line number skew when check-ins are done.
389//
390// Revision 1.9  2011/08/24 22:05:36  acg
391//  Torsten Maehne: initialization changes to remove warnings.
392//
393// Revision 1.8  2011/05/09 04:07:37  acg
394//  Philipp A. Hartmann:
395//    (1) Restore hierarchy in all phase callbacks.
396//    (2) Ensure calls to before_end_of_elaboration.
397//
398// Revision 1.7  2011/04/19 02:36:26  acg
399//  Philipp A. Hartmann: new aysnc_update and mutex support.
400//
401// Revision 1.6  2011/02/18 20:31:05  acg
402//  Philipp A. Hartmann: added error messages for calls that cannot be done
403//  after elaboration.
404//
405// Revision 1.5  2011/02/18 20:23:45  acg
406//  Andy Goodrich: Copyright update.
407//
408// Revision 1.4  2011/02/14 17:50:16  acg
409//  Andy Goodrich: testing for sc_port and sc_export instantiations during
410//  end of elaboration and issuing appropriate error messages.
411//
412// Revision 1.3  2010/12/07 20:36:49  acg
413//  Andy Goodrich: fix pointer that should have been initialized to zero.
414//
415// Revision 1.2  2010/12/07 19:50:36  acg
416//  Andy Goodrich: addition of writer policies, courtesy of Philipp Hartmann.
417//
418// Revision 1.1.1.1  2006/12/15 20:20:04  acg
419// SystemC 2.3
420//
421// Revision 1.4  2006/01/26 21:00:50  acg
422//  Andy Goodrich: conversion to use sc_event::notify(SC_ZERO_TIME) instead of
423//  sc_event::notify_delayed()
424//
425// Revision 1.3  2006/01/13 18:47:42  acg
426// Added $Log command so that CVS comments are reproduced in the source.
427//
428
429// Taf!
430