sc_fifo.hh revision 13324
1/*
2 * Copyright 2018 Google, Inc.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met: redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer;
8 * redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution;
11 * neither the name of the copyright holders nor the names of its
12 * contributors may be used to endorse or promote products derived from
13 * this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 * Authors: Gabe Black
28 */
29
30#ifndef __SYSTEMC_EXT_CHANNEL_SC_FIFO_HH__
31#define __SYSTEMC_EXT_CHANNEL_SC_FIFO_HH__
32
33#include <list>
34#include <string>
35
36#include "../core/sc_module.hh" // for sc_gen_unique_name
37#include "../core/sc_prim.hh"
38#include "../utils/sc_report_handler.hh"
39#include "messages.hh"
40#include "sc_fifo_in_if.hh"
41#include "sc_fifo_out_if.hh"
42
43namespace sc_core
44{
45
46class sc_port_base;
47class sc_event;
48
49template <class T>
50class sc_fifo : public sc_fifo_in_if<T>,
51                public sc_fifo_out_if<T>,
52                public sc_prim_channel
53{
54  public:
55    explicit sc_fifo(int size=16) :
56            sc_fifo_in_if<T>(), sc_fifo_out_if<T>(),
57            sc_prim_channel(sc_gen_unique_name("fifo")),
58            _size(size), _readsHappened(false), _reader(NULL), _writer(NULL)
59    {}
60    explicit sc_fifo(const char *name, int size=16) :
61            sc_fifo_in_if<T>(), sc_fifo_out_if<T>(),
62            sc_prim_channel(name), _size(size), _readsHappened(false),
63            _reader(NULL), _writer(NULL)
64    {}
65    virtual ~sc_fifo() {}
66
67    virtual void
68    register_port(sc_port_base &port, const char *iface_type_name)
69    {
70        std::string tn(iface_type_name);
71        if (tn == typeid(sc_fifo_in_if<T>).name() ||
72                tn == typeid(sc_fifo_blocking_in_if<T>).name()) {
73            if (_reader)
74                SC_REPORT_ERROR(SC_ID_MORE_THAN_ONE_FIFO_READER_, "");
75            _reader = &port;
76        } else if (tn == typeid(sc_fifo_out_if<T>).name() ||
77                tn == typeid(sc_fifo_blocking_out_if<T>).name()) {
78            if (_writer)
79                SC_REPORT_ERROR(SC_ID_MORE_THAN_ONE_FIFO_WRITER_, "");
80            _writer = &port;
81        } else {
82            SC_REPORT_ERROR(SC_ID_BIND_IF_TO_PORT_,
83                    "sc_fifo<T> port not recognized");
84        }
85    }
86
87    virtual void
88    read(T &t)
89    {
90        while (num_available() == 0)
91            sc_core::wait(_dataWriteEvent);
92        _readsHappened = true;
93        t = _entries.front();
94        _entries.pop_front();
95        request_update();
96    }
97    virtual T
98    read()
99    {
100        T t;
101        read(t);
102        return t;
103    }
104    virtual bool
105    nb_read(T &t)
106    {
107        if (num_available()) {
108            read(t);
109            return true;
110        } else {
111            return false;
112        }
113    }
114    operator T() { return read(); }
115
116    virtual void
117    write(const T &t)
118    {
119        while (num_free() == 0)
120            sc_core::wait(_dataReadEvent);
121        _pending.emplace_back(t);
122        request_update();
123    }
124    virtual bool
125    nb_write(const T &t)
126    {
127        if (num_free()) {
128            write(t);
129            return true;
130        } else {
131            return false;
132        }
133    }
134    sc_fifo<T> &
135    operator = (const T &t)
136    {
137        write(t);
138        return *this;
139    }
140
141    virtual const sc_event &
142    data_written_event() const
143    {
144        return _dataWriteEvent;
145    }
146    virtual const sc_event &
147    data_read_event() const
148    {
149        return _dataReadEvent;
150    }
151
152    virtual int num_available() const { return _entries.size(); }
153    virtual int
154    num_free() const
155    {
156        return _size - _entries.size() - _pending.size();
157    }
158
159    virtual void
160    print(std::ostream &os=std::cout) const
161    {
162        for (typename ::std::list<T>::iterator pos = _pending.begin();
163                pos != _pending.end(); pos++) {
164            os << *pos << ::std::endl;
165        }
166        for (typename ::std::list<T>::iterator pos = _entries.begin();
167                pos != _entries.end(); pos++) {
168            os << *pos << ::std::endl;
169        }
170    }
171    virtual void
172    dump(std::ostream &os=std::cout) const
173    {
174        os << "name = " << name() << std::endl;
175        int idx = 0;
176        for (typename ::std::list<T>::iterator pos = _pending.begin();
177                pos != _pending.end(); pos++) {
178            os << "value[" << idx++ << "] = " << *pos << ::std::endl;
179        }
180        for (typename ::std::list<T>::iterator pos = _entries.begin();
181                pos != _entries.end(); pos++) {
182            os << "value[" << idx++ << "] = " << *pos << ::std::endl;
183        }
184    }
185    virtual const char *kind() const { return "sc_fifo"; }
186
187  protected:
188    virtual void
189    update()
190    {
191        if (!_pending.empty()) {
192            _dataWriteEvent.notify(SC_ZERO_TIME);
193            _entries.insert(_entries.end(), _pending.begin(), _pending.end());
194            _pending.clear();
195        }
196        if (_readsHappened) {
197            _readsHappened = false;
198            _dataReadEvent.notify(SC_ZERO_TIME);
199        }
200    }
201
202  private:
203    // Disabled
204    sc_fifo(const sc_fifo<T> &) :
205            sc_fifo_in_if<T>(), sc_fifo_in_if<T>(), sc_prim_channel()
206    {}
207    sc_fifo &operator = (const sc_fifo<T> &) { return *this; }
208
209    sc_gem5::InternalScEvent _dataReadEvent;
210    sc_gem5::InternalScEvent _dataWriteEvent;
211
212    sc_port_base *_reader;
213    sc_port_base *_writer;
214
215    int _size;
216    mutable std::list<T> _entries;
217    mutable std::list<T> _pending;
218    bool _readsHappened;
219};
220
221template <class T>
222inline std::ostream &
223operator << (std::ostream &os, const sc_fifo<T> &f)
224{
225    f.print(os);
226    return os;
227}
228
229} // namespace sc_core
230
231#endif  //__SYSTEMC_EXT_CHANNEL_SC_FIFO_HH__
232