MatchLib
nvhls_serdes.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 // nvhls_serdes.h
18 //========================================================================
19 // Implements the Serializer and Deserializer classes
20 
21 #ifndef NVHLS_SERDES_H
22 #define NVHLS_SERDES_H
23 
24 #include <systemc.h>
25 
26 #include <nvhls_int.h>
27 #include <nvhls_types.h>
28 #include <nvhls_packet.h>
29 #include <nvhls_connections.h>
30 #include <hls_globals.h>
31 #include <fifo.h>
32 //------------------------------------------------------------------------
33 // serializer for store-forward router
34 //------------------------------------------------------------------------
35 // Converts a Packet into sequence of Flits
36 // Flits have flit_id, packet_id, data and dest field
37 // Packet has packet_id, data and dest field
70 template <typename packet_t, typename flit_t, RouterType Rtype = StoreForward>
71 class serializer : public sc_module {
72  public:
73  sc_in_clk clk;
74  sc_in<bool> rst;
75 
76  Connections::In<packet_t> in_packet;
77  Connections::Out<flit_t> out_flit;
78  static const int header_data_width = flit_t::data_width - packet_t::dest_width;
79  static const int num_flits = (((packet_t::data_width-header_data_width) % flit_t::data_width) == 0) ? ((packet_t::data_width-header_data_width) / flit_t::data_width) : ((packet_t::data_width-header_data_width) / flit_t::data_width+1) ;
80  enum { width = 0 };
81  void Process();
82 
83  SC_HAS_PROCESS(serializer);
84  serializer(sc_module_name name)
85  : sc_module(name),
86  clk("clk"),
87  rst("rst"),
88  in_packet("in_packet"),
89  out_flit("out_flit") {
90  SC_THREAD(Process);
91  sensitive << clk.pos();
93  };
94 };
95 
96 template <typename packet_t, typename flit_t, RouterType Rtype>
98  in_packet.Reset();
99  out_flit.Reset();
100  wait();
101 
102  while (1) {
103  packet_t packet_reg;
104  flit_t flit_reg;
105  NVUINTW(packet_t::data_width) data;
106 
107  if (in_packet.PopNB(packet_reg)) {
108  // Assuming packet_t::data_width is multiple of flit_t::data_width
109  flit_reg.dest = packet_reg.dest;
110  flit_reg.packet_id = packet_reg.packet_id;
111  data = packet_reg.data;
112  for (int i = 0; i < num_flits; i++) {
113  if (num_flits == 1) {
114  flit_reg.flit_id.set(FlitId2bit::SNGL);
115  } else if (i == 0) {
116  flit_reg.flit_id.set(FlitId2bit::HEAD);
117  } else if (i == num_flits - 1) {
118  flit_reg.flit_id.set(FlitId2bit::TAIL);
119  } else {
120  flit_reg.flit_id.set(FlitId2bit::BODY);
121  }
122  flit_reg.data =
123  nvhls::get_slc<flit_t::data_width>(data, i * flit_t::data_width);
124  out_flit.Push(flit_reg);
125  }
126  }
127  wait();
128  }
129 }
130 
131 //------------------------------------------------------------------------
132 // serializer specialization for WormHole router
133 //------------------------------------------------------------------------
134 // Converts a Packet into sequence of Flits
135 // Flits have flit_id, packet_id, and data field
136 // Packet has packet_id, data and dest field
162 template <int PacketDataWidth, int DestWidthPerHop, int MaxHops,
163  int PacketIdWidth, int FlitDataWidth, class FlitId>
165  Packet<PacketDataWidth, DestWidthPerHop, MaxHops, PacketIdWidth>,
166  Flit<FlitDataWidth, 0, 0, PacketIdWidth, FlitId, WormHole>, WormHole>
167  : public sc_module {
169  packet_t;
171 
172  public:
173  sc_in_clk clk;
174  sc_in<bool> rst;
175 
176  static const int header_data_width = flit_t::data_width - packet_t::dest_width;
177  // num_flits indicates number of data flits. route flits are not counted
178  static const int num_flits = (((packet_t::data_width-header_data_width) % flit_t::data_width) == 0) ? ((packet_t::data_width-header_data_width) / flit_t::data_width) : ((packet_t::data_width-header_data_width) / flit_t::data_width+1) ;
179  static const int log_num_flits = nvhls::index_width<num_flits+1>::val;
180  Connections::In<packet_t> in_packet;
181  Connections::Out<flit_t> out_flit;
182  enum { width = 0 };
183 
184  void Process() {
185  in_packet.Reset();
186  out_flit.Reset();
187  NVUINTW(log_num_flits) num = 0;
188  packet_t packet_reg;
189  wait();
190  while (1) {
191  flit_t flit_reg;
192  if (num == 0) {
193  packet_reg = in_packet.Pop();
194  flit_reg.packet_id = packet_reg.packet_id;
195  flit_reg.data = packet_reg.dest;
196  NVUINTW(header_data_width) header_data = nvhls::get_slc<header_data_width>(packet_reg.data, 0);
197  flit_reg.data = nvhls::set_slc(flit_reg.data, header_data, packet_t::dest_width);
198  flit_reg.flit_id.set(
199  FlitId2bit::HEAD); // Destination is sent in first flit
200  num++;
201  } else {
202  flit_reg.packet_id = packet_reg.packet_id;
203  if (num == num_flits) {
204  flit_reg.flit_id.set(FlitId2bit::TAIL);
205  int num_minus_one = num - 1;
206  flit_reg.data = nvhls::get_slc(
207  packet_reg.data, packet_t::data_width - 1, num_minus_one * flit_t::data_width + header_data_width);
208  num = 0;
209  } else {
210  flit_reg.flit_id.set(FlitId2bit::BODY);
211  int num_minus_one = num - 1;
212  flit_reg.data = nvhls::get_slc<flit_t::data_width>(
213  packet_reg.data, num_minus_one * flit_t::data_width + header_data_width);
214  num++;
215  }
216  }
217  out_flit.Push(flit_reg);
218  wait();
219  }
220  }
221 
222  SC_HAS_PROCESS(serializer);
223  serializer(sc_module_name name)
224  : sc_module(name),
225  clk("clk"),
226  rst("rst"),
227  in_packet("in_packet"),
228  out_flit("out_flit") {
229  SC_THREAD(Process);
230  sensitive << clk.pos();
232  }
233 };
234 
235 //------------------------------------------------------------------------
236 // serializer specialization for WormHole router without packet-id
237 //------------------------------------------------------------------------
238 // Converts a Packet into sequence of Flits
246 template <int PacketDataWidth, int DestWidthPerHop, int MaxHops,
247  int FlitDataWidth, class FlitId>
248 class serializer<Packet<PacketDataWidth, DestWidthPerHop, MaxHops, 0>,
249  Flit<FlitDataWidth, 0, 0, 0, FlitId, WormHole>, WormHole>
250  : public sc_module {
253 
254  public:
255  sc_in_clk clk;
256  sc_in<bool> rst;
257 
258  // num_flits indicates number of data flits. route flits are not counted
259  static const int num_flits = ((packet_t::data_width % flit_t::data_width) == 0) ? (packet_t::data_width / flit_t::data_width) : (packet_t::data_width / flit_t::data_width+1) ;
260  Connections::In<packet_t> in_packet;
261  Connections::Out<flit_t> out_flit;
262  enum { width = 0 };
263 
264  void Process() {
265  in_packet.Reset();
266  out_flit.Reset();
267  wait();
268  while (1) {
269  packet_t packet_reg;
270  flit_t flit_reg;
271 
272  if (in_packet.PopNB(packet_reg)) {
273  flit_reg.data = packet_reg.dest;
274  flit_reg.flit_id.set(
275  FlitId2bit::HEAD); // Destination is sent in first flit
276  out_flit.Push(flit_reg);
277 #pragma hls_unroll yes
278  for (int i = 0; i < num_flits; i++) {
279  // Single packet flit is not possible. We have atleast 1 route flit
280  // and 1 data flit. Flit_id cannot be 3
281  if (i == num_flits - 1) {
282  flit_reg.flit_id.set(FlitId2bit::TAIL);
283  } else {
284  flit_reg.flit_id.set(FlitId2bit::BODY);
285  }
286  flit_reg.data = nvhls::get_slc<flit_t::data_width>(
287  packet_reg.data, i * flit_t::data_width);
288  out_flit.Push(flit_reg);
289  }
290  }
291  wait();
292  }
293  }
294 
295  SC_HAS_PROCESS(serializer);
296  serializer(sc_module_name name)
297  : sc_module(name),
298  clk("clk"),
299  rst("rst"),
300  in_packet("in_packet"),
301  out_flit("out_flit") {
302  SC_THREAD(Process);
303  sensitive << clk.pos();
305  }
306 };
307 
308 //------------------------------------------------------------------------
309 // deserializer for store-forward router
310 //------------------------------------------------------------------------
311 // Converts a sequence of Flits into a packet
312 // Flits have flit_id, packet_id, data and dest field
313 // Packet has packet_id, data and dest field
347 template <typename packet_t, typename flit_t, int buffersize,
348  RouterType Rtype = StoreForward>
349 class deserializer : public sc_module {
350  public:
351  sc_in_clk clk;
352  sc_in<bool> rst;
353 
354  Connections::Out<packet_t> out_packet;
355  Connections::In<flit_t> in_flit;
356  enum { width = 0 };
357  flit_t flit_reg;
358  // Buffer to store flits from different packets
359  packet_t buffer[buffersize];
360  static const int logbufsize = (nvhls::index_width<buffersize>::val);
361  typedef NVUINTW(logbufsize) BuffIdx;
362 
363  // FIFO to store buffer idxes that are available for a new packet
365 
366  static const int num_flits = packet_t::data_width / flit_t::data_width;
367  static const int log_num_flits =
369  NVUINTW(log_num_flits)
370  num_flits_received[buffersize]; // Stores the number of flits received for
371  // every packet
372  void Process();
373 
374  SC_HAS_PROCESS(deserializer);
375  deserializer(sc_module_name name)
376  : sc_module(name),
377  clk("clk"),
378  rst("rst"),
379  out_packet("out_packet"),
380  in_flit("in_flit") {
381  SC_THREAD(Process);
382  sensitive << clk.pos();
384  };
385 };
386 
387 template <typename packet_t, typename flit_t, int buffersize, RouterType Rtype>
389  out_packet.Reset();
390  in_flit.Reset();
391 // Reset fifo
392 #pragma hls_unroll yes
393  for (int i = 0; i < buffersize; i++) {
394  if (!fifo.isFull()) {
395  fifo.push(i);
396  }
397  }
398 
399  wait();
400 
401  int packet_pos; // Indicates position in the buffer where flit is being
402  // inserted
403  while (1) {
404  if (in_flit.PopNB(flit_reg)) {
405  // First flit or Single-flit packet. Allocate new buffer and set valid to
406  // 1
407  if (flit_reg.flit_id.isHeader()) {
408  NVHLS_ASSERT_MSG(!fifo.isEmpty(), "FIFO empty");
409  packet_pos = fifo.pop();
410  buffer[packet_pos].packet_id = flit_reg.packet_id;
411  buffer[packet_pos].dest = flit_reg.dest;
412  buffer[packet_pos].data =
413  nvhls::set_slc(buffer[packet_pos].data, flit_reg.data, 0);
414  num_flits_received[packet_pos] = 1;
415  } else {
416 // Search for buffer storing the packet and insert flit in appropriate position.
417 // Assuming Flits arrive in-order
418 #pragma hls_unroll yes
419  for (int i = 0; i < buffersize; i++) {
420  BuffIdx head = fifo.get_head();
421  BuffIdx tail = fifo.get_tail();
422  // Check if buffer entry is valid
423  if((((tail < head) && ((i >= tail) && (i < head))) ||
424  ((head < tail) && ((i >= tail) || (i < head))) || fifo.isFull()) && (!fifo.isEmpty())) {
425  if (buffer[i].packet_id == flit_reg.packet_id) {
426  buffer[i].data =
427  nvhls::set_slc(buffer[i].data, flit_reg.data,
428  num_flits_received[i] * flit_t::data_width);
429  num_flits_received[i]++;
430  packet_pos = i;
431  }
432  }
433  }
434  }
435  // Last flit or Single-flit packet. Write data out. Assuming all packet
436  // and flit sizes are same in the network
437  if (flit_reg.flit_id.isTail()) {
438  out_packet.Push(buffer[packet_pos]);
439  // Release buffer and insert to fifo
440  NVHLS_ASSERT_MSG(!fifo.isFull(), "FIFO full");
441  fifo.push(packet_pos);
442  }
443  }
444  wait();
445  }
446 };
447 
448 //------------------------------------------------------------------------
449 // deserializer specialization for Wormhole Router
450 //------------------------------------------------------------------------
451 // Converts a Packet into sequence of Flits
452 // Flits have flit_id, packet_id, data and dest field
453 // Packet has packet_id, data and dest field
484 template <int PacketDataWidth, int DestWidthPerHop, int MaxHops,
485  int PacketIdWidth, int FlitDataWidth, class FlitId, int buffersize>
487  Packet<PacketDataWidth, DestWidthPerHop, MaxHops, PacketIdWidth>,
488  Flit<FlitDataWidth, 0, 0, PacketIdWidth, FlitId, WormHole>, buffersize,
489  WormHole> : public sc_module {
491  packet_t;
493 
494  public:
495  sc_in_clk clk;
496  sc_in<bool> rst;
497 
498  Connections::Out<packet_t> out_packet;
499  Connections::In<flit_t> in_flit;
500  enum { width = 0 };
501  // Buffer to store packets
502  packet_t buffer[buffersize];
503  static const int logbufsize = (nvhls::index_width<buffersize>::val);
504  typedef NVUINTW(logbufsize) BuffIdx;
505 
506  // FIFO to store buffer idxes that are available for a new packet
508 
509  static const int num_flits = packet_t::data_width / flit_t::data_width;
510  static const int log_num_flits = (nvhls::index_width<num_flits>::val);
511  NVUINTW(log_num_flits)
512  num_flits_received[buffersize]; // Stores the number of flits received for
513  // every packet
514  void Process() {
515  out_packet.Reset();
516  in_flit.Reset();
517 // Reset fifo
518 #pragma hls_unroll yes
519  for (int i = 0; i < buffersize; i++) {
520  if (!fifo.isFull()) {
521  fifo.push(i);
522  }
523  }
524 
525  wait();
526 
527  int packet_pos; // Indicates position in the buffer where flit is being
528  // inserted
529  while (1) {
530  flit_t flit_reg;
531  if (in_flit.PopNB(flit_reg)) {
532  // First flit or Single-flit packet. Allocate new buffer and set valid
533  // to 1
534  if (flit_reg.flit_id.isHeader()) {
535  NVHLS_ASSERT_MSG(!fifo.isEmpty(), "FIFO empty");
536  packet_pos = fifo.pop();
537  buffer[packet_pos].packet_id = flit_reg.packet_id;
538  buffer[packet_pos].dest = flit_reg.data;
539  num_flits_received[packet_pos] = 0;
540  } else {
541 // Search for buffer storing the packet and insert flit in appropriate position.
542 // Assuming Flits arrive in-order
543 #pragma hls_unroll yes
544  for (int i = 0; i < buffersize; i++) {
545  // Check if buffer entry is valid
546  BuffIdx head = fifo.get_head();
547  BuffIdx tail = fifo.get_tail();
548  if((((tail < head) && ((i >= tail) && (i < head))) ||
549  ((head < tail) && ((i >= tail) || (i < head))) || fifo.isFull()) && (!fifo.isEmpty())) {
550  if (buffer[i].packet_id == flit_reg.packet_id) {
551  buffer[i].data =
552  nvhls::set_slc(buffer[i].data, flit_reg.data,
553  num_flits_received[i] * flit_t::data_width);
554  num_flits_received[i]++;
555  packet_pos = i;
556  }
557  }
558  }
559  }
560  // Last flit or Single-flit packet. Write data out.
561  if (flit_reg.flit_id.isTail()) {
562  out_packet.Push(buffer[packet_pos]);
563  // Release buffer
564  NVHLS_ASSERT_MSG(!fifo.isFull(), "FIFO full");
565  fifo.push(packet_pos);
566  }
567  }
568  wait();
569  }
570  }
571 
572  SC_HAS_PROCESS(deserializer);
573  deserializer(sc_module_name name)
574  : sc_module(name),
575  clk("clk"),
576  rst("rst"),
577  out_packet("out_packet"),
578  in_flit("in_flit") {
579  SC_THREAD(Process);
580  sensitive << clk.pos();
582  }
583 };
584 
585 //------------------------------------------------------------------------
586 // deserializer (specialization for Wormhole flit without input buffer)
587 //------------------------------------------------------------------------
617 template <int PacketDataWidth, int DestWidthPerHop, int MaxHops,
618  int PacketIdWidth, int FlitDataWidth, class FlitId>
620  Packet<PacketDataWidth, DestWidthPerHop, MaxHops, PacketIdWidth>,
621  Flit<FlitDataWidth, 0, 0, PacketIdWidth, FlitId, WormHole>, 0,
622  WormHole> : public sc_module {
625 
626  public:
627  sc_in_clk clk;
628  sc_in<bool> rst;
629 
630  Connections::Out<packet_t> out_packet;
631  Connections::In<flit_t> in_flit;
632  enum { width = 0 };
633  // Buffer to store packets.
634  packet_t buffer;
635  static const int header_data_width = flit_t::data_width - packet_t::dest_width;
636  // num_flits indicates number of data flits. route flits are not counted.
637  static const int num_flits = (((packet_t::data_width-header_data_width) % flit_t::data_width) == 0) ? ((packet_t::data_width-header_data_width) / flit_t::data_width) : ((packet_t::data_width-header_data_width) / flit_t::data_width+1) ;
638  static const int log_num_flits = nvhls::index_width<num_flits>::val;
639  NVUINTW(log_num_flits) num_flits_received; // Stores the number of flits received for every packet
640  void Process();
641 
642  SC_HAS_PROCESS(deserializer);
643  deserializer(sc_module_name name)
644  : sc_module(name),
645  clk("clk"),
646  rst("rst"),
647  out_packet("out_packet"),
648  in_flit("in_flit") {
649  SC_THREAD(Process);
650  sensitive << clk.pos();
652  };
653 };
654 
655 template <int PacketDataWidth, int DestWidthPerHop, int MaxHops,
656  int PacketIdWidth, int FlitDataWidth, class FlitId>
657 void deserializer<
660  WormHole>::Process() {
661  out_packet.Reset();
662  in_flit.Reset();
663  num_flits_received = 0;
664  buffer.data = 0;
665  wait();
666 
667  while (1) {
668  flit_t flit_reg;
669  if (in_flit.PopNB(flit_reg)) {
670  // First flit
671  if (flit_reg.flit_id.isHeader()) {
672  buffer.dest = static_cast<NVUINTW(packet_t::dest_width)> (flit_reg.data);
673  buffer.data = nvhls::get_slc<header_data_width>(flit_reg.data, packet_t::dest_width);
674  num_flits_received = 0;
675  } else {
676  buffer.data |= (static_cast<NVUINTW(PacketDataWidth)>(flit_reg.data) << num_flits_received * flit_t::data_width + header_data_width);
677  num_flits_received++;
678  }
679  // Last flit or Single-flit packet. Write data out.
680  if (flit_reg.flit_id.isTail()) {
681  out_packet.Push(buffer);
682  num_flits_received = 0;
683  buffer.data = 0;
684  }
685  }
686  wait();
687  }
688 }
689 
690 #endif /*NVHLS_SERDES_H*/
Parameterized implementation of a network packet.
Definition: nvhls_packet.h:71
Deserializer for store-forward router.
Definition: nvhls_serdes.h:349
serializer for store-forward router
Definition: nvhls_serdes.h:71
#define NVHLS_ASSERT_MSG(X, MSG)
Definition: nvhls_assert.h:135
NVUINTW(Wrapped< T >::width) TypeToNVUINT(T in)
Convert Type to NVUINT.
Definition: TypeToBits.h:115
type1 set_slc(type1 X, type2 Y, const unsigned int i)
Function that replaces slice of bits.
Definition: nvhls_int.h:387
nvhls_t< W >::nvuint_t get_slc(type X, const unsigned int i)
Function that returns slice of bits.
Definition: nvhls_int.h:437
#define NVHLS_NEG_RESET_SIGNAL_IS(port)
ENABLE_SYNC_RESET define: Select synchronous or asynchronous reset.
Definition: nvhls_module.h:39
Compute index width of a constant.
Definition: nvhls_int.h:285