MatchLib
All Classes Namespaces Files Functions Modules Pages
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
70template <typename packet_t, typename flit_t, RouterType Rtype = StoreForward>
71class 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
96template <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
162template <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;
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
246template <int PacketDataWidth, int DestWidthPerHop, int MaxHops,
247 int FlitDataWidth, class FlitId>
248class 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 }
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
347template <typename packet_t, typename flit_t, int buffersize,
348 RouterType Rtype = StoreForward>
349class 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
387template <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
484template <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//------------------------------------------------------------------------
617template <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
655template <int PacketDataWidth, int DestWidthPerHop, int MaxHops,
656 int PacketIdWidth, int FlitDataWidth, class FlitId>
657void 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*/
Configurable FIFO class.
Definition fifo.h:65
Parameterized implementation of a network packet.
Deserializer for store-forward router.
serializer for store-forward router
#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
type1 set_slc(type1 X, type2 Y, const unsigned int i)
Function that replaces slice of bits.
Definition nvhls_int.h:387
#define NVHLS_NEG_RESET_SIGNAL_IS(port)
ENABLE_SYNC_RESET define: Select synchronous or asynchronous reset.
Compute index width of a constant.
Definition nvhls_int.h:285