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_reset.cpp -- Support for reset. 23 24 Original Author: Andy Goodrich, Forte Design Systems 25 26 CHANGE LOG AT THE END OF THE FILE 27 *****************************************************************************/ 28 29 30#include "sysc/kernel/sc_simcontext.h" 31#include "sysc/kernel/sc_reset.h" 32#include "sysc/kernel/sc_process_handle.h" 33#include "sysc/communication/sc_signal.h" 34#include "sysc/communication/sc_signal_ports.h" 35 36 37// THE SYSTEMC PROOF OF CONCEPT SIMULATOR RESET SIGNAL IMPLEMENTATION: 38// 39// (1) An instance of the sc_reset class is attached to each sc_signal<bool> 40// that is used as a reset signal. 41// 42// (2) Each process that is senstive to a reset signal will be registered in the 43// sc_reset class attached to that reset signal. 44// 45// (3) When a change in the value of a reset signal occurs it invokes the 46// notify_processes() method of its sc_reset object instance. The 47// notify_processes() method will call the reset_changed() method of each 48// process that is registered with it to inform the process that 49// state of the reset signal has changed. 50// 51// (4) A process may have multiple reset signals, so counters are kept for the 52// number of active asynchronous, and synchronous, reset signals that are 53// active. Those counters are incremented and decremented in the process' 54// reset_changed() method. 55// 56// (5) When a process' semantics() method is called the current reset state is 57// checked, and a reset sequence is initiated if the process is in reset. 58// This will occur every time an SC_METHOD is dispatched. SC_CTHREAD and 59// and SC_THREAD instances, only go through the semantics() method they 60// initially start up. So the reset check is duplicated in the suspend_me() 61// method, the tail of which will execute each time the thread is 62// dispatched. 63 64namespace sc_core { 65 66class sc_reset_finder; 67static sc_reset_finder* reset_finder_q=0; // Q of reset finders to reconcile. 68 69//============================================================================== 70// sc_reset_finder - place holder class for a port reset signal until it is 71// bound and an interface class is available. When the port 72// has been bound the information in this class will be used 73// to initialize its sc_reset object instance. 74//============================================================================== 75class sc_reset_finder { 76 friend class sc_reset; 77 public: 78 sc_reset_finder( bool async, const sc_in<bool>* port_p, bool level, 79 sc_process_b* target_p); 80 sc_reset_finder( bool async, const sc_inout<bool>* port_p, bool level, 81 sc_process_b* target_p); 82 sc_reset_finder( bool async, const sc_out<bool>* port_p, bool level, 83 sc_process_b* target_p); 84 85 protected: 86 bool m_async; // True if asynchronous reset. 87 bool m_level; // Level for reset. 88 sc_reset_finder* m_next_p; // Next reset finder in list. 89 const sc_in<bool>* m_in_p; // Port for which reset is needed. 90 const sc_inout<bool>* m_inout_p; // Port for which reset is needed. 91 const sc_out<bool>* m_out_p; // Port for which reset is needed. 92 sc_process_b* m_target_p; // Process to reset. 93 94 private: // disabled 95 sc_reset_finder( const sc_reset_finder& ); 96 const sc_reset_finder& operator = ( const sc_reset_finder& ); 97}; 98 99inline sc_reset_finder::sc_reset_finder( 100 bool async, const sc_in<bool>* port_p, bool level, sc_process_b* target_p) : 101 m_async(async), m_level(level), m_next_p(0), m_in_p(port_p), m_inout_p(0), 102 m_out_p(0), m_target_p(target_p) 103{ 104 m_next_p = reset_finder_q; 105 reset_finder_q = this; 106} 107 108inline sc_reset_finder::sc_reset_finder( 109 bool async, const sc_inout<bool>* port_p, bool level, sc_process_b* target_p 110) : 111 m_async(async), m_level(level), m_next_p(0), m_in_p(0), m_inout_p(port_p), 112 m_out_p(0), m_target_p(target_p) 113{ 114 m_next_p = reset_finder_q; 115 reset_finder_q = this; 116} 117 118inline sc_reset_finder::sc_reset_finder( 119 bool async, const sc_out<bool>* port_p, bool level, sc_process_b* target_p 120) : 121 m_async(async), m_level(level), m_next_p(0), m_in_p(0), m_inout_p(0), 122 m_out_p(port_p), m_target_p(target_p) 123{ 124 m_next_p = reset_finder_q; 125 reset_finder_q = this; 126} 127 128 129//------------------------------------------------------------------------------ 130//"sc_reset::notify_processes" 131// 132// Notify processes that there is a change in the reset signal value. 133//------------------------------------------------------------------------------ 134void sc_reset::notify_processes() 135{ 136 bool active; // true if reset is active. 137 sc_reset_target* entry_p; // reset entry processing. 138 std::vector<sc_reset_target>::size_type process_i; // index of process resetting. 139 std::vector<sc_reset_target>::size_type process_n; // # of processes to reset. 140 bool value; // value of our signal. 141 142 value = m_iface_p->read(); 143 process_n = m_targets.size(); 144 for ( process_i = 0; process_i < process_n; process_i++ ) 145 { 146 entry_p = &m_targets[process_i]; 147 active = ( entry_p->m_level == value ); 148 entry_p->m_process_p->reset_changed( entry_p->m_async, active ); 149 } 150} 151 152 153//------------------------------------------------------------------------------ 154//"sc_reset::reconcile_resets" 155// 156// This static method processes the sc_reset_finders to establish the actual 157// reset connections. 158// 159// Notes: 160// (1) If reset is asserted we tell the process that it is in reset. 161//------------------------------------------------------------------------------ 162void sc_reset::reconcile_resets() 163{ 164 const sc_signal_in_if<bool>* iface_p; // Interface to reset signal. 165 sc_reset_finder* next_p; // Next finder to process. 166 sc_reset_finder* now_p; // Finder currently processing. 167 sc_reset_target reset_target; // Target's reset entry. 168 sc_reset* reset_p; // Reset object to use. 169 170 for ( now_p = reset_finder_q; now_p; now_p = next_p ) 171 { 172 next_p = now_p->m_next_p; 173 if ( now_p->m_in_p ) 174 { 175 iface_p = DCAST<const sc_signal_in_if<bool>*>( 176 now_p->m_in_p->get_interface()); 177 } 178 else if ( now_p->m_inout_p ) 179 { 180 iface_p = DCAST<const sc_signal_in_if<bool>*>( 181 now_p->m_inout_p->get_interface()); 182 } 183 else 184 { 185 iface_p = DCAST<const sc_signal_in_if<bool>*>( 186 now_p->m_out_p->get_interface()); 187 } 188 assert( iface_p != 0 ); 189 reset_p = iface_p->is_reset(); 190 now_p->m_target_p->m_resets.push_back(reset_p); 191 reset_target.m_async = now_p->m_async; 192 reset_target.m_level = now_p->m_level; 193 reset_target.m_process_p = now_p->m_target_p; 194 reset_p->m_targets.push_back(reset_target); 195 if ( iface_p->read() == now_p->m_level ) // see note 1 above 196 now_p->m_target_p->initially_in_reset( now_p->m_async ); 197 delete now_p; 198 } 199} 200 201 202//------------------------------------------------------------------------------ 203//"sc_reset::remove_process" 204// 205// This method removes the supplied process from the list of processes that 206// should be notified when there is a change in the value of the reset signal. 207// 208// Arguments: 209// process_p -> process to be removed. 210//------------------------------------------------------------------------------ 211void sc_reset::remove_process( sc_process_b* process_p ) 212{ 213 int process_i; // Index of process resetting. 214 int process_n; // # of processes to reset. 215 216 process_n = m_targets.size(); 217 for ( process_i = 0; process_i < process_n; ) 218 { 219 if ( m_targets[process_i].m_process_p == process_p ) 220 { 221 m_targets[process_i] = m_targets[process_n-1]; 222 process_n--; 223 m_targets.resize(process_n); 224 } 225 else 226 { 227 process_i++; 228 } 229 } 230} 231 232//------------------------------------------------------------------------------ 233//"sc_reset::reset_signal_is - ports" 234// 235// These overloads of the reset_signal_is() method will register the active 236// process with the sc_reset object instance associated with the supplied port. 237// If the port does not yet have a pointer to its sc_signal<bool> instance it 238// will create an sc_reset_finder class object instance that will be used 239// to set the process' reset information when the port has been bound. 240// 241// Arguments: 242// async = true if the reset signal is asynchronous, false if not. 243// port = port for sc_signal<bool> that will provide the reset signal. 244// level = level at which reset is active, either true or false. 245//------------------------------------------------------------------------------ 246void sc_reset::reset_signal_is( bool async, const sc_in<bool>& port, bool level) 247{ 248 const sc_signal_in_if<bool>* iface_p; 249 sc_process_b* process_p; 250 251 process_p = (sc_process_b*)sc_get_current_process_handle(); 252 assert( process_p ); 253 process_p->m_has_reset_signal = true; 254 switch ( process_p->proc_kind() ) 255 { 256 case SC_THREAD_PROC_: 257 case SC_METHOD_PROC_: 258 case SC_CTHREAD_PROC_: 259 iface_p = DCAST<const sc_signal_in_if<bool>*>(port.get_interface()); 260 if ( iface_p ) 261 reset_signal_is( async, *iface_p, level ); 262 else 263 new sc_reset_finder( async, &port, level, process_p ); 264 break; 265 default: 266 SC_REPORT_ERROR(SC_ID_UNKNOWN_PROCESS_TYPE_, process_p->name()); 267 break; 268 } 269} 270 271void sc_reset::reset_signal_is( 272 bool async, const sc_inout<bool>& port, bool level ) 273{ 274 const sc_signal_in_if<bool>* iface_p; 275 sc_process_b* process_p; 276 277 process_p = (sc_process_b*)sc_get_current_process_handle(); 278 assert( process_p ); 279 process_p->m_has_reset_signal = true; 280 switch ( process_p->proc_kind() ) 281 { 282 case SC_THREAD_PROC_: 283 case SC_METHOD_PROC_: 284 case SC_CTHREAD_PROC_: 285 iface_p = DCAST<const sc_signal_in_if<bool>*>(port.get_interface()); 286 if ( iface_p ) 287 reset_signal_is( async, *iface_p, level ); 288 else 289 new sc_reset_finder( async, &port, level, process_p ); 290 break; 291 default: 292 SC_REPORT_ERROR(SC_ID_UNKNOWN_PROCESS_TYPE_, process_p->name()); 293 break; 294 } 295} 296 297void sc_reset::reset_signal_is( 298 bool async, const sc_out<bool>& port, bool level ) 299{ 300 const sc_signal_in_if<bool>* iface_p; 301 sc_process_b* process_p; 302 303 process_p = (sc_process_b*)sc_get_current_process_handle(); 304 assert( process_p ); 305 process_p->m_has_reset_signal = true; 306 switch ( process_p->proc_kind() ) 307 { 308 case SC_THREAD_PROC_: 309 case SC_METHOD_PROC_: 310 case SC_CTHREAD_PROC_: 311 iface_p = DCAST<const sc_signal_in_if<bool>*>(port.get_interface()); 312 if ( iface_p ) 313 reset_signal_is( async, *iface_p, level ); 314 else 315 new sc_reset_finder( async, &port, level, process_p ); 316 break; 317 default: 318 SC_REPORT_ERROR(SC_ID_UNKNOWN_PROCESS_TYPE_, process_p->name()); 319 break; 320 } 321} 322 323//------------------------------------------------------------------------------ 324//"sc_reset::reset_signal_is" 325// 326// This static method will register the active process instance as being 327// reset by the sc_signal<bool> whose interface has been supplied. If no 328// sc_reset object instance has been attached to the sc_signal<bool> yet, it 329// will be created and attached. The active process instance is pushed into 330// the list of processes that the sc_reset object instance should notify if 331// the value of the reset signal changes. 332// 333// Arguments: 334// async = true if the reset signal is asynchronous, false if not. 335// iface = interface for the reset signal. 336// level = is the level at which reset is active, either true or false. 337// Notes: 338// (1) If reset is asserted we tell the process that it is in reset 339// initially. 340//------------------------------------------------------------------------------ 341void sc_reset::reset_signal_is( 342 bool async, const sc_signal_in_if<bool>& iface, bool level ) 343{ 344 sc_process_b* process_p; // process adding reset for. 345 sc_reset_target reset_target; // entry to build for the process. 346 sc_reset* reset_p; // reset object. 347 348 process_p = sc_process_b::last_created_process_base(); 349 assert( process_p ); 350 process_p->m_has_reset_signal = true; 351 switch ( process_p->proc_kind() ) 352 { 353 case SC_METHOD_PROC_: 354 case SC_CTHREAD_PROC_: 355 case SC_THREAD_PROC_: 356 reset_p = iface.is_reset(); 357 process_p->m_resets.push_back(reset_p); 358 reset_target.m_async = async; 359 reset_target.m_level = level; 360 reset_target.m_process_p = process_p; 361 reset_p->m_targets.push_back(reset_target); 362 if ( iface.read() == level ) process_p->initially_in_reset( async ); 363 break; 364 default: 365 SC_REPORT_ERROR(SC_ID_UNKNOWN_PROCESS_TYPE_, process_p->name()); 366 break; 367 } 368} 369 370} // namespace sc_core 371 372// $Log: sc_reset.cpp,v $ 373// Revision 1.16 2011/08/26 20:46:10 acg 374// Andy Goodrich: moved the modification log to the end of the file to 375// eliminate source line number skew when check-ins are done. 376// 377// Revision 1.15 2011/08/24 22:05:51 acg 378// Torsten Maehne: initialization changes to remove warnings. 379// 380// Revision 1.14 2011/04/08 22:37:34 acg 381// Andy Goodrich: documentation of the reset mechanism and additional 382// documentation of methods. Removal of check for SC_METHODs in 383// sc_reset_signal_is() that should not have been there. 384// 385// Revision 1.13 2011/03/20 15:13:01 acg 386// Andy Goodrich: set the reset flag for async_reset_signal_is to catch 387// the suspend() corner case. 388// 389// Revision 1.12 2011/03/20 13:43:23 acg 390// Andy Goodrich: added async_signal_is() plus suspend() as a corner case. 391// 392// Revision 1.11 2011/03/06 19:57:11 acg 393// Andy Goodrich: refinements for the illegal suspend - synchronous reset 394// interaction. 395// 396// Revision 1.10 2011/02/18 20:27:14 acg 397// Andy Goodrich: Updated Copyrights. 398// 399// Revision 1.9 2011/02/13 21:47:37 acg 400// Andy Goodrich: update copyright notice. 401// 402// Revision 1.8 2011/02/01 21:08:26 acg 403// Andy Goodrich: new multiple reset support. 404// 405// Revision 1.7 2011/01/06 18:04:38 acg 406// Andy Goodrich: removed commented out code. 407// 408// Revision 1.6 2010/12/07 20:09:13 acg 409// Andy Goodrich: removed sc_signal overloads since already have sc_signal_in_if overloads. 410// 411// Revision 1.5 2010/11/20 17:10:56 acg 412// Andy Goodrich: reset processing changes for new IEEE 1666 standard. 413// 414// Revision 1.4 2009/05/22 16:06:29 acg 415// Andy Goodrich: process control updates. 416// 417// Revision 1.3 2009/03/12 22:59:58 acg 418// Andy Goodrich: updates for 2.4 stuff. 419// 420// Revision 1.2 2008/05/22 17:06:26 acg 421// Andy Goodrich: updated copyright notice to include 2008. 422// 423// Revision 1.1.1.1 2006/12/15 20:20:05 acg 424// SystemC 2.3 425// 426// Revision 1.7 2006/12/02 20:58:19 acg 427// Andy Goodrich: updates from 2.2 for IEEE 1666 support. 428// 429// Revision 1.5 2006/04/11 23:13:21 acg 430// Andy Goodrich: Changes for reduced reset support that only includes 431// sc_cthread, but has preliminary hooks for expanding to method and thread 432// processes also. 433// 434// Revision 1.4 2006/01/24 20:49:05 acg 435// Andy Goodrich: changes to remove the use of deprecated features within the 436// simulator, and to issue warning messages when deprecated features are used. 437// 438// Revision 1.3 2006/01/13 18:44:30 acg 439// Added $Log to record CVS changes into the source. 440// 441