MatchLib
All Classes Namespaces Files Functions Modules Pages
ArbitratedScratchpadDP.h
1/*
2 * Copyright (c) 2016-2020, 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
57template<unsigned int kNumBanks, unsigned int kNumReadPorts,unsigned int
58kNumWritePorts, 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
113 mem_array_sep <WordType, kNumBanks * kEntriesPerBank, kNumBanks> banks;
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 hls_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 hls_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 hls_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
Crossbar with conflict arbitration and input queuing.
ArbitratedScratchpad with dual port support.
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)
#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 index width of a constant.
Definition nvhls_int.h:285