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_phase_callback_registry.cpp -- Implementation of phase callback registry 23 24 Original Author: Philipp A. Hartmann, OFFIS, 2013-02-15 25 26 CHANGE LOG AT END OF FILE 27 *****************************************************************************/ 28 29#include "sysc/kernel/sc_object.h" 30#include "sysc/kernel/sc_phase_callback_registry.h" 31#include "sysc/kernel/sc_kernel_ids.h" 32#include "sysc/utils/sc_report.h" 33 34#include <algorithm> 35#include <functional> 36 37namespace sc_core { 38 39#if SC_HAS_PHASE_CALLBACKS_ 40 41sc_phase_callback_registry::sc_phase_callback_registry( sc_simcontext& simc ) 42 : m_simc( &simc ) 43#if 0 44 , m_cb_eval_vec() 45#endif 46 , m_cb_update_vec() 47 , m_cb_timestep_vec() 48{} 49 50sc_phase_callback_registry::~sc_phase_callback_registry() 51{} 52 53static const sc_phase_callback_registry::mask_type 54 SC_PHASE_CALLBACK_MASK = SC_STATUS_ANY; 55 56namespace /* anonymous */ { 57 58struct entry_match 59 : std::unary_function< sc_phase_callback_registry::entry, bool > 60{ 61 typedef sc_phase_callback_registry::cb_type* ref_type; 62 63 explicit 64 entry_match( ref_type ref ) 65 : ref_(ref) 66 {} 67 68 result_type operator()( argument_type e ) 69 { return e.target == ref_; } 70private: 71 sc_phase_callback_registry::cb_type * ref_; 72 73}; // entry_match 74 75template< typename T > 76inline void 77erase_remove( std::vector<T>* vec, T const& t ) 78{ 79 vec->erase( std::remove( vec->begin(), vec->end(), t ) ); 80} 81 82} // namespace anonymous 83 84 85sc_phase_callback_registry::mask_type 86sc_phase_callback_registry::validate_mask( cb_type& cb 87 , mask_type m 88 , bool warn = false ) 89{ 90 if( SC_UNLIKELY_(m & ~SC_PHASE_CALLBACK_MASK) ) 91 { 92 if( warn ) 93 { 94 std::stringstream ss; 95 ss << cb.name() << ": invalid phase callback mask: " 96 << (sc_status)m; 97 SC_REPORT_WARNING( SC_ID_PHASE_CALLBACK_REGISTER_ 98 , ss.str().c_str() ); 99 } 100 m &= SC_PHASE_CALLBACK_MASK; 101 } 102 103 mask_type check_mask; 104 105 // elaboration callbacks 106 check_mask = ( SC_ELABORATION 107 | SC_BEFORE_END_OF_ELABORATION 108 | SC_END_OF_ELABORATION ); 109 if( SC_UNLIKELY_( (m & check_mask ) && m_simc->elaboration_done() ) ) 110 { 111 if( warn ) 112 { 113 std::stringstream ss; 114 ss << cb.name() << ": elaboration done\n\t " 115 << (sc_status)( m & check_mask ) << " callback(s) ignored"; 116 SC_REPORT_WARNING(SC_ID_PHASE_CALLBACK_REGISTER_ 117 , ss.str().c_str() ); 118 } 119 m &= ~check_mask; 120 } 121 122 check_mask = (SC_BEFORE_END_OF_ELABORATION | SC_END_OF_ELABORATION); 123 if( SC_UNLIKELY_(m & SC_ELABORATION) ) 124 { 125 if( warn ) 126 { 127 std::stringstream ss; 128 ss << cb.name() << ": " << SC_ELABORATION 129 << ":\n\t substituted by " << (sc_status)(check_mask); 130 SC_REPORT_WARNING( SC_ID_PHASE_CALLBACK_REGISTER_ 131 , ss.str().c_str() ); 132 } 133 m &= ~SC_ELABORATION; 134 m |= check_mask; 135 } 136 137 check_mask = ( SC_END_OF_INITIALIZATION 138#if 0 139 | SC_END_OF_EVALUATION 140#endif 141 | SC_END_OF_UPDATE 142 | SC_BEFORE_TIMESTEP ); 143 if( SC_UNLIKELY_(m & SC_RUNNING) ) 144 { 145 if( warn ) 146 { 147 std::stringstream ss; 148 ss << cb.name() << ": " << SC_RUNNING 149 << ":\n\t substituted by " << (sc_status)(check_mask); 150 SC_REPORT_WARNING( SC_ID_PHASE_CALLBACK_REGISTER_ 151 , ss.str().c_str() ); 152 } 153 m &= ~SC_RUNNING; 154 m |= check_mask; 155 } 156 return m; 157} 158 159 160sc_phase_callback_registry::mask_type 161sc_phase_callback_registry::register_callback( cb_type& cb, mask_type m ) 162{ 163 storage_type::iterator it = 164 find_if( m_cb_vec.begin(), m_cb_vec.end(), entry_match(&cb) ); 165 166 m = validate_mask(cb, m, /* warn */ true ); 167 168 mask_type diff_mask = m; 169 mask_type new_mask = m; 170 171 if( it != m_cb_vec.end() ) // update existing entry 172 { 173 // update masks 174 new_mask = (*it).mask | m; 175 diff_mask = ~(*it).mask & m; 176 (*it).mask = new_mask; 177 } 178 else // new entry 179 { 180 if( !m ) // empty, do nothing 181 return SC_UNITIALIZED; 182 183 entry new_entry = { &cb, new_mask }; 184 m_cb_vec.push_back( new_entry ); 185 } 186 187 // add to callback shortcut sets 188#if 0 189 if( diff_mask & SC_END_OF_EVALUATION ) 190 m_cb_eval_vec.push_back( &cb ); 191#endif 192 if( diff_mask & SC_END_OF_UPDATE ) 193 m_cb_update_vec.push_back( &cb ); 194 if( diff_mask & SC_BEFORE_TIMESTEP ) 195 m_cb_timestep_vec.push_back( &cb ); 196 197 return new_mask; 198} 199 200 201sc_phase_callback_registry::mask_type 202sc_phase_callback_registry::unregister_callback( cb_type& cb, mask_type m ) 203{ 204 storage_type::iterator it = 205 find_if( m_cb_vec.begin(), m_cb_vec.end(), entry_match(&cb) ); 206 207 m = validate_mask(cb, m); 208 209 mask_type diff_mask = m; 210 mask_type new_mask = m; 211 212 if( it == m_cb_vec.end() ) { // not registered 213 return SC_UNITIALIZED; 214 } 215 216 // update masks 217 new_mask = (*it).mask & ~m; 218 diff_mask = (*it).mask & m; 219 (*it).mask = new_mask; 220 221 if( !new_mask ) 222 m_cb_vec.erase(it); 223 224 // drop from callback shortcut sets 225#if 0 226 if( diff_mask & SC_END_OF_EVALUATION ) 227 erase_remove( &m_cb_eval_vec, &cb ); 228#endif 229 if( diff_mask & SC_END_OF_UPDATE ) 230 erase_remove( &m_cb_update_vec, &cb ); 231 if( diff_mask & SC_BEFORE_TIMESTEP ) 232 erase_remove( &m_cb_timestep_vec, &cb ); 233 234 return new_mask; 235} 236 237 238// generic implementation (for non-critical callbacks) 239// - also restores hierarchy around callback object 240void 241sc_phase_callback_registry::do_callback( sc_status s ) const 242{ 243 typedef storage_type::const_iterator it_type; 244 storage_type const & vec = m_cb_vec; 245 246 for(it_type it = vec.begin(), end = vec.end(); it != end; ++it) { 247 if( s & it->mask ) { 248 sc_object::hierarchy_scope scope(it->target); 249 it->target->do_simulation_phase_callback(); 250 } 251 } 252} 253 254#else // ! SC_HAS_PHASE_CALLBACKS_ 255 256sc_phase_callback_registry::sc_phase_callback_registry( sc_simcontext& ){} 257sc_phase_callback_registry::~sc_phase_callback_registry(){} 258 259static inline void 260warn_phase_callbacks( sc_core::sc_object const& obj ) 261{ 262 static bool warned = false; 263 if (!warned) 264 { 265 std::stringstream ss; 266 ss << obj.name() << ".\n" 267 << "Please recompile SystemC with " 268 "\"SC_ENABLE_SIMULATION_PHASE_CALLBACKS\" defined."; 269 SC_REPORT_WARNING( SC_ID_PHASE_CALLBACKS_UNSUPPORTED_ 270 , ss.str().c_str() ); 271 } 272} 273 274sc_phase_callback_registry::mask_type 275sc_phase_callback_registry::register_callback( cb_type& cb, mask_type ) 276{ 277 warn_phase_callbacks( cb ); 278 return SC_UNITIALIZED; 279} 280 281sc_phase_callback_registry::mask_type 282sc_phase_callback_registry::unregister_callback( cb_type& cb, mask_type ) 283{ 284 warn_phase_callbacks( cb ); 285 return SC_UNITIALIZED; 286} 287 288#endif // ! SC_HAS_PHASE_CALLBACKS_ 289 290} // namespace sc_core 291 292/***************************************************************************** 293 294 MODIFICATION LOG - modifiers, enter your name, affiliation, date and 295 changes you are making here. 296 297 Name, Affiliation, Date: 298 Description of Modification: 299 300 *****************************************************************************/ 301// Taf! 302