17 #ifndef __WHVCROUTER_H__ 18 #define __WHVCROUTER_H__ 39 #include <nvhls_packet.h> 40 #include <nvhls_vector.h> 42 #include <hls_globals.h> 44 #include <one_hot_to_bin.h> 45 #include <nvhls_assert.h> 48 template <
int NumLPorts,
int NumRports,
int NumVchannels,
int BufferSize,
52 typedef FlitType Flit_t;
55 num_lports = NumLPorts,
56 num_rports = NumRports,
57 num_ports = num_lports + num_rports,
58 num_vchannels = NumVchannels,
63 buffersize = BufferSize,
67 typedef NVUINTW(log_buffersizeplus1) Credit_t;
68 typedef NVUINTW(1) Credit_ret_t;
71 Connections::In<Flit_t> in_port[num_ports];
72 Connections::Out<Flit_t> out_port[num_ports];
78 Connections::In<Credit_ret_t> in_credit[num_ports * num_vchannels];
79 Connections::Out<Credit_ret_t> out_credit[num_ports * num_vchannels];
87 Credit_t credit_recv[num_ports * num_vchannels];
88 Credit_t credit_send[num_ports * num_vchannels];
91 Flit_t flit_out[num_ports];
97 sensitive << clk.pos();
102 void receive_credit() {
103 Credit_ret_t credit_in;
104 #pragma hls_unroll yes 105 for (
int i = 0; i < num_ports * num_vchannels; i++) {
106 if (in_credit[i].PopNB(credit_in)) {
107 credit_recv[i] = credit_recv[i] + credit_in;
112 NVHLS_ASSERT_MSG(credit_recv[i] <= buffersize,
"Total credits received cannot be larger than Buffer size");
117 #pragma hls_unroll yes 118 for (
int i = 0; i < num_ports * num_vchannels; i++) {
119 if (credit_send[i] > 0) {
120 Credit_ret_t credit_out = 1;
121 bool temp = out_credit[i].PushNB(credit_out);
135 Flit_t inflit[num_ports];
136 #pragma hls_unroll yes 137 for (
int i = 0; i < num_ports; i++) {
138 if (in_port[i].PopNB(inflit[i])) {
139 DCOUT(sc_time_stamp() <<
": " << name() <<
" Read input from port-" << i
141 if (num_vchannels > 1) {
142 NVUINTW(log_num_vchannels) vcin_tmp = inflit[i].get_packet_id();
143 NVHLS_ASSERT_MSG(!ififo.isFull(i * num_vchannels + vcin_tmp),
"Input fifo is full");
144 ififo.push(inflit[i], i * num_vchannels + vcin_tmp);
147 ififo.push(inflit[i], i);
153 void peek_ififo(Flit_t flit_in[num_ports],
154 NVUINTW(log_num_vchannels) vcin[num_ports],
155 NVUINTW(num_ports) in_valid) {
157 #pragma hls_unroll yes 158 for (
int i = 0; i < num_ports; i++) {
161 flit_in[i] = ififo.peek(i * num_vchannels + vcin[i]);
162 DCOUT(sc_time_stamp()
163 <<
": " << name() << hex <<
" Read from FIFO:" 164 << i * num_vchannels + vcin[i] <<
" Flit< " << flit_in[i].flit_id
165 <<
"," << flit_in[i].data.to_uint64() <<
">" << dec << endl);
170 void crossbar_traversal(Flit_t flit_in[num_ports],
bool is_push[num_ports],
171 NVUINTW(log_num_ports) select_id[num_ports],
172 NVUINTW(log_num_vchannels) vcin[num_ports],
173 NVUINTW(log_num_vchannels) vcout[num_ports]) {
174 #pragma hls_unroll yes 175 for (
int i = 0; i < num_ports; i++) {
177 flit_out[i] = flit_in[select_id[i]];
178 vcout[i] = vcin[select_id[i]];
184 virtual void reset() { }
185 virtual void run() { }
188 for (
int i = 0; i < num_ports; i++)
190 for (
int i = 0; i < num_ports; i++)
192 for (
int i = 0; i < num_ports * num_vchannels; i++)
193 out_credit[i].Reset();
194 for (
int i = 0; i < num_ports * num_vchannels; i++)
195 in_credit[i].Reset();
200 for (
int i = 0; i < num_ports * num_vchannels; i++) {
202 credit_recv[i] = buffersize;
205 #pragma hls_pipeline_init_interval 1 255 template <
int NumLPorts,
int NumRports,
int NumVchannels,
int BufferSize,
256 typename FlitType,
int MaxHops>
261 typedef FlitType Flit_t;
263 num_lports = BaseClass::num_lports,
264 num_rports = BaseClass::num_rports,
265 num_ports = BaseClass::num_ports,
266 num_vchannels = BaseClass::num_vchannels,
267 log_num_rports = BaseClass::log_num_rports,
268 log_num_ports = BaseClass::log_num_ports,
269 log_num_vchannels = BaseClass::log_num_vchannels,
270 dest_width_per_hop = log_num_rports + num_lports,
271 dest_width = MaxHops * dest_width_per_hop,
282 NVUINTW(num_ports) out_dest[num_ports][num_vchannels];
288 bool is_get_new_packet[num_ports * num_vchannels];
290 void inputvc_arbiter(
NVUINTW(log_num_vchannels) vcin[num_ports],
291 NVUINTW(num_ports) & in_valid) {
292 #pragma hls_unroll yes 293 for (
int i = 0; i < num_ports; i++) {
298 if (num_vchannels > 1) {
299 NVUINTW(num_vchannels) vcin_valid = 0;
300 NVUINTW(log_num_vchannels) vcin_local = 0;
301 #pragma hls_unroll yes 302 for (
int j = 0; j < num_vchannels; j++) {
303 if ((!this->ififo.isEmpty(i * num_vchannels + j))) {
304 vcin_valid[num_vchannels - j - 1] = 1;
308 if (in_valid[i] == 1) {
311 NVUINTW(log_num_vchannels)>(vcin_valid);
312 vcin[i] = num_vchannels - vcin_local - 1;
315 #pragma hls_unroll yes 316 for (
int i = 0; i < num_ports; i++) {
318 if (!this->ififo.isEmpty(i)) {
326 void compute_route(Flit_t flit_in[num_ports],
327 NVUINTW(log_num_vchannels) vcin[num_ports],
330 #pragma hls_unroll yes 331 for (
int i = 0; i < num_ports; i++) {
334 if (flit_in[i].flit_id.isHeader()) {
336 route = nvhls::get_slc<dest_width>(flit_in[i].data, 0);
338 out_dest_local = nvhls::get_slc<dest_width_per_hop>(route, 0);
339 NVUINTW(dest_width) next_dests_local = route >> dest_width_per_hop;
343 ldest = nvhls::get_slc<num_lports>(out_dest_local, 0);
345 rdest = nvhls::get_slc<log_num_rports>(out_dest_local, num_lports);
346 NVUINTW(num_rports) rdest_1hot = 0;
347 if (next_dests_local != 0) {
348 rdest_1hot[rdest] = 1;
350 out_dest[i][vcin[i]] =
351 (
static_cast<NVUINTW(num_ports)
>(rdest_1hot) << num_lports) |
358 void flit_output(
bool is_push[num_ports],
359 NVUINTW(log_num_vchannels) vcout[num_ports]) {
361 #pragma hls_unroll yes 362 for (
int i = 0; i < num_ports; i++) {
363 if (is_push[i] ==
true || out_stall[i] == 1) {
364 bool temp = this->out_port[i].PushNB(this->flit_out[i]);
365 if (this->flit_out[i].flit_id.isTail()) {
366 is_get_new_packet[i * num_vchannels + vcout[i]] =
true;
368 is_get_new_packet[i * num_vchannels + vcout[i]] =
false;
374 this->credit_recv[i * num_vchannels + vcout[i]]--;
376 DCOUT(sc_time_stamp()
377 <<
": " << this->name() <<
" OutPort " << i
378 <<
" Push success??: " << temp <<
" Decrementing Credit status " 379 << i * num_vchannels + vcout[i] <<
": " 380 << this->credit_recv[i * num_vchannels + vcout[i]]
381 <<
" [Router] Out_stall: " << out_stall[i] << endl);
386 void arbitration(Flit_t flit_in[num_ports],
NVUINTW(num_ports) in_valid,
387 NVUINTW(log_num_vchannels) vcin[num_ports],
388 NVUINTW(num_ports) valid[num_ports],
389 NVUINTW(num_ports) select[num_ports],
390 NVUINTW(log_num_ports) select_id[num_ports]) {
392 #pragma hls_unroll yes 393 for (
int i = 0; i < num_ports; i++) {
397 #pragma hls_unroll yes 398 for (
int i = 0; i < num_ports; i++) {
400 bool not_head_flit = (!flit_in[i].flit_id.isHeader());
402 #pragma hls_unroll yes 403 for (
int k = 0; k < num_ports;
405 int out_idx = k * num_vchannels + vcin[i];
412 (((this->credit_recv[out_idx] != 0) && (out_dest[i][vcin[i]][k] == 1) &&
413 (is_get_new_packet[out_idx] || not_head_flit) &&
428 #ifdef ENABLE_MULTICAST 430 NVUINTW((num_ports * num_vchannels))
432 NVUINTW(log_num_ports) remote_portid[num_ports];
433 NVUINTW(log_num_lports) local_portid[num_ports];
435 #pragma hls_unroll yes 436 for (
int i = 0; i < num_ports; i++) {
437 #pragma hls_unroll yes 438 for (
int l = 0; l < num_lports;
440 #pragma hls_unroll yes 441 for (
int r = num_lports; r < num_ports; r++) {
442 if (out_dest[i][vcin[i]][l] && out_dest[i][vcin[i]][r]) {
443 is_multicast[i * num_vchannels + vcin[i]] = 1;
444 remote_portid[i] = r;
446 if (!(valid[l][i] && valid[r][i])) {
462 #pragma hls_unroll yes 463 for (
int i = 0; i < num_ports; i++) {
467 select[i] = arbiter[i].pick(valid[i]);
469 NVUINTW(num_ports) select_temp = select[i];
470 NVUINTW(log_num_ports) select_id_temp;
471 one_hot_to_bin<num_ports, log_num_ports>(select_temp, select_id_temp);
472 select_id[i] = select_id_temp;
483 #ifdef ENABLE_MULTICAST 485 #pragma hls_unroll yes 486 for (
int i = 0; i < num_lports;
488 if (select[i] != 0 &&
489 is_multicast[(select_id[i] * num_vchannels + vcin[select_id[i]])] &&
490 valid[remote_portid[select_id[i]]][select_id[i]]) {
491 select[remote_portid[select_id[i]]] = select[i];
492 select_id[remote_portid[select_id[i]]] = select_id[i];
502 #pragma hls_unroll yes 503 for (
int i = num_lports; i < num_ports;
505 if (select[i] != 0 &&
506 is_multicast[(select_id[i] * num_vchannels + vcin[select_id[i]])] &&
507 (valid[i][select_id[local_portid[select_id[i]]]] == 0)) {
522 for (
int i = 0; i < num_ports * num_vchannels; i++) {
523 is_get_new_packet[i] =
true;
529 this->receive_credit();
532 Flit_t flit_in[num_ports];
533 NVUINTW(log_num_vchannels) vcin[num_ports];
534 NVUINTW(num_ports) in_valid = 0;
539 inputvc_arbiter(vcin, in_valid);
543 this->peek_ififo(flit_in, vcin, in_valid);
549 compute_route(flit_in, vcin, in_valid);
553 NVUINTW(num_ports) valid[num_ports], select[num_ports];
554 NVUINTW(log_num_ports) select_id[num_ports];
563 arbitration(flit_in, in_valid, vcin, valid, select, select_id);
568 NVUINTW(num_ports) is_popfifo = 0;
569 bool is_push[num_ports];
570 #pragma hls_unroll yes 571 for (
int i = 0; i < num_ports;
574 if (select[i] != 0) {
575 is_popfifo[select_id[i]] = 1;
586 #pragma hls_unroll yes 587 for (
int i = 0; i < num_ports; i++) {
588 if (is_popfifo[i] == 1) {
589 this->ififo.incrHead(i * num_vchannels + vcin[i]);
593 this->credit_send[i * num_vchannels + vcin[i]]++;
594 NVHLS_ASSERT_MSG(this->credit_send[i * num_vchannels + vcin[i]] <= BaseClass::buffersize,
"Total credits cannot be larger than buffer size");
600 NVUINTW(log_num_vchannels) vcout[num_ports];
602 this->crossbar_traversal(flit_in, is_push, select_id, vcin, vcout);
608 flit_output(is_push, vcout);
612 #endif //__WHVCROUTER_H__ type1 set_slc(type1 X, type2 Y, const unsigned int i)
Function that replaces slice of bits.
type2 leading_ones(type1 X)
LeadingOne Detector.
Wormhole Router with virtual channels.
Compute index width of a constant.
#define NVHLS_ASSERT_MSG(X, MSG)
#define NVHLS_NEG_RESET_SIGNAL_IS(port)
ENABLE_SYNC_RESET define: Select synchronous or asynchronous reset.Matchlib uses asynchronous, active-low reset by default. Defining ENABLE_SYNC_RESET will use synchronous, active-low reset instead. The macros NVHLS_NEG_RESET_SIGNAL_IS() and NVHLS_POS_RESET_SIGNAL_IS() can be used in place of SystemC's reset_signal_is() and async_reset_signal_is() so that ENABLE_SYNC_RESET can select type.