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 __TLM_CORE_1_REQ_RSP_CHANNELS_FIFO_CIRCULAR_BUFFER_HH__
21#define __TLM_CORE_1_REQ_RSP_CHANNELS_FIFO_CIRCULAR_BUFFER_HH__
22
23#include <iostream>
24
25namespace tlm
26{
27
28template <typename T>
29class circular_buffer
30{
31  public:
32    explicit circular_buffer(int size=0);
33    ~circular_buffer();
34
35    void resize(int size);
36    void clear();
37
38    T read();
39    void write(const T &);
40
41    bool is_empty() const { return used() == 0; }
42    bool is_full() const { return free() == 0; }
43
44    int size() const { return m_size; }
45    int used() const { return m_used; }
46    int free() const { return m_free; }
47
48    const T &read_data() const { return buf_read(m_buf, m_ri); }
49    const T &
50    peek_data(int i) const
51    {
52        return buf_read(m_buf, (m_ri + i) % size());
53    }
54
55    T &
56    poke_data(int i)
57    {
58        return buf_read(m_buf, (m_wi + i) % size());
59    }
60
61    void debug() const;
62
63  private:
64    void increment_write_pos(int i=1);
65    void increment_read_pos(int i=1);
66
67    void init();
68
69    // Disabled.
70    circular_buffer(const circular_buffer<T> &b);
71    circular_buffer<T> &operator = (const circular_buffer<T> &);
72
73    void *buf_alloc(int size);
74    void buf_free(void *&buf);
75    void buf_write(void *buf, int n, const T &t);
76    T &buf_read(void *buf, int n) const;
77    void buf_clear(void *buf, int n);
78
79  private:
80    int m_size; // size of the buffer
81    void *m_buf; // the buffer
82    int m_free; // number of free spaces
83    int m_used; // number of used spaces
84    int m_ri; // index of next read
85    int m_wi; // index of next write
86};
87
88template <typename T>
89void
90circular_buffer<T>::debug() const
91{
92    std::cout << "Buffer debug" << std::endl;
93    std::cout << "Size : " << size() << std::endl;
94    std::cout << "Free/Used " << free() << "/" << used() << std::endl;
95    std::cout << "Indices : r/w = " << m_ri << "/" << m_wi << std::endl;
96
97    if (is_empty()) {
98        std::cout << "empty" << std::endl;
99    }
100
101    if (is_full()) {
102        std::cout << "full" << std::endl;
103    }
104
105    std::cout << "Data : " << std::endl;
106    for (int i = 0; i < used(); i++) {
107        std::cout << peek_data( i ) << std::endl;
108    }
109}
110
111template <typename T>
112circular_buffer<T>::circular_buffer(int size) : m_size(size), m_buf(0)
113{
114    init();
115}
116
117template <typename T>
118void
119circular_buffer<T>::clear()
120{
121    for (int i = 0; i < used(); i++) {
122        buf_clear(m_buf, (m_ri + i) % m_size);
123    }
124    m_free = m_size;
125    m_used = m_ri = m_wi = 0;
126}
127
128template <typename T>
129circular_buffer<T>::~circular_buffer()
130{
131    clear();
132    buf_free(m_buf);
133}
134
135template <typename T>
136void
137circular_buffer<T>::resize(int size)
138{
139    int i;
140    void *new_buf = buf_alloc(size);
141
142    for (i = 0; i < size && i < used(); i++) {
143        buf_write(new_buf, i, peek_data(i));
144        buf_clear(m_buf, (m_ri + i) % m_size);
145    }
146
147    buf_free(m_buf);
148
149    m_size = size;
150    m_ri = 0;
151    m_wi = i % m_size;
152    m_used = i;
153    m_free = m_size - m_used;
154
155    m_buf = new_buf;
156}
157
158
159template <typename T>
160void
161circular_buffer<T>::init()
162{
163    if (m_size > 0) {
164        m_buf = buf_alloc(m_size);
165    }
166
167    m_free = m_size;
168    m_used = 0;
169    m_ri = 0;
170    m_wi = 0;
171}
172
173template <typename T>
174T
175circular_buffer<T>::read()
176{
177    T t = read_data();
178
179    buf_clear(m_buf, m_ri);
180    increment_read_pos();
181
182    return t;
183}
184
185template <typename T>
186void
187circular_buffer<T>::write(const T &t)
188{
189    buf_write(m_buf, m_wi, t);
190    increment_write_pos();
191}
192
193template <typename T>
194void
195circular_buffer<T>::increment_write_pos(int i)
196{
197    m_wi = (m_wi + i) % m_size;
198    m_used += i;
199    m_free -= i;
200}
201
202template <typename T>
203void
204circular_buffer<T>::increment_read_pos(int i)
205{
206    m_ri = (m_ri + i) % m_size;
207    m_used -= i;
208    m_free += i;
209}
210
211template <typename T>
212inline void *
213circular_buffer<T>::buf_alloc(int size)
214{
215    return new unsigned char [size * sizeof(T)];
216}
217
218template <typename T>
219inline void
220circular_buffer<T>::buf_free(void *&buf)
221{
222    delete [] static_cast<unsigned char *>(buf);
223    buf = nullptr;
224}
225
226template <typename T>
227inline void
228circular_buffer<T>::buf_write(void *buf, int n, const T &t)
229{
230    T *p = static_cast<T *>(buf) + n;
231    new (p)T(t);
232}
233
234template <typename T>
235inline T &
236circular_buffer<T>::buf_read(void *buf, int n) const
237{
238    T *p = static_cast<T *>(buf) + n;
239    return *p;
240}
241
242template <typename T>
243inline void
244circular_buffer<T>::buf_clear(void *buf, int n)
245{
246    T *p = static_cast<T *>(buf) + n;
247    p->~T();
248}
249
250} // namespace tlm
251
252#endif /* __TLM_CORE_1_REQ_RSP_CHANNELS_FIFO_CIRCULAR_BUFFER_HH__ */
253