sc_event.cpp revision 12027
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_event.cpp -- 23 24 Original Author: Martin Janssen, Synopsys, Inc., 2001-05-21 25 26 CHANGE LOG APPEARS AT THE END OF THE FILE 27 *****************************************************************************/ 28 29#include <stdlib.h> 30#include <string.h> 31 32#include "sysc/kernel/sc_event.h" 33#include "sysc/kernel/sc_kernel_ids.h" 34#include "sysc/kernel/sc_phase_callback_registry.h" 35#include "sysc/kernel/sc_process.h" 36#include "sysc/kernel/sc_process_handle.h" 37#include "sysc/kernel/sc_simcontext_int.h" 38#include "sysc/kernel/sc_object_manager.h" 39#include "sysc/utils/sc_utils_ids.h" 40 41namespace sc_core { 42 43// ---------------------------------------------------------------------------- 44// CLASS : sc_event 45// 46// The event class. 47// ---------------------------------------------------------------------------- 48 49const char* 50sc_event::basename() const 51{ 52 const char* p = strrchr( m_name.c_str(), SC_HIERARCHY_CHAR ); 53 return p ? (p + 1) : m_name.c_str(); 54} 55 56void 57sc_event::cancel() 58{ 59 // cancel a delta or timed notification 60 switch( m_notify_type ) { 61 case DELTA: { 62 // remove this event from the delta events set 63 m_simc->remove_delta_event( this ); 64 m_notify_type = NONE; 65 break; 66 } 67 case TIMED: { 68 // remove this event from the timed events set 69 sc_assert( m_timed != 0 ); 70 m_timed->m_event = 0; 71 m_timed = 0; 72 m_notify_type = NONE; 73 break; 74 } 75 default: 76 ; 77 } 78} 79 80 81void 82sc_event::notify() 83{ 84 // immediate notification 85 if( 86 // coming from sc_prim_channel::update 87 m_simc->update_phase() 88#if SC_HAS_PHASE_CALLBACKS_ 89 // coming from phase callbacks 90 || m_simc->notify_phase() 91#endif 92 ) 93 { 94 SC_REPORT_ERROR( SC_ID_IMMEDIATE_NOTIFICATION_, "" ); 95 return; 96 } 97 cancel(); 98 trigger(); 99} 100 101void 102sc_event::notify( const sc_time& t ) 103{ 104 if( m_notify_type == DELTA ) { 105 return; 106 } 107 if( t == SC_ZERO_TIME ) { 108# if SC_HAS_PHASE_CALLBACKS_ 109 if( SC_UNLIKELY_( m_simc->get_status() 110 & (SC_END_OF_UPDATE|SC_BEFORE_TIMESTEP) ) ) 111 { 112 std::stringstream msg; 113 msg << m_simc->get_status() 114 << ":\n\t delta notification of `" 115 << name() << "' ignored"; 116 SC_REPORT_WARNING( SC_ID_PHASE_CALLBACK_FORBIDDEN_ 117 , msg.str().c_str() ); 118 return; 119 } 120# endif 121 if( m_notify_type == TIMED ) { 122 // remove this event from the timed events set 123 sc_assert( m_timed != 0 ); 124 m_timed->m_event = 0; 125 m_timed = 0; 126 } 127 // add this event to the delta events set 128 m_delta_event_index = m_simc->add_delta_event( this ); 129 m_notify_type = DELTA; 130 return; 131 } 132# if SC_HAS_PHASE_CALLBACKS_ 133 if( SC_UNLIKELY_( m_simc->get_status() 134 & (SC_END_OF_UPDATE|SC_BEFORE_TIMESTEP) ) ) 135 { 136 std::stringstream msg; 137 msg << m_simc->get_status() 138 << ":\n\t timed notification of `" 139 << name() << "' ignored"; 140 SC_REPORT_WARNING( SC_ID_PHASE_CALLBACK_FORBIDDEN_ 141 , msg.str().c_str() ); 142 return; 143 } 144# endif 145 if( m_notify_type == TIMED ) { 146 sc_assert( m_timed != 0 ); 147 if( m_timed->m_notify_time <= m_simc->time_stamp() + t ) { 148 return; 149 } 150 // remove this event from the timed events set 151 m_timed->m_event = 0; 152 m_timed = 0; 153 } 154 // add this event to the timed events set 155 sc_event_timed* et = new sc_event_timed( this, m_simc->time_stamp() + t ); 156 m_simc->add_timed_event( et ); 157 m_timed = et; 158 m_notify_type = TIMED; 159} 160 161static void sc_warn_notify_delayed() 162{ 163 static bool warn_notify_delayed=true; 164 if ( warn_notify_delayed ) 165 { 166 warn_notify_delayed = false; 167 SC_REPORT_INFO(SC_ID_IEEE_1666_DEPRECATION_, 168 "notify_delayed(...) is deprecated, use notify(sc_time) instead" ); 169 } 170} 171 172void 173sc_event::notify_delayed() 174{ 175 sc_warn_notify_delayed(); 176 if( m_notify_type != NONE ) { 177 SC_REPORT_ERROR( SC_ID_NOTIFY_DELAYED_, 0 ); 178 } 179 // add this event to the delta events set 180 m_delta_event_index = m_simc->add_delta_event( this ); 181 m_notify_type = DELTA; 182} 183 184void 185sc_event::notify_delayed( const sc_time& t ) 186{ 187 sc_warn_notify_delayed(); 188 if( m_notify_type != NONE ) { 189 SC_REPORT_ERROR( SC_ID_NOTIFY_DELAYED_, 0 ); 190 } 191 if( t == SC_ZERO_TIME ) { 192 // add this event to the delta events set 193 m_delta_event_index = m_simc->add_delta_event( this ); 194 m_notify_type = DELTA; 195 } else { 196 // add this event to the timed events set 197 sc_event_timed* et = new sc_event_timed( this, 198 m_simc->time_stamp() + t ); 199 m_simc->add_timed_event( et ); 200 m_timed = et; 201 m_notify_type = TIMED; 202 } 203} 204 205// +---------------------------------------------------------------------------- 206// |"sc_event::register_event" 207// | 208// | This method sets the name of this object instance and optionally adds 209// | it to the object manager's hierarchy. The object instance will be 210// | inserted into the object manager's hierarchy if one of the following is 211// | true: 212// | (a) the leaf name is non-null and does not start with 213// | SC_KERNEL_EVENT_PREFIX. 214// | (b) the event is being created before the start of simulation. 215// | 216// | Arguments: 217// | leaf_name = leaf name of the object or NULL. 218// +---------------------------------------------------------------------------- 219void sc_event::register_event( const char* leaf_name ) 220{ 221 sc_object_manager* object_manager = m_simc->get_object_manager(); 222 m_parent_p = m_simc->active_object(); 223 224 // No name provided, if we are not executing then create a name: 225 226 if( !leaf_name || !leaf_name[0] ) 227 { 228 if ( sc_is_running( m_simc ) ) return; 229 leaf_name = sc_gen_unique_name("event"); 230 } 231 232 // Create a hierarchichal name and place it into the object manager if 233 // its not a kernel event: 234 235 object_manager->create_name( leaf_name ).swap( m_name ); 236 237 if ( strncmp( leaf_name, SC_KERNEL_EVENT_PREFIX, 238 strlen(SC_KERNEL_EVENT_PREFIX) ) ) 239 { 240 object_manager->insert_event(m_name, this); 241 if ( m_parent_p ) 242 m_parent_p->add_child_event( this ); 243 else 244 m_simc->add_child_event( this ); 245 } 246} 247 248void 249sc_event::reset() 250{ 251 m_notify_type = NONE; 252 m_delta_event_index = -1; 253 m_timed = 0; 254 // clear the dynamic sensitive methods 255 m_methods_dynamic.resize(0); 256 // clear the dynamic sensitive threads 257 m_threads_dynamic.resize(0); 258} 259 260// +---------------------------------------------------------------------------- 261// |"sc_event::sc_event(name)" 262// | 263// | This is the object instance constructor for named sc_event instances. 264// | If the name is non-null or the this is during elaboration add the 265// | event to the object hierarchy. 266// | 267// | Arguments: 268// | name = name of the event. 269// +---------------------------------------------------------------------------- 270sc_event::sc_event( const char* name ) : 271 m_name(), 272 m_parent_p(NULL), 273 m_simc( sc_get_curr_simcontext() ), 274 m_notify_type( NONE ), 275 m_delta_event_index( -1 ), 276 m_timed( 0 ), 277 m_methods_static(), 278 m_methods_dynamic(), 279 m_threads_static(), 280 m_threads_dynamic() 281{ 282 // Skip simulator's internally defined events. 283 284 register_event( name ); 285} 286 287// +---------------------------------------------------------------------------- 288// |"sc_event::sc_event(name)" 289// | 290// | This is the object instance constructor for non-named sc_event instances. 291// | If this is during elaboration add create a name and add it to the object 292// | hierarchy. 293// +---------------------------------------------------------------------------- 294sc_event::sc_event() : 295 m_name(), 296 m_parent_p(NULL), 297 m_simc( sc_get_curr_simcontext() ), 298 m_notify_type( NONE ), 299 m_delta_event_index( -1 ), 300 m_timed( 0 ), 301 m_methods_static(), 302 m_methods_dynamic(), 303 m_threads_static(), 304 m_threads_dynamic() 305{ 306 307 register_event( NULL ); 308} 309 310// +---------------------------------------------------------------------------- 311// |"sc_event::~sc_event" 312// | 313// | This is the object instance destructor for this class. It cancels any 314// | outstanding waits and removes the event from the object manager's 315// | instance table if it has a name. 316// +---------------------------------------------------------------------------- 317sc_event::~sc_event() 318{ 319 cancel(); 320 if ( m_name.length() != 0 ) 321 { 322 sc_object_manager* object_manager_p = m_simc->get_object_manager(); 323 object_manager_p->remove_event( m_name ); 324 } 325} 326 327// +---------------------------------------------------------------------------- 328// |"sc_event::trigger" 329// | 330// | This method "triggers" this object instance. This consists of scheduling 331// | for execution all the processes that are schedulable and waiting on this 332// | event. 333// +---------------------------------------------------------------------------- 334void 335sc_event::trigger() 336{ 337 int last_i; // index of last element in vector now accessing. 338 int size; // size of vector now accessing. 339 340 341 // trigger the static sensitive methods 342 343 if( ( size = m_methods_static.size() ) != 0 ) 344 { 345 sc_method_handle* l_methods_static = &m_methods_static[0]; 346 int i = size - 1; 347 do { 348 sc_method_handle method_h = l_methods_static[i]; 349 method_h->trigger_static(); 350 } while( -- i >= 0 ); 351 } 352 353 // trigger the dynamic sensitive methods 354 355 356 if( ( size = m_methods_dynamic.size() ) != 0 ) 357 { 358 last_i = size - 1; 359 sc_method_handle* l_methods_dynamic = &m_methods_dynamic[0]; 360 for ( int i = 0; i <= last_i; i++ ) 361 { 362 sc_method_handle method_h = l_methods_dynamic[i]; 363 if ( method_h->trigger_dynamic( this ) ) 364 { 365 l_methods_dynamic[i] = l_methods_dynamic[last_i]; 366 last_i--; 367 i--; 368 } 369 } 370 m_methods_dynamic.resize(last_i+1); 371 } 372 373 374 // trigger the static sensitive threads 375 376 if( ( size = m_threads_static.size() ) != 0 ) 377 { 378 sc_thread_handle* l_threads_static = &m_threads_static[0]; 379 int i = size - 1; 380 do { 381 sc_thread_handle thread_h = l_threads_static[i]; 382 thread_h->trigger_static(); 383 } while( -- i >= 0 ); 384 } 385 386 // trigger the dynamic sensitive threads 387 388 if( ( size = m_threads_dynamic.size() ) != 0 ) 389 { 390 last_i = size - 1; 391 sc_thread_handle* l_threads_dynamic = &m_threads_dynamic[0]; 392 for ( int i = 0; i <= last_i; i++ ) 393 { 394 sc_thread_handle thread_h = l_threads_dynamic[i]; 395 if ( thread_h->trigger_dynamic( this ) ) 396 { 397 l_threads_dynamic[i] = l_threads_dynamic[last_i]; 398 i--; 399 last_i--; 400 } 401 } 402 m_threads_dynamic.resize(last_i+1); 403 } 404 405 m_notify_type = NONE; 406 m_delta_event_index = -1; 407 m_timed = 0; 408} 409 410 411bool 412sc_event::remove_static( sc_method_handle method_h_ ) const 413{ 414 int size; 415 if ( ( size = m_methods_static.size() ) != 0 ) { 416 sc_method_handle* l_methods_static = &m_methods_static[0]; 417 for( int i = size - 1; i >= 0; -- i ) { 418 if( l_methods_static[i] == method_h_ ) { 419 l_methods_static[i] = l_methods_static[size - 1]; 420 m_methods_static.resize(size-1); 421 return true; 422 } 423 } 424 } 425 return false; 426} 427 428bool 429sc_event::remove_static( sc_thread_handle thread_h_ ) const 430{ 431 int size; 432 if ( ( size = m_threads_static.size() ) != 0 ) { 433 sc_thread_handle* l_threads_static = &m_threads_static[0]; 434 for( int i = size - 1; i >= 0; -- i ) { 435 if( l_threads_static[i] == thread_h_ ) { 436 l_threads_static[i] = l_threads_static[size - 1]; 437 m_threads_static.resize(size-1); 438 return true; 439 } 440 } 441 } 442 return false; 443} 444 445bool 446sc_event::remove_dynamic( sc_method_handle method_h_ ) const 447{ 448 int size; 449 if ( ( size = m_methods_dynamic.size() ) != 0 ) { 450 sc_method_handle* l_methods_dynamic = &m_methods_dynamic[0]; 451 for( int i = size - 1; i >= 0; -- i ) { 452 if( l_methods_dynamic[i] == method_h_ ) { 453 l_methods_dynamic[i] = l_methods_dynamic[size - 1]; 454 m_methods_dynamic.resize(size-1); 455 return true; 456 } 457 } 458 } 459 return false; 460} 461 462bool 463sc_event::remove_dynamic( sc_thread_handle thread_h_ ) const 464{ 465 int size; 466 if ( ( size= m_threads_dynamic.size() ) != 0 ) { 467 sc_thread_handle* l_threads_dynamic = &m_threads_dynamic[0]; 468 for( int i = size - 1; i >= 0; -- i ) { 469 if( l_threads_dynamic[i] == thread_h_ ) { 470 l_threads_dynamic[i] = l_threads_dynamic[size - 1]; 471 m_threads_dynamic.resize(size-1); 472 return true; 473 } 474 } 475 } 476 return false; 477} 478 479 480// ---------------------------------------------------------------------------- 481// CLASS : sc_event_timed 482// 483// Class for storing the time to notify a timed event. 484// ---------------------------------------------------------------------------- 485 486// dedicated memory management; not MT-Safe 487 488union sc_event_timed_u 489{ 490 sc_event_timed_u* next; 491 char dummy[sizeof( sc_event_timed )]; 492}; 493 494static 495sc_event_timed_u* free_list = 0; 496 497void* 498sc_event_timed::allocate() 499{ 500 const int ALLOC_SIZE = 64; 501 502 if( free_list == 0 ) { 503 free_list = (sc_event_timed_u*) malloc( ALLOC_SIZE * 504 sizeof( sc_event_timed ) ); 505 int i = 0; 506 for( ; i < ALLOC_SIZE - 1; ++ i ) { 507 free_list[i].next = &free_list[i + 1]; 508 } 509 free_list[i].next = 0; 510 } 511 512 sc_event_timed_u* q = free_list; 513 free_list = free_list->next; 514 return q; 515} 516 517void 518sc_event_timed::deallocate( void* p ) 519{ 520 if( p != 0 ) { 521 sc_event_timed_u* q = RCAST<sc_event_timed_u*>( p ); 522 q->next = free_list; 523 free_list = q; 524 } 525} 526 527 528// ---------------------------------------------------------------------------- 529// CLASS : sc_event_list 530// 531// Base class for lists of events. 532// ---------------------------------------------------------------------------- 533 534void 535sc_event_list::push_back( const sc_event& e ) 536{ 537 // make sure e is not already in the list 538 if ( m_events.size() != 0 ) { 539 const sc_event** l_events = &m_events[0]; 540 for( int i = m_events.size() - 1; i >= 0; -- i ) { 541 if( &e == l_events[i] ) { 542 // event already in the list; ignore 543 return; 544 } 545 } 546 } 547 m_events.push_back( &e ); 548} 549 550void 551sc_event_list::push_back( const sc_event_list& el ) 552{ 553 m_events.reserve( size() + el.size() ); 554 for ( int i = el.m_events.size() - 1; i >= 0; --i ) 555 { 556 push_back( *el.m_events[i] ); 557 } 558 el.auto_delete(); 559} 560 561void 562sc_event_list::add_dynamic( sc_method_handle method_h ) const 563{ 564 m_busy++; 565 if ( m_events.size() != 0 ) { 566 const sc_event* const * l_events = &m_events[0]; 567 for( int i = m_events.size() - 1; i >= 0; -- i ) { 568 l_events[i]->add_dynamic( method_h ); 569 } 570 } 571} 572 573void 574sc_event_list::add_dynamic( sc_thread_handle thread_h ) const 575{ 576 m_busy++; 577 if ( m_events.size() != 0 ) { 578 const sc_event* const* l_events = &m_events[0]; 579 for( int i = m_events.size() - 1; i >= 0; -- i ) { 580 l_events[i]->add_dynamic( thread_h ); 581 } 582 } 583} 584 585void 586sc_event_list::remove_dynamic( sc_method_handle method_h, 587 const sc_event* e_not ) const 588{ 589 if ( m_events.size() != 0 ) { 590 const sc_event* const* l_events = &m_events[0]; 591 for( int i = m_events.size() - 1; i >= 0; -- i ) { 592 const sc_event* e = l_events[i]; 593 if( e != e_not ) { 594 e->remove_dynamic( method_h ); 595 } 596 } 597 } 598} 599 600void 601sc_event_list::remove_dynamic( sc_thread_handle thread_h, 602 const sc_event* e_not ) const 603{ 604 if ( m_events.size() != 0 ) { 605 const sc_event* const* l_events = &m_events[0]; 606 for( int i = m_events.size() - 1; i >= 0; -- i ) { 607 const sc_event* e = l_events[i]; 608 if( e != e_not ) { 609 e->remove_dynamic( thread_h ); 610 } 611 } 612 } 613} 614 615void 616sc_event_list::report_premature_destruction() const 617{ 618 // TDB: reliably detect premature destruction 619 // 620 // If an event list is used as a member of a module, 621 // its lifetime may (correctly) end, although there 622 // are processes currently waiting for it. 623 // 624 // Detecting (and ignoring) this corner-case is quite 625 // difficult for similar reasons to the sc_is_running() 626 // return value during the destruction of the module 627 // hierarchy. 628 // 629 // Ignoring the lifetime checks for now, if no process 630 // is currently running (which is only part of the story): 631 632 if( sc_get_current_process_handle().valid() ) { 633 // FIXME: improve error-handling 634 sc_assert( false && "sc_event_list prematurely destroyed" ); 635 } 636 637} 638 639void 640sc_event_list::report_invalid_modification() const 641{ 642 // FIXME: improve error-handling 643 sc_assert( false && "sc_event_list modfied while being waited on" ); 644} 645 646// ---------------------------------------------------------------------------- 647// Deprecated functional notation for notifying events. 648// ---------------------------------------------------------------------------- 649 650static void sc_warn_notify() 651{ 652 static bool warn_notify=true; 653 if ( warn_notify ) 654 { 655 SC_REPORT_INFO(SC_ID_IEEE_1666_DEPRECATION_, 656 "the notify() function is deprecated use sc_event::notify()" ); 657 warn_notify = false; 658 } 659} 660 661void 662notify( sc_event& e ) 663{ 664 sc_warn_notify(); 665 e.notify(); 666} 667 668void 669notify( const sc_time& t, sc_event& e ) 670{ 671 sc_warn_notify(); 672 e.notify( t ); 673} 674 675void 676notify( double v, sc_time_unit tu, sc_event& e ) 677{ 678 sc_warn_notify(); 679 e.notify( v, tu ); 680} 681 682} // namespace sc_core 683 684// $Log: sc_event.cpp,v $ 685// Revision 1.17 2011/08/26 20:46:09 acg 686// Andy Goodrich: moved the modification log to the end of the file to 687// eliminate source line number skew when check-ins are done. 688// 689// Revision 1.16 2011/08/24 22:05:50 acg 690// Torsten Maehne: initialization changes to remove warnings. 691// 692// Revision 1.15 2011/03/12 21:07:51 acg 693// Andy Goodrich: changes to kernel generated event support. 694// 695// Revision 1.14 2011/03/06 15:55:52 acg 696// Andy Goodrich: changes for named events. 697// 698// Revision 1.13 2011/03/05 01:39:21 acg 699// Andy Goodrich: changes for named events. 700// 701// Revision 1.12 2011/02/19 08:33:25 acg 702// Andy Goodrich: remove }'s that should have been removed before. 703// 704// Revision 1.11 2011/02/19 08:30:53 acg 705// Andy Goodrich: Moved process queueing into trigger_static from 706// sc_event::notify. 707// 708// Revision 1.10 2011/02/18 20:27:14 acg 709// Andy Goodrich: Updated Copyrights. 710// 711// Revision 1.9 2011/02/17 19:49:51 acg 712// Andy Goodrich: 713// (1) Changed signature of trigger_dynamic() to return a bool again. 714// (2) Moved process run queue processing into trigger_dynamic(). 715// 716// Revision 1.8 2011/02/16 22:37:30 acg 717// Andy Goodrich: clean up to remove need for ps_disable_pending. 718// 719// Revision 1.7 2011/02/13 21:47:37 acg 720// Andy Goodrich: update copyright notice. 721// 722// Revision 1.6 2011/02/01 21:02:28 acg 723// Andy Goodrich: new return code for trigger_dynamic() calls. 724// 725// Revision 1.5 2011/01/18 20:10:44 acg 726// Andy Goodrich: changes for IEEE1666_2011 semantics. 727// 728// Revision 1.4 2011/01/06 18:04:05 acg 729// Andy Goodrich: added code to leave disabled processes on the dynamic 730// method and thread queues. 731// 732// Revision 1.3 2008/05/22 17:06:25 acg 733// Andy Goodrich: updated copyright notice to include 2008. 734// 735// Revision 1.2 2007/01/17 22:44:30 acg 736// Andy Goodrich: fix for Microsoft compiler. 737// 738// Revision 1.7 2006/04/11 23:13:20 acg 739// Andy Goodrich: Changes for reduced reset support that only includes 740// sc_cthread, but has preliminary hooks for expanding to method and thread 741// processes also. 742// 743// Revision 1.6 2006/01/25 00:31:19 acg 744// Andy Goodrich: Changed over to use a standard message id of 745// SC_ID_IEEE_1666_DEPRECATION for all deprecation messages. 746// 747// Revision 1.5 2006/01/24 20:59:11 acg 748// Andy Goodrich: fix up of CVS comments, new version roll. 749// 750// Revision 1.4 2006/01/24 20:48:14 acg 751// Andy Goodrich: added deprecation warnings for notify_delayed(). Added two 752// new implementation-dependent methods, notify_next_delta() & notify_internal() 753// to replace calls to notify_delayed() from within the simulator. These two 754// new methods are simpler than notify_delayed() and should speed up simulations 755// 756// Revision 1.3 2006/01/13 18:44:29 acg 757// Added $Log to record CVS changes into the source. 758 759// Taf! 760