MatchLib
ArbitratedScratchpad.h
1 /*
2  * Copyright (c) 2016-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 ARBITRATED_SCRATCHPAD_H
17 #define ARBITRATED_SCRATCHPAD_H
18 
19 #include <nvhls_int.h>
20 #include <nvhls_types.h>
21 #include <nvhls_message.h>
22 #include <fifo.h>
23 #include <Arbiter.h>
24 #include <mem_array.h>
25 #include <arbitrated_crossbar.h>
26 #include <ArbitratedScratchpad/ArbitratedScratchpadTypes.h>
27 #include <crossbar.h>
55 template <typename DataType, unsigned int CapacityInBytes,
56  unsigned int NumInputs, unsigned int NumBanks,
57  unsigned int InputQueueLen>
59 
60  public:
61  //------------Constants Here---------------------------
62  static const int kDebugLevel = 2;
63  // Derived parameters
64  static const int addr_width = nvhls::nbits<CapacityInBytes - 1>::val;
65  static const int log2_nbanks = (NumBanks == 1) ? 1 : nvhls::nbits<NumBanks - 1>::val;
66  static const int log2_inputs = (NumInputs == 1) ? 1 : nvhls::nbits<NumInputs - 1>::val;
67 
68  static const bool is_nbanks_power_of_2 = (NumBanks & (NumBanks - 1)) == 0;
69  static const int bank_addr_width = (is_nbanks_power_of_2 && (NumBanks > 1)) ? (addr_width - log2_nbanks) : (addr_width - log2_nbanks + 1);
70 
71  //------------Local typedefs---------------------------
72  typedef NVUINTW(log2_nbanks) bank_sel_t; // index of bank
73  typedef NVUINTW(bank_addr_width) bank_addr_t; // address within bank
74  typedef NVUINTW(log2_inputs) input_sel_t; // index of input
75 
76  struct bank_req_t : public nvhls_message {
77  NVUINT1 do_store;
78  bank_addr_t addr;
79  DataType wdata;
80  input_sel_t input_chan;
81  static const int width = 1 + bank_addr_width + Wrapped<DataType>::width + log2_inputs;
82 
83  template <unsigned int Size>
84  void Marshall(Marshaller<Size>& m) {
85  m& do_store;
86  m& addr;
87  m& wdata;
88  m& input_chan;
89  }
90  };
91  struct bank_rsp_t : public nvhls_message {
92  NVUINT1 valid;
93  DataType rdata;
94  static const int width = 1 + Wrapped<DataType>::width;
95 
96  template <unsigned int Size>
97  void Marshall(Marshaller<Size>& m) {
98  m& rdata;
99  m& valid;
100  }
101  };
102 
103  typedef cli_req_t<DataType, addr_width, NumInputs> req_t; // request input type
104  typedef cli_rsp_t<DataType, NumInputs> rsp_t; // response output type
105 
106  //------------Local Variables Here---------------------
108  bank_req_t bank_reqs[NumInputs];
109  bank_rsp_t bank_rsps[NumInputs];
110 
112  request_xbar;
113 
114  void compute_bank_request(req_t &curr_cli_req, bank_req_t bank_req[NumInputs],
115  bank_sel_t bank_sel[NumInputs],
116  bool bank_req_valid[NumInputs]) {
117 
118  // For each request, compute the bank request fields
119  #pragma hls_unroll yes
120  for (unsigned in_chan = 0; in_chan < NumInputs; in_chan++) {
121 
122  // Get the target bank
123  if (NumInputs == 1) {
124  bank_sel[in_chan] = 0;
125  } else {
126  if (is_nbanks_power_of_2) {
127  bank_sel[in_chan] = nvhls::get_slc<log2_nbanks>(curr_cli_req.addr[in_chan], 0);
128  } else {
129  bank_sel[in_chan] = curr_cli_req.addr[in_chan] % NumBanks;
130  }
131  }
132  // Compile the bank request
133  bank_req[in_chan].do_store = (curr_cli_req.valids[in_chan] == true) &&
134  (curr_cli_req.type.val == CLITYPE_T::STORE);
135 
136  if (NumInputs == 1) {
137  bank_req[in_chan].addr = curr_cli_req.addr[in_chan];
138  } else {
139  if (is_nbanks_power_of_2) {
140  bank_req[in_chan].addr = nvhls::get_slc<addr_width - log2_nbanks>(curr_cli_req.addr[in_chan], log2_nbanks);
141  } else {
142  bank_req[in_chan].addr = curr_cli_req.addr[in_chan] / NumBanks;
143  }
144  }
145 
146  if (bank_req[in_chan].do_store) {
147  bank_req[in_chan].wdata = curr_cli_req.data[in_chan];
148  }
149 
150  // Cast current input to input index type
151  input_sel_t input_idx = in_chan;
152  bank_req[in_chan].input_chan = input_idx;
153 
154  // Set the request valid flag
155  bank_req_valid[in_chan] = (curr_cli_req.valids[in_chan] == true);
156  }
157  }
158 
159  void banks_load_store(bank_req_t bank_req[NumBanks],
160  bool bank_req_valid[NumBanks],
161  bank_rsp_t bank_rsp[NumBanks]) {
162  #pragma hls_unroll yes
163  for (unsigned bank = 0; bank < NumBanks; bank++) {
164  if (bank_req_valid[bank] == true) {
165  if (!bank_req[bank].do_store) {
166  bank_rsp[bank].valid = true;
167  bank_rsp[bank].rdata = banks.read(bank_req[bank].addr, bank);
168  } else {
169  banks.write(bank_req[bank].addr, bank, bank_req[bank].wdata);
170  bank_rsp[bank].valid = false;
171  }
172  } else {
173  bank_rsp[bank].valid = false;
174  }
175  }
176  }
177 
178  public:
179  ArbitratedScratchpad() { reset(); }
180 
181  void reset() { request_xbar.reset(); }
182 
183  #ifdef HLS_ALGORITHMICC
184  void load_store(req_t &curr_cli_req, rsp_t &load_rsp,
185  bool input_ready[NumInputs]) {
186  bank_req_t bank_req[NumInputs];
187  bank_sel_t bank_sel[NumInputs];
188  bool bank_req_valid[NumInputs];
189 
190  compute_bank_request(curr_cli_req, bank_req, bank_sel, bank_req_valid);
191  #else
192  void load_store(bank_req_t bank_req[NumInputs],
193  bank_sel_t bank_sel[NumInputs],
194  bool bank_req_valid[NumInputs],
195  rsp_t &load_rsp, bool input_ready[NumInputs]) {
196  #endif
197  CDCOUT("\tinputs:" << endl, kDebugLevel);
198  for (unsigned i = 0; i < NumInputs; ++i) {
199  CDCOUT("\t" << i << " :"
200  << " valid=" << bank_req_valid[i]
201  << " select=" << bank_sel[i]
202  << " addr=" << bank_req[i].addr
203  << " wdata=" << bank_req[i].wdata
204  << " load=" << !bank_req[i].do_store
205  << " store=" << bank_req[i].do_store
206  << " input=" << bank_req[i].input_chan << endl, kDebugLevel);
207  }
208  CDCOUT("\t------" << endl, kDebugLevel);
209 
210  bank_req_t bank_req_winner[NumBanks];
211  bool bank_req_winner_valid[NumBanks];
212  request_xbar.run(bank_req, bank_sel, bank_req_valid, bank_req_winner,
213  bank_req_winner_valid, input_ready);
214 
215  CDCOUT("\t\tbank winner transactions:" << endl, kDebugLevel);
216  for (unsigned i = 0; i < NumBanks; ++i) {
217  CDCOUT("\t\t" << i << " :"
218  << " valid=" << bank_req_winner_valid[i]
219  << " addr=" << bank_req_winner[i].addr
220  << " wdata=" << bank_req_winner[i].wdata
221  << " load=" << !bank_req_winner[i].do_store
222  << " store=" << bank_req_winner[i].do_store
223  << " input=" << bank_req_winner[i].input_chan << endl, kDebugLevel);
224  }
225  CDCOUT("\t\t------" << endl, kDebugLevel);
226  CDCOUT("\t\tinput_ready:" << endl, kDebugLevel);
227  for (unsigned i = 0; i < NumInputs; ++i) {
228  CDCOUT("\t\t" << i << " : ready=" << input_ready[i] << endl, kDebugLevel);
229  }
230  CDCOUT("\t\t------" << endl, kDebugLevel);
231 
232  bank_rsp_t bank_rsp[NumBanks];
233  banks_load_store(bank_req_winner, bank_req_winner_valid, bank_rsp);
234 
235  // Prepare the inputs for response crossbar
236  DataType data_in[NumBanks];
237  bool valid_in[NumBanks];
238  bank_sel_t source[NumInputs];
239  bool valid_src[NumInputs];
240  DataType data_out[NumInputs];
241  bool valid_out[NumInputs];
242 
243  #pragma hls_unroll yes
244  for (unsigned out = 0; out < NumInputs; out++) {
245  valid_src[out] = false;
246  }
247 
248  #pragma hls_unroll yes
249  for (unsigned bank = 0; bank < NumBanks; bank++) {
250  valid_in[bank] = bank_rsp[bank].valid;
251  data_in[bank] = bank_rsp[bank].rdata;
252  if (bank_rsp[bank].valid) {
253  source[bank_req_winner[bank].input_chan] = bank;
254  valid_src[bank_req_winner[bank].input_chan] = true;
255  }
256  }
257 
258  crossbar<DataType, NumBanks, NumInputs>(data_in, valid_in, source,
259  valid_src, data_out, valid_out);
260 
261  #pragma hls_unroll yes
262  for (unsigned out = 0; out < NumInputs; out++) {
263  load_rsp.valids[out] = valid_out[out];
264  load_rsp.data[out] = data_out[out];
265  }
266  }
267 
268 }; // end ArbitratedScratchpad class
269 
270 #endif // end ARBITRATED_SCRATCHPAD_H
Crossbar with conflict arbitration and input queuing.
Scratchpad Memories with arbitration and queuing.
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 CDCOUT(x, y)
Definition: hls_globals.h:73
nvhls_t< W >::nvuint_t get_slc(type X, const unsigned int i)
Function that returns slice of bits.
Definition: nvhls_int.h:437
Compute number of bits to represent a constant.
Definition: nvhls_int.h:118