1/*****************************************************************************
2
3  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
4  more contributor license agreements.  See the NOTICE file distributed
5  with this work for additional information regarding copyright ownership.
6  Accellera licenses this file to you under the Apache License, Version 2.0
7  (the "License"); you may not use this file except in compliance with the
8  License.  You may obtain a copy of the License at
9
10    http://www.apache.org/licenses/LICENSE-2.0
11
12  Unless required by applicable law or agreed to in writing, software
13  distributed under the License is distributed on an "AS IS" BASIS,
14  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
15  implied.  See the License for the specific language governing
16  permissions and limitations under the License.
17
18 *****************************************************************************/
19
20#ifndef __SYSTEMC_EXT_TLM_CORE_1_REQ_RSP_CHANNELS_FIFO_FIFO_HH__
21#define __SYSTEMC_EXT_TLM_CORE_1_REQ_RSP_CHANNELS_FIFO_FIFO_HH__
22
23//
24// This implements put, get and peek
25//
26// It also implements 0 and infinite size fifos - but the size
27// zero fifos aren't rendezvous like zero length fifos, they simply are both
28// full and empty at the same time.
29//
30// The size can be dynamically changed using the resize interface
31//
32// To get an infinite fifo use a -ve size in the constructor.
33// The absolute value of the size is taken as the starting size of the
34// actual physical buffer.
35//
36
37#include "../../interfaces/fifo_ifs.hh"
38#include "circular_buffer.hh"
39
40namespace tlm
41{
42
43template <typename T>
44class tlm_fifo : public virtual tlm_fifo_get_if<T>,
45    public virtual tlm_fifo_put_if<T>, public sc_core::sc_prim_channel
46{
47  public:
48    // Constructors.
49    explicit tlm_fifo(int size_=1) :
50        sc_core::sc_prim_channel(sc_core::sc_gen_unique_name("fifo"))
51    {
52        init(size_);
53    }
54
55    explicit tlm_fifo(const char *name_, int size_=1) :
56        sc_core::sc_prim_channel(name_)
57    {
58        init(size_);
59    }
60
61    // Destructor..
62    virtual ~tlm_fifo() {}
63
64    // Tlm get interface.
65    T get(tlm_tag<T> * =nullptr);
66
67    bool nb_get(T &);
68    bool nb_can_get(tlm_tag<T> * =nullptr) const;
69    const sc_core::sc_event &
70    ok_to_get(tlm_tag<T> * =nullptr) const
71    {
72        return m_data_written_event;
73    }
74
75    // Tlm peek interface.
76    T peek(tlm_tag<T> * =nullptr) const;
77
78    bool nb_peek(T &) const;
79    bool nb_can_peek(tlm_tag<T> * =nullptr) const;
80    const sc_core::sc_event &
81    ok_to_peek(tlm_tag<T> * =nullptr) const
82    {
83        return m_data_written_event;
84    }
85
86    // Tlm put interface.
87    void put(const T &);
88
89    bool nb_put(const T &);
90    bool nb_can_put(tlm_tag<T> * =nullptr) const;
91    const sc_core::sc_event &
92    ok_to_put(tlm_tag<T> * =nullptr) const
93    {
94        return m_data_read_event;
95    }
96
97    // Resize if.
98    void nb_expand(unsigned int n=1);
99    void nb_unbound(unsigned int n=16);
100
101    bool nb_reduce(unsigned int n=1);
102    bool nb_bound(unsigned int n);
103
104    // Debug interface.
105    bool nb_peek(T &, int n) const;
106    bool nb_poke(const T &, int n=0);
107
108    int used() const { return m_num_readable - m_num_read; }
109    int size() const { return m_size; }
110
111    void
112    debug() const
113    {
114        if (is_empty())
115            std::cout << "empty" << std::endl;
116        if (is_full())
117            std::cout << "full" << std::endl;
118
119        std::cout << "size " << size() << " - " << used() << " used "
120                  << std::endl;
121        std::cout << "readable " << m_num_readable << std::endl;
122        std::cout << "written/read " << m_num_written << "/" << m_num_read
123                  << std::endl;
124    }
125
126    // Support functions.
127    static const char * const kind_string;
128    const char *kind() const { return kind_string; }
129
130  protected:
131    sc_core::sc_event &
132    read_event(tlm_tag<T> * =nullptr)
133    {
134        return m_data_read_event;
135    }
136
137    void update();
138    void init(int);
139
140    circular_buffer<T> buffer;
141
142    int m_size; // logical size of fifo
143
144    int m_num_readable; // #samples readable
145    int m_num_read; // #samples read during this delta cycle
146    int m_num_written; // #samples written during this delta cycle
147    bool m_expand; // has an expand occurred during this delta cycle ?
148    // #samples read without notify during this delta cycle
149    int m_num_read_no_notify;
150
151    sc_core::sc_event m_data_read_event;
152    sc_core::sc_event m_data_written_event;
153
154  private:
155    // disabled
156    tlm_fifo(const tlm_fifo<T> &);
157    tlm_fifo &operator = (const tlm_fifo<T> &);
158
159    //
160    // use nb_can_get() and nb_can_put() rather than the following two
161    // private functions
162    //
163
164    bool is_empty() const { return used() == 0; }
165
166    bool
167    is_full() const
168    {
169        if (size() < 0)
170            return false;
171        else
172            return size() <= m_num_readable + m_num_written;
173    }
174};
175
176template <typename T>
177const char *const tlm_fifo<T>::kind_string = "tlm_fifo";
178
179/******************************************************************
180//
181// init and update
182//
183******************************************************************/
184
185template <typename T>
186inline void
187tlm_fifo<T>::init(int size_)
188{
189    if (size_ > 0) {
190        buffer.resize( size_ );
191    } else if (size_ < 0) {
192        buffer.resize(-size_);
193    } else {
194        buffer.resize(16);
195    }
196
197    m_size = size_;
198    m_num_readable = 0;
199    m_num_read = 0;
200    m_num_written = 0;
201    m_expand = false;
202    m_num_read_no_notify = false;
203}
204
205template <typename T>
206inline void
207tlm_fifo<T>::update()
208{
209    if (m_num_read > m_num_read_no_notify || m_expand) {
210        m_data_read_event.notify(sc_core::SC_ZERO_TIME);
211    }
212
213    if (m_num_written > 0) {
214        m_data_written_event.notify(sc_core::SC_ZERO_TIME);
215    }
216
217    m_expand = false;
218    m_num_read = 0;
219    m_num_written = 0;
220    m_num_readable = buffer.used();
221    m_num_read_no_notify = 0;
222}
223
224} // namespace tlm
225
226#include "fifo_peek.hh"
227#include "fifo_put_get.hh"
228#include "fifo_resize.hh"
229
230#endif /* __SYSTEMC_EXT_TLM_CORE_1_REQ_RSP_CHANNELS_FIFO_FIFO_HH__ */
231