MatchLib
fifo.h
1 /*
2  * Copyright (c) 2017-2022, NVIDIA CORPORATION. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License")
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #ifndef FIFO_H
17 #define FIFO_H
18 
19 #include <nvhls_types.h>
20 #include <mem_array.h>
21 #include <nvhls_assert.h>
64 template <typename DataType, unsigned int FifoLen, unsigned int NumBanks = 1>
65 class FIFO {
66 
67  public:
68  static const int BankSelWidth =
69  (NumBanks == 1) ? 1 : nvhls::nbits<NumBanks - 1>::val;
70  static const int AddrWidth =
71  (FifoLen == 1) ? 1 : nvhls::nbits<FifoLen - 1>::val;
72  typedef NVUINTW(BankSelWidth) BankIdx;
73  typedef NVUINTW(AddrWidth) FifoIdx;
74  typedef NVUINTW(AddrWidth+1) FifoIdxPlusOne;
75 
76  FifoIdx head[NumBanks]; // where to read from
77  FifoIdx tail[NumBanks]; // where to write to
78  // FifoLen is number of entries in each bank
80  bool last_action_was_push[NumBanks];
81  static const int width = mem_array_sep<DataType, FifoLen * NumBanks, NumBanks>::width + 2 * NumBanks * AddrWidth + NumBanks;
82 
83  // Function to do modulo increment of pointer
84  FifoIdx ModIncr(FifoIdx curr_idx) {
85  if (curr_idx == FifoLen - 1) {
86  return 0;
87  }
88  return curr_idx + 1;
89  }
90 
91  // Constructor
92  FIFO() {
93 #pragma hls_unroll yes
94  for (unsigned i = 0; i < NumBanks; i++) {
95  head[i] = 0;
96  tail[i] = 0;
97  last_action_was_push[i] = false;
98  }
99  }
100 
101  // Function to push data to FIFO
102  void push(DataType wr_data, BankIdx bidx = 0) {
103  NVHLS_ASSERT_MSG(!isFull(bidx), "Pushing data to full FIFO");
104  FifoIdx tail_local = tail[bidx];
105  fifo_body.write(tail_local, bidx, wr_data);
106  tail[bidx] = ModIncr(tail_local);
107  last_action_was_push[bidx] = true;
108  }
109 
110  // Function to pop data from FIFO
111  DataType pop(BankIdx bidx = 0) {
112  NVHLS_ASSERT_MSG(!isEmpty(bidx), "Popping data from empty FIFO");
113  FifoIdx head_local = head[bidx];
114  DataType rd_data = fifo_body.read(head_local, bidx);
115  head[bidx] = ModIncr(head_local);
116  last_action_was_push[bidx] = false;
117  return rd_data;
118  }
119 
120  // Function to increment the head pointer (emulate a pop)
121  void incrHead(BankIdx bidx = 0) {
122  NVHLS_ASSERT_MSG(!isEmpty(bidx), "Incrementing Head of empty FIFO");
123  FifoIdx head_local = head[bidx];
124  head[bidx] = ModIncr(head_local);
125  last_action_was_push[bidx] = false;
126  }
127 
128  // Function to peek from FIFO
129  DataType peek(BankIdx bidx = 0) {
130  NVHLS_ASSERT_MSG(!isEmpty(bidx), "Peeking data from empty FIFO");
131  FifoIdx head_local = head[bidx];
132  return fifo_body.read(head_local, bidx);
133  }
134 
135  // Checks if FIFO is empty
136  bool isEmpty(BankIdx bidx = 0) {
137  FifoIdx head_local = head[bidx];
138  FifoIdx tail_local = tail[bidx];
139  return (tail_local == head_local) && (!last_action_was_push[bidx]);
140  }
141 
142  // Checks if FIFO is full
143  bool isFull(BankIdx bidx = 0) {
144  FifoIdx head_local = head[bidx];
145  FifoIdx tail_local = tail[bidx];
146  return (tail_local == head_local) && (last_action_was_push[bidx]);
147  }
148 
149  // Returns number of entries filled in FIFO
150  FifoIdxPlusOne NumFilled(BankIdx bidx = 0) {
151  FifoIdx head_local = head[bidx];
152  FifoIdx tail_local = tail[bidx];
153  if (isEmpty(bidx)) {
154  return 0;
155  }
156  if (isFull(bidx)) {
157  return FifoLen;
158  }
159  if (head_local < tail_local) {
160  return (tail_local - head_local);
161  } else {
162  return (FifoLen - head_local + tail_local);
163  }
164  }
165 
166  // Returns number of empty entries in FIFO
167  FifoIdxPlusOne NumAvailable(BankIdx bidx = 0) {
168  return (FifoLen - NumFilled(bidx));
169  }
170 
171  // Reset head and tail pointers
172  void reset() {
173 #pragma hls_unroll yes
174  for (unsigned i = 0; i < NumBanks; i++) {
175  head[i] = 0;
176  tail[i] = 0;
177  last_action_was_push[i] = false;
178  }
179  }
180 
181  FifoIdx get_head(BankIdx bidx = 0) { return head[bidx]; }
182  FifoIdx get_tail(BankIdx bidx = 0) { return tail[bidx]; }
183 
184  template<unsigned int Size>
185  void Marshall(Marshaller<Size>& m) {
186  for (unsigned i = 0; i < NumBanks; i++) {
187  m & head[i];
188  }
189  for (unsigned i = 0; i < NumBanks; i++) {
190  m & tail[i];
191  }
192  m & fifo_body;
193  for (unsigned i = 0; i < NumBanks; i++) {
194  m & last_action_was_push[i];
195  }
196  }
197 
198 }; // end FIFO class
199 
200 template <typename DataType, unsigned int NumBanks>
201 class FIFO<DataType, 0, NumBanks> { // 0 entries, NumBanks
202  // make sure no one is accessing a fifo with 0 entries ever
203  // it will still be fine to create it
204  static const int BankSelWidth =
205  (NumBanks == 1) ? 1 : nvhls::nbits<NumBanks - 1>::val;
206 
207  public:
208  typedef NVUINTW(BankSelWidth) BankIdx;
209  typedef NVUINTW(1) FifoIdx;
210  FIFO() {}
211 
212  void push(DataType wr_data, BankIdx bidx = 0) {NVHLS_ASSERT_MSG(0, "FIFO size is zero");}
213 
214  DataType pop(BankIdx bidx = 0) { NVHLS_ASSERT_MSG(0, "FIFO size is zero"); return DataType(); }
215 
216  void incrHead(BankIdx bidx = 0) {NVHLS_ASSERT_MSG(0, "FIFO size is zero"); }
217 
218  DataType peek(BankIdx bidx = 0) { NVHLS_ASSERT_MSG(0, "FIFO size is zero"); return DataType(); }
219 
220  bool isEmpty(BankIdx bidx = 0) {NVHLS_ASSERT_MSG(0, "FIFO size is zero"); return true; }
221 
222  bool isFull(BankIdx bidx = 0) {NVHLS_ASSERT_MSG(0, "FIFO size is zero"); return true; }
223 
224  FifoIdx NumFilled(BankIdx bidx = 0) {NVHLS_ASSERT_MSG(0, "FIFO size is zero"); return 0; }
225 
226  FifoIdx NumAvailable(BankIdx bidx = 0) {NVHLS_ASSERT_MSG(0, "FIFO size is zero"); return 0; }
227 
228  void reset() {}
229 };
230 
238 template <typename DataType>
239 class FIFO<DataType, 1, 1> {
240  DataType data;
241  bool valid;
242 
243  public:
244  static const int width = Wrapped<DataType>::width + 1;
245  typedef NVUINTW(1) T; //redundant
246 
247  FIFO() {reset();}
248 
249  inline void push(DataType wr_data, T bidx = 0)
250  {
251  NVHLS_ASSERT_MSG(!isFull(), "Pushing data to full FIFO");
252  data = wr_data;
253  valid = true;
254  }
255 
256  inline DataType pop(T bidx = 0)
257  {
258  incrHead();
259  return data;
260  }
261 
262  inline void incrHead(T bidx = 0)
263  {
264  NVHLS_ASSERT_MSG(!isEmpty(), "Incrementing head of empty FIFO");
265  valid = false;
266  }
267 
268  inline DataType peek(T bidx = 0)
269  {
270  NVHLS_ASSERT_MSG(!isEmpty(), "Peeking data from empty FIFO");
271  return data;
272  }
273 
274  inline bool isEmpty(T bidx = 0)
275  {
276  return !valid;
277  }
278 
279  inline bool isFull(T bidx = 0)
280  {
281  return valid;
282  }
283 
284  inline T NumFilled(T bidx = 0) {
285  return valid;
286  }
287 
288  inline T NumAvailable(T bidx = 0) {
289  return !valid;
290  }
291 
292  inline void reset()
293  {
294  valid = false;
295  }
296  template<unsigned int Size>
297  void Marshall(Marshaller<Size>& m) {
298  m & valid;
299  m & data;
300  }
301 };
310 template <typename DataType, unsigned int NumBanks>
311 class FIFO<DataType, 1, NumBanks> {
312  DataType data[NumBanks];
313  bool valid[NumBanks];
314  static const int width = NumBanks * Wrapped<DataType>::width + NumBanks;
315 
316  public:
317  static const int BankSelWidth =
318  (NumBanks == 1) ? 1 : nvhls::nbits<NumBanks - 1>::val;
319  typedef NVUINTW(BankSelWidth) BankIdx;
320  typedef NVUINTW(1) T;
321 
322  FIFO() {
323  reset();
324  }
325 
326  inline void push(DataType wr_data, BankIdx bidx = 0) {
327  NVHLS_ASSERT_MSG(!isFull(bidx), "Pushing data to full FIFO");
328  data[bidx] = wr_data;
329  valid[bidx] = true;
330  }
331 
332  inline DataType pop(BankIdx bidx = 0) {
333  incrHead(bidx);
334  return data[bidx];
335  }
336 
337  inline void incrHead(BankIdx bidx = 0) {
338  NVHLS_ASSERT_MSG(!isEmpty(bidx), "Incrementing Head of empty FIFO");
339  valid[bidx] = false;
340  }
341 
342  inline DataType peek(BankIdx bidx = 0) {
343  NVHLS_ASSERT_MSG(!isEmpty(bidx), "Peeking data from empty FIFO");
344  return data[bidx];
345  }
346 
347  inline bool isEmpty(BankIdx bidx = 0) {
348  return !valid[bidx];
349  }
350 
351  inline bool isFull(BankIdx bidx = 0) {
352  return valid[bidx];
353  }
354 
355  inline T NumFilled(T bidx = 0) {
356  return valid;
357  }
358 
359  inline T NumAvailable(T bidx = 0) {
360  return !valid;
361  }
362 
363  inline void reset() {
364  #pragma hls_unroll yes
365  for(unsigned i=0; i<NumBanks; i++) {
366  valid[i] = false;
367  }
368  }
369  template<unsigned int Size>
370  void Marshall(Marshaller<Size>& m) {
371  for (unsigned i = 0; i < NumBanks; i++) {
372  m & valid[i];
373  }
374  for (unsigned i = 0; i < NumBanks; i++) {
375  m & data[i];
376  }
377  }
378 };
379 
380 #endif // end #define FIFO_H macro
Configurable FIFO class.
Definition: fifo.h:65
Abstract Memory Class.
Definition: mem_array.h:83
#define NVHLS_ASSERT_MSG(X, MSG)
Definition: nvhls_assert.h:135
Compute number of bits to represent a constant.
Definition: nvhls_int.h:118