| /***************************************************************************** |
| |
| Licensed to Accellera Systems Initiative Inc. (Accellera) under one or |
| more contributor license agreements. See the NOTICE file distributed |
| with this work for additional information regarding copyright ownership. |
| Accellera licenses this file to you under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with the |
| License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
| implied. See the License for the specific language governing |
| permissions and limitations under the License. |
| |
| *****************************************************************************/ |
| |
| /***************************************************************************** |
| |
| sc_clock.cpp -- The clock channel. |
| |
| Original Author: Martin Janssen, Synopsys, Inc., 2001-05-21 |
| |
| CHANGE LOG IS AT THE END OF THE FILE |
| *****************************************************************************/ |
| |
| // using notify_delayed(). |
| // |
| // Revision 1.4 2006/01/18 21:42:26 acg |
| // Andy Goodrich: Changes for check writer support, and tightening up sc_clock |
| // port usage. |
| // |
| // Revision 1.3 2006/01/13 18:47:41 acg |
| // Added $Log command so that CVS comments are reproduced in the source. |
| // |
| |
| #include "sysc/communication/sc_clock.h" |
| #include "sysc/communication/sc_communication_ids.h" |
| #include "sysc/kernel/sc_simcontext.h" |
| #include "sysc/kernel/sc_process.h" |
| #include "sysc/kernel/sc_spawn.h" |
| #include "sysc/utils/sc_utils_ids.h" |
| |
| namespace sc_core { |
| |
| // ---------------------------------------------------------------------------- |
| // CLASS : sc_clock |
| // |
| // The clock channel. |
| // ---------------------------------------------------------------------------- |
| |
| // constructors |
| |
| sc_clock::sc_clock() : |
| base_type( sc_gen_unique_name( "clock" ) ), |
| m_period(), m_duty_cycle(), m_start_time(), m_posedge_first(), |
| m_posedge_time(), m_negedge_time(), |
| m_next_posedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) + |
| "_next_posedge_event").c_str()), |
| m_next_negedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) + |
| "_next_negedge_event").c_str()) |
| |
| { |
| init( sc_time::from_value(simcontext()->m_time_params->default_time_unit), |
| 0.5, |
| SC_ZERO_TIME, |
| true ); |
| |
| m_next_posedge_event.notify_internal( m_start_time ); |
| } |
| |
| sc_clock::sc_clock( const char* name_ ) : |
| base_type( name_ ), |
| m_period(), m_duty_cycle(), m_start_time(), m_posedge_first(), |
| m_posedge_time(), m_negedge_time(), |
| m_next_posedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) + |
| std::string(name_) + "_next_posedge_event").c_str()), |
| m_next_negedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) + |
| std::string(name_) + "_next_negedge_event").c_str()) |
| { |
| init( sc_time::from_value(simcontext()->m_time_params->default_time_unit), |
| 0.5, |
| SC_ZERO_TIME, |
| true ); |
| |
| m_next_posedge_event.notify_internal( m_start_time ); |
| } |
| |
| sc_clock::sc_clock( const char* name_, |
| const sc_time& period_, |
| double duty_cycle_, |
| const sc_time& start_time_, |
| bool posedge_first_ ) : |
| base_type( name_ ), |
| m_period(), m_duty_cycle(), m_start_time(), m_posedge_first(), |
| m_posedge_time(), m_negedge_time(), |
| m_next_posedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) + |
| std::string(name_) + "_next_posedge_event").c_str()), |
| m_next_negedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) + |
| std::string(name_) + "_next_negedge_event").c_str()) |
| { |
| init( period_, |
| duty_cycle_, |
| start_time_, |
| posedge_first_ ); |
| |
| if( posedge_first_ ) { |
| // posedge first |
| m_next_posedge_event.notify_internal( m_start_time ); |
| } else { |
| // negedge first |
| m_next_negedge_event.notify_internal( m_start_time ); |
| } |
| } |
| |
| sc_clock::sc_clock( const char* name_, |
| double period_v_, |
| sc_time_unit period_tu_, |
| double duty_cycle_ ) : |
| base_type( name_ ), |
| m_period(), m_duty_cycle(), m_start_time(), m_posedge_first(), |
| m_posedge_time(), m_negedge_time(), |
| m_next_posedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) + |
| std::string(name_) + "_next_posedge_event").c_str()), |
| m_next_negedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) + |
| std::string(name_) + "_next_negedge_event").c_str()) |
| { |
| init( sc_time( period_v_, period_tu_, simcontext() ), |
| duty_cycle_, |
| SC_ZERO_TIME, |
| true ); |
| |
| // posedge first |
| m_next_posedge_event.notify_internal( m_start_time ); |
| } |
| |
| sc_clock::sc_clock( const char* name_, |
| double period_v_, |
| sc_time_unit period_tu_, |
| double duty_cycle_, |
| double start_time_v_, |
| sc_time_unit start_time_tu_, |
| bool posedge_first_ ) : |
| base_type( name_ ), |
| m_period(), m_duty_cycle(), m_start_time(), m_posedge_first(), |
| m_posedge_time(), m_negedge_time(), |
| m_next_posedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) + |
| std::string(name_) + "_next_posedge_event").c_str()), |
| m_next_negedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) + |
| std::string(name_) + "_next_negedge_event").c_str()) |
| { |
| init( sc_time( period_v_, period_tu_, simcontext() ), |
| duty_cycle_, |
| sc_time( start_time_v_, start_time_tu_, simcontext() ), |
| posedge_first_ ); |
| |
| if( posedge_first_ ) { |
| // posedge first |
| m_next_posedge_event.notify_internal( m_start_time ); |
| } else { |
| // negedge first |
| m_next_negedge_event.notify_internal( m_start_time ); |
| } |
| } |
| |
| // for backward compatibility with 1.0 |
| sc_clock::sc_clock( const char* name_, |
| double period_, // in default time units |
| double duty_cycle_, |
| double start_time_, // in default time units |
| bool posedge_first_ ) : |
| base_type( name_ ), |
| m_period(), m_duty_cycle(), m_start_time(), m_posedge_first(), |
| m_posedge_time(), m_negedge_time(), |
| m_next_posedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) + |
| std::string(name_) + "_next_posedge_event").c_str()), |
| m_next_negedge_event( (std::string(SC_KERNEL_EVENT_PREFIX) + |
| std::string(name_) + "_next_negedge_event").c_str()) |
| { |
| static bool warn_sc_clock=true; |
| if ( warn_sc_clock ) |
| { |
| warn_sc_clock = false; |
| SC_REPORT_INFO(SC_ID_IEEE_1666_DEPRECATION_, |
| "\n sc_clock(const char*, double, double, double, bool)\n" |
| " is deprecated use a form that includes sc_time or\n" |
| " sc_time_unit"); |
| } |
| |
| sc_time default_time = |
| sc_time::from_value( simcontext()->m_time_params->default_time_unit ); |
| |
| init( ( period_ * default_time ), |
| duty_cycle_, |
| ( start_time_ * default_time ), |
| posedge_first_ ); |
| |
| if( posedge_first_ ) { |
| // posedge first |
| m_next_posedge_event.notify_internal( m_start_time ); |
| } else { |
| // negedge first |
| m_next_negedge_event.notify_internal( m_start_time ); |
| } |
| } |
| |
| |
| //------------------------------------------------------------------------------ |
| //"sc_clock::before_end_of_elaboration" |
| // |
| // This callback is used to spawn the edge processes for this object instance. |
| // The processes are created here rather than the constructor for the object |
| // so that the processes are registered with the global simcontext rather |
| // than the scope of the clock's parent. |
| //------------------------------------------------------------------------------ |
| #if ( defined(_MSC_VER) && _MSC_VER < 1300 ) //VC++6.0 doesn't support sc_spawn with functor. |
| # define sc_clock_posedge_callback(ptr) sc_clock_posedge_callback |
| |
| # define sc_clock_negedge_callback(ptr) sc_clock_negedge_callback |
| |
| # define sc_spawn(a,b,c) { \ |
| sc_process_handle result(new sc_spawn_object<a>(a(this),b,c)); \ |
| } |
| #endif // ( defined(_MSC_VER) && _MSC_VER < 1300 ) |
| |
| void sc_clock::before_end_of_elaboration() |
| { |
| std::string gen_base; |
| sc_spawn_options posedge_options; // Options for posedge process. |
| sc_spawn_options negedge_options; // Options for negedge process. |
| |
| posedge_options.spawn_method(); |
| posedge_options.dont_initialize(); |
| posedge_options.set_sensitivity(&m_next_posedge_event); |
| gen_base = basename(); |
| gen_base += "_posedge_action"; |
| sc_spawn(sc_clock_posedge_callback(this), |
| sc_gen_unique_name( gen_base.c_str() ), &posedge_options); |
| |
| negedge_options.spawn_method(); |
| negedge_options.dont_initialize(); |
| negedge_options.set_sensitivity(&m_next_negedge_event); |
| gen_base = basename(); |
| gen_base += "_negedge_action"; |
| sc_spawn( sc_clock_negedge_callback(this), |
| sc_gen_unique_name( gen_base.c_str() ), &negedge_options ); |
| } |
| |
| //clear VC++6.0 macros |
| #undef sc_clock_posedge_callback |
| #undef sc_clock_negedge_callback |
| #undef sc_spawn |
| |
| // destructor (does nothing) |
| |
| sc_clock::~sc_clock() |
| {} |
| |
| void sc_clock::register_port( sc_port_base& /*port*/, const char* if_typename_ ) |
| { |
| std::string nm( if_typename_ ); |
| if( nm == typeid( sc_signal_inout_if<bool> ).name() ) { |
| SC_REPORT_ERROR(SC_ID_ATTEMPT_TO_BIND_CLOCK_TO_OUTPUT_, ""); |
| } |
| } |
| |
| void |
| sc_clock::write( const bool& /* value */ ) |
| { |
| SC_REPORT_ERROR(SC_ID_ATTEMPT_TO_WRITE_TO_CLOCK_, ""); |
| } |
| |
| // interface methods |
| |
| // get the current time |
| |
| const sc_time& |
| sc_clock::time_stamp() |
| { |
| return sc_time_stamp(); |
| } |
| |
| |
| // error reporting |
| |
| void |
| sc_clock::report_error( const char* id, const char* add_msg ) const |
| { |
| char msg[BUFSIZ]; |
| if( add_msg != 0 ) { |
| std::sprintf( msg, "%s: clock '%s'", add_msg, name() ); |
| } else { |
| std::sprintf( msg, "clock '%s'", name() ); |
| } |
| SC_REPORT_ERROR( id, msg ); |
| } |
| |
| |
| void |
| sc_clock::init( const sc_time& period_, |
| double duty_cycle_, |
| const sc_time& start_time_, |
| bool posedge_first_ ) |
| { |
| if( period_ == SC_ZERO_TIME ) { |
| report_error( SC_ID_CLOCK_PERIOD_ZERO_, |
| "increase the period" ); |
| } |
| m_period = period_; |
| m_posedge_first = posedge_first_; |
| |
| if( duty_cycle_ <= 0.0 || duty_cycle_ >= 1.0 ) { |
| m_duty_cycle = 0.5; |
| } else { |
| m_duty_cycle = duty_cycle_; |
| } |
| |
| m_negedge_time = m_period * m_duty_cycle; |
| m_posedge_time = m_period - m_negedge_time; |
| |
| if( m_negedge_time == SC_ZERO_TIME ) { |
| report_error( SC_ID_CLOCK_HIGH_TIME_ZERO_, |
| "increase the period or increase the duty cycle" ); |
| } |
| if( m_posedge_time == SC_ZERO_TIME ) { |
| report_error( SC_ID_CLOCK_LOW_TIME_ZERO_, |
| "increase the period or decrease the duty cycle" ); |
| } |
| |
| if( posedge_first_ ) { |
| this->m_cur_val = false; |
| this->m_new_val = false; |
| } else { |
| this->m_cur_val = true; |
| this->m_new_val = true; |
| } |
| |
| m_start_time = start_time_; |
| |
| } |
| |
| } // namespace sc_core |
| |
| /***************************************************************************** |
| |
| MODIFICATION LOG - modifiers, enter your name, affiliation, date and |
| changes you are making here. |
| |
| Name, Affiliation, Date: Bishnupriya Bhattacharya, Cadence Design Systems, |
| Andy Goodrich, Forte Design Systems, |
| 3 October, 2003 |
| Description of Modification: sc_clock inherits from sc_signal<bool> only |
| instead of sc_signal_in_if<bool> and sc_module. |
| The 2 methods posedge_action() and |
| negedge_action() are created using sc_spawn(). |
| boost::bind() is not required, instead a local |
| bind function can be used since the signatures |
| of the spawned functions are statically known. |
| |
| Name, Affiliation, Date: |
| Description of Modification: |
| |
| *****************************************************************************/ |
| |
| // $Log: sc_clock.cpp,v $ |
| // Revision 1.7 2011/08/26 20:45:39 acg |
| // Andy Goodrich: moved the modification log to the end of the file to |
| // eliminate source line number skew when check-ins are done. |
| // |
| // Revision 1.6 2011/08/24 22:05:35 acg |
| // Torsten Maehne: initialization changes to remove warnings. |
| // |
| // Revision 1.5 2011/08/15 16:43:24 acg |
| // Torsten Maehne: changes to remove unused argument warnings. |
| // |
| // Revision 1.4 2011/03/12 21:07:42 acg |
| // Andy Goodrich: changes to kernel generated event support. |
| // |
| // Revision 1.3 2011/03/06 15:55:08 acg |
| // Andy Goodrich: Changes for named events. |
| // |
| // Revision 1.2 2011/02/18 20:23:45 acg |
| // Andy Goodrich: Copyright update. |
| // |
| // Revision 1.1.1.1 2006/12/15 20:20:04 acg |
| // SystemC 2.3 |
| // |
| // Revision 1.8 2006/04/18 23:36:50 acg |
| // Andy Goodrich: made add_trace_internal public until I can figure out |
| // how to do a friend specification for sc_trace in an environment where |
| // there are partial template and full template specifications for its |
| // arguments. |
| // |
| // Revision 1.7 2006/04/17 16:38:42 acg |
| // Andy Goodrich: added more context to the deprecation message for the |
| // sc_clock constructor. |
| // |
| // Revision 1.6 2006/01/25 00:31:11 acg |
| // Andy Goodrich: Changed over to use a standard message id of |
| // SC_ID_IEEE_1666_DEPRECATION for all deprecation messages. |
| // |
| // Revision 1.5 2006/01/24 20:43:24 acg |
| // Andy Goodrich: convert notify_delayed() calls into notify_internal() calls. |
| // notify_internal() is an implementation dependent version of notify_delayed() |
| // that is simpler, and does not trigger the deprecation warning one would get |
| |
| // Taf! |