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_port.cpp -- Base classes of all port classes. 23 24 Original Author: Martin Janssen, Synopsys, Inc., 2001-05-21 25 26 CHANGE LOG AT THE END OF THE FILE 27 *****************************************************************************/ 28 29#include "sysc/kernel/sc_simcontext.h" 30#include "sysc/kernel/sc_module.h" 31#include "sysc/kernel/sc_object_int.h" 32#include "sysc/kernel/sc_method_process.h" 33#include "sysc/kernel/sc_thread_process.h" 34#include "sysc/communication/sc_communication_ids.h" 35#include "sysc/utils/sc_utils_ids.h" 36#include "sysc/communication/sc_event_finder.h" 37#include "sysc/communication/sc_port.h" 38#include "sysc/communication/sc_signal_ifs.h" 39 40namespace sc_core { 41 42// ---------------------------------------------------------------------------- 43// STRUCT : sc_bind_elem 44// ---------------------------------------------------------------------------- 45 46struct sc_bind_elem 47{ 48 // constructors 49 sc_bind_elem(); 50 explicit sc_bind_elem( sc_interface* interface_ ); 51 explicit sc_bind_elem( sc_port_base* parent_ ); 52 53 sc_interface* iface; 54 sc_port_base* parent; 55}; 56 57 58// IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII 59 60// constructors 61 62sc_bind_elem::sc_bind_elem() 63: iface( 0 ), 64 parent( 0 ) 65{} 66 67sc_bind_elem::sc_bind_elem( sc_interface* interface_ ) 68: iface( interface_ ), 69 parent( 0 ) 70{} 71 72sc_bind_elem::sc_bind_elem( sc_port_base* parent_ ) 73: iface( 0 ), 74 parent( parent_ ) 75{} 76 77 78// ---------------------------------------------------------------------------- 79// STRUCT : sc_bind_ef 80// ---------------------------------------------------------------------------- 81 82struct sc_bind_ef 83{ 84 // constructor 85 sc_bind_ef( sc_process_b* , sc_event_finder* ); 86 87 // destructor 88 ~sc_bind_ef(); 89 90 sc_process_b* handle; 91 sc_event_finder* event_finder; 92}; 93 94 95// IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII 96 97// constructor 98 99sc_bind_ef::sc_bind_ef( sc_process_b* handle_, 100 sc_event_finder* event_finder_ ) 101: handle( handle_ ), 102 event_finder( event_finder_ ) 103{} 104 105 106// destructor 107 108sc_bind_ef::~sc_bind_ef() 109{ 110} 111 112 113// ---------------------------------------------------------------------------- 114// STRUCT : sc_bind_info 115// ---------------------------------------------------------------------------- 116 117struct sc_bind_info 118{ 119 // constructor 120 explicit sc_bind_info( int max_size_, 121 sc_port_policy policy_=SC_ONE_OR_MORE_BOUND ); 122 123 // destructor 124 ~sc_bind_info(); 125 126 int max_size() const; 127 sc_port_policy policy() const; 128 int size() const; 129 130 int m_max_size; 131 sc_port_policy m_policy; 132 std::vector<sc_bind_elem*> vec; 133 bool has_parent; 134 int last_add; 135 bool is_leaf; 136 bool complete; 137 138 std::vector<sc_bind_ef*> thread_vec; 139 std::vector<sc_bind_ef*> method_vec; 140}; 141 142 143// IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII 144 145// constructor 146 147sc_bind_info::sc_bind_info( int max_size_, sc_port_policy policy_ ) 148: m_max_size( max_size_ ), 149 m_policy( policy_ ), 150 vec(), 151 has_parent( false ), 152 last_add( -1 ), 153 is_leaf( true ), 154 complete( false ), 155 thread_vec(), 156 method_vec() 157{} 158 159 160// destructor 161 162sc_bind_info::~sc_bind_info() 163{ 164 for( int i = size() - 1; i >= 0; -- i ) { 165 delete vec[i]; 166 } 167} 168 169 170int 171sc_bind_info::max_size() const 172{ 173 return m_max_size ? m_max_size : (int) vec.size(); 174} 175 176sc_port_policy 177sc_bind_info::policy() const 178{ 179 return m_policy; 180} 181 182int 183sc_bind_info::size() const 184{ 185 return vec.size(); 186} 187 188 189 190// ---------------------------------------------------------------------------- 191// CLASS : sc_port_base 192// 193// Abstract base class for class sc_port_b. 194// ---------------------------------------------------------------------------- 195 196// This method exists to get around a problem in VCC 6.0 where you cannot 197// have a friend class that is templated. So sc_port_b<IF> calls this class 198// instead of sc_process_b::add_static_event. 199 200void sc_port_base::add_static_event( 201 sc_method_handle process_p, const sc_event& event ) const 202{ 203 process_p->add_static_event( event ); 204} 205 206void sc_port_base::add_static_event( 207 sc_thread_handle process_p, const sc_event& event ) const 208{ 209 process_p->add_static_event( event ); 210} 211 212// return number of interfaces that will be bound, or are bound: 213 214int sc_port_base::bind_count() 215{ 216 if ( m_bind_info ) 217 return m_bind_info->size(); 218 else 219 return interface_count(); 220} 221 222// error reporting 223 224void 225sc_port_base::report_error( const char* id, const char* add_msg ) const 226{ 227 char msg[BUFSIZ]; 228 if( add_msg != 0 ) { 229 std::sprintf( msg, "%s: port '%s' (%s)", add_msg, name(), kind() ); 230 } else { 231 std::sprintf( msg, "port '%s' (%s)", name(), kind() ); 232 } 233 SC_REPORT_ERROR( id, msg ); 234} 235 236 237// constructors 238 239sc_port_base::sc_port_base( 240 int max_size_, sc_port_policy policy 241) : 242 sc_object( sc_gen_unique_name( "port" ) ), 243 m_bind_info(NULL) 244{ 245 simcontext()->get_port_registry()->insert( this ); 246 m_bind_info = new sc_bind_info( max_size_, policy ); 247} 248 249sc_port_base::sc_port_base( 250 const char* name_, int max_size_, sc_port_policy policy 251) : 252 sc_object( name_ ), 253 m_bind_info(NULL) 254{ 255 simcontext()->get_port_registry()->insert( this ); 256 m_bind_info = new sc_bind_info( max_size_, policy ); 257} 258 259 260// destructor 261 262sc_port_base::~sc_port_base() 263{ 264 simcontext()->get_port_registry()->remove( this ); 265 delete m_bind_info; 266} 267 268 269// bind interface to this port 270 271void 272sc_port_base::bind( sc_interface& interface_ ) 273{ 274 if( m_bind_info == 0 ) { 275 // cannot bind an interface after elaboration 276 report_error( SC_ID_BIND_IF_TO_PORT_, "simulation running" ); 277 } 278 279 m_bind_info->vec.push_back( new sc_bind_elem( &interface_ ) ); 280 281 if( ! m_bind_info->has_parent ) { 282 // add (cache) the interface 283 add_interface( &interface_ ); 284 m_bind_info->last_add ++; 285 } 286} 287 288 289// bind parent port to this port 290 291void 292sc_port_base::bind( this_type& parent_ ) 293{ 294 if( m_bind_info == 0 ) { 295 // cannot bind a parent port after elaboration 296 report_error( SC_ID_BIND_PORT_TO_PORT_, "simulation running" ); 297 } 298 299 if( &parent_ == this ) { 300 report_error( SC_ID_BIND_PORT_TO_PORT_, "same port" ); 301 } 302 303 // check if parent port is already bound to this port 304#if 0 305 for( int i = m_bind_info->size() - 1; i >= 0; -- i ) { 306 if( &parent_ == m_bind_info->vec[i]->parent ) { 307 report_error( SC_ID_BIND_PORT_TO_PORT_, "already bound" ); 308 } 309 } 310#endif // 311 312 m_bind_info->vec.push_back( new sc_bind_elem( &parent_ ) ); 313 m_bind_info->has_parent = true; 314 parent_.m_bind_info->is_leaf = false; 315} 316 317// called by construction_done (null by default) 318 319void sc_port_base::before_end_of_elaboration() 320{} 321 322// called by elaboration_done (does nothing) 323 324void 325sc_port_base::end_of_elaboration() 326{} 327 328// called by sc_port_registry::start_simulation (does nothing by default) 329 330void sc_port_base::start_of_simulation() 331{} 332 333// called by sc_port_registry::simulation_done (does nothing by default) 334 335void sc_port_base::end_of_simulation() 336{} 337 338 339// called by class sc_module for positional binding 340 341int 342sc_port_base::pbind( sc_interface& interface_ ) 343{ 344 if( m_bind_info == 0 ) { 345 // cannot bind an interface after elaboration 346 report_error( SC_ID_BIND_IF_TO_PORT_, "simulation running" ); 347 } 348 349 if( m_bind_info->size() != 0 ) { 350 // first interface already bound 351 return 1; 352 } 353 354 return vbind( interface_ ); 355} 356 357int 358sc_port_base::pbind( sc_port_base& parent_ ) 359{ 360 if( m_bind_info == 0 ) { 361 // cannot bind a parent port after elaboration 362 report_error( SC_ID_BIND_PORT_TO_PORT_, "simulation running" ); 363 } 364 365 if( m_bind_info->size() != 0 ) { 366 // first interface already bound 367 return 1; 368 } 369 370 return vbind( parent_ ); 371} 372 373 374// called by the sc_sensitive* classes 375 376void 377sc_port_base::make_sensitive( sc_thread_handle handle_, 378 sc_event_finder* event_finder_ ) const 379{ 380 assert( m_bind_info != 0 ); 381 m_bind_info->thread_vec.push_back( 382 new sc_bind_ef( (sc_process_b*)handle_, event_finder_ ) ); 383} 384 385void 386sc_port_base::make_sensitive( sc_method_handle handle_, 387 sc_event_finder* event_finder_ ) const 388{ 389 assert( m_bind_info != 0 ); 390 m_bind_info->method_vec.push_back( 391 new sc_bind_ef( (sc_process_b*)handle_, event_finder_ ) ); 392} 393 394 395// support methods 396 397int 398sc_port_base::first_parent() 399{ 400 for( int i = 0; i < m_bind_info->size(); ++ i ) { 401 if( m_bind_info->vec[i]->parent != 0 ) { 402 return i; 403 } 404 } 405 return -1; 406} 407 408void 409sc_port_base::insert_parent( int i ) 410{ 411 std::vector<sc_bind_elem*>& vec = m_bind_info->vec; 412 413 this_type* parent = vec[i]->parent; 414 415 416 // IF OUR PARENT HAS NO BINDING THEN IGNORE IT: 417 // 418 // Note that the zeroing of the parent pointer must occur before this 419 // test 420 421 vec[i]->parent = 0; 422 if ( parent->m_bind_info->vec.size() == 0 ) return; 423 424 vec[i]->iface = parent->m_bind_info->vec[0]->iface; 425 int n = parent->m_bind_info->size() - 1; 426 if( n > 0 ) { 427 // resize the bind vector (by adding new elements) 428 for( int k = 0; k < n; ++ k ) { 429 vec.push_back( new sc_bind_elem() ); 430 } 431 // move elements in the bind vector 432 for( int k = m_bind_info->size() - n - 1; k > i; -- k ) { 433 vec[k + n]->iface = vec[k]->iface; 434 vec[k + n]->parent = vec[k]->parent; 435 } 436 // insert parent interfaces into the bind vector 437 for( int k = i + 1; k <= i + n; ++ k ) { 438 vec[k]->iface = parent->m_bind_info->vec[k - i]->iface; 439 vec[k]->parent = 0; 440 } 441 } 442} 443 444 445// called when elaboration is done 446 447void 448sc_port_base::complete_binding() 449{ 450 char msg_buffer[128]; // For error message construction. 451 452 // IF BINDING HAS ALREADY BEEN COMPLETED IGNORE THIS CALL: 453 454 assert( m_bind_info != 0 ); 455 if( m_bind_info->complete ) { 456 return; 457 } 458 459 // COMPLETE BINDING OF OUR PARENT PORTS SO THAT WE CAN USE THAT INFORMATION: 460 461 int i = first_parent(); 462 while( i >= 0 ) { 463 m_bind_info->vec[i]->parent->complete_binding(); 464 insert_parent( i ); 465 i = first_parent(); 466 } 467 468 // LOOP OVER BINDING INFORMATION TO COMPLETE THE BINDING PROCESS: 469 470 int size; 471 for( int j = 0; j < m_bind_info->size(); ++ j ) { 472 sc_interface* iface = m_bind_info->vec[j]->iface; 473 474 // if the interface is zero this was for an unbound port. 475 if ( iface == 0 ) continue; 476 477 // add (cache) the interface 478 if( j > m_bind_info->last_add ) { 479 add_interface( iface ); 480 } 481 482 // only register "leaf" ports (ports without children) 483 if( m_bind_info->is_leaf ) { 484 iface->register_port( *this, if_typename() ); 485 } 486 487 // complete static sensitivity for methods 488 size = m_bind_info->method_vec.size(); 489 for( int k = 0; k < size; ++ k ) { 490 sc_bind_ef* p = m_bind_info->method_vec[k]; 491 const sc_event& event = ( p->event_finder != 0 ) 492 ? p->event_finder->find_event(iface) 493 : iface->default_event(); 494 p->handle->add_static_event( event ); 495 } 496 497 // complete static sensitivity for threads 498 size = m_bind_info->thread_vec.size(); 499 for( int k = 0; k < size; ++ k ) { 500 sc_bind_ef* p = m_bind_info->thread_vec[k]; 501 const sc_event& event = ( p->event_finder != 0 ) 502 ? p->event_finder->find_event(iface) 503 : iface->default_event(); 504 p->handle->add_static_event( event ); 505 } 506 507 } 508 509 // MAKE SURE THE PROPER NUMBER OF BINDINGS OCCURRED: 510 // 511 // Make sure there are enough bindings, and not too many. 512 513 int actual_binds = interface_count(); 514 515 if ( actual_binds > m_bind_info->max_size() ) 516 { 517 sprintf(msg_buffer, "%d binds exceeds maximum of %d allowed", 518 actual_binds, m_bind_info->max_size() ); 519 report_error( SC_ID_COMPLETE_BINDING_, msg_buffer ); 520 } 521 switch ( m_bind_info->policy() ) 522 { 523 case SC_ONE_OR_MORE_BOUND: 524 if ( actual_binds < 1 ) { 525 report_error( SC_ID_COMPLETE_BINDING_, "port not bound" ); 526 } 527 break; 528 case SC_ALL_BOUND: 529 if ( actual_binds < m_bind_info->max_size() || actual_binds < 1 ) { 530 sprintf(msg_buffer, "%d actual binds is less than required %d", 531 actual_binds, m_bind_info->max_size() ); 532 report_error( SC_ID_COMPLETE_BINDING_, msg_buffer ); 533 } 534 break; 535 default: // SC_ZERO_OR_MORE_BOUND: 536 break; 537 } 538 539 540 // CLEAN UP: FREE BINDING STORAGE: 541 542 size = m_bind_info->method_vec.size(); 543 for( int k = 0; k < size; ++ k ) { 544 delete m_bind_info->method_vec[k]; 545 } 546 m_bind_info->method_vec.resize(0); 547 548 size = m_bind_info->thread_vec.size(); 549 for( int k = 0; k < size; ++ k ) { 550 delete m_bind_info->thread_vec[k]; 551 } 552 m_bind_info->thread_vec.resize(0); 553 554 m_bind_info->complete = true; 555} 556 557void 558sc_port_base::construction_done() 559{ 560 sc_module* parent = static_cast<sc_module*>( get_parent_object() ); 561 sc_object::hierarchy_scope scope( parent ); 562 before_end_of_elaboration(); 563} 564 565void 566sc_port_base::elaboration_done() 567{ 568 assert( m_bind_info != 0 && m_bind_info->complete ); 569 delete m_bind_info; 570 m_bind_info = 0; 571 572 sc_module* parent = static_cast<sc_module*>( get_parent_object() ); 573 sc_object::hierarchy_scope scope( parent ); 574 end_of_elaboration(); 575} 576 577void 578sc_port_base::start_simulation() 579{ 580 sc_module* parent = static_cast<sc_module*>( get_parent_object() ); 581 sc_object::hierarchy_scope scope( parent ); 582 start_of_simulation(); 583} 584 585void 586sc_port_base::simulation_done() 587{ 588 sc_module* parent = static_cast<sc_module*>( get_parent_object() ); 589 sc_object::hierarchy_scope scope( parent ); 590 end_of_simulation(); 591} 592 593 594// ---------------------------------------------------------------------------- 595// CLASS : sc_port_registry 596// 597// Registry for all ports. 598// FOR INTERNAL USE ONLY! 599// ---------------------------------------------------------------------------- 600 601void 602sc_port_registry::insert( sc_port_base* port_ ) 603{ 604 if( sc_is_running() ) { 605 port_->report_error( SC_ID_INSERT_PORT_, "simulation running" ); 606 } 607 608 if( m_simc->elaboration_done() ) { 609 port_->report_error( SC_ID_INSERT_PORT_, "elaboration done" ); 610 } 611 612#if defined(DEBUG_SYSTEMC) 613 // check if port_ is already inserted 614 for( int i = size() - 1; i >= 0; -- i ) { 615 if( port_ == m_port_vec[i] ) { 616 port_->report_error( SC_ID_INSERT_PORT_, "port already inserted" ); 617 } 618 } 619#endif 620 621 // append the port to the current module's vector of ports 622 sc_module* curr_module = m_simc->hierarchy_curr(); 623 if( curr_module == 0 ) { 624 port_->report_error( SC_ID_PORT_OUTSIDE_MODULE_ ); 625 } 626 curr_module->append_port( port_ ); 627 628 // insert 629 m_port_vec.push_back( port_ ); 630} 631 632void 633sc_port_registry::remove( sc_port_base* port_ ) 634{ 635 int i; 636 for( i = size() - 1; i >= 0; -- i ) { 637 if( port_ == m_port_vec[i] ) { 638 break; 639 } 640 } 641 if( i == -1 ) { 642 port_->report_error( SC_ID_REMOVE_PORT_, "port not registered" ); 643 } 644 645 // remove 646 m_port_vec[i] = m_port_vec[size() - 1]; 647 m_port_vec.resize(size()-1); 648} 649 650 651// constructor 652 653sc_port_registry::sc_port_registry( sc_simcontext& simc_ ) 654: m_construction_done(0), 655 m_port_vec(), 656 m_simc( &simc_ ) 657{ 658} 659 660 661// destructor 662 663sc_port_registry::~sc_port_registry() 664{ 665} 666 667// called when construction is done 668 669bool 670sc_port_registry::construction_done() 671{ 672 if( size() == m_construction_done ) 673 // nothing has been updated 674 return true; 675 676 for( int i = size()-1; i >= m_construction_done; --i ) { 677 m_port_vec[i]->construction_done(); 678 } 679 680 m_construction_done = size(); 681 return false; 682} 683 684// called when when elaboration is done 685 686void 687sc_port_registry::complete_binding() 688{ 689 for( int i = size() - 1; i >= 0; -- i ) { 690 m_port_vec[i]->complete_binding(); 691 } 692} 693 694 695// called when elaboration is done 696 697void 698sc_port_registry::elaboration_done() 699{ 700 complete_binding(); 701 702 for( int i = size() - 1; i >= 0; -- i ) { 703 m_port_vec[i]->elaboration_done(); 704 } 705} 706 707// called before simulation begins 708 709void 710sc_port_registry::start_simulation() 711{ 712 for( int i = size() - 1; i >= 0; -- i ) { 713 m_port_vec[i]->start_simulation(); 714 } 715} 716 717// called after simulation ends 718 719void 720sc_port_registry::simulation_done() 721{ 722 for( int i = size() - 1; i >= 0; -- i ) { 723 m_port_vec[i]->simulation_done(); 724 } 725} 726 727// This is a static member function. 728 729void 730sc_port_registry::replace_port( sc_port_registry* /* registry */ ) 731{ 732} 733 734void sc_warn_port_constructor() 735{ 736 static bool warn_port_constructor=true; 737 if ( warn_port_constructor ) 738 { 739 warn_port_constructor = false; 740 SC_REPORT_INFO(SC_ID_IEEE_1666_DEPRECATION_, 741 "interface and/or port binding in port constructors is deprecated" 742 ); 743 } 744} 745 746} // namespace sc_core 747 748 749/***************************************************************************** 750 751 MODIFICATION LOG - modifiers, enter your name, affiliation, date and 752 changes you are making here. 753 754 Name, Affiliation, Date: Andy Goodrich, Forte Design Systems 755 Bishnupriya Bhattacharya, Cadence Design Systems, 756 25 August, 2003 757 Description of Modification: phase callbacks 758 759 Name, Affiliation, Date: Andy Goodrich, Forte Design Systems 760 12 December, 2005 761 Description of Modification: multiport binding policy changes 762 763 *****************************************************************************/ 764 765 766// $Log: sc_port.cpp,v $ 767// Revision 1.8 2011/08/24 22:05:36 acg 768// Torsten Maehne: initialization changes to remove warnings. 769// 770// Revision 1.7 2011/08/15 16:43:24 acg 771// Torsten Maehne: changes to remove unused argument warnings. 772// 773// Revision 1.6 2011/08/07 19:08:01 acg 774// Andy Goodrich: moved logs to end of file so line number synching works 775// better between versions. 776// 777// Revision 1.5 2011/08/07 18:53:09 acg 778// Philipp A. Hartmann: add virtual instances of the bind function for 779// base classes to eliminate warning messages for clang platforms. 780// 781// Revision 1.4 2011/05/09 04:07:37 acg 782// Philipp A. Hartmann: 783// (1) Restore hierarchy in all phase callbacks. 784// (2) Ensure calls to before_end_of_elaboration. 785// 786// Revision 1.3 2011/02/18 20:23:45 acg 787// Andy Goodrich: Copyright update. 788// 789// Revision 1.2 2011/02/14 17:50:16 acg 790// Andy Goodrich: testing for sc_port and sc_export instantiations during 791// end of elaboration and issuing appropriate error messages. 792// 793// Revision 1.1.1.1 2006/12/15 20:20:04 acg 794// SystemC 2.3 795// 796// Revision 1.11 2006/08/29 23:34:59 acg 797// Andy Goodrich: added bind_count() method to allow users to determine which 798// ports are connected in before_end_of_elaboration(). 799// 800// Revision 1.10 2006/05/08 17:52:47 acg 801// Andy Goodrich: 802// (1) added David Long's forward declarations for friend functions, 803// methods, and operators to keep the Microsoft compiler happy. 804// (2) Added delta_count() method to sc_prim_channel for use by 805// sc_signal so that the friend declaration in sc_simcontext.h 806// can be for a non-templated class (i.e., sc_prim_channel.) 807// 808// Revision 1.9 2006/02/02 20:43:09 acg 809// Andy Goodrich: Added an existence linked list to sc_event_finder so that 810// the dynamically allocated instances can be freed after port binding 811// completes. This replaces the individual deletions in ~sc_bind_ef, as these 812// caused an exception if an sc_event_finder instance was used more than 813// once, due to a double freeing of the instance. 814// 815// Revision 1.7 2006/01/26 21:00:50 acg 816// Andy Goodrich: conversion to use sc_event::notify(SC_ZERO_TIME) instead of 817// sc_event::notify_delayed() 818// 819// Revision 1.6 2006/01/25 00:31:11 acg 820// Andy Goodrich: Changed over to use a standard message id of 821// SC_ID_IEEE_1666_DEPRECATION for all deprecation messages. 822// 823// Revision 1.5 2006/01/24 20:46:31 acg 824// Andy Goodrich: changes to eliminate use of deprecated features. For instance, 825// using notify(SC_ZERO_TIME) in place of notify_delayed(). 826// 827// Revision 1.4 2006/01/13 20:41:59 acg 828// Andy Goodrich: Changes to add port registration to the things that are 829// checked when SC_NO_WRITE_CHECK is not defined. 830// 831// Revision 1.3 2006/01/13 18:47:42 acg 832// Added $Log command so that CVS comments are reproduced in the source. 833// 834 835// Taf! 836