MatchLib
All Classes Namespaces Files Functions Modules Pages
nvhls_connections_buffered_ports.h
1/*
2 * Copyright (c) 2016-2024, 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_connections_buffered_ports.h
18//========================================================================
19
20#ifndef NVHLS_CONNECTIONS_BUFFERED_PORTS_H_
21#define NVHLS_CONNECTIONS_BUFFERED_PORTS_H_
22
23#include <iomanip>
24#include <systemc.h>
25#include <nvhls_assert.h>
26#include <nvhls_marshaller.h>
27#include <nvhls_module.h>
28#include <fifo.h>
29#include <ccs_p2p.h>
30
31namespace Connections {
32
33template <typename Message, int BufferSize = 1, connections_port_t port_marshall_type = AUTO_PORT>
34class InBuffered : public InBlocking<Message, port_marshall_type> {
36
37 public:
38 InBuffered() : InBlocking<Message, port_marshall_type>(), fifo() {}
39
40 explicit InBuffered(const char* name) : InBlocking<Message, port_marshall_type>(name), fifo() {}
41
42 void Reset() {
43 InBlocking<Message,port_marshall_type>::Reset();
44 fifo.reset();
45 }
46
47 // Empty
48 bool Empty() { return fifo.isEmpty(); }
49
50 Message Pop() { return fifo.pop(); }
51
52 void IncrHead() { fifo.incrHead(); }
53
54 Message Peek() { return fifo.peek(); }
55
56 void TransferNB() {
57
58 if (!fifo.isFull()) {
59 Message dat;
60 if (this->PopNB(dat)) {
61 fifo.push(dat);
62 }
63 }
64 }
65};
66
67template <typename Message, int BufferSize = 1, connections_port_t port_marshall_type = AUTO_PORT>
68class OutBuffered : public OutBlocking<Message, port_marshall_type> {
70 typedef NVUINTW(nvhls::index_width<BufferSize+1>::val) AddressPlusOne;
71 public:
72 OutBuffered() : OutBlocking<Message, port_marshall_type>(), fifo() {}
73
74 explicit OutBuffered(const char* name) : OutBlocking<Message, port_marshall_type>(name), fifo() {}
75
76 void Reset() {
77 OutBlocking<Message,port_marshall_type>::Reset();
78 fifo.reset();
79 }
80
81 // Full
82 bool Full() { return fifo.isFull(); }
83 // Empty
84 bool Empty() { return fifo.isEmpty(); }
85
86 AddressPlusOne NumAvailable() { return fifo.NumAvailable(); }
87
88 void Push(const Message& dat) { fifo.push(dat); }
89
90 void TransferNB() {
91 if (!fifo.isEmpty()) {
92 Message dat = fifo.peek();
93 if (this->PushNB(dat)) {
94 fifo.pop();
95 }
96 }
97 }
98};
99
100
101//------------------------------------------------------------------------
102// Helper class for Bypass and Pipeline
103//------------------------------------------------------------------------
104
105template <typename Message, connections_port_t port_marshall_type = AUTO_PORT>
107
108template <typename Message>
109class StateSignal<Message, SYN_PORT> {
110 public:
111 // Interface
112 typedef Wrapped<Message> WMessage;
113 static const unsigned int width = WMessage::width;
114 typedef sc_lv<WMessage::width> MsgBits;
115 sc_signal<MsgBits> dat;
116
117 StateSignal() : dat(sc_gen_unique_name("dat")) {}
118
119 StateSignal(sc_module_name name) : dat(CONNECTIONS_CONCAT(name, "_dat")) { }
120
121 void reset_state() {
122 dat.write(0);
123 }
124};
125
126template <typename Message>
127class StateSignal<Message, MARSHALL_PORT> {
128 public:
129 // Interface
130 typedef Wrapped<Message> WMessage;
131 static const unsigned int width = WMessage::width;
132 typedef sc_lv<WMessage::width> MsgBits;
133 sc_signal<MsgBits> dat;
134
135 StateSignal() : dat(sc_gen_unique_name("dat")) {}
136
137 StateSignal(sc_module_name name) : dat(CONNECTIONS_CONCAT(name, "_dat")) { }
138
139 void reset_state() {
140 dat.write(0);
141 }
142};
143
144template <typename Message>
145class StateSignal<Message, DIRECT_PORT> {
146 public:
147 // Interface
148 sc_signal<Message> dat;
149
150 StateSignal() : dat(sc_gen_unique_name("dat")) {}
151
152 StateSignal(sc_module_name name) : dat(CONNECTIONS_CONCAT(name, "_dat")) { }
153
154 void reset_state() {
155 Message dc;
156 dat.write(dc);
157 }
158};
159
160// Because of ports not existing in TLM_PORT and the code depending on it,
161// we remap to DIRECT_PORT here.
162template <typename Message>
163class StateSignal<Message, TLM_PORT> : public StateSignal<Message, DIRECT_PORT>
164{
165 public:
167 StateSignal(sc_module_name name) : StateSignal<Message, DIRECT_PORT>(name) {}
168};
169
170//------------------------------------------------------------------------
171// Bypass
172//------------------------------------------------------------------------
173
174template <typename Message, connections_port_t port_marshall_type>
175class Bypass : public sc_module {
176 SC_HAS_PROCESS(Bypass);
177
178 public:
179 static const int kDebugLevel = 3;
180 // Interface
181 sc_in_clk clk;
182 sc_in<bool> rst;
183 In<Message, port_marshall_type> enq;
184 Out<Message, port_marshall_type> deq;
185
186 Bypass()
187 : sc_module(sc_module_name(sc_gen_unique_name("byp"))),
188 clk("clk"),
189 rst("rst") {
190 Init();
191 }
192
193 Bypass(sc_module_name name) : sc_module(name), clk("clk"), rst("rst") {
194 Init();
195 }
196
197 protected:
198 typedef bool Bit;
199
200 // Internal wires
201 sc_signal<Bit> wen;
202
203 // Internal state
204 sc_signal<Bit> full;
206
207 // Helper functions
208 void Init() {
209#ifdef CONNECTIONS_SIM_ONLY
210 enq.disable_spawn();
211 deq.disable_spawn();
212#endif
213
214 SC_METHOD(EnqRdy);
215 sensitive << full;
216
217 SC_METHOD(DeqVld);
218 sensitive << enq.vld << full;
219
220 SC_METHOD(WriteEn);
221 sensitive << enq.vld << deq.rdy << full;
222
223 SC_METHOD(BypassMux);
224 sensitive << enq.dat << state.dat << full;
225
226 SC_THREAD(Seq);
227 sensitive << clk.pos();
229 }
230
231 // Combinational logic
232
233 // Write enable
234 void WriteEn() {
235 wen.write(enq.vld.read() && !deq.rdy.read() && !full.read());
236 }
237
238 // Enqueue ready
239 void EnqRdy() { enq.rdy.write(!full.read()); }
240
241 // Dequeue valid
242 void DeqVld() {
243 deq.vld.write(full.read() || (!full.read() && enq.vld.read()));
244 }
245
246 // Bypass mux
247 void BypassMux() {
248 if (full.read()) {
249 deq.dat.write(state.dat.read());
250 } else {
251 deq.dat.write(enq.dat.read());
252 }
253 }
254
255 // Sequential logic
256 void Seq() {
257 // Reset state
258 full.write(0);
259 state.dat.write(0);
260
261 wait();
262
263 while (1) {
264 // Full update
265 if (deq.rdy.read()) {
266 full.write(false);
267 } else if (enq.vld.read() && !deq.rdy.read() && !full.read()) {
268 full.write(true);
269 }
270
271 // State Update
272 if (wen.read()) {
273 state.dat.write(enq.dat.read());
274 }
275 wait();
276 }
277 }
278
279#ifndef __SYNTHESIS__
280 public:
281 void line_trace() {
282 if (rst.read()) {
283 unsigned int width = (Message().length() / 4);
284 // Enqueue port
285 if (enq.vld.read() && enq.rdy.read()) {
286 CDCOUT(std::hex << std::setw(width) << enq.dat.read(), kDebugLevel);
287 } else {
288 CDCOUT(std::setw(width + 1) << " ", kDebugLevel);
289 }
290
291 CDCOUT(" ( " << full.read() << " ) ", kDebugLevel);
292
293 // Dequeue port
294 if (deq.vld.read() && deq.rdy.read()) {
295 CDCOUT(std::hex << std::setw(width) << deq.dat.read(), kDebugLevel);
296 } else {
297 CDCOUT(std::setw(width + 1) << " ", kDebugLevel);
298 }
299 CDCOUT(" | ", kDebugLevel);
300 }
301 }
302#endif
303};
304
305// Because of ports not existing in TLM_PORT and the code depending on it,
306// we remap to DIRECT_PORT here.
307template <typename Message>
308class Bypass<Message, TLM_PORT> : public Bypass<Message, DIRECT_PORT>
309{
310 public:
312 Bypass(sc_module_name name) : Bypass<Message, DIRECT_PORT>(name) {}
313};
314
315//------------------------------------------------------------------------
316// Pipeline
317//------------------------------------------------------------------------
318
319template <typename Message, connections_port_t port_marshall_type>
320class Pipeline : public sc_module {
321 SC_HAS_PROCESS(Pipeline);
322
323 public:
324 static const int kDebugLevel = 3;
325 // Interface
326 sc_in_clk clk;
327 sc_in<bool> rst;
328 In<Message, port_marshall_type> enq;
329 Out<Message, port_marshall_type> deq;
330
331 Pipeline()
332 : sc_module(sc_module_name(sc_gen_unique_name("byp"))),
333 clk("clk"),
334 rst("rst") {
335 Init();
336 }
337
338 Pipeline(sc_module_name name) : sc_module(name), clk("clk"), rst("rst") {
339 Init();
340 }
341
342 protected:
343 typedef bool Bit;
344
345 // Internal wires
346 sc_signal<Bit> wen;
347
348 // Internal state
349 sc_signal<Bit> full;
351
352 // Helper functions
353 void Init() {
354#ifdef CONNECTIONS_SIM_ONLY
355 enq.disable_spawn();
356 deq.disable_spawn();
357#endif
358
359 SC_METHOD(EnqRdy);
360 sensitive << full << deq.rdy;
361
362 SC_METHOD(DeqVld);
363 sensitive << full;
364
365 SC_METHOD(WriteEn);
366 sensitive << enq.vld << deq.rdy << full;
367
368 SC_METHOD(DeqMsg);
369 sensitive << state.dat;
370
371 SC_THREAD(Seq);
372 sensitive << clk.pos();
374 }
375
376 // Combinational logic
377
378 // Internal state write enable: incoming dat is valid and (internal state is
379 // not set or outgoing channel is ready.
380 void WriteEn() {
381 wen.write(enq.vld.read() && (!full.read() || (full && deq.rdy.read())));
382 }
383
384 // Enqueue ready if either internal state is not set or outgoing channel is
385 // ready.
386 void EnqRdy() { enq.rdy.write(!full.read() || (full && deq.rdy.read())); }
387
388 // Dequeue valid if the internal state is set.
389 void DeqVld() { deq.vld.write(full.read()); }
390
391 // Dequeue Msg is from the internal state.
392 void DeqMsg() { deq.dat.write(state.dat.read()); }
393
394 // Sequential logic
395 void Seq() {
396 // Reset state
397 full.write(0);
398 state.reset_state();
399
400 wait();
401
402 while (1) {
403 // Full update
404 if (full.read() && deq.rdy.read() && !enq.vld.read()) {
405 full.write(false);
406 } else if (enq.vld.read() &&
407 (!full.read() || (full.read() && deq.rdy.read()))) {
408 full.write(true);
409 }
410
411 // State Update
412 if (wen.read()) {
413 state.dat.write(enq.dat.read());
414 }
415 wait();
416 }
417 }
418
419#ifndef __SYNTHESIS__
420 public:
421 void line_trace() {
422 if (rst.read()) {
423 unsigned int width = (Message().length() / 4);
424 // Enqueue port
425 if (enq.vld.read() && enq.rdy.read()) {
426 CDCOUT(std::hex << std::setw(width) << enq.dat.read(), kDebugLevel);
427 } else {
428 CDCOUT(std::setw(width + 1) << " ", kDebugLevel);
429 }
430
431 CDCOUT(" ( " << full.read() << " ) ", kDebugLevel);
432
433 // Dequeue port
434 if (deq.vld.read() && deq.rdy.read()) {
435 CDCOUT(std::hex << std::setw(width) << deq.dat.read(), kDebugLevel);
436 } else {
437 CDCOUT(std::setw(width + 1) << " ", kDebugLevel);
438 }
439 CDCOUT(" | ", kDebugLevel);
440 }
441 }
442#endif
443};
444
445// Because of ports not existing in TLM_PORT and the code depending on it,
446// we remap to DIRECT_PORT here.
447template <typename Message>
448class Pipeline<Message, TLM_PORT> : public Pipeline<Message, DIRECT_PORT>
449{
450 public:
452 Pipeline(sc_module_name name) : Pipeline<Message, DIRECT_PORT>(name) {}
453};
454
455
456//
457// NEW FEATURE: Buffered Bypass Channel.
458// This is a BypassBuffered channel that can have depth > 1.
459// W.r.t the Bypass it takes one more template parameter.
460// TODO: It may also work with depth = 1, but it hasn't been tested.
461
462//------------------------------------------------------------------------
463// BypassBuffered
464//------------------------------------------------------------------------
465
466template <typename Message, unsigned int NumEntries, connections_port_t port_marshall_type = AUTO_PORT>
467class BypassBuffered : public sc_module {
468 SC_HAS_PROCESS(BypassBuffered);
469
470 public:
471 static const int kDebugLevel = 3;
472 // Interface
473 sc_in_clk clk;
474 sc_in<bool> rst;
475 In<Message, port_marshall_type> enq;
476 Out<Message, port_marshall_type> deq;
477
479 : sc_module(sc_module_name(sc_gen_unique_name("byp"))),
480 clk("clk"),
481 rst("rst") {
482 Init();
483 }
484
485 BypassBuffered(sc_module_name name) : sc_module(name), clk("clk"), rst("rst") {
486 Init();
487 }
488
489 protected:
490 typedef bool Bit;
491 static const int AddrWidth = nvhls::nbits<NumEntries - 1>::val;
492 typedef NVUINTW(AddrWidth) BuffIdx;
493
494 // Internal wires
495 sc_signal<Bit> full_next;
496 sc_signal<BuffIdx> head_next;
497 sc_signal<BuffIdx> tail_next;
498
499 // Internal state
500 sc_signal<Bit> full;
501 sc_signal<BuffIdx> head;
502 sc_signal<BuffIdx> tail;
504
505 // Helper functions
506 void Init() {
507#ifdef CONNECTIONS_SIM_ONLY
508 enq.disable_spawn();
509 deq.disable_spawn();
510#endif
511
512 SC_METHOD(EnqRdy);
513 sensitive << full;
514
515 SC_METHOD(DeqVld);
516 sensitive << full << head << tail << enq.vld;
517
518 SC_METHOD(DeqMsg);
519#ifndef __SYNTHESIS__
520 sensitive << deq.rdy << full << head << tail << enq.vld << enq.dat;
521#else
522 sensitive << full << head << tail << enq.dat;
523#endif
524
525 SC_METHOD(HeadNext);
526 sensitive << enq.vld << full << head << tail << deq.rdy;
527
528 SC_METHOD(TailNext);
529 sensitive << deq.rdy << full << head << tail;
530
531 SC_METHOD(FullNext);
532 sensitive << enq.vld << deq.rdy << full << head << tail;
533
534 SC_THREAD(Seq);
535 sensitive << clk.pos();
537
538 // Needed so that DeqMsg always has a good tail value
539 tail.write(0);
540 }
541
542 // Combinational logic
543
544 // Enqueue ready
545 void EnqRdy() { enq.rdy.write(!full.read()); }
546
547 // Dequeue valid
548 void DeqVld() {
549 bool empty = (!full.read() && (head.read() == tail.read()));
550 deq.vld.write(!empty || enq.vld.read());
551 }
552
553 // Dequeue messsage
554 void DeqMsg() {
555 bool empty = (!full.read() && (head.read() == tail.read()));
556#ifndef __SYNTHESIS__
557 bool do_deq = !empty || enq.vld.read();
558 if (do_deq) {
559#endif
560 if (!empty) {
561 deq.dat.write(buffer[tail.read()].dat.read());
562 } else {
563 deq.dat.write(enq.dat.read());
564 }
565#ifndef __SYNTHESIS__
566 } else {
567 deq.dat.write(0);
568 }
569#endif
570 }
571
572 // Head next calculations
573 void HeadNext() {
574 bool empty = (!full.read() && (head.read() == tail.read()));
575 bool do_enq = (enq.vld.read() && !full.read() &&
576 !(empty && deq.rdy.read()));
577 BuffIdx head_inc;
578 if ((head.read() + 1) == NumEntries)
579 head_inc = 0;
580 else
581 head_inc = head.read() + 1;
582
583 if (do_enq)
584 head_next.write(head_inc);
585 else
586 head_next.write(head.read());
587 }
588
589 // Tail next calculations
590 void TailNext() {
591 bool empty = (!full.read() && (head.read() == tail.read()));
592 bool do_deq = (deq.rdy.read() && !empty);
593 BuffIdx tail_inc;
594 if ((tail.read() + 1) == NumEntries)
595 tail_inc = 0;
596 else
597 tail_inc = tail.read() + 1;
598
599 if (do_deq)
600 tail_next.write(tail_inc);
601 else
602 tail_next.write(tail.read());
603 }
604
605 // Full next calculations
606 void FullNext() {
607 bool empty = (!full.read() && (head.read() == tail.read()));
608 bool do_enq = (enq.vld.read() && !full.read() &&
609 !(empty && deq.rdy.read()));
610 bool do_deq = (deq.rdy.read() && !empty);
611
612 BuffIdx head_inc;
613 if ((head.read() + 1) == NumEntries)
614 head_inc = 0;
615 else
616 head_inc = head.read() + 1;
617
618 if (do_enq && !do_deq && (head_inc == tail.read()))
619 full_next.write(1);
620 else if (do_deq && full.read())
621 full_next.write(0);
622 else
623 full_next.write(full.read());
624 }
625
626 // Sequential logic
627 void Seq() {
628 // Reset state
629 full.write(0);
630 head.write(0);
631 tail.write(0);
632#pragma hls_unroll yes
633 for (unsigned int i = 0; i < NumEntries; ++i)
634 buffer[i].dat.reset_state();
635
636 wait();
637
638 while (1) {
639
640 // Head update
641 head.write(head_next);
642
643 // Tail update
644 tail.write(tail_next);
645
646 // Full update
647 full.write(full_next);
648
649 // Enqueue message
650 bool empty = (!full.read() && (head.read() == tail.read()));
651
652 if (enq.vld.read() && !full.read() &&
653 !(empty && deq.rdy.read())) {
654 buffer[head.read()].dat.write(enq.dat.read());
655 }
656
657 wait();
658 }
659 }
660
661#ifndef __SYNTHESIS__
662 public:
663 void line_trace() {
664 if (rst.read()) {
665 unsigned int width = (Message().length() / 4);
666 // Enqueue port
667 if (enq.vld.read() && enq.rdy.read()) {
668 CDCOUT(std::hex << std::setw(width) << enq.dat.read(), kDebugLevel);
669 } else {
670 CDCOUT(std::setw(width + 1) << " ", kDebugLevel);
671 }
672
673 CDCOUT(" ( " << full.read() << " ) ", kDebugLevel);
674
675 // Dequeue port
676 if (deq.vld.read() && deq.rdy.read()) {
677 CDCOUT(std::hex << std::setw(width) << deq.dat.read(), kDebugLevel);
678 } else {
679 CDCOUT(std::setw(width + 1) << " ", kDebugLevel);
680 }
681 CDCOUT(" | ", kDebugLevel);
682 }
683 }
684#endif
685};
686
687// Because of ports not existing in TLM_PORT and the code depending on it,
688// we remap to DIRECT_PORT here.
689template <typename Message, unsigned int NumEntries>
690class BypassBuffered<Message, NumEntries, TLM_PORT> : public BypassBuffered<Message, NumEntries, DIRECT_PORT>
691{
692 public:
695};
696
697
698//------------------------------------------------------------------------
699// Buffer
700//------------------------------------------------------------------------
701
702template <typename Message, unsigned int NumEntries, connections_port_t port_marshall_type>
703class Buffer : public sc_module {
704 SC_HAS_PROCESS(Buffer);
705
706 public:
707 static const int kDebugLevel = 3;
708 // Interface
709 sc_in_clk clk;
710 sc_in<bool> rst;
711 In<Message, port_marshall_type> enq;
712 Out<Message, port_marshall_type> deq;
713
714 Buffer()
715 : sc_module(sc_module_name(sc_gen_unique_name("buffer"))),
716 clk("clk"),
717 rst("rst") {
718 Init();
719 }
720
721 Buffer(sc_module_name name) : sc_module(name), clk("clk"), rst("rst") {
722 Init();
723 }
724
725 protected:
726 typedef bool Bit;
727 static const int AddrWidth = nvhls::index_width<NumEntries>::val;
728 typedef NVUINTW(AddrWidth) BuffIdx;
729
730 // Internal wires
731 sc_signal<Bit> full_next;
732 sc_signal<BuffIdx> head_next;
733 sc_signal<BuffIdx> tail_next;
734
735 // Internal state
736 sc_signal<Bit> full;
737 sc_signal<BuffIdx> head;
738 sc_signal<BuffIdx> tail;
740
741 // Helper functions
742 void Init() {
743#ifdef CONNECTIONS_SIM_ONLY
744 enq.disable_spawn();
745 deq.disable_spawn();
746#endif
747
748 SC_METHOD(EnqRdy);
749 sensitive << full;
750
751 SC_METHOD(DeqVld);
752 sensitive << full << head << tail;
753
754 SC_METHOD(DeqMsg);
755#ifndef __SYNTHESIS__
756 sensitive << deq.rdy << full << head << tail;
757#else
758 sensitive << tail;
759#endif
760
761 SC_METHOD(HeadNext);
762 sensitive << enq.vld << full << head;
763
764 SC_METHOD(TailNext);
765 sensitive << deq.rdy << full << head << tail;
766
767 SC_METHOD(FullNext);
768 sensitive << enq.vld << deq.rdy << full << head << tail;
769
770 SC_THREAD(Seq);
771 sensitive << clk.pos();
773
774 // Needed so that DeqMsg always has a good tail value
775 tail.write(0);
776 }
777
778 // Combinational logic
779
780 // Enqueue ready
781 void EnqRdy() { enq.rdy.write(!full.read()); }
782
783 // Dequeue valid
784 void DeqVld() {
785 bool empty = (!full.read() && (head.read() == tail.read()));
786 deq.vld.write(!empty);
787 }
788
789 // Dequeue messsage
790 void DeqMsg() {
791#ifndef __SYNTHESIS__
792 bool empty = (!full.read() && (head.read() == tail.read()));
793 bool do_deq = !empty;
794 if (do_deq) {
795#endif
796 deq.dat.write(buffer[tail.read()].dat.read());
797#ifndef __SYNTHESIS__
798 } else {
799 deq.dat.write(0);
800 }
801#endif
802 }
803
804 // Head next calculations
805 void HeadNext() {
806 bool do_enq = (enq.vld.read() && !full.read());
807 BuffIdx head_inc;
808 if ((head.read() + 1) == NumEntries)
809 head_inc = 0;
810 else
811 head_inc = head.read() + 1;
812
813 if (do_enq)
814 head_next.write(head_inc);
815 else
816 head_next.write(head.read());
817 }
818
819 // Tail next calculations
820 void TailNext() {
821 bool empty = (!full.read() && (head.read() == tail.read()));
822 bool do_deq = (deq.rdy.read() && !empty);
823 BuffIdx tail_inc;
824 if ((tail.read() + 1) == NumEntries)
825 tail_inc = 0;
826 else
827 tail_inc = tail.read() + 1;
828
829 if (do_deq)
830 tail_next.write(tail_inc);
831 else
832 tail_next.write(tail.read());
833 }
834
835 // Full next calculations
836 void FullNext() {
837 bool empty = (!full.read() && (head.read() == tail.read()));
838 bool do_enq = (enq.vld.read() && !full.read());
839 bool do_deq = (deq.rdy.read() && !empty);
840
841 BuffIdx head_inc;
842 if ((head.read() + 1) == NumEntries)
843 head_inc = 0;
844 else
845 head_inc = head.read() + 1;
846
847 if (do_enq && !do_deq && (head_inc == tail.read()))
848 full_next.write(1);
849 else if (do_deq && full.read())
850 full_next.write(0);
851 else
852 full_next.write(full.read());
853 }
854
855 // Sequential logic
856 void Seq() {
857 // Reset state
858 full.write(0);
859 head.write(0);
860 tail.write(0);
861#pragma hls_unroll yes
862 for (unsigned int i = 0; i < NumEntries; ++i)
863 buffer[i].reset_state();
864
865 wait();
866
867 while (1) {
868 // Head update
869 head.write(head_next);
870
871 // Tail update
872 tail.write(tail_next);
873
874 // Full update
875 full.write(full_next);
876
877 // Enqueue message
878 if (enq.vld.read() && !full.read()) {
879 buffer[head.read()].dat.write(enq.dat.read());
880 }
881
882 wait();
883 }
884 }
885
886#ifndef __SYNTHESIS__
887 public:
888 void line_trace() {
889 if (rst.read()) {
890 unsigned int width = (Message().length() / 4);
891 // Enqueue port
892 if (enq.vld.read() && enq.rdy.read()) {
893 CDCOUT(std::hex << std::setw(width) << enq.dat.read(), kDebugLevel);
894 } else {
895 CDCOUT(std::setw(width + 1) << " ", kDebugLevel);
896 }
897
898 CDCOUT(" ( " << full.read() << " ) ", kDebugLevel);
899
900 // Dequeue port
901 if (deq.vld.read() && deq.rdy.read()) {
902 CDCOUT(std::hex << std::setw(width) << deq.dat.read(), kDebugLevel);
903 } else {
904 CDCOUT(std::setw(width + 1) << " ", kDebugLevel);
905 }
906 CDCOUT(" | ", kDebugLevel);
907 }
908 }
909#endif
910};
911
912// Because of ports not existing in TLM_PORT and the code depending on it,
913// we remap to DIRECT_PORT here.
914template <typename Message, unsigned int NumEntries>
915class Buffer<Message, NumEntries, TLM_PORT> : public Buffer<Message, NumEntries, DIRECT_PORT>
916{
917 public:
919 Buffer(sc_module_name name) : Buffer<Message, NumEntries, DIRECT_PORT>(name) {}
920};
921
923// Sink and Source
925
926template <typename MessageType, connections_port_t port_marshall_type = AUTO_PORT>
927class Sink : public sc_module {
928 SC_HAS_PROCESS(Sink);
929 public:
930 // External interface
931 sc_in_clk clk;
932 sc_in<bool> rst;
933 In<MessageType, port_marshall_type> in;
934
935 // Constructor
936 Sink(sc_module_name nm)
937 : sc_module(nm),
938 clk("clk"),
939 rst("rst"),
940 in("in") {
941 SC_THREAD(DoSink);
942 sensitive << clk.pos();
944 }
945 static const unsigned int width = 0;
946 template <unsigned int Size>
947 void Marshall(Marshaller<Size>& m) {
948 }
949
950 protected:
951 // Behavior
952 void DoSink() {
953 in.Reset();
954 wait();
955 while (1) {
956 in.Pop();
957 }
958 }
959
960 // Binding
961 template <typename C>
962 void operator()(C& rhs) {
963 in.Bind(rhs);
964 }
965};
966
967template <typename MessageType, connections_port_t port_marshall_type = AUTO_PORT>
968class DummySink : public sc_module {
969 SC_HAS_PROCESS(DummySink);
970 public:
971 // External interface
972 sc_in_clk clk;
973 sc_in<bool> rst;
974 In<MessageType, port_marshall_type> in;
975
976 // Constructor
977 DummySink(sc_module_name nm)
978 : sc_module(nm),
979 clk("clk"),
980 rst("rst"),
981 in("in") {
982 SC_THREAD(DoSink);
983 sensitive << clk.pos();
985 }
986 static const unsigned int width = 0;
987 template <unsigned int Size>
988 void Marshall(Marshaller<Size>& m) {
989 }
990
991 protected:
992 // Behavior
993 void DoSink() {
994 in.Reset();
995 wait();
996 while (1) {
997 wait();
998 }
999 }
1000
1001 // Binding
1002 template <typename C>
1003 void operator()(C& rhs) {
1004 in.Bind(rhs);
1005 }
1006};
1007
1008template <typename MessageType, connections_port_t port_marshall_type = AUTO_PORT>
1009class DummySource : public sc_module {
1010 SC_HAS_PROCESS(DummySource);
1011 public:
1012 // External interface
1013 sc_in_clk clk;
1014 sc_in<bool> rst;
1015 Out<MessageType, port_marshall_type> out;
1016
1017 // Constructor
1018 DummySource(sc_module_name nm)
1019 : sc_module(nm),
1020 clk("clk"),
1021 rst("rst"),
1022 out("out") {
1023 SC_THREAD(DoSource);
1024 sensitive << clk.pos();
1026 }
1027 static const unsigned int width = 0;
1028 template <unsigned int Size>
1029 void Marshall(Marshaller<Size>& m) {
1030 }
1031
1032 protected:
1033 // Behavior
1034 void DoSource() {
1035 out.Reset();
1036 wait();
1037 while (1) {
1038 wait();
1039 }
1040 }
1041
1042 // Binding
1043 template <typename C>
1044 void operator()(C& rhs) {
1045 out.Bind(rhs);
1046 }
1047};
1048
1049//
1050// NEW FEATURE: ChannelBinder class
1051// This class binds together a channel to two ports.
1052// It works with any type of port and channel.
1053// TODO: add constructors that take clk and rst from the sender
1054// module. They take as argument the sender module instead of its output
1055// port.
1056//
1057
1058template <typename Message, unsigned int NumEntries = 1>
1060
1061 public:
1062
1063 Combinational<Message> enq;
1064 Combinational<Message> deq;
1065
1066 // Combinational binding
1067 ChannelBinder(InBlocking<Message>& in,
1068 OutBlocking<Message>& out,
1069 Combinational<Message>& chan)
1070 : enq(sc_gen_unique_name("bind_enq")),
1071 deq(sc_gen_unique_name("bind_deq")) {
1072
1073 out(chan);
1074 in(chan);
1075 }
1076
1077 // Combinational binding w/ extra clk and rst arguments
1078 ChannelBinder(InBlocking<Message>& in,
1079 OutBlocking<Message>& out,
1080 Combinational<Message>& chan,
1081 sc_in_clk& clk, sc_in<bool>& rst)
1082 : enq(sc_gen_unique_name("bind_enq")),
1083 deq(sc_gen_unique_name("bind_deq")) {
1084
1085 out(chan);
1086 in(chan);
1087 }
1088
1089 // Bypass (depth 1) binding w/ clk and rst arguments.
1090 ChannelBinder(InBlocking<Message>& in,
1091 OutBlocking<Message>& out,
1092 Bypass<Message>& chan,
1093 sc_in_clk& clk, sc_in<bool>& rst)
1094 : enq(sc_gen_unique_name("bind_enq")),
1095 deq(sc_gen_unique_name("bind_deq")) {
1096
1097 out(enq);
1098 chan.clk(clk);
1099 chan.rst(rst);
1100 chan.enq(enq);
1101 chan.deq(deq);
1102 in(deq);
1103 }
1104
1105 // BypassBuffered (any depth) binding w/ clk and rst arguments.
1106 ChannelBinder(InBlocking<Message>& in,
1107 OutBlocking<Message>& out,
1109 sc_in_clk& clk, sc_in<bool>& rst)
1110 : enq(sc_gen_unique_name("bind_enq")),
1111 deq(sc_gen_unique_name("bind_deq")) {
1112
1113 out(enq);
1114 chan.clk(clk);
1115 chan.rst(rst);
1116 chan.enq(enq);
1117 chan.deq(deq);
1118 in(deq);
1119
1120 }
1121
1122 // Pipeline binding w/ clk and rst arguments.
1123 ChannelBinder(InBlocking<Message>& in,
1124 OutBlocking<Message>& out,
1125 Pipeline<Message>& chan,
1126 sc_in_clk& clk, sc_in<bool>& rst)
1127 : enq(sc_gen_unique_name("bind_enq")),
1128 deq(sc_gen_unique_name("bind_deq")) {
1129
1130 out(enq);
1131 chan.clk(clk);
1132 chan.rst(rst);
1133 chan.enq(enq);
1134 chan.deq(deq);
1135 in(deq);
1136 }
1137
1138 // Buffer binding w/ clk and rst arguments.
1139 ChannelBinder(InBlocking<Message>& in,
1140 OutBlocking<Message>& out,
1142 sc_in_clk& clk, sc_in<bool>& rst)
1143 : enq(sc_gen_unique_name("bind_enq")),
1144 deq(sc_gen_unique_name("bind_deq")) {
1145
1146 out(enq);
1147 chan.clk(clk);
1148 chan.rst(rst);
1149 chan.enq(enq);
1150 chan.deq(deq);
1151 in(deq);
1152
1153 }
1154};
1155
1156
1157} // namespace Connections
1158
1159
1160#endif // NVHLS_CONNECTIONS_BUFFERED_PORTS_H_
1161
Configurable FIFO class.
Definition fifo.h:65
#define CDCOUT(x, y)
Definition hls_globals.h:73
#define NVUINTW(width)
Definition nvhls_types.h:35
#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
Compute number of bits to represent a constant.
Definition nvhls_int.h:118