MatchLib
Loading...
Searching...
No Matches
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>
55template <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 #pragma map_to_operator [CCORE]
184 #pragma ccore_type combinational
185 void pseudo_cam(const bank_req_t bank_req_winner[NumBanks], const bank_rsp_t bank_rsp[NumBanks],
186 unsigned bank, unsigned &res, bool &en) {
187 res = 0;
188 en = false;
189 for (unsigned i = 0; i < NumBanks; i++)
190 {
191 if ( (bank_req_winner[i].input_chan == bank) && bank_rsp[i].valid)
192 {
193 res = i;
194 en = true;
195 }
196 }
197 }
198
199 #ifdef HLS_ALGORITHMICC
200 void load_store(req_t &curr_cli_req, rsp_t &load_rsp,
201 bool input_ready[NumInputs]) {
202 bank_req_t bank_req[NumInputs];
203 bank_sel_t bank_sel[NumInputs];
204 bool bank_req_valid[NumInputs];
205
206 compute_bank_request(curr_cli_req, bank_req, bank_sel, bank_req_valid);
207 #else
208 void load_store(bank_req_t bank_req[NumInputs],
209 bank_sel_t bank_sel[NumInputs],
210 bool bank_req_valid[NumInputs],
211 rsp_t &load_rsp, bool input_ready[NumInputs]) {
212 #endif
213 CDCOUT("\tinputs:" << endl, kDebugLevel);
214 for (unsigned i = 0; i < NumInputs; ++i) {
215 CDCOUT("\t" << i << " :"
216 << " valid=" << bank_req_valid[i]
217 << " select=" << bank_sel[i]
218 << " addr=" << bank_req[i].addr
219 << " wdata=" << bank_req[i].wdata
220 << " load=" << !bank_req[i].do_store
221 << " store=" << bank_req[i].do_store
222 << " input=" << bank_req[i].input_chan << endl, kDebugLevel);
223 }
224 CDCOUT("\t------" << endl, kDebugLevel);
225
226 bank_req_t bank_req_winner[NumBanks];
227 bool bank_req_winner_valid[NumBanks];
228 request_xbar.run(bank_req, bank_sel, bank_req_valid, bank_req_winner,
229 bank_req_winner_valid, input_ready);
230
231 CDCOUT("\t\tbank winner transactions:" << endl, kDebugLevel);
232 for (unsigned i = 0; i < NumBanks; ++i) {
233 CDCOUT("\t\t" << i << " :"
234 << " valid=" << bank_req_winner_valid[i]
235 << " addr=" << bank_req_winner[i].addr
236 << " wdata=" << bank_req_winner[i].wdata
237 << " load=" << !bank_req_winner[i].do_store
238 << " store=" << bank_req_winner[i].do_store
239 << " input=" << bank_req_winner[i].input_chan << endl, kDebugLevel);
240 }
241 CDCOUT("\t\t------" << endl, kDebugLevel);
242 CDCOUT("\t\tinput_ready:" << endl, kDebugLevel);
243 for (unsigned i = 0; i < NumInputs; ++i) {
244 CDCOUT("\t\t" << i << " : ready=" << input_ready[i] << endl, kDebugLevel);
245 }
246 CDCOUT("\t\t------" << endl, kDebugLevel);
247
248 bank_rsp_t bank_rsp[NumBanks];
249 banks_load_store(bank_req_winner, bank_req_winner_valid, bank_rsp);
250
251 // Prepare the inputs for response crossbar
252 DataType data_in[NumBanks];
253 bool valid_in[NumBanks];
254 bank_sel_t source[NumInputs];
255 bool valid_src[NumInputs];
256 DataType data_out[NumInputs];
257 bool valid_out[NumInputs];
258
259 #pragma hls_unroll yes
260 for (unsigned out = 0; out < NumInputs; out++) {
261 valid_src[out] = false;
262 }
263
264 #pragma hls_unroll yes
265 for (unsigned bank = 0; bank < NumBanks; bank++) {
266 valid_in[bank] = bank_rsp[bank].valid;
267 data_in[bank] = bank_rsp[bank].rdata;
268 }
269
270 #pragma hls_unroll yes
271 for (unsigned inp = 0; inp < NumInputs; inp++) {
272 unsigned res;
273 bool en;
274 pseudo_cam(bank_req_winner, bank_rsp, inp, res, en);
275 source[inp] = res;
276 valid_src[inp] = en;
277 }
278
279 crossbar<DataType, NumBanks, NumInputs>(data_in, valid_in, source,
280 valid_src, data_out, valid_out);
281
282 #pragma hls_unroll yes
283 for (unsigned out = 0; out < NumInputs; out++) {
284 load_rsp.valids[out] = valid_out[out];
285 load_rsp.data[out] = data_out[out];
286 }
287 }
288
289}; // end ArbitratedScratchpad class
290
291#endif // end ARBITRATED_SCRATCHPAD_H
Crossbar with conflict arbitration and input queuing.
Scratchpad Memories with arbitration and queuing.
Abstract Memory Class.
Definition mem_array.h:83
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
#define NVUINTW(width)
Definition nvhls_types.h:35
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