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_clock.cpp -- The clock channel. 23 24 Original Author: Martin Janssen, Synopsys, Inc., 2001-05-21 25 26 CHANGE LOG IS AT THE END OF THE FILE 27 *****************************************************************************/ 28 29// using notify_delayed(). 30// 31// Revision 1.4 2006/01/18 21:42:26 acg 32// Andy Goodrich: Changes for check writer support, and tightening up sc_clock 33// port usage. 34// 35// Revision 1.3 2006/01/13 18:47:41 acg 36// Added $Log command so that CVS comments are reproduced in the source. 37// 38 39#include "sysc/communication/sc_clock.h" 40#include "sysc/communication/sc_communication_ids.h" 41#include "sysc/kernel/sc_simcontext.h" 42#include "sysc/kernel/sc_process.h" 43#include "sysc/kernel/sc_spawn.h" 44#include "sysc/utils/sc_utils_ids.h" 45 46namespace sc_core { 47 48// ---------------------------------------------------------------------------- 49// CLASS : sc_clock 50// 51// The clock channel. 52// ---------------------------------------------------------------------------- 53 54// constructors 55 56sc_clock::sc_clock() : 57 base_type( sc_gen_unique_name( "clock" ) ), 58 m_period(), m_duty_cycle(), m_start_time(), m_posedge_first(), 59 m_posedge_time(), m_negedge_time(), 60 m_next_posedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) + 61 "_next_posedge_event").c_str()), 62 m_next_negedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) + 63 "_next_negedge_event").c_str()) 64 65{ 66 init( sc_time::from_value(simcontext()->m_time_params->default_time_unit), 67 0.5, 68 SC_ZERO_TIME, 69 true ); 70 71 m_next_posedge_event.notify_internal( m_start_time ); 72} 73 74sc_clock::sc_clock( const char* name_ ) : 75 base_type( name_ ), 76 m_period(), m_duty_cycle(), m_start_time(), m_posedge_first(), 77 m_posedge_time(), m_negedge_time(), 78 m_next_posedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) + 79 std::string(name_) + "_next_posedge_event").c_str()), 80 m_next_negedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) + 81 std::string(name_) + "_next_negedge_event").c_str()) 82{ 83 init( sc_time::from_value(simcontext()->m_time_params->default_time_unit), 84 0.5, 85 SC_ZERO_TIME, 86 true ); 87 88 m_next_posedge_event.notify_internal( m_start_time ); 89} 90 91sc_clock::sc_clock( const char* name_, 92 const sc_time& period_, 93 double duty_cycle_, 94 const sc_time& start_time_, 95 bool posedge_first_ ) : 96 base_type( name_ ), 97 m_period(), m_duty_cycle(), m_start_time(), m_posedge_first(), 98 m_posedge_time(), m_negedge_time(), 99 m_next_posedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) + 100 std::string(name_) + "_next_posedge_event").c_str()), 101 m_next_negedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) + 102 std::string(name_) + "_next_negedge_event").c_str()) 103{ 104 init( period_, 105 duty_cycle_, 106 start_time_, 107 posedge_first_ ); 108 109 if( posedge_first_ ) { 110 // posedge first 111 m_next_posedge_event.notify_internal( m_start_time ); 112 } else { 113 // negedge first 114 m_next_negedge_event.notify_internal( m_start_time ); 115 } 116} 117 118sc_clock::sc_clock( const char* name_, 119 double period_v_, 120 sc_time_unit period_tu_, 121 double duty_cycle_ ) : 122 base_type( name_ ), 123 m_period(), m_duty_cycle(), m_start_time(), m_posedge_first(), 124 m_posedge_time(), m_negedge_time(), 125 m_next_posedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) + 126 std::string(name_) + "_next_posedge_event").c_str()), 127 m_next_negedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) + 128 std::string(name_) + "_next_negedge_event").c_str()) 129{ 130 init( sc_time( period_v_, period_tu_, simcontext() ), 131 duty_cycle_, 132 SC_ZERO_TIME, 133 true ); 134 135 // posedge first 136 m_next_posedge_event.notify_internal( m_start_time ); 137} 138 139sc_clock::sc_clock( const char* name_, 140 double period_v_, 141 sc_time_unit period_tu_, 142 double duty_cycle_, 143 double start_time_v_, 144 sc_time_unit start_time_tu_, 145 bool posedge_first_ ) : 146 base_type( name_ ), 147 m_period(), m_duty_cycle(), m_start_time(), m_posedge_first(), 148 m_posedge_time(), m_negedge_time(), 149 m_next_posedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) + 150 std::string(name_) + "_next_posedge_event").c_str()), 151 m_next_negedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) + 152 std::string(name_) + "_next_negedge_event").c_str()) 153{ 154 init( sc_time( period_v_, period_tu_, simcontext() ), 155 duty_cycle_, 156 sc_time( start_time_v_, start_time_tu_, simcontext() ), 157 posedge_first_ ); 158 159 if( posedge_first_ ) { 160 // posedge first 161 m_next_posedge_event.notify_internal( m_start_time ); 162 } else { 163 // negedge first 164 m_next_negedge_event.notify_internal( m_start_time ); 165 } 166} 167 168// for backward compatibility with 1.0 169sc_clock::sc_clock( const char* name_, 170 double period_, // in default time units 171 double duty_cycle_, 172 double start_time_, // in default time units 173 bool posedge_first_ ) : 174 base_type( name_ ), 175 m_period(), m_duty_cycle(), m_start_time(), m_posedge_first(), 176 m_posedge_time(), m_negedge_time(), 177 m_next_posedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) + 178 std::string(name_) + "_next_posedge_event").c_str()), 179 m_next_negedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) + 180 std::string(name_) + "_next_negedge_event").c_str()) 181{ 182 static bool warn_sc_clock=true; 183 if ( warn_sc_clock ) 184 { 185 warn_sc_clock = false; 186 SC_REPORT_INFO(SC_ID_IEEE_1666_DEPRECATION_, 187 "\n sc_clock(const char*, double, double, double, bool)\n" 188 " is deprecated use a form that includes sc_time or\n" 189 " sc_time_unit"); 190 } 191 192 sc_time default_time = 193 sc_time::from_value( simcontext()->m_time_params->default_time_unit ); 194 195 init( ( period_ * default_time ), 196 duty_cycle_, 197 ( start_time_ * default_time ), 198 posedge_first_ ); 199 200 if( posedge_first_ ) { 201 // posedge first 202 m_next_posedge_event.notify_internal( m_start_time ); 203 } else { 204 // negedge first 205 m_next_negedge_event.notify_internal( m_start_time ); 206 } 207} 208 209 210//------------------------------------------------------------------------------ 211//"sc_clock::before_end_of_elaboration" 212// 213// This callback is used to spawn the edge processes for this object instance. 214// The processes are created here rather than the constructor for the object 215// so that the processes are registered with the global simcontext rather 216// than the scope of the clock's parent. 217//------------------------------------------------------------------------------ 218#if ( defined(_MSC_VER) && _MSC_VER < 1300 ) //VC++6.0 doesn't support sc_spawn with functor. 219# define sc_clock_posedge_callback(ptr) sc_clock_posedge_callback 220 221# define sc_clock_negedge_callback(ptr) sc_clock_negedge_callback 222 223# define sc_spawn(a,b,c) { \ 224 sc_process_handle result(new sc_spawn_object<a>(a(this),b,c)); \ 225 } 226#endif // ( defined(_MSC_VER) && _MSC_VER < 1300 ) 227 228void sc_clock::before_end_of_elaboration() 229{ 230 std::string gen_base; 231 sc_spawn_options posedge_options; // Options for posedge process. 232 sc_spawn_options negedge_options; // Options for negedge process. 233 234 posedge_options.spawn_method(); 235 posedge_options.dont_initialize(); 236 posedge_options.set_sensitivity(&m_next_posedge_event); 237 gen_base = basename(); 238 gen_base += "_posedge_action"; 239 sc_spawn(sc_clock_posedge_callback(this), 240 sc_gen_unique_name( gen_base.c_str() ), &posedge_options); 241 242 negedge_options.spawn_method(); 243 negedge_options.dont_initialize(); 244 negedge_options.set_sensitivity(&m_next_negedge_event); 245 gen_base = basename(); 246 gen_base += "_negedge_action"; 247 sc_spawn( sc_clock_negedge_callback(this), 248 sc_gen_unique_name( gen_base.c_str() ), &negedge_options ); 249} 250 251//clear VC++6.0 macros 252#undef sc_clock_posedge_callback 253#undef sc_clock_negedge_callback 254#undef sc_spawn 255 256// destructor (does nothing) 257 258sc_clock::~sc_clock() 259{} 260 261void sc_clock::register_port( sc_port_base& /*port*/, const char* if_typename_ ) 262{ 263 std::string nm( if_typename_ ); 264 if( nm == typeid( sc_signal_inout_if<bool> ).name() ) { 265 SC_REPORT_ERROR(SC_ID_ATTEMPT_TO_BIND_CLOCK_TO_OUTPUT_, ""); 266 } 267} 268 269void 270sc_clock::write( const bool& /* value */ ) 271{ 272 SC_REPORT_ERROR(SC_ID_ATTEMPT_TO_WRITE_TO_CLOCK_, ""); 273} 274 275// interface methods 276 277// get the current time 278 279const sc_time& 280sc_clock::time_stamp() 281{ 282 return sc_time_stamp(); 283} 284 285 286// error reporting 287 288void 289sc_clock::report_error( const char* id, const char* add_msg ) const 290{ 291 char msg[BUFSIZ]; 292 if( add_msg != 0 ) { 293 std::sprintf( msg, "%s: clock '%s'", add_msg, name() ); 294 } else { 295 std::sprintf( msg, "clock '%s'", name() ); 296 } 297 SC_REPORT_ERROR( id, msg ); 298} 299 300 301void 302sc_clock::init( const sc_time& period_, 303 double duty_cycle_, 304 const sc_time& start_time_, 305 bool posedge_first_ ) 306{ 307 if( period_ == SC_ZERO_TIME ) { 308 report_error( SC_ID_CLOCK_PERIOD_ZERO_, 309 "increase the period" ); 310 } 311 m_period = period_; 312 m_posedge_first = posedge_first_; 313 314 if( duty_cycle_ <= 0.0 || duty_cycle_ >= 1.0 ) { 315 m_duty_cycle = 0.5; 316 } else { 317 m_duty_cycle = duty_cycle_; 318 } 319 320 m_negedge_time = m_period * m_duty_cycle; 321 m_posedge_time = m_period - m_negedge_time; 322 323 if( m_negedge_time == SC_ZERO_TIME ) { 324 report_error( SC_ID_CLOCK_HIGH_TIME_ZERO_, 325 "increase the period or increase the duty cycle" ); 326 } 327 if( m_posedge_time == SC_ZERO_TIME ) { 328 report_error( SC_ID_CLOCK_LOW_TIME_ZERO_, 329 "increase the period or decrease the duty cycle" ); 330 } 331 332 if( posedge_first_ ) { 333 this->m_cur_val = false; 334 this->m_new_val = false; 335 } else { 336 this->m_cur_val = true; 337 this->m_new_val = true; 338 } 339 340 m_start_time = start_time_; 341 342} 343 344} // namespace sc_core 345 346/***************************************************************************** 347 348 MODIFICATION LOG - modifiers, enter your name, affiliation, date and 349 changes you are making here. 350 351 Name, Affiliation, Date: Bishnupriya Bhattacharya, Cadence Design Systems, 352 Andy Goodrich, Forte Design Systems, 353 3 October, 2003 354 Description of Modification: sc_clock inherits from sc_signal<bool> only 355 instead of sc_signal_in_if<bool> and sc_module. 356 The 2 methods posedge_action() and 357 negedge_action() are created using sc_spawn(). 358 boost::bind() is not required, instead a local 359 bind function can be used since the signatures 360 of the spawned functions are statically known. 361 362 Name, Affiliation, Date: 363 Description of Modification: 364 365 *****************************************************************************/ 366 367// $Log: sc_clock.cpp,v $ 368// Revision 1.7 2011/08/26 20:45:39 acg 369// Andy Goodrich: moved the modification log to the end of the file to 370// eliminate source line number skew when check-ins are done. 371// 372// Revision 1.6 2011/08/24 22:05:35 acg 373// Torsten Maehne: initialization changes to remove warnings. 374// 375// Revision 1.5 2011/08/15 16:43:24 acg 376// Torsten Maehne: changes to remove unused argument warnings. 377// 378// Revision 1.4 2011/03/12 21:07:42 acg 379// Andy Goodrich: changes to kernel generated event support. 380// 381// Revision 1.3 2011/03/06 15:55:08 acg 382// Andy Goodrich: Changes for named events. 383// 384// Revision 1.2 2011/02/18 20:23:45 acg 385// Andy Goodrich: Copyright update. 386// 387// Revision 1.1.1.1 2006/12/15 20:20:04 acg 388// SystemC 2.3 389// 390// Revision 1.8 2006/04/18 23:36:50 acg 391// Andy Goodrich: made add_trace_internal public until I can figure out 392// how to do a friend specification for sc_trace in an environment where 393// there are partial template and full template specifications for its 394// arguments. 395// 396// Revision 1.7 2006/04/17 16:38:42 acg 397// Andy Goodrich: added more context to the deprecation message for the 398// sc_clock constructor. 399// 400// Revision 1.6 2006/01/25 00:31:11 acg 401// Andy Goodrich: Changed over to use a standard message id of 402// SC_ID_IEEE_1666_DEPRECATION for all deprecation messages. 403// 404// Revision 1.5 2006/01/24 20:43:24 acg 405// Andy Goodrich: convert notify_delayed() calls into notify_internal() calls. 406// notify_internal() is an implementation dependent version of notify_delayed() 407// that is simpler, and does not trigger the deprecation warning one would get 408 409// Taf! 410