MatchLib
fifo.h
1 /*
2  * Copyright (c) 2017-2019, 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  m & tail[i];
189  m & last_action_was_push[i];
190  }
191  m & fifo_body;
192  }
193 
194 }; // end FIFO class
195 
196 template <typename DataType, unsigned int NumBanks>
197 class FIFO<DataType, 0, NumBanks> { // 0 entries, NumBanks
198  // make sure no one is accessing a fifo with 0 entries ever
199  // it will still be fine to create it
200  static const int BankSelWidth =
201  (NumBanks == 1) ? 1 : nvhls::nbits<NumBanks - 1>::val;
202 
203  public:
204  typedef NVUINTW(BankSelWidth) BankIdx;
205  typedef NVUINTW(1) FifoIdx;
206  FIFO() {}
207 
208  void push(DataType wr_data, BankIdx bidx = 0) {NVHLS_ASSERT_MSG(0, "FIFO size is zero");}
209 
210  DataType pop(BankIdx bidx = 0) { NVHLS_ASSERT_MSG(0, "FIFO size is zero"); return DataType(); }
211 
212  void incrHead(BankIdx bidx = 0) {NVHLS_ASSERT_MSG(0, "FIFO size is zero"); }
213 
214  DataType peek(BankIdx bidx = 0) { NVHLS_ASSERT_MSG(0, "FIFO size is zero"); return DataType(); }
215 
216  bool isEmpty(BankIdx bidx = 0) {NVHLS_ASSERT_MSG(0, "FIFO size is zero"); return true; }
217 
218  bool isFull(BankIdx bidx = 0) {NVHLS_ASSERT_MSG(0, "FIFO size is zero"); return true; }
219 
220  FifoIdx NumFilled(BankIdx bidx = 0) {NVHLS_ASSERT_MSG(0, "FIFO size is zero"); return 0; }
221 
222  FifoIdx NumAvailable(BankIdx bidx = 0) {NVHLS_ASSERT_MSG(0, "FIFO size is zero"); return 0; }
223 
224  void reset() {}
225 };
226 
234 template <typename DataType>
235 class FIFO<DataType, 1, 1> {
236  DataType data;
237  bool valid;
238 
239  public:
240  static const int width = Wrapped<DataType>::width + 1;
241  typedef NVUINTW(1) T; //redundant
242 
243  FIFO() {reset();}
244 
245  inline void push(DataType wr_data, T bidx = 0)
246  {
247  NVHLS_ASSERT_MSG(!isFull(), "Pushing data to full FIFO");
248  data = wr_data;
249  valid = true;
250  }
251 
252  inline DataType pop(T bidx = 0)
253  {
254  incrHead();
255  return data;
256  }
257 
258  inline void incrHead(T bidx = 0)
259  {
260  NVHLS_ASSERT_MSG(!isEmpty(), "Incrementing head of empty FIFO");
261  valid = false;
262  }
263 
264  inline DataType peek(T bidx = 0)
265  {
266  NVHLS_ASSERT_MSG(!isEmpty(), "Peeking data from empty FIFO");
267  return data;
268  }
269 
270  inline bool isEmpty(T bidx = 0)
271  {
272  return !valid;
273  }
274 
275  inline bool isFull(T bidx = 0)
276  {
277  return valid;
278  }
279 
280  inline T NumFilled(T bidx = 0) {
281  return valid;
282  }
283 
284  inline T NumAvailable(T bidx = 0) {
285  return !valid;
286  }
287 
288  inline void reset()
289  {
290  valid = false;
291  }
292  template<unsigned int Size>
293  void Marshall(Marshaller<Size>& m) {
294  m & valid;
295  m & data;
296  }
297 };
306 template <typename DataType, unsigned int NumBanks>
307 class FIFO<DataType, 1, NumBanks> {
308  DataType data[NumBanks];
309  bool valid[NumBanks];
310  static const int width = NumBanks * Wrapped<DataType>::width + NumBanks;
311 
312  public:
313  static const int BankSelWidth =
314  (NumBanks == 1) ? 1 : nvhls::nbits<NumBanks - 1>::val;
315  typedef NVUINTW(BankSelWidth) BankIdx;
316  typedef NVUINTW(1) T;
317 
318  FIFO() {
319  reset();
320  }
321 
322  inline void push(DataType wr_data, BankIdx bidx = 0) {
323  NVHLS_ASSERT_MSG(!isFull(bidx), "Pushing data to full FIFO");
324  data[bidx] = wr_data;
325  valid[bidx] = true;
326  }
327 
328  inline DataType pop(BankIdx bidx = 0) {
329  incrHead(bidx);
330  return data[bidx];
331  }
332 
333  inline void incrHead(BankIdx bidx = 0) {
334  NVHLS_ASSERT_MSG(!isEmpty(bidx), "Incrementing Head of empty FIFO");
335  valid[bidx] = false;
336  }
337 
338  inline DataType peek(BankIdx bidx = 0) {
339  NVHLS_ASSERT_MSG(!isEmpty(bidx), "Peeking data from empty FIFO");
340  return data[bidx];
341  }
342 
343  inline bool isEmpty(BankIdx bidx = 0) {
344  return !valid[bidx];
345  }
346 
347  inline bool isFull(BankIdx bidx = 0) {
348  return valid[bidx];
349  }
350 
351  inline T NumFilled(T bidx = 0) {
352  return valid;
353  }
354 
355  inline T NumAvailable(T bidx = 0) {
356  return !valid;
357  }
358 
359  inline void reset() {
360  #pragma hls_unroll yes
361  for(unsigned i=0; i<NumBanks; i++) {
362  valid[i] = false;
363  }
364  }
365  template<unsigned int Size>
366  void Marshall(Marshaller<Size>& m) {
367  for (unsigned i = 0; i < NumBanks; i++) {
368  m & valid[i];
369  m & data[i];
370  }
371  }
372 };
373 
374 #endif // end #define FIFO_H macro
Compute number of bits to represent a constant.
Definition: nvhls_int.h:118
#define NVHLS_ASSERT_MSG(X, MSG)
Definition: nvhls_assert.h:116
Configurable FIFO class.
Definition: fifo.h:65