| /***************************************************************************** | |
| 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_phase_callback_registry.cpp -- Implementation of phase callback registry | |
| Original Author: Philipp A. Hartmann, OFFIS, 2013-02-15 | |
| CHANGE LOG AT END OF FILE | |
| *****************************************************************************/ | |
| #include "sysc/kernel/sc_object.h" | |
| #include "sysc/kernel/sc_phase_callback_registry.h" | |
| #include "sysc/kernel/sc_kernel_ids.h" | |
| #include "sysc/utils/sc_report.h" | |
| #include <algorithm> | |
| #include <functional> | |
| namespace sc_core { | |
| #if SC_HAS_PHASE_CALLBACKS_ | |
| sc_phase_callback_registry::sc_phase_callback_registry( sc_simcontext& simc ) | |
| : m_simc( &simc ) | |
| #if 0 | |
| , m_cb_eval_vec() | |
| #endif | |
| , m_cb_update_vec() | |
| , m_cb_timestep_vec() | |
| {} | |
| sc_phase_callback_registry::~sc_phase_callback_registry() | |
| {} | |
| static const sc_phase_callback_registry::mask_type | |
| SC_PHASE_CALLBACK_MASK = SC_STATUS_ANY; | |
| namespace /* anonymous */ { | |
| struct entry_match | |
| : std::unary_function< sc_phase_callback_registry::entry, bool > | |
| { | |
| typedef sc_phase_callback_registry::cb_type* ref_type; | |
| explicit | |
| entry_match( ref_type ref ) | |
| : ref_(ref) | |
| {} | |
| result_type operator()( argument_type e ) | |
| { return e.target == ref_; } | |
| private: | |
| sc_phase_callback_registry::cb_type * ref_; | |
| }; // entry_match | |
| template< typename T > | |
| inline void | |
| erase_remove( std::vector<T>* vec, T const& t ) | |
| { | |
| vec->erase( std::remove( vec->begin(), vec->end(), t ) ); | |
| } | |
| } // namespace anonymous | |
| sc_phase_callback_registry::mask_type | |
| sc_phase_callback_registry::validate_mask( cb_type& cb | |
| , mask_type m | |
| , bool warn = false ) | |
| { | |
| if( SC_UNLIKELY_(m & ~SC_PHASE_CALLBACK_MASK) ) | |
| { | |
| if( warn ) | |
| { | |
| std::stringstream ss; | |
| ss << cb.name() << ": invalid phase callback mask: " | |
| << (sc_status)m; | |
| SC_REPORT_WARNING( SC_ID_PHASE_CALLBACK_REGISTER_ | |
| , ss.str().c_str() ); | |
| } | |
| m &= SC_PHASE_CALLBACK_MASK; | |
| } | |
| mask_type check_mask; | |
| // elaboration callbacks | |
| check_mask = ( SC_ELABORATION | |
| | SC_BEFORE_END_OF_ELABORATION | |
| | SC_END_OF_ELABORATION ); | |
| if( SC_UNLIKELY_( (m & check_mask ) && m_simc->elaboration_done() ) ) | |
| { | |
| if( warn ) | |
| { | |
| std::stringstream ss; | |
| ss << cb.name() << ": elaboration done\n\t " | |
| << (sc_status)( m & check_mask ) << " callback(s) ignored"; | |
| SC_REPORT_WARNING(SC_ID_PHASE_CALLBACK_REGISTER_ | |
| , ss.str().c_str() ); | |
| } | |
| m &= ~check_mask; | |
| } | |
| check_mask = (SC_BEFORE_END_OF_ELABORATION | SC_END_OF_ELABORATION); | |
| if( SC_UNLIKELY_(m & SC_ELABORATION) ) | |
| { | |
| if( warn ) | |
| { | |
| std::stringstream ss; | |
| ss << cb.name() << ": " << SC_ELABORATION | |
| << ":\n\t substituted by " << (sc_status)(check_mask); | |
| SC_REPORT_WARNING( SC_ID_PHASE_CALLBACK_REGISTER_ | |
| , ss.str().c_str() ); | |
| } | |
| m &= ~SC_ELABORATION; | |
| m |= check_mask; | |
| } | |
| check_mask = ( SC_END_OF_INITIALIZATION | |
| #if 0 | |
| | SC_END_OF_EVALUATION | |
| #endif | |
| | SC_END_OF_UPDATE | |
| | SC_BEFORE_TIMESTEP ); | |
| if( SC_UNLIKELY_(m & SC_RUNNING) ) | |
| { | |
| if( warn ) | |
| { | |
| std::stringstream ss; | |
| ss << cb.name() << ": " << SC_RUNNING | |
| << ":\n\t substituted by " << (sc_status)(check_mask); | |
| SC_REPORT_WARNING( SC_ID_PHASE_CALLBACK_REGISTER_ | |
| , ss.str().c_str() ); | |
| } | |
| m &= ~SC_RUNNING; | |
| m |= check_mask; | |
| } | |
| return m; | |
| } | |
| sc_phase_callback_registry::mask_type | |
| sc_phase_callback_registry::register_callback( cb_type& cb, mask_type m ) | |
| { | |
| storage_type::iterator it = | |
| find_if( m_cb_vec.begin(), m_cb_vec.end(), entry_match(&cb) ); | |
| m = validate_mask(cb, m, /* warn */ true ); | |
| mask_type diff_mask = m; | |
| mask_type new_mask = m; | |
| if( it != m_cb_vec.end() ) // update existing entry | |
| { | |
| // update masks | |
| new_mask = (*it).mask | m; | |
| diff_mask = ~(*it).mask & m; | |
| (*it).mask = new_mask; | |
| } | |
| else // new entry | |
| { | |
| if( !m ) // empty, do nothing | |
| return SC_UNITIALIZED; | |
| entry new_entry = { &cb, new_mask }; | |
| m_cb_vec.push_back( new_entry ); | |
| } | |
| // add to callback shortcut sets | |
| #if 0 | |
| if( diff_mask & SC_END_OF_EVALUATION ) | |
| m_cb_eval_vec.push_back( &cb ); | |
| #endif | |
| if( diff_mask & SC_END_OF_UPDATE ) | |
| m_cb_update_vec.push_back( &cb ); | |
| if( diff_mask & SC_BEFORE_TIMESTEP ) | |
| m_cb_timestep_vec.push_back( &cb ); | |
| return new_mask; | |
| } | |
| sc_phase_callback_registry::mask_type | |
| sc_phase_callback_registry::unregister_callback( cb_type& cb, mask_type m ) | |
| { | |
| storage_type::iterator it = | |
| find_if( m_cb_vec.begin(), m_cb_vec.end(), entry_match(&cb) ); | |
| m = validate_mask(cb, m); | |
| mask_type diff_mask = m; | |
| mask_type new_mask = m; | |
| if( it == m_cb_vec.end() ) { // not registered | |
| return SC_UNITIALIZED; | |
| } | |
| // update masks | |
| new_mask = (*it).mask & ~m; | |
| diff_mask = (*it).mask & m; | |
| (*it).mask = new_mask; | |
| if( !new_mask ) | |
| m_cb_vec.erase(it); | |
| // drop from callback shortcut sets | |
| #if 0 | |
| if( diff_mask & SC_END_OF_EVALUATION ) | |
| erase_remove( &m_cb_eval_vec, &cb ); | |
| #endif | |
| if( diff_mask & SC_END_OF_UPDATE ) | |
| erase_remove( &m_cb_update_vec, &cb ); | |
| if( diff_mask & SC_BEFORE_TIMESTEP ) | |
| erase_remove( &m_cb_timestep_vec, &cb ); | |
| return new_mask; | |
| } | |
| // generic implementation (for non-critical callbacks) | |
| // - also restores hierarchy around callback object | |
| void | |
| sc_phase_callback_registry::do_callback( sc_status s ) const | |
| { | |
| typedef storage_type::const_iterator it_type; | |
| storage_type const & vec = m_cb_vec; | |
| for(it_type it = vec.begin(), end = vec.end(); it != end; ++it) { | |
| if( s & it->mask ) { | |
| sc_object::hierarchy_scope scope(it->target); | |
| it->target->do_simulation_phase_callback(); | |
| } | |
| } | |
| } | |
| #else // ! SC_HAS_PHASE_CALLBACKS_ | |
| sc_phase_callback_registry::sc_phase_callback_registry( sc_simcontext& ){} | |
| sc_phase_callback_registry::~sc_phase_callback_registry(){} | |
| static inline void | |
| warn_phase_callbacks( sc_core::sc_object const& obj ) | |
| { | |
| static bool warned = false; | |
| if (!warned) | |
| { | |
| std::stringstream ss; | |
| ss << obj.name() << ".\n" | |
| << "Please recompile SystemC with " | |
| "\"SC_ENABLE_SIMULATION_PHASE_CALLBACKS\" defined."; | |
| SC_REPORT_WARNING( SC_ID_PHASE_CALLBACKS_UNSUPPORTED_ | |
| , ss.str().c_str() ); | |
| } | |
| } | |
| sc_phase_callback_registry::mask_type | |
| sc_phase_callback_registry::register_callback( cb_type& cb, mask_type ) | |
| { | |
| warn_phase_callbacks( cb ); | |
| return SC_UNITIALIZED; | |
| } | |
| sc_phase_callback_registry::mask_type | |
| sc_phase_callback_registry::unregister_callback( cb_type& cb, mask_type ) | |
| { | |
| warn_phase_callbacks( cb ); | |
| return SC_UNITIALIZED; | |
| } | |
| #endif // ! SC_HAS_PHASE_CALLBACKS_ | |
| } // namespace sc_core | |
| /***************************************************************************** | |
| MODIFICATION LOG - modifiers, enter your name, affiliation, date and | |
| changes you are making here. | |
| Name, Affiliation, Date: | |
| Description of Modification: | |
| *****************************************************************************/ | |
| // Taf! |