/* * 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_FIFO_HH__ #define __SYSTEMC_EXT_CHANNEL_SC_FIFO_HH__ #include #include #include "../core/sc_module.hh" // for sc_gen_unique_name #include "../core/sc_prim.hh" #include "../utils/sc_report_handler.hh" #include "messages.hh" #include "sc_fifo_in_if.hh" #include "sc_fifo_out_if.hh" namespace sc_core { class sc_port_base; class sc_event; template class sc_fifo : public sc_fifo_in_if, public sc_fifo_out_if, public sc_prim_channel { public: explicit sc_fifo(int size=16) : sc_fifo_in_if(), sc_fifo_out_if(), sc_prim_channel(sc_gen_unique_name("fifo")), _size(size), _num_free(size), _num_available(0), _readsHappened(false), _writesHappened(false), _reader(NULL), _writer(NULL) {} explicit sc_fifo(const char *name, int size=16) : sc_fifo_in_if(), sc_fifo_out_if(), sc_prim_channel(name), _size(size), _num_free(size), _num_available(0), _readsHappened(false), _writesHappened(false), _reader(NULL), _writer(NULL) {} virtual ~sc_fifo() {} virtual void register_port(sc_port_base &port, const char *iface_type_name) { std::string tn(iface_type_name); if (tn == typeid(sc_fifo_in_if).name() || tn == typeid(sc_fifo_blocking_in_if).name()) { if (_reader) SC_REPORT_ERROR(SC_ID_MORE_THAN_ONE_FIFO_READER_, ""); _reader = &port; } else if (tn == typeid(sc_fifo_out_if).name() || tn == typeid(sc_fifo_blocking_out_if).name()) { if (_writer) SC_REPORT_ERROR(SC_ID_MORE_THAN_ONE_FIFO_WRITER_, ""); _writer = &port; } else { SC_REPORT_ERROR(SC_ID_BIND_IF_TO_PORT_, "sc_fifo port not recognized"); } } virtual void read(T &t) { while (num_available() == 0) sc_core::wait(_dataWriteEvent); _readsHappened = true; t = _entries.front(); _entries.pop_front(); _num_available--; request_update(); } virtual T read() { T t; read(t); return t; } virtual bool nb_read(T &t) { if (num_available()) { read(t); return true; } else { return false; } } operator T() { return read(); } virtual void write(const T &t) { while (num_free() == 0) sc_core::wait(_dataReadEvent); _writesHappened = true; _entries.emplace_back(t); _num_free--; request_update(); } virtual bool nb_write(const T &t) { if (num_free()) { write(t); return true; } else { return false; } } sc_fifo & operator = (const T &t) { write(t); return *this; } virtual const sc_event & data_written_event() const { return _dataWriteEvent; } virtual const sc_event & data_read_event() const { return _dataReadEvent; } virtual int num_available() const { return _num_available; } virtual int num_free() const { return _num_free; } virtual void print(std::ostream &os=std::cout) const { for (typename ::std::list::iterator pos = _entries.begin(); pos != _entries.end(); pos++) { os << *pos << ::std::endl; } } virtual void dump(std::ostream &os=std::cout) const { os << "name = " << name() << std::endl; int idx = 0; for (typename ::std::list::iterator pos = _entries.begin(); pos != _entries.end(); pos++) { os << "value[" << idx++ << "] = " << *pos << ::std::endl; } } virtual const char *kind() const { return "sc_fifo"; } protected: virtual void update() { _num_available = _entries.size(); _num_free = _size - _num_available; if (_writesHappened) { _writesHappened = false; _dataWriteEvent.notify(SC_ZERO_TIME); } if (_readsHappened) { _readsHappened = false; _dataReadEvent.notify(SC_ZERO_TIME); } } private: // Disabled sc_fifo(const sc_fifo &) : sc_fifo_in_if(), sc_fifo_in_if(), sc_prim_channel() {} sc_fifo &operator = (const sc_fifo &) { return *this; } sc_gem5::InternalScEvent _dataReadEvent; sc_gem5::InternalScEvent _dataWriteEvent; sc_port_base *_reader; sc_port_base *_writer; int _size; int _num_free; int _num_available; mutable std::list _entries; bool _readsHappened; bool _writesHappened; }; template inline std::ostream & operator << (std::ostream &os, const sc_fifo &f) { f.print(os); return os; } } // namespace sc_core #endif //__SYSTEMC_EXT_CHANNEL_SC_FIFO_HH__