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