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