/* * Copyright 2018 Google, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer; * redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution; * neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Gabe Black */ #ifndef __SYSTEMC_EXT_CHANNEL_SC_SIGNAL_HH__ #define __SYSTEMC_EXT_CHANNEL_SC_SIGNAL_HH__ #include #include #include #include "../core/sc_event.hh" #include "../core/sc_module.hh" // for sc_gen_unique_name #include "../core/sc_prim.hh" #include "../dt/bit/sc_logic.hh" #include "sc_signal_inout_if.hh" namespace sc_core { class sc_port_base; } // namespace sc_core namespace sc_gem5 { class Process; class Reset; class ScSignalBase : public sc_core::sc_prim_channel { public: virtual const char *kind() const { return "sc_signal"; } protected: ScSignalBase(const char *_name); virtual ~ScSignalBase(); const sc_core::sc_event &defaultEvent() const; const sc_core::sc_event &valueChangedEvent() const; bool event() const; void _signalChange(); virtual sc_core::sc_writer_policy get_writer_policy() const = 0; InternalScEvent _valueChangedEvent; uint64_t _changeStamp; sc_core::sc_port_base *_gem5WriterPort; }; class ScSignalBaseBinary : public ScSignalBase { protected: ScSignalBaseBinary(const char *_name); mutable std::vector _resets; void _signalReset(sc_gem5::Reset *reset); void _signalReset(); const sc_core::sc_event &posedgeEvent() const; const sc_core::sc_event &negedgeEvent() const; bool posedge() const; bool negedge() const; InternalScEvent _posedgeEvent; InternalScEvent _negedgeEvent; uint64_t _posStamp; uint64_t _negStamp; }; template class ScSignalBasePicker : public ScSignalBase { protected: ScSignalBasePicker(const char *_name) : ScSignalBase(_name) {} }; template <> class ScSignalBasePicker : public ScSignalBaseBinary { protected: ScSignalBasePicker(const char *_name) : ScSignalBaseBinary(_name) {} }; template <> class ScSignalBasePicker : public ScSignalBaseBinary { protected: ScSignalBasePicker(const char *_name) : ScSignalBaseBinary(_name) {} }; template class WriteChecker; template <> class WriteChecker { public: WriteChecker(ScSignalBase *_sig); void checkPort(sc_core::sc_port_base &port, std::string iface_type_name, std::string out_name); void checkWriter(); private: ScSignalBase *sig; sc_core::sc_port_base *firstPort; Process *proc; uint64_t writeStamp; }; template <> class WriteChecker { public: WriteChecker(ScSignalBase *_sig); void checkPort(sc_core::sc_port_base &port, std::string iface_type_name, std::string out_name); void checkWriter(); private: ScSignalBase *sig; Process *proc; uint64_t writeStamp; }; template class ScSignalBaseT : public ScSignalBasePicker, public sc_core::sc_signal_inout_if { public: ScSignalBaseT(const char *_name) : ScSignalBasePicker(_name), m_cur_val(T()), m_new_val(T()), _checker(this) {} ScSignalBaseT(const char *_name, const T &initial_value) : ScSignalBasePicker(_name), m_cur_val(initial_value), m_new_val(initial_value), _checker(this) {} virtual ~ScSignalBaseT() {} virtual void register_port(sc_core::sc_port_base &port, const char *iface_type_name) { # if !defined(SC_NO_WRITE_CHECK) { _checker.checkPort(port, iface_type_name, typeid(sc_core::sc_signal_inout_if).name()); } # endif } virtual const T &read() const { return m_cur_val; } operator const T&() const { return read(); } virtual void write(const T &t) { # if !defined(SC_NO_WRITE_CHECK) { _checker.checkWriter(); } # endif m_new_val = t; bool changed = !(m_cur_val == m_new_val); if (changed) this->request_update(); } virtual const sc_core::sc_event & default_event() const { return ScSignalBase::defaultEvent(); } virtual const sc_core::sc_event & value_changed_event() const { return ScSignalBase::valueChangedEvent(); } virtual void print(std::ostream &os=std::cout) const { os << m_cur_val; } virtual void dump(std::ostream &os=std::cout) const { os << " name = " << this->name() << ::std::endl; os << " value = " << m_cur_val << ::std::endl; os << "new value = " << m_new_val << ::std::endl; } virtual bool event() const { return ScSignalBase::event(); } virtual sc_core::sc_writer_policy get_writer_policy() const { return WRITER_POLICY; } protected: // These members which store the current and future value of the signal // are not specified in the standard but are referred to directly by one // of the tests. T m_cur_val; T m_new_val; WriteChecker _checker; }; template class ScSignalBinary : public ScSignalBaseT { public: ScSignalBinary(const char *_name) : ScSignalBaseT(_name) {} ScSignalBinary(const char *_name, const T& initial_value) : ScSignalBaseT(_name, initial_value) {} const sc_core::sc_event & posedge_event() const { return ScSignalBaseBinary::posedgeEvent(); } const sc_core::sc_event & negedge_event() const { return ScSignalBaseBinary::negedgeEvent(); } bool posedge() const { return ScSignalBaseBinary::posedge(); } bool negedge() const { return ScSignalBaseBinary::negedge(); } }; } // namespace sc_gem5 namespace sc_core { template class sc_signal : public sc_gem5::ScSignalBaseT { public: sc_signal() : sc_gem5::ScSignalBaseT( sc_gen_unique_name("signal")) {} explicit sc_signal(const char *name) : sc_gem5::ScSignalBaseT(name) {} explicit sc_signal(const char *name, const T &initial_value) : sc_gem5::ScSignalBaseT(name, initial_value) {} virtual ~sc_signal() {} sc_signal & operator = (const T &t) { this->write(t); return *this; } sc_signal & operator = (const sc_signal &s) { this->write(s.read()); return *this; } protected: virtual void update() { if (this->m_new_val == this->m_cur_val) return; this->m_cur_val = this->m_new_val; this->_signalChange(); } private: // Disabled sc_signal(const sc_signal &); }; template inline std::ostream & operator << (std::ostream &os, const sc_signal &s) { os << s.read(); return os; } template class sc_signal : public sc_gem5::ScSignalBinary { public: sc_signal() : sc_gem5::ScSignalBinary( sc_gen_unique_name("signal")) {} explicit sc_signal(const char *name) : sc_gem5::ScSignalBinary(name) {} explicit sc_signal(const char *name, const bool &initial_value) : sc_gem5::ScSignalBinary(name, initial_value) {} virtual ~sc_signal() {} sc_signal & operator = (const bool &b) { this->write(b); return *this; } sc_signal & operator = (const sc_signal &s) { this->write(s.read()); return *this; } protected: virtual void update() { if (this->m_new_val == this->m_cur_val) return; this->m_cur_val = this->m_new_val; this->_signalReset(); this->_signalChange(); if (this->m_cur_val) { this->_posStamp = ::sc_gem5::getChangeStamp(); this->_posedgeEvent.notify(SC_ZERO_TIME); } else { this->_negStamp = ::sc_gem5::getChangeStamp(); this->_negedgeEvent.notify(SC_ZERO_TIME); } } private: bool _addReset(sc_gem5::Reset *reset) const { this->_resets.push_back(reset); return true; } // Disabled sc_signal(const sc_signal &); }; template class sc_signal : public sc_gem5::ScSignalBinary { public: sc_signal() : sc_gem5::ScSignalBinary( sc_gen_unique_name("signal")) {} explicit sc_signal(const char *name) : sc_gem5::ScSignalBinary(name) {} explicit sc_signal(const char *name, const sc_dt::sc_logic &initial_value) : sc_gem5::ScSignalBinary( name, initial_value) {} virtual ~sc_signal() {} sc_signal & operator = (const sc_dt::sc_logic &l) { this->write(l); return *this; } sc_signal & operator = (const sc_signal &s) { this->write(s.read()); return *this; } protected: virtual void update() { if (this->m_new_val == this->m_cur_val) return; this->m_cur_val = this->m_new_val; this->_signalChange(); if (this->m_cur_val == sc_dt::SC_LOGIC_1) { this->_posStamp = ::sc_gem5::getChangeStamp(); this->_posedgeEvent.notify(SC_ZERO_TIME); } else if (this->m_cur_val == sc_dt::SC_LOGIC_0) { this->_negStamp = ::sc_gem5::getChangeStamp(); this->_negedgeEvent.notify(SC_ZERO_TIME); } } private: // Disabled sc_signal(const sc_signal &); }; } // namespace sc_core #endif //__SYSTEMC_EXT_CHANNEL_SC_SIGNAL_HH__