| /***************************************************************************** | |
| 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_signal.cpp -- The sc_signal<T> primitive channel class. | |
| Original Author: Martin Janssen, Synopsys, Inc., 2001-05-21 | |
| CHANGE LOG IS AT THE END OF THE FILE | |
| *****************************************************************************/ | |
| #include "sysc/communication/sc_communication_ids.h" | |
| #include "sysc/utils/sc_utils_ids.h" | |
| #include "sysc/communication/sc_signal.h" | |
| #include "sysc/datatypes/int/sc_signed.h" | |
| #include "sysc/datatypes/int/sc_unsigned.h" | |
| #include "sysc/datatypes/bit/sc_lv_base.h" | |
| #include "sysc/kernel/sc_reset.h" | |
| #include <sstream> | |
| using sc_dt::sc_lv_base; | |
| using sc_dt::sc_signed; | |
| using sc_dt::sc_unsigned; | |
| using sc_dt::int64; | |
| using sc_dt::uint64; | |
| namespace sc_core { | |
| // to avoid code bloat in sc_signal<T> | |
| void | |
| sc_signal_invalid_writer( sc_object* target, sc_object* first_writer, | |
| sc_object* second_writer, bool check_delta ) | |
| { | |
| if ( second_writer ) | |
| { | |
| std::stringstream msg; | |
| msg | |
| << "\n signal " | |
| "`" << target->name() << "' " | |
| "(" << target->kind() << ")" | |
| << "\n first driver " | |
| "`" << first_writer->name() << "' " | |
| " (" << first_writer->kind() << ")" | |
| << "\n second driver " | |
| "`" << second_writer->name() << "' " | |
| "(" << second_writer->kind() << ")"; | |
| if( check_delta ) | |
| { | |
| msg << "\n first conflicting write in delta cycle " | |
| << sc_delta_count(); | |
| } | |
| SC_REPORT_ERROR( SC_ID_MORE_THAN_ONE_SIGNAL_DRIVER_, | |
| msg.str().c_str() ); | |
| } | |
| } | |
| bool | |
| sc_writer_policy_check_port:: | |
| check_port( sc_object* target, sc_port_base * port_, bool is_output ) | |
| { | |
| if ( is_output && sc_get_curr_simcontext()->write_check() ) | |
| { | |
| // an out or inout port; only one can be connected | |
| if( m_output != 0) { | |
| sc_signal_invalid_writer( target, m_output, port_, false ); | |
| return false; | |
| } else { | |
| m_output = port_; | |
| } | |
| } | |
| return true; | |
| } | |
| void sc_deprecated_get_data_ref() | |
| { | |
| static bool warn_get_data_ref_deprecated=true; | |
| if ( warn_get_data_ref_deprecated ) | |
| { | |
| warn_get_data_ref_deprecated=false; | |
| SC_REPORT_INFO(SC_ID_IEEE_1666_DEPRECATION_, | |
| "get_data_ref() is deprecated, use read() instead" ); | |
| } | |
| } | |
| void sc_deprecated_get_new_value() | |
| { | |
| static bool warn_new_value=true; | |
| if ( warn_new_value ) | |
| { | |
| warn_new_value=false; | |
| SC_REPORT_INFO(SC_ID_IEEE_1666_DEPRECATION_, | |
| "sc_signal<T>::get_new_value() is deprecated"); | |
| } | |
| } | |
| void sc_deprecated_trace() | |
| { | |
| static bool warn_trace_deprecated=true; | |
| if ( warn_trace_deprecated ) | |
| { | |
| warn_trace_deprecated=false; | |
| SC_REPORT_INFO(SC_ID_IEEE_1666_DEPRECATION_, | |
| "sc_signal<T>::trace() is deprecated"); | |
| } | |
| } | |
| sc_event* | |
| sc_lazy_kernel_event( sc_event** ev, const char* name ) | |
| { | |
| if ( !*ev ) { | |
| std::string kernel_name = SC_KERNEL_EVENT_PREFIX "_"; | |
| kernel_name.append( name ); | |
| *ev = new sc_event( kernel_name.c_str() ); | |
| } | |
| return *ev; | |
| } | |
| // IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII | |
| template< sc_writer_policy POL > | |
| void | |
| sc_signal<bool,POL>::register_port( sc_port_base& port_, | |
| const char* if_typename_ ) | |
| { | |
| bool is_output = std::string( if_typename_ ) == typeid(if_type).name(); | |
| if( !policy_type::check_port( this, &port_, is_output ) ) | |
| ((void)0); // fallback? error has been suppressed ... | |
| } | |
| // write the new value | |
| template< sc_writer_policy POL > | |
| void | |
| sc_signal<bool,POL>::write( const bool& value_ ) | |
| { | |
| bool value_changed = !( m_cur_val == value_ ); | |
| if ( !policy_type::check_write(this, value_changed) ) | |
| return; | |
| m_new_val = value_; | |
| if( value_changed ) { | |
| request_update(); | |
| } | |
| } | |
| template< sc_writer_policy POL > | |
| inline | |
| void | |
| sc_signal<bool,POL>::print( ::std::ostream& os ) const | |
| { | |
| os << m_cur_val; | |
| } | |
| template< sc_writer_policy POL > | |
| void | |
| sc_signal<bool,POL>::dump( ::std::ostream& os ) const | |
| { | |
| os << " name = " << name() << ::std::endl; | |
| os << " value = " << m_cur_val << ::std::endl; | |
| os << "new value = " << m_new_val << ::std::endl; | |
| } | |
| template< sc_writer_policy POL > | |
| void | |
| sc_signal<bool,POL>::update() | |
| { | |
| policy_type::update(); | |
| if( !( m_new_val == m_cur_val ) ) { | |
| do_update(); | |
| } | |
| } | |
| template< sc_writer_policy POL > | |
| void | |
| sc_signal<bool,POL>::do_update() | |
| { | |
| // order of execution below is important, the notify_processes() call | |
| // must come after the update of m_cur_val for things to work properly! | |
| m_cur_val = m_new_val; | |
| if ( m_reset_p ) m_reset_p->notify_processes(); | |
| if ( m_change_event_p ) m_change_event_p->notify_next_delta(); | |
| sc_event* event_p = this->m_cur_val | |
| ? m_posedge_event_p : m_negedge_event_p; | |
| if ( event_p ) event_p->notify_next_delta(); | |
| m_change_stamp = simcontext()->change_stamp(); | |
| } | |
| // (edge) event methods | |
| template< sc_writer_policy POL > | |
| const sc_event& | |
| sc_signal<bool,POL>::value_changed_event() const | |
| { | |
| return *sc_lazy_kernel_event(&m_change_event_p,"value_changed_event"); | |
| } | |
| template< sc_writer_policy POL > | |
| const sc_event& | |
| sc_signal<bool,POL>::posedge_event() const | |
| { | |
| return *sc_lazy_kernel_event(&m_posedge_event_p,"posedge_event"); | |
| } | |
| template< sc_writer_policy POL > | |
| const sc_event& | |
| sc_signal<bool,POL>::negedge_event() const | |
| { | |
| return *sc_lazy_kernel_event(&m_negedge_event_p,"negedge_event"); | |
| } | |
| // reset support: | |
| template< sc_writer_policy POL > | |
| sc_reset* | |
| sc_signal<bool,POL>::is_reset() const | |
| { | |
| sc_reset* result_p; | |
| if ( !m_reset_p ) m_reset_p = new sc_reset( this ); | |
| result_p = m_reset_p; | |
| return result_p; | |
| } | |
| // destructor | |
| template< sc_writer_policy POL > | |
| sc_signal<bool,POL>::~sc_signal() | |
| { | |
| delete m_change_event_p; | |
| delete m_negedge_event_p; | |
| delete m_posedge_event_p; | |
| delete m_reset_p; | |
| } | |
| // IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII | |
| template< sc_writer_policy POL > | |
| void | |
| sc_signal<sc_dt::sc_logic,POL>::register_port( sc_port_base& port_, | |
| const char* if_typename_ ) | |
| { | |
| bool is_output = std::string( if_typename_ ) == typeid(if_type).name(); | |
| if( !policy_type::check_port( this, &port_, is_output ) ) | |
| ((void)0); // fallback? error has been suppressed ... | |
| } | |
| // write the new value | |
| template< sc_writer_policy POL > | |
| inline | |
| void | |
| sc_signal<sc_dt::sc_logic,POL>::write( const sc_dt::sc_logic& value_ ) | |
| { | |
| bool value_changed = !( m_cur_val == value_ ); | |
| if ( !policy_type::check_write(this, value_changed) ) | |
| return; | |
| m_new_val = value_; | |
| if( value_changed ) { | |
| request_update(); | |
| } | |
| } | |
| template< sc_writer_policy POL > | |
| inline | |
| void | |
| sc_signal<sc_dt::sc_logic,POL>::print( ::std::ostream& os ) const | |
| { | |
| os << m_cur_val; | |
| } | |
| template< sc_writer_policy POL > | |
| void | |
| sc_signal<sc_dt::sc_logic,POL>::dump( ::std::ostream& os ) const | |
| { | |
| os << " name = " << name() << ::std::endl; | |
| os << " value = " << m_cur_val << ::std::endl; | |
| os << "new value = " << m_new_val << ::std::endl; | |
| } | |
| template< sc_writer_policy POL > | |
| void | |
| sc_signal<sc_dt::sc_logic,POL>::update() | |
| { | |
| policy_type::update(); | |
| if( !( m_new_val == m_cur_val ) ) { | |
| do_update(); | |
| } | |
| } | |
| template< sc_writer_policy POL > | |
| void | |
| sc_signal<sc_dt::sc_logic,POL>::do_update() | |
| { | |
| m_cur_val = m_new_val; | |
| if ( m_change_event_p ) m_change_event_p->notify_next_delta(); | |
| if( m_posedge_event_p && (this->m_cur_val == sc_dt::SC_LOGIC_1) ) { | |
| m_posedge_event_p->notify_next_delta(); | |
| } | |
| else if( m_negedge_event_p && (this->m_cur_val == sc_dt::SC_LOGIC_0) ) { | |
| m_negedge_event_p->notify_next_delta(); | |
| } | |
| m_change_stamp = simcontext()->change_stamp(); | |
| } | |
| // (edge) event methods | |
| template< sc_writer_policy POL > | |
| const sc_event& | |
| sc_signal<sc_dt::sc_logic,POL>::value_changed_event() const | |
| { | |
| return *sc_lazy_kernel_event(&m_change_event_p,"value_changed_event"); | |
| } | |
| template< sc_writer_policy POL > | |
| const sc_event& | |
| sc_signal<sc_dt::sc_logic,POL>::posedge_event() const | |
| { | |
| return *sc_lazy_kernel_event(&m_posedge_event_p,"posedge_event"); | |
| } | |
| template< sc_writer_policy POL > | |
| const sc_event& | |
| sc_signal<sc_dt::sc_logic,POL>::negedge_event() const | |
| { | |
| return *sc_lazy_kernel_event(&m_negedge_event_p,"negedge_event"); | |
| } | |
| // template instantiations for writer policies | |
| template class sc_signal<bool,SC_ONE_WRITER>; | |
| template class sc_signal<bool,SC_MANY_WRITERS>; | |
| template class sc_signal<bool,SC_UNCHECKED_WRITERS>; | |
| template class sc_signal<sc_dt::sc_logic,SC_ONE_WRITER>; | |
| template class sc_signal<sc_dt::sc_logic,SC_MANY_WRITERS>; | |
| template class sc_signal<sc_dt::sc_logic,SC_UNCHECKED_WRITERS>; | |
| } // namespace sc_core | |
| /* | |
| $Log: sc_signal.cpp,v $ | |
| Revision 1.9 2011/08/26 20:45:42 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.8 2011/02/18 20:23:45 acg | |
| Andy Goodrich: Copyright update. | |
| Revision 1.7 2011/02/18 20:08:14 acg | |
| Philipp A. Hartmann: addition of include for sstream for MSVC. | |
| Revision 1.6 2011/01/25 20:50:37 acg | |
| Andy Goodrich: changes for IEEE 1666 2011. | |
| Revision 1.5 2010/12/07 19:50:36 acg | |
| Andy Goodrich: addition of writer policies, courtesy of Philipp Hartmann. | |
| Revision 1.3 2007/04/09 21:59:49 acg | |
| Andy Goodrich: fixed multiple write notification bug where writes | |
| done outside the simulator were being treated as multiple writes. | |
| Revision 1.2 2007/04/02 17:24:01 acg | |
| Andy Goodrich: added check for null writer pointers in sc_signal invalid | |
| writer method. | |
| Revision 1.1.1.1 2006/12/15 20:20:04 acg | |
| SystemC 2.3 | |
| Revision 1.7 2006/04/11 23:11:57 acg | |
| Andy Goodrich: Changes for reset support that only includes | |
| sc_cthread_process instances. | |
| Revision 1.6 2006/03/13 20:19:44 acg | |
| Andy Goodrich: changed sc_event instances into pointers to sc_event instances | |
| that are allocated as needed. This saves considerable storage for large | |
| numbers of signals, etc. | |
| Revision 1.5 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.4 2006/01/24 20:46:32 acg | |
| Andy Goodrich: changes to eliminate use of deprecated features. For instance, | |
| using notify(SC_ZERO_TIME) in place of notify_delayed(). | |
| Revision 1.3 2006/01/18 21:42:26 acg | |
| Andy Goodrich: Changes for check writer support, and tightening up sc_clock | |
| port usage. | |
| Revision 1.2 2006/01/03 23:18:26 acg | |
| Changed copyright to include 2006. | |
| Revision 1.1.1.1 2005/12/19 23:16:43 acg | |
| First check in of SystemC 2.1 into its own archive. | |
| Revision 1.14 2005/09/15 23:01:51 acg | |
| Added std:: prefix to appropriate methods and types to get around | |
| issues with the Edison Front End. | |
| Revision 1.13 2005/05/08 19:04:06 acg | |
| Fix bug in concat_set(int64,off). Other changes from 2.1 examples usage. | |
| Revision 1.12 2005/04/04 00:15:51 acg | |
| Changes for directory name change to sys from systemc. | |
| Changes for sc_string going to std::string. | |
| Changes for sc_pvector going to std::vector. | |
| Changes for reference pools for bit and part selections. | |
| Changes for const sc_concatref support. | |
| Revision 1.10 2005/03/21 22:31:32 acg | |
| Changes to sc_core namespace. | |
| Revision 1.9 2004/09/27 21:02:54 acg | |
| Andy Goodrich - Forte Design Systems, Inc. | |
| - Added a $Log comment so that CVS checkin comments will appear in | |
| checked out source. | |
| */ | |
| // Taf! |