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