MatchLib
ArbitratedScratchpadDP.h
1 /*
2  * Copyright (c) 2016-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 
17 #ifndef __ARBITRATEDSCRATCHPADDP__
18 #define __ARBITRATEDSCRATCHPADDP__
19 
20 #include <nvhls_int.h>
21 #include <nvhls_types.h>
22 #include <nvhls_assert.h>
23 #include <nvhls_message.h>
24 #include <arbitrated_crossbar.h>
25 #include <crossbar.h>
26 #include <hls_globals.h>
27 
57 template<unsigned int kNumBanks, unsigned int kNumReadPorts,unsigned int
58 kNumWritePorts, unsigned int kEntriesPerBank, typename WordType, bool isSF=true, bool IsSPRAM=false>
60 
61  static const unsigned int kReadPortIndexSize = nvhls::index_width<kNumReadPorts>::val;
62  static const unsigned int kWritePortIndexSize = nvhls::index_width<kNumWritePorts>::val;
63  static const unsigned int kBankIndexSize = nvhls::index_width<kNumBanks>::val;
64  static const unsigned int kLocalIndexSize = nvhls::index_width<kEntriesPerBank>::val;
65  typedef NVUINTW(kReadPortIndexSize) ReadPortIndex;
66  typedef NVUINTW(kWritePortIndexSize) WritePortIndex;
67  typedef NVUINTW(kBankIndexSize) BankIndex;
68  typedef NVUINTW(kLocalIndexSize) LocalIndex;
69  static const unsigned int kAddressSize = nvhls::index_width<kNumBanks * kEntriesPerBank>::val;
70  typedef NVUINTW(kAddressSize) Address;
71  typedef NVUINTW(kNumReadPorts) ReadPortBitVector;
72  typedef NVUINTW(kNumWritePorts) WritePortBitVector;
73  typedef bool Ack;
74 
75 
76  class bankwrite_req_t : public nvhls_message {
77  public:
78  LocalIndex localindex;
79  WordType data;
80  static const int width = WordType::width + LocalIndex::width;
81  template <unsigned int Size>
82  void Marshall(Marshaller<Size>& m) {
83  m& localindex;
84  m& data;
85  }
86  };
87 
88  class bankread_req_t : public nvhls_message {
89  public:
90  LocalIndex localindex;
91  static const int width = LocalIndex::width;
92 
93  template <unsigned int Size>
94  void Marshall(Marshaller<Size>& m) {
95  m& localindex;
96  }
97  };
98 
99  class bankread_rsp_t : public nvhls_message {
100  public:
101  bool valid;
102  WordType rdata;
103  static const int width = 1 + WordType::width;
104 
105  template <unsigned int Size>
106  void Marshall(Marshaller<Size>& m) {
107  m& rdata;
108  m& valid;
109  }
110  };
111 
112  // Local state
116 
117  void compute_bankread_request(Address read_address[kNumReadPorts], bool read_req_valid[kNumReadPorts],
118  bankread_req_t bankread_req[kNumReadPorts],
119  BankIndex bankread_sel[kNumReadPorts],
120  bool bankread_req_valid[kNumReadPorts]) {
121 
122  // For each request, compute the bank request fields
123  #pragma hls_unroll yes
124  for (unsigned in_chan = 0; in_chan < kNumReadPorts; in_chan++) {
125  bankread_sel[in_chan] = GetBankIndex(read_address[in_chan]);
126  bankread_req[in_chan].localindex = GetLocalIndex(read_address[in_chan]);
127  bankread_req_valid[in_chan] = (read_req_valid[in_chan] == true);
128  }
129  }
130 
131  void compute_bankwrite_request(Address write_address[kNumWritePorts], bool write_req_valid[kNumWritePorts],
132  WordType write_data[kNumWritePorts],
133  bankwrite_req_t bankwrite_req[kNumWritePorts],
134  BankIndex bankwrite_sel[kNumWritePorts],
135  bool bankwrite_req_valid[kNumWritePorts]) {
136 
137  // For each request, compute the bank request fields
138  #pragma hls_unroll yes
139  for (unsigned in_chan = 0; in_chan < kNumWritePorts; in_chan++) {
140  bankwrite_sel[in_chan] = GetBankIndex(write_address[in_chan]);
141  bankwrite_req[in_chan].localindex = GetLocalIndex(write_address[in_chan]);
142  bankwrite_req[in_chan].data = write_data[in_chan];
143  bankwrite_req_valid[in_chan] = (write_req_valid[in_chan] == true);
144  }
145  }
146 
147 
148  void banks_load_store(bankread_req_t bankread_req[kNumBanks],
149  bool bankread_req_valid[kNumBanks],
150  bankwrite_req_t bankwrite_req[kNumBanks],
151  bool bankwrite_req_valid[kNumBanks],
152  bankread_rsp_t bankread_rsp[kNumBanks],
153  NVUINTW(kEntriesPerBank) valid_entry[kNumBanks]
154  ) {
155  #pragma hls_unroll yes
156  for (unsigned bank = 0; bank < kNumBanks; bank++) {
157  if (IsSPRAM == false) {
158  if (bankread_req_valid[bank] == true) {
159  bankread_rsp[bank].valid = true;
160  // Check for data forwarding
161  if (isSF && (bankwrite_req_valid[bank] == true) && (bankread_req[bank].localindex == bankwrite_req[bank].localindex)) {
162  bankread_rsp[bank].rdata = bankwrite_req[bank].data;
163  } else if (valid_entry[bank][bankread_req[bank].localindex]) {
164  bankread_rsp[bank].rdata = banks.read(bankread_req[bank].localindex, bank);
165  } else {
166  bankread_rsp[bank].rdata = 0;
167  }
168  } else {
169  bankread_rsp[bank].rdata = 0;
170  bankread_rsp[bank].valid = false;
171  }
172  if (bankwrite_req_valid[bank] == true) {
173  banks.write(bankwrite_req[bank].localindex, bank, bankwrite_req[bank].data);
174  }
175  } else {
176  //if (bankread_req_valid[bank] == true) {
177  // bankread_rsp[bank].valid = true;
178  // // Check for data forwarding
179  // if ((bankwrite_req_valid[bank] == true) && (bankread_req[bank].localindex == bankwrite_req[bank].localindex)) {
180  // bankread_rsp[bank].rdata = bankwrite_req[bank].data;
181  // } else {
182  // if (valid_entry[bank][bankread_req[bank].localindex]) {
183  // bankread_rsp[bank].rdata = banks.read(bankread_req[bank].localindex, bank);
184  // }
185  // }
186  //} else {
187  // bankread_rsp[bank].rdata = 0;
188  // bankread_rsp[bank].valid = false;
189  // if (bankwrite_req_valid[bank] == true) {
190  // banks.write(bankwrite_req[bank].localindex, bank, bankwrite_req[bank].data);
191  // }
192  //}
193 
194  if (bankwrite_req_valid[bank] == true) {
195  banks.write(bankwrite_req[bank].localindex, bank, bankwrite_req[bank].data);
196  NVHLS_ASSERT_MSG(bankread_req_valid[bank] == false, "Bank read and write valid cannot be true simultaneously for single-port RAM");
197  bankread_rsp[bank].rdata = 0;
198  bankread_rsp[bank].valid = false;
199  } else {
200  if (bankread_req_valid[bank] == true) {
201  bankread_rsp[bank].valid = true;
202  if (valid_entry[bank][bankread_req[bank].localindex]) {
203  bankread_rsp[bank].rdata = banks.read(bankread_req[bank].localindex, bank);
204  }
205  else {
206  // waived code from coverage review
207  #ifdef COV_ENABLE
208  "CTC SKIP";
209  #endif
210 
211  bankread_rsp[bank].rdata = 0;
212 
213  #ifdef COV_ENABLE
214  "CTC ENDSKIP";
215  #endif
216  }
217  }
218  }
219  }
220  }
221  }
222 
223  public:
224 
225  // Helper Functions
226  BankIndex GetBankIndex(Address a) {
227  if (kNumBanks == 1) {
228  return 0;
229  } else {
230  return nvhls::get_slc(a, kBankIndexSize - 1, 0);
231  }
232  }
233 
234  LocalIndex GetLocalIndex(Address a) {
235  if (kNumBanks == 1) {
236  return a;
237  } else {
238  return nvhls::get_slc(a, kAddressSize - 1, kBankIndexSize);
239  }
240  }
241 
242  void clear() {
243  // waived code from coverage review
244  #ifdef COV_ENABLE
245  "CTC SKIP";
246  #endif
247  banks.reset();
248  #ifdef COV_ENABLE
249  "CTC ENDSKIP";
250  #endif
251  }
252 
253  void run(Address read_address[kNumReadPorts], bool read_req_valid[kNumReadPorts],
254  Address write_address[kNumWritePorts], bool write_req_valid[kNumWritePorts],
255  WordType write_data[kNumWritePorts],
256  Ack read_ack[kNumReadPorts], Ack write_ack[kNumWritePorts],
257  bool read_ready[kNumReadPorts],
258  WordType port_read_out[kNumReadPorts], bool port_read_out_valid[kNumReadPorts]
259 ) {
260  NVUINTW(kEntriesPerBank) valid_entry[kNumBanks];
261  #pragma hls_unroll yes
262  for (unsigned i = 0; i < kNumBanks; i++) {
263  valid_entry[i] = ~0;
264  }
265  run(read_address, read_req_valid,
266  write_address, write_req_valid,
267  write_data,
268  read_ack, write_ack,
269  read_ready,
270  port_read_out, port_read_out_valid, valid_entry);
271 
272 }
273  void run(Address read_address[kNumReadPorts], bool read_req_valid[kNumReadPorts],
274  Address write_address[kNumWritePorts], bool write_req_valid[kNumWritePorts],
275  WordType write_data[kNumWritePorts],
276  Ack read_ack[kNumReadPorts], Ack write_ack[kNumWritePorts],
277  bool read_ready[kNumReadPorts],
278  WordType port_read_out[kNumReadPorts], bool port_read_out_valid[kNumReadPorts],
279  NVUINTW(kEntriesPerBank) valid_entry[kNumBanks]
280 ) {
281 
282  bankread_req_t bankread_req[kNumReadPorts];
283  BankIndex bankread_sel[kNumReadPorts];
284  bool bankread_req_valid[kNumReadPorts];
285  compute_bankread_request(read_address, read_req_valid, bankread_req, bankread_sel,
286  bankread_req_valid);
287 
288  bankwrite_req_t bankwrite_req[kNumWritePorts];
289  BankIndex bankwrite_sel[kNumWritePorts];
290  bool bankwrite_req_valid[kNumWritePorts];
291  compute_bankwrite_request(write_address, write_req_valid, write_data,
292  bankwrite_req, bankwrite_sel,
293  bankwrite_req_valid);
294 
295  bool read_done[kNumReadPorts];
296  bankread_req_t bankread_req_winner[kNumBanks];
297  bool bankread_req_winner_valid[kNumBanks];
298  ReadPortIndex read_source[kNumBanks];
299  read_arbxbar.run(bankread_req, bankread_sel, bankread_req_valid, bankread_req_winner,
300  bankread_req_winner_valid, read_done, read_source);
301 
302  #pragma unroll yes
303  for (unsigned int i=0; i < kNumReadPorts; i++) {
304  read_ack[i] = read_done[i] && read_req_valid[i];
305  read_ready[i] = read_done[i] || (!read_req_valid[i]);
306  }
307 
308 
309 
310  bankwrite_req_t bankwrite_req_winner[kNumBanks];
311  bool bankwrite_req_winner_valid[kNumBanks];
312  bool write_ready[kNumWritePorts];
313  WritePortIndex write_source[kNumBanks];
314  write_arbxbar.run(bankwrite_req, bankwrite_sel, bankwrite_req_valid, bankwrite_req_winner,
315  bankwrite_req_winner_valid, write_ready, write_source);
316 
317  #pragma unroll yes
318  for (unsigned int i=0; i < kNumWritePorts; i++)
319  write_ack[i] = write_ready[i] && write_req_valid[i];
320  if (IsSPRAM) {
321  #pragma unroll yes
322  for (unsigned bank = 0; bank < kNumBanks; bank++) {
323  if (bankread_req_winner_valid[bank] && bankwrite_req_winner_valid[bank]) {
324  bankread_req_winner_valid[bank] = false;
325  read_ack[read_source[bank]] = false;
326  }
327  }
328  }
329  bankread_rsp_t bankread_rsp[kNumBanks];
330  banks_load_store(bankread_req_winner,
331  bankread_req_winner_valid,
332  bankwrite_req_winner,
333  bankwrite_req_winner_valid,
334  bankread_rsp, valid_entry);
335 
336  // Prepare the inputs for response crossbar
337  WordType bank_read_out[kNumBanks];
338  bool bank_read_out_valid[kNumBanks];
339  BankIndex bank_read_data_source[kNumReadPorts];
340  #pragma hls_unroll yes
341  for (unsigned bank = 0; bank < kNumBanks; bank++) {
342  bank_read_out_valid[bank] = bankread_rsp[bank].valid;
343  bank_read_out[bank] = bankread_rsp[bank].rdata;
344  }
345  #pragma hls_unroll yes
346  for (unsigned i = 0; i < kNumReadPorts; i++) {
347  bank_read_data_source[i] = bankread_sel[i];
348  }
349  // response crossbar traversal
350  WordType port_read_out_local[kNumReadPorts];
351  bool port_read_out_valid_local[kNumReadPorts];
352  crossbar<WordType, kNumBanks, kNumReadPorts>(bank_read_out, bank_read_out_valid, bank_read_data_source, read_ack,
353  port_read_out_local, port_read_out_valid_local);
354  #pragma hls_unroll yes
355  for (unsigned i = 0; i < kNumReadPorts; i++) {
356  port_read_out_valid[i] = port_read_out_valid_local[i];
357  }
358  #pragma hls_unroll yes
359  for (unsigned i = 0; i < kNumReadPorts; i++) {
360  if (port_read_out_valid[i]) {
361  port_read_out[i] = port_read_out_local[i];
362  }
363  }
364  }
365 
366 };
367 
368 
369 #endif
Compute index width of a constant.
Definition: nvhls_int.h:285
nvhls_t< W >::nvuint_t get_slc(type X, const unsigned int i)
Function that returns slice of bits.
Definition: nvhls_int.h:437
void run(DataType data_in[NumInputs], OutputIdx dest_in[NumInputs], bool valid_in[NumInputs], DataType data_out[NumOutputs], bool valid_out[NumOutputs], bool ready[NumInputs], InputIdx source[NumOutputs])
Top-Level function for Arbitrated Crossbar.
#define NVHLS_ASSERT_MSG(X, MSG)
Definition: nvhls_assert.h:116
ArbitratedScratchpad with dual port support.
#define NVUINTW(width)
Definition: nvhls_types.h:35