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 static const int kDebugLevel = 2;
53 typedef FlitType Flit_t;
56 num_lports = NumLPorts,
57 num_rports = NumRports,
58 num_ports = num_lports + num_rports,
59 num_vchannels = NumVchannels,
64 buffersize = BufferSize,
68 typedef NVUINTW(log_buffersizeplus1) Credit_t;
69 typedef NVUINTW(1) Credit_ret_t;
72 Connections::In<Flit_t> in_port[num_ports];
73 Connections::Out<Flit_t> out_port[num_ports];
79 Connections::In<Credit_ret_t> in_credit[num_ports * num_vchannels];
80 Connections::Out<Credit_ret_t> out_credit[num_ports * num_vchannels];
88 Credit_t credit_recv[num_ports * num_vchannels];
89 Credit_t credit_send[num_ports * num_vchannels];
92 Flit_t flit_out[num_ports];
98 sensitive << clk.pos();
103 void receive_credit() {
104 Credit_ret_t credit_in;
105 #pragma hls_unroll yes
106 for (
int i = 0; i < num_ports * num_vchannels; i++) {
107 if (in_credit[i].PopNB(credit_in)) {
108 credit_recv[i] = credit_recv[i] + credit_in;
109 CDCOUT(sc_time_stamp() <<
": " << name()
110 <<
" Read credit from credit port-"
111 << i <<
" " << credit_recv[i] << endl, kDebugLevel);
113 NVHLS_ASSERT_MSG(credit_recv[i] <= buffersize,
"Total credits received cannot be larger than Buffer size");
118 #pragma hls_unroll yes
119 for (
int i = 0; i < num_ports * num_vchannels; i++) {
120 if (credit_send[i] > 0) {
121 Credit_ret_t credit_out = 1;
122 bool temp = out_credit[i].PushNB(credit_out);
126 CDCOUT(sc_time_stamp() <<
": " << name() <<
" Returning credit to port"
127 << i <<
" credit_send=" << credit_send[i]
128 <<
" Success: " << temp << endl, kDebugLevel);
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 CDCOUT(sc_time_stamp() <<
": " << name() <<
" Read input from port-" << i
140 << endl, kDebugLevel);
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]);
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, kDebugLevel);
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 static const int kDebugLevel = 2;
262 typedef FlitType Flit_t;
264 num_lports = BaseClass::num_lports,
265 num_rports = BaseClass::num_rports,
266 num_ports = BaseClass::num_ports,
267 num_vchannels = BaseClass::num_vchannels,
268 log_num_rports = BaseClass::log_num_rports,
269 log_num_ports = BaseClass::log_num_ports,
270 log_num_vchannels = BaseClass::log_num_vchannels,
271 dest_width_per_hop = log_num_rports + num_lports,
272 dest_width = MaxHops * dest_width_per_hop,
283 NVUINTW(num_ports) out_dest[num_ports][num_vchannels];
286 NVUINTW(num_ports) out_stall;
289 bool is_get_new_packet[num_ports * num_vchannels];
291 void inputvc_arbiter(NVUINTW(log_num_vchannels) vcin[num_ports],
292 NVUINTW(num_ports) & in_valid) {
293 #pragma hls_unroll yes
294 for (
int i = 0; i < num_ports; i++) {
299 if (num_vchannels > 1) {
300 NVUINTW(num_vchannels) vcin_valid = 0;
301 NVUINTW(log_num_vchannels) vcin_local = 0;
302 #pragma hls_unroll yes
303 for (
int j = 0; j < num_vchannels; j++) {
304 if ((!this->ififo.isEmpty(i * num_vchannels + j))) {
305 vcin_valid[num_vchannels - j - 1] = 1;
309 if (in_valid[i] == 1) {
312 NVUINTW(log_num_vchannels)>(vcin_valid);
313 vcin[i] = num_vchannels - vcin_local - 1;
316 #pragma hls_unroll yes
317 for (
int i = 0; i < num_ports; i++) {
319 if (!this->ififo.isEmpty(i)) {
327 void compute_route(Flit_t flit_in[num_ports],
328 NVUINTW(log_num_vchannels) vcin[num_ports],
329 NVUINTW(num_ports) in_valid) {
331 #pragma hls_unroll yes
332 for (
int i = 0; i < num_ports; i++) {
335 if (flit_in[i].flit_id.isHeader()) {
337 route = nvhls::get_slc<dest_width>(flit_in[i].data, 0);
338 NVUINTW(dest_width_per_hop)
339 out_dest_local = nvhls::get_slc<dest_width_per_hop>(route, 0);
340 NVUINTW(dest_width) next_dests_local = route >> dest_width_per_hop;
344 ldest = nvhls::get_slc<num_lports>(out_dest_local, 0);
345 NVUINTW(log_num_rports)
346 rdest = nvhls::get_slc<log_num_rports>(out_dest_local, num_lports);
347 NVUINTW(num_rports) rdest_1hot = 0;
348 if (next_dests_local != 0) {
349 rdest_1hot[rdest] = 1;
351 out_dest[i][vcin[i]] =
352 (
static_cast<NVUINTW(num_ports)
>(rdest_1hot) << num_lports) |
359 void flit_output(
bool is_push[num_ports],
360 NVUINTW(log_num_vchannels) vcout[num_ports]) {
362 #pragma hls_unroll yes
363 for (
int i = 0; i < num_ports; i++) {
364 if (is_push[i] ==
true || out_stall[i] == 1) {
365 bool temp = this->out_port[i].PushNB(this->flit_out[i]);
366 if (this->flit_out[i].flit_id.isTail()) {
367 is_get_new_packet[i * num_vchannels + vcout[i]] =
true;
369 is_get_new_packet[i * num_vchannels + vcout[i]] =
false;
375 this->credit_recv[i * num_vchannels + vcout[i]]--;
378 <<
": " << this->name() <<
" OutPort " << i
379 <<
" Push success??: " << temp <<
" Decrementing Credit status "
380 << i * num_vchannels + vcout[i] <<
": "
381 << this->credit_recv[i * num_vchannels + vcout[i]]
382 <<
" [Router] Out_stall: " << out_stall[i] << endl, kDebugLevel);
387 void arbitration(Flit_t flit_in[num_ports], NVUINTW(num_ports) in_valid,
388 NVUINTW(log_num_vchannels) vcin[num_ports],
389 NVUINTW(num_ports) valid[num_ports],
390 NVUINTW(num_ports) select[num_ports],
391 NVUINTW(log_num_ports) select_id[num_ports]) {
393 #pragma hls_unroll yes
394 for (
int i = 0; i < num_ports; i++) {
398 #pragma hls_unroll yes
399 for (
int i = 0; i < num_ports; i++) {
401 bool not_head_flit = (!flit_in[i].flit_id.isHeader());
403 #pragma hls_unroll yes
404 for (
int k = 0; k < num_ports;
406 int out_idx = k * num_vchannels + vcin[i];
413 (((this->credit_recv[out_idx] != 0) && (out_dest[i][vcin[i]][k] == 1) &&
414 (is_get_new_packet[out_idx] || not_head_flit) &&
418 CDCOUT(sc_time_stamp() <<
": " << this->name() <<
" Input Port:" << i
419 <<
"Output port: " << k <<
" VC: " << vcin[i] <<
" valid: "
420 << valid[k][i] <<
" OutStall: " << out_stall[k]
421 <<
" Credit: " << this->credit_recv[out_idx] <<
" GetnewPacket: "
422 << is_get_new_packet[out_idx] << hex <<
" Flit " <<
" <"
423 << flit_in[i].flit_id <<
"," << flit_in[i].data.to_uint64()
424 << dec <<
">" << endl, kDebugLevel);
429 #ifdef ENABLE_MULTICAST
431 NVUINTW((num_ports * num_vchannels))
433 NVUINTW(log_num_ports) remote_portid[num_ports];
434 NVUINTW(log_num_lports) local_portid[num_ports];
436 #pragma hls_unroll yes
437 for (
int i = 0; i < num_ports; i++) {
438 #pragma hls_unroll yes
439 for (
int l = 0; l < num_lports;
441 #pragma hls_unroll yes
442 for (
int r = num_lports; r < num_ports; r++) {
443 if (out_dest[i][vcin[i]][l] && out_dest[i][vcin[i]][r]) {
444 is_multicast[i * num_vchannels + vcin[i]] = 1;
445 remote_portid[i] = r;
447 if (!(valid[l][i] && valid[r][i])) {
451 CDCOUT(sc_time_stamp() <<
": " << this->name() <<
" Input Port:" << i
452 <<
" Local port: " << l <<
" Remote port: " << r
453 <<
" VC: " << vcin[i] <<
" valid: "<< valid[l][i]
454 <<
" Multicast: " << is_multicast[i*num_vchannels + vcin[i]]
455 << endl, kDebugLevel);
464 #pragma hls_unroll yes
465 for (
int i = 0; i < num_ports; i++) {
469 select[i] = arbiter[i].pick(valid[i]);
471 NVUINTW(num_ports) select_temp = select[i];
472 NVUINTW(log_num_ports) select_id_temp;
473 one_hot_to_bin<num_ports, log_num_ports>(select_temp, select_id_temp);
474 select_id[i] = select_id_temp;
475 CDCOUT(sc_time_stamp() <<
": " << this->name() << hex <<
" Output Port:"
476 << i <<
" Valid: " << valid[i].to_uint64() <<
" Select : "
477 << select[i].to_int64() << dec
478 #ifdef ENABLE_MULTICAST
479 <<
"Multicast: " << is_multicast[(select_id[i]*num_vchannels+vcin[select_id[i]])]
481 << endl, kDebugLevel);
485 #ifdef ENABLE_MULTICAST
487 #pragma hls_unroll yes
488 for (
int i = 0; i < num_lports;
490 if (select[i] != 0 &&
491 is_multicast[(select_id[i] * num_vchannels + vcin[select_id[i]])] &&
492 valid[remote_portid[select_id[i]]][select_id[i]]) {
493 select[remote_portid[select_id[i]]] = select[i];
494 select_id[remote_portid[select_id[i]]] = select_id[i];
495 CDCOUT(sc_time_stamp() <<
": " << this->name() <<
" Output Port:" << i
496 <<
"Input port: " << select_id[i] <<
" Remote port: "
497 << remote_portid[select_id[i]] <<
" VC: "
498 << vcin[select_id[i]] <<
"Remote Select: "
499 << select[remote_portid[select_id[i]]] <<
" Local Select: "
500 << select[i] << endl, kDebugLevel);
505 #pragma hls_unroll yes
506 for (
int i = num_lports; i < num_ports;
508 if (select[i] != 0 &&
509 is_multicast[(select_id[i] * num_vchannels + vcin[select_id[i]])] &&
510 (valid[i][select_id[local_portid[select_id[i]]]] == 0)) {
512 CDCOUT(
"Set Select = 0 for Output port: " << i << endl, kDebugLevel);
513 CDCOUT(sc_time_stamp() <<
": " << this->name() <<
" Output Port:" << i
514 <<
"Input port: " << select_id[i] <<
" Remote port: "
515 << remote_portid[select_id[i]] <<
" VC: "
516 << vcin[select_id[i]] <<
"Remote Select: " << select[i]
517 <<
" Local Select: " << select[local_portid[select_id[i]]]
518 << endl, kDebugLevel);
526 for (
int i = 0; i < num_ports * num_vchannels; i++) {
527 is_get_new_packet[i] =
true;
533 this->receive_credit();
536 Flit_t flit_in[num_ports];
537 NVUINTW(log_num_vchannels) vcin[num_ports];
538 NVUINTW(num_ports) in_valid = 0;
543 inputvc_arbiter(vcin, in_valid);
547 this->peek_ififo(flit_in, vcin, in_valid);
553 compute_route(flit_in, vcin, in_valid);
557 NVUINTW(num_ports) valid[num_ports], select[num_ports];
558 NVUINTW(log_num_ports) select_id[num_ports];
567 arbitration(flit_in, in_valid, vcin, valid, select, select_id);
572 NVUINTW(num_ports) is_popfifo = 0;
573 bool is_push[num_ports];
574 #pragma hls_unroll yes
575 for (
int i = 0; i < num_ports;
578 if (select[i] != 0) {
579 is_popfifo[select_id[i]] = 1;
581 CDCOUT(sc_time_stamp() <<
": " << this->name() <<
" Port:" << i <<
"Select: "
582 << select[i] <<
" select_id " << select_id[i]
583 <<
" Valid:" << valid[i] <<
"PopFifo: " <<
584 is_popfifo[select_id[i]] << endl, kDebugLevel);
589 #pragma hls_unroll yes
590 for (
int i = 0; i < num_ports; i++) {
591 if (is_popfifo[i] == 1) {
592 this->ififo.incrHead(i * num_vchannels + vcin[i]);
593 CDCOUT(sc_time_stamp() <<
": " << this->name() <<
" Popped FIFO of port-"
594 << i <<
" VC-" << vcin[i] << endl, kDebugLevel);
595 this->credit_send[i * num_vchannels + vcin[i]]++;
596 NVHLS_ASSERT_MSG(this->credit_send[i * num_vchannels + vcin[i]] <= BaseClass::buffersize,
"Total credits cannot be larger than buffer size");
602 NVUINTW(log_num_vchannels) vcout[num_ports];
604 this->crossbar_traversal(flit_in, is_push, select_id, vcin, vcout);
610 flit_output(is_push, vcout);
Wormhole Router with virtual channels.
#define NVHLS_ASSERT_MSG(X, MSG)
type1 set_slc(type1 X, type2 Y, const unsigned int i)
Function that replaces slice of bits.
type2 leading_ones(type1 X)
LeadingOne Detector.
#define NVHLS_NEG_RESET_SIGNAL_IS(port)
ENABLE_SYNC_RESET define: Select synchronous or asynchronous reset.
Compute index width of a constant.