blob: a048c09bed9401e4fd06a06b4a62a38e923ed3b4 [file] [log] [blame]
/*
* 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 <list>
#include <string>
#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 T>
class sc_fifo : public sc_fifo_in_if<T>,
public sc_fifo_out_if<T>,
public sc_prim_channel
{
public:
explicit sc_fifo(int size=16) :
sc_fifo_in_if<T>(), sc_fifo_out_if<T>(),
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<T>(), sc_fifo_out_if<T>(),
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<T>).name() ||
tn == typeid(sc_fifo_blocking_in_if<T>).name()) {
if (_reader)
SC_REPORT_ERROR(SC_ID_MORE_THAN_ONE_FIFO_READER_, "");
_reader = &port;
} else if (tn == typeid(sc_fifo_out_if<T>).name() ||
tn == typeid(sc_fifo_blocking_out_if<T>).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<T> 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<T> &
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<T>::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<T>::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<T> &) : sc_fifo_in_if<T>(), sc_prim_channel()
{}
sc_fifo &operator = (const sc_fifo<T> &) { 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<T> _entries;
bool _readsHappened;
bool _writesHappened;
};
template <class T>
inline std::ostream &
operator << (std::ostream &os, const sc_fifo<T> &f)
{
f.print(os);
return os;
}
} // namespace sc_core
#endif //__SYSTEMC_EXT_CHANNEL_SC_FIFO_HH__