1 /*
2     Copyright (c) 2005-2021 Intel Corporation
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 #include <cstdio>
18 #include <cassert>
19 
20 #include "oneapi/tbb/global_control.h"
21 
22 #include "common/utility/utility.hpp"
23 #include "common/utility/get_default_num_threads.hpp"
24 
25 #if _MSC_VER
26 #pragma warning( \
27     disable : 4503) // Suppress "decorated name length exceeded, name was truncated" warning
28 #endif
29 
30 #define USE_TWO_BIT_FULL_ADDER 1
31 
32 #include "basics.hpp"
33 #include "one_bit_adder.hpp"
34 #if USE_TWO_BIT_FULL_ADDER
35 #include "two_bit_adder.hpp"
36 #else
37 #include "four_bit_adder.hpp"
38 #endif
39 #include "D_latch.hpp"
40 
41 // User-specified globals with default values
42 bool verbose = false; // prints bin details and other diagnostics to screen
43 bool silent = false; // suppress all output except for time
44 
45 int main(int argc, char *argv[]) {
46     utility::thread_number_range threads(utility::get_default_num_threads);
47     utility::parse_cli_arguments(
48         argc,
49         argv,
50         utility::cli_argument_pack()
51             //"-h" option for displaying help is present implicitly
52             .positional_arg(threads, "#threads", utility::thread_number_range_desc)
53             .arg(verbose, "verbose", "   print diagnostic output to screen")
54             .arg(silent, "silent", "    limits output to timing info; overrides verbose"));
55 
56     if (silent)
57         verbose = false; // make silent override verbose
58 
59     oneapi::tbb::tick_count start = oneapi::tbb::tick_count::now();
60     for (int p = threads.first; p <= threads.last; p = threads.step(p)) {
61         oneapi::tbb::global_control c(oneapi::tbb::global_control::max_allowed_parallelism, p);
62         if (!silent)
63             std::cout << "graph test running on " << p << " threads."
64                       << "\n";
65 
66         oneapi::tbb::flow::graph g;
67 
68         { // test buffer: 0, 1
69             buffer b(g);
70             toggle input(g);
71             led output(
72                 g, "OUTPUT", false); // false means we will explicitly call display to see LED
73 
74             make_edge(input.get_out(), input_port<0>(b));
75             make_edge(output_port<0>(b), output.get_in());
76 
77             if (!silent)
78                 printf("Testing buffer...\n");
79             input.activate(); // 0
80             g.wait_for_all();
81             if (!silent)
82                 output.display();
83             assert(output.get_value() == low);
84             input.flip(); // 1
85             g.wait_for_all();
86             if (!silent)
87                 output.display();
88             assert(output.get_value() == high);
89         }
90 
91         { // test not_gate: 0, 1
92             not_gate n(g);
93             toggle input(g);
94             led output(g, "OUTPUT", false);
95 
96             make_edge(input.get_out(), input_port<0>(n));
97             make_edge(output_port<0>(n), output.get_in());
98 
99             if (!silent)
100                 printf("Testing not_gate...\n");
101             input.activate(); // 0
102             g.wait_for_all();
103             if (!silent)
104                 output.display();
105             assert(output.get_value() == high);
106             input.flip(); // 1
107             g.wait_for_all();
108             if (!silent)
109                 output.display();
110             assert(output.get_value() == low);
111         }
112 
113         { // test two-input and_gate: 00, 01, 10, 11
114             and_gate<2> a(g);
115             toggle input0(g);
116             toggle input1(g);
117             led output(g, "OUTPUT", false);
118 
119             make_edge(input0.get_out(), input_port<0>(a));
120             make_edge(input1.get_out(), input_port<1>(a));
121             make_edge(output_port<0>(a), output.get_in());
122 
123             if (!silent)
124                 printf("Testing and_gate...\n");
125             input1.activate();
126             input0.activate(); // 0 0
127             g.wait_for_all();
128             if (!silent)
129                 output.display();
130             assert(output.get_value() == low);
131             input0.flip(); // 0 1
132             g.wait_for_all();
133             if (!silent)
134                 output.display();
135             assert(output.get_value() == low);
136             input1.flip();
137             input0.flip(); // 1 0
138             g.wait_for_all();
139             if (!silent)
140                 output.display();
141             assert(output.get_value() == low);
142             input0.flip(); // 1 1
143             g.wait_for_all();
144             if (!silent)
145                 output.display();
146             assert(output.get_value() == high);
147         }
148 
149         { // test three-input or_gate: 000, 001, 010, 100, 011, 101, 110, 111
150             or_gate<3> o(g);
151             toggle input0(g);
152             toggle input1(g);
153             toggle input2(g);
154             led output(g, "OUTPUT", false);
155 
156             make_edge(input0.get_out(), input_port<0>(o));
157             make_edge(input1.get_out(), input_port<1>(o));
158             make_edge(input2.get_out(), input_port<2>(o));
159             make_edge(output_port<0>(o), output.get_in());
160 
161             if (!silent)
162                 printf("Testing or_gate...\n");
163             input2.activate();
164             input1.activate();
165             input0.activate(); // 0 0 0
166             g.wait_for_all();
167             if (!silent)
168                 output.display();
169             assert(output.get_value() == low);
170             input0.flip(); // 0 0 1
171             g.wait_for_all();
172             if (!silent)
173                 output.display();
174             assert(output.get_value() == high);
175             input1.flip();
176             input0.flip(); // 0 1 0
177             g.wait_for_all();
178             if (!silent)
179                 output.display();
180             assert(output.get_value() == high);
181             input2.flip();
182             input1.flip(); // 1 0 0
183             g.wait_for_all();
184             if (!silent)
185                 output.display();
186             assert(output.get_value() == high);
187             input2.flip();
188             input1.flip();
189             input0.flip(); // 0 1 1
190             g.wait_for_all();
191             if (!silent)
192                 output.display();
193             assert(output.get_value() == high);
194             input2.flip();
195             input1.flip(); // 1 0 1
196             g.wait_for_all();
197             if (!silent)
198                 output.display();
199             assert(output.get_value() == high);
200             input1.flip();
201             input0.flip(); // 1 1 0
202             g.wait_for_all();
203             if (!silent)
204                 output.display();
205             assert(output.get_value() == high);
206             input0.flip(); // 1 1 1
207             g.wait_for_all();
208             if (!silent)
209                 output.display();
210             assert(output.get_value() == high);
211         }
212 
213         { // test two-input xor_gate: 00, 01, 10, 11
214             xor_gate<2> x(g);
215             toggle input0(g);
216             toggle input1(g);
217             led output(g, "OUTPUT", false);
218 
219             make_edge(input0.get_out(), input_port<0>(x));
220             make_edge(input1.get_out(), input_port<1>(x));
221             make_edge(output_port<0>(x), output.get_in());
222 
223             if (!silent)
224                 printf("Testing xor_gate...\n");
225             input1.activate();
226             input0.activate(); // 0 0
227             g.wait_for_all();
228             if (!silent)
229                 output.display();
230             assert(output.get_value() == low);
231             input0.flip(); // 0 1
232             g.wait_for_all();
233             if (!silent)
234                 output.display();
235             assert(output.get_value() == high);
236             input1.flip();
237             input0.flip(); // 1 0
238             g.wait_for_all();
239             if (!silent)
240                 output.display();
241             assert(output.get_value() == high);
242             input0.flip(); // 1 1
243             g.wait_for_all();
244             if (!silent)
245                 output.display();
246             assert(output.get_value() == low);
247         }
248 
249         { // test two-input nor_gate: 00, 01, 10, 11
250             nor_gate<2> n(g);
251             toggle input0(g);
252             toggle input1(g);
253             led output(g, "OUTPUT", false);
254 
255             make_edge(input0.get_out(), input_port<0>(n));
256             make_edge(input1.get_out(), input_port<1>(n));
257             make_edge(output_port<0>(n), output.get_in());
258 
259             if (!silent)
260                 printf("Testing nor_gate...\n");
261             input1.activate();
262             input0.activate(); // 0 0
263             g.wait_for_all();
264             if (!silent)
265                 output.display();
266             assert(output.get_value() == high);
267             input0.flip(); // 0 1
268             g.wait_for_all();
269             if (!silent)
270                 output.display();
271             assert(output.get_value() == low);
272             input1.flip();
273             input0.flip(); // 1 0
274             g.wait_for_all();
275             if (!silent)
276                 output.display();
277             assert(output.get_value() == low);
278             input0.flip(); // 1 1
279             g.wait_for_all();
280             if (!silent)
281                 output.display();
282             assert(output.get_value() == low);
283         }
284 
285         { // test steady_signal and digit
286             steady_signal input0(g, high);
287             steady_signal input1(g, low);
288             and_gate<2> a(g);
289             or_gate<2> o(g);
290             xor_gate<2> x(g);
291             nor_gate<2> n(g);
292             digit output(g, "OUTPUT", false);
293 
294             make_edge(input0.get_out(), input_port<0>(a));
295             make_edge(input1.get_out(), input_port<1>(a));
296             make_edge(output_port<0>(a), input_port<0>(output));
297 
298             make_edge(input0.get_out(), input_port<0>(o));
299             make_edge(input1.get_out(), input_port<1>(o));
300             make_edge(output_port<0>(o), input_port<1>(output));
301 
302             make_edge(input0.get_out(), input_port<0>(x));
303             make_edge(input1.get_out(), input_port<1>(x));
304             make_edge(output_port<0>(x), input_port<2>(output));
305 
306             make_edge(input0.get_out(), input_port<0>(n));
307             make_edge(input1.get_out(), input_port<1>(n));
308             make_edge(output_port<0>(n), input_port<3>(output));
309 
310             if (!silent)
311                 printf("Testing steady_signal...\n");
312             input0.activate(); // 1
313             input1.activate(); // 0
314             g.wait_for_all();
315             if (!silent)
316                 output.display();
317             assert(output.get_value() == 6);
318         }
319 
320         { // test push_button
321             push_button p(g);
322             buffer b(g);
323             led output(g, "OUTPUT", !silent); // true means print all LED state changes
324 
325             make_edge(p.get_out(), input_port<0>(b));
326             make_edge(output_port<0>(b), output.get_in());
327 
328             if (!silent)
329                 printf("Testing push_button...\n");
330             p.press();
331             p.release();
332             p.press();
333             p.release();
334             g.wait_for_all();
335         }
336 
337         { // test one_bit_adder
338             one_bit_adder my_adder(g);
339             toggle A(g);
340             toggle B(g);
341             toggle CarryIN(g);
342             led Sum(g, "SUM");
343             led CarryOUT(g, "CarryOUT");
344 
345             make_edge(A.get_out(), input_port<P::A0>(my_adder));
346             make_edge(B.get_out(), input_port<P::B0>(my_adder));
347             make_edge(CarryIN.get_out(), input_port<P::CI>(my_adder));
348             make_edge(output_port<P::S0>(my_adder), Sum.get_in());
349             make_edge(output_port<1>(my_adder), CarryOUT.get_in());
350 
351             A.activate();
352             B.activate();
353             CarryIN.activate();
354 
355             if (!silent)
356                 printf("A on\n");
357             A.flip();
358             g.wait_for_all();
359             if (!silent)
360                 Sum.display();
361             if (!silent)
362                 CarryOUT.display();
363             assert((Sum.get_value() == high) && (CarryOUT.get_value() == low));
364 
365             if (!silent)
366                 printf("A off\n");
367             A.flip();
368             g.wait_for_all();
369             if (!silent)
370                 Sum.display();
371             if (!silent)
372                 CarryOUT.display();
373             assert((Sum.get_value() == low) && (CarryOUT.get_value() == low));
374 
375             if (!silent)
376                 printf("B on\n");
377             B.flip();
378             g.wait_for_all();
379             if (!silent)
380                 Sum.display();
381             if (!silent)
382                 CarryOUT.display();
383             assert((Sum.get_value() == high) && (CarryOUT.get_value() == low));
384             if (!silent)
385                 printf("B off\n");
386             B.flip();
387             g.wait_for_all();
388             if (!silent)
389                 Sum.display();
390             if (!silent)
391                 CarryOUT.display();
392             assert((Sum.get_value() == low) && (CarryOUT.get_value() == low));
393 
394             if (!silent)
395                 printf("CarryIN on\n");
396             CarryIN.flip();
397             g.wait_for_all();
398             if (!silent)
399                 Sum.display();
400             if (!silent)
401                 CarryOUT.display();
402             assert((Sum.get_value() == high) && (CarryOUT.get_value() == low));
403             if (!silent)
404                 printf("CarryIN off\n");
405             CarryIN.flip();
406             g.wait_for_all();
407             if (!silent)
408                 Sum.display();
409             if (!silent)
410                 CarryOUT.display();
411             assert((Sum.get_value() == low) && (CarryOUT.get_value() == low));
412 
413             if (!silent)
414                 printf("A&B on\n");
415             A.flip();
416             B.flip();
417             g.wait_for_all();
418             if (!silent)
419                 Sum.display();
420             if (!silent)
421                 CarryOUT.display();
422             assert((Sum.get_value() == low) && (CarryOUT.get_value() == high));
423             if (!silent)
424                 printf("A&B off\n");
425             A.flip();
426             B.flip();
427             g.wait_for_all();
428             if (!silent)
429                 Sum.display();
430             if (!silent)
431                 CarryOUT.display();
432             assert((Sum.get_value() == low) && (CarryOUT.get_value() == low));
433 
434             if (!silent)
435                 printf("A&CarryIN on\n");
436             A.flip();
437             CarryIN.flip();
438             g.wait_for_all();
439             if (!silent)
440                 Sum.display();
441             if (!silent)
442                 CarryOUT.display();
443             assert((Sum.get_value() == low) && (CarryOUT.get_value() == high));
444             if (!silent)
445                 printf("A&CarryIN off\n");
446             A.flip();
447             CarryIN.flip();
448             g.wait_for_all();
449             if (!silent)
450                 Sum.display();
451             if (!silent)
452                 CarryOUT.display();
453             assert((Sum.get_value() == low) && (CarryOUT.get_value() == low));
454 
455             if (!silent)
456                 printf("B&CarryIN on\n");
457             B.flip();
458             CarryIN.flip();
459             g.wait_for_all();
460             if (!silent)
461                 Sum.display();
462             if (!silent)
463                 CarryOUT.display();
464             assert((Sum.get_value() == low) && (CarryOUT.get_value() == high));
465             if (!silent)
466                 printf("B&CarryIN off\n");
467             B.flip();
468             CarryIN.flip();
469             g.wait_for_all();
470             if (!silent)
471                 Sum.display();
472             if (!silent)
473                 CarryOUT.display();
474             assert((Sum.get_value() == low) && (CarryOUT.get_value() == low));
475 
476             if (!silent)
477                 printf("A&B&CarryIN on\n");
478             A.flip();
479             B.flip();
480             CarryIN.flip();
481             g.wait_for_all();
482             if (!silent)
483                 Sum.display();
484             if (!silent)
485                 CarryOUT.display();
486             assert((Sum.get_value() == high) && (CarryOUT.get_value() == high));
487             if (!silent)
488                 printf("A&B&CarryIN off\n");
489             A.flip();
490             B.flip();
491             CarryIN.flip();
492             g.wait_for_all();
493             if (!silent)
494                 Sum.display();
495             if (!silent)
496                 CarryOUT.display();
497             assert((Sum.get_value() == low) && (CarryOUT.get_value() == low));
498         }
499 
500 #if USE_TWO_BIT_FULL_ADDER
501         { // test two_bit_adder
502             if (!silent)
503                 printf("testing two_bit adder\n");
504             two_bit_adder two_adder(g);
505             std::vector<toggle> A(2, toggle(g));
506             std::vector<toggle> B(2, toggle(g));
507             toggle CarryIN(g);
508             digit Sum(g, "SUM");
509             led CarryOUT(g, "CarryOUT");
510 
511             make_edge(A[0].get_out(), input_port<P::A0>(two_adder));
512             make_edge(B[0].get_out(), input_port<P::B0>(two_adder));
513             make_edge(output_port<P::S0>(two_adder), input_port<0>(Sum));
514 
515             make_edge(A[1].get_out(), input_port<P::A1>(two_adder));
516             make_edge(B[1].get_out(), input_port<P::B1>(two_adder));
517             make_edge(output_port<P::S1>(two_adder), input_port<1>(Sum));
518 
519             make_edge(CarryIN.get_out(), input_port<P::CI>(two_adder));
520             make_edge(output_port<P::CO>(two_adder), CarryOUT.get_in());
521 
522             // Activate all switches at low state
523             for (int i = 0; i < 2; ++i) {
524                 A[i].activate();
525                 B[i].activate();
526             }
527             CarryIN.activate();
528 
529             if (!silent)
530                 printf("1+0\n");
531             A[0].flip();
532             g.wait_for_all();
533             if (!silent)
534                 Sum.display();
535             if (!silent)
536                 CarryOUT.display();
537             assert((Sum.get_value() == 1) && (CarryOUT.get_value() == low));
538 
539             if (!silent)
540                 printf("0+1\n");
541             A[0].flip();
542             B[0].flip();
543             g.wait_for_all();
544             if (!silent)
545                 Sum.display();
546             if (!silent)
547                 CarryOUT.display();
548             assert((Sum.get_value() == 1) && (CarryOUT.get_value() == low));
549         }
550 #else
551         { // test four_bit_adder
552             four_bit_adder four_adder(g);
553             std::vector<toggle> A(4, toggle(g));
554             std::vector<toggle> B(4, toggle(g));
555             toggle CarryIN(g);
556             digit Sum(g, "SUM");
557             led CarryOUT(g, "CarryOUT");
558 
559             make_edge(A[0].get_out(), input_port<P::A0>(four_adder));
560             make_edge(B[0].get_out(), input_port<P::B0>(four_adder));
561             make_edge(output_port<P::S0>(four_adder), input_port<0>(Sum));
562 
563             make_edge(A[1].get_out(), input_port<P::A1>(four_adder));
564             make_edge(B[1].get_out(), input_port<P::B1>(four_adder));
565             make_edge(output_port<P::S1>(four_adder), input_port<1>(Sum));
566 
567             make_edge(A[2].get_out(), input_port<P::A2>(four_adder));
568             make_edge(B[2].get_out(), input_port<P::B2>(four_adder));
569             make_edge(output_port<P::S2>(four_adder), input_port<2>(Sum));
570 
571             make_edge(A[3].get_out(), input_port<P::A3>(four_adder));
572             make_edge(B[3].get_out(), input_port<P::B3>(four_adder));
573             make_edge(output_port<P::S3>(four_adder), input_port<3>(Sum));
574 
575             make_edge(CarryIN.get_out(), input_port<P::CI>(four_adder));
576             make_edge(output_port<P::CO>(four_adder), CarryOUT.get_in());
577 
578             // Activate all switches at low state
579             for (int i = 0; i < 4; ++i) {
580                 A[i].activate();
581                 B[i].activate();
582             }
583             CarryIN.activate();
584 
585             if (!silent)
586                 printf("1+0\n");
587             A[0].flip();
588             g.wait_for_all();
589             if (!silent)
590                 Sum.display();
591             if (!silent)
592                 CarryOUT.display();
593             assert((Sum.get_value() == 1) && (CarryOUT.get_value() == low));
594 
595             if (!silent)
596                 printf("0+1\n");
597             A[0].flip();
598             B[0].flip();
599             g.wait_for_all();
600             if (!silent)
601                 Sum.display();
602             if (!silent)
603                 CarryOUT.display();
604             assert((Sum.get_value() == 1) && (CarryOUT.get_value() == low));
605 
606             if (!silent)
607                 printf("3+4\n");
608             A[0].flip();
609             A[1].flip();
610             B[0].flip();
611             B[2].flip();
612             g.wait_for_all();
613             if (!silent)
614                 Sum.display();
615             if (!silent)
616                 CarryOUT.display();
617             assert((Sum.get_value() == 7) && (CarryOUT.get_value() == low));
618 
619             if (!silent)
620                 printf("6+1\n");
621             A[0].flip();
622             A[2].flip();
623             B[0].flip();
624             B[2].flip();
625             g.wait_for_all();
626             if (!silent)
627                 Sum.display();
628             if (!silent)
629                 CarryOUT.display();
630             assert((Sum.get_value() == 7) && (CarryOUT.get_value() == low));
631 
632             if (!silent)
633                 printf("0+0+carry\n");
634             A[1].flip();
635             A[2].flip();
636             B[0].flip();
637             CarryIN.flip();
638             g.wait_for_all();
639             if (!silent)
640                 Sum.display();
641             if (!silent)
642                 CarryOUT.display();
643             assert((Sum.get_value() == 1) && (CarryOUT.get_value() == low));
644 
645             if (!silent)
646                 printf("15+15+carry\n");
647             A[0].flip();
648             A[1].flip();
649             A[2].flip();
650             A[3].flip();
651             B[0].flip();
652             B[1].flip();
653             B[2].flip();
654             B[3].flip();
655             g.wait_for_all();
656             if (!silent)
657                 Sum.display();
658             if (!silent)
659                 CarryOUT.display();
660             assert((Sum.get_value() == 0xf) && (CarryOUT.get_value() == high));
661 
662             if (!silent)
663                 printf("8+8\n");
664             A[0].flip();
665             A[1].flip();
666             A[2].flip();
667             B[0].flip();
668             B[1].flip();
669             B[2].flip();
670             CarryIN.flip();
671             g.wait_for_all();
672             if (!silent)
673                 Sum.display();
674             if (!silent)
675                 CarryOUT.display();
676             assert((Sum.get_value() == 0) && (CarryOUT.get_value() == high));
677 
678             if (!silent)
679                 printf("0+0\n");
680             A[3].flip();
681             B[3].flip();
682             g.wait_for_all();
683             if (!silent)
684                 Sum.display();
685             if (!silent)
686                 CarryOUT.display();
687             assert((Sum.get_value() == 0) && (CarryOUT.get_value() == low));
688         }
689 #endif
690 
691         { // test D_latch
692             D_latch my_d_latch(g);
693             toggle D(g);
694             pulse E(g, 500, 4); // clock changes every 500ms; stops after 4 changes
695             led Q(g, " Q", verbose); // if true, LEDs print at every state change
696             led notQ(g, "~Q", verbose);
697 
698             make_edge(D.get_out(), input_port<0>(my_d_latch));
699             make_edge(E.get_out(), input_port<1>(my_d_latch));
700             make_edge(output_port<0>(my_d_latch), Q.get_in());
701             make_edge(output_port<1>(my_d_latch), notQ.get_in());
702 
703             D.activate();
704 
705             if (!silent)
706                 printf("Toggling D\n");
707             E.activate();
708             D.flip();
709             g.wait_for_all();
710             if (!silent && !verbose) {
711                 Q.display();
712                 notQ.display();
713             }
714             assert((Q.get_value() == high) && (notQ.get_value() == low));
715             E.reset();
716 
717             if (!silent)
718                 printf("Toggling D\n");
719             E.activate();
720             D.flip();
721             g.wait_for_all();
722             if (!silent && !verbose) {
723                 Q.display();
724                 notQ.display();
725             }
726             assert((Q.get_value() == low) && (notQ.get_value() == high));
727             E.reset();
728 
729             if (!silent)
730                 printf("Toggling D\n");
731             E.activate();
732             D.flip();
733             g.wait_for_all();
734             if (!silent && !verbose) {
735                 Q.display();
736                 notQ.display();
737             }
738             assert((Q.get_value() == high) && (notQ.get_value() == low));
739             E.reset();
740 
741             if (!silent)
742                 printf("Toggling D\n");
743             E.activate();
744             D.flip();
745             g.wait_for_all();
746             if (!silent && !verbose) {
747                 Q.display();
748                 notQ.display();
749             }
750             assert((Q.get_value() == low) && (notQ.get_value() == high));
751             E.reset();
752 
753             if (!silent)
754                 printf("Toggling D\n");
755             E.activate();
756             D.flip();
757             g.wait_for_all();
758             if (!silent && !verbose) {
759                 Q.display();
760                 notQ.display();
761             }
762             assert((Q.get_value() == high) && (notQ.get_value() == low));
763         }
764     }
765     utility::report_elapsed_time((oneapi::tbb::tick_count::now() - start).seconds());
766     return 0;
767 }
768