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 #ifndef TBB_examples_logic_sim_basic_H
18 #define TBB_examples_logic_sim_basic_H
19
20 #include <cstdio>
21
22 #include <string>
23 #include <tuple>
24
25 #include "oneapi/tbb/tick_count.h"
26 #include "oneapi/tbb/flow_graph.h"
27 #include "common/utility/utility.hpp"
28
29 #ifndef _WIN32
30 #include <sys/time.h>
31 #include <unistd.h>
32
rt_sleep(int msec)33 void rt_sleep(int msec) {
34 usleep(msec * 1000);
35 }
36
37 #else //_WIN32
38
39 #undef OLDUNIXTIME
40 #undef STDTIME
41
42 #include <windows.h>
43
rt_sleep(int msec)44 void rt_sleep(int msec) {
45 Sleep(msec);
46 }
47 #endif /* _WIN32 */
48
49 using oneapi::tbb::flow::make_edge;
50 using oneapi::tbb::flow::cast_to;
51 using oneapi::tbb::flow::input_port;
52 using oneapi::tbb::flow::output_port;
53
54 typedef enum { low = 0, high, undefined } signal_t;
55
56 template <int N>
57 class gate;
58
59 template <>
60 class gate<1>
61 : public oneapi::tbb::flow::composite_node<std::tuple<signal_t>, std::tuple<signal_t>> {
62 protected:
63 typedef oneapi::tbb::flow::indexer_node<signal_t> input_port_t;
64 typedef oneapi::tbb::flow::multifunction_node<input_port_t::output_type, std::tuple<signal_t>>
65 gate_fn_t;
66 typedef gate_fn_t::output_ports_type ports_type;
67 typedef oneapi::tbb::flow::composite_node<std::tuple<signal_t>, std::tuple<signal_t>> base_type;
68
69 public:
70 template <typename Body>
gate(oneapi::tbb::flow::graph & g,Body b)71 gate(oneapi::tbb::flow::graph& g, Body b)
72 : base_type(g),
73 my_graph(g),
74 in_ports(g),
75 gate_fn(g, 1, b) {
76 make_edge(in_ports, gate_fn);
77 base_type::input_ports_type input_tuple(input_port<0>(in_ports));
78 base_type::output_ports_type output_tuple(output_port<0>(gate_fn));
79 base_type::set_external_ports(input_tuple, output_tuple);
80 base_type::add_visible_nodes(in_ports, gate_fn);
81 }
~gate()82 virtual ~gate() {}
operator =(const gate & src)83 gate& operator=(const gate& src) {
84 return *this;
85 }
86
87 protected:
88 oneapi::tbb::flow::graph& my_graph;
89
90 private:
91 input_port_t in_ports;
92 gate_fn_t gate_fn;
93 };
94
95 template <>
96 class gate<2> : public oneapi::tbb::flow::composite_node<std::tuple<signal_t, signal_t>,
97 std::tuple<signal_t>> {
98 protected:
99 typedef oneapi::tbb::flow::indexer_node<signal_t, signal_t> input_port_t;
100 typedef oneapi::tbb::flow::multifunction_node<input_port_t::output_type, std::tuple<signal_t>>
101 gate_fn_t;
102 typedef gate_fn_t::output_ports_type ports_type;
103 typedef oneapi::tbb::flow::composite_node<std::tuple<signal_t, signal_t>, std::tuple<signal_t>>
104 base_type;
105
106 public:
107 template <typename Body>
gate(oneapi::tbb::flow::graph & g,Body b)108 gate(oneapi::tbb::flow::graph& g, Body b)
109 : base_type(g),
110 my_graph(g),
111 in_ports(g),
112 gate_fn(g, 1, b) {
113 make_edge(in_ports, gate_fn);
114 base_type::input_ports_type input_tuple(input_port<0>(in_ports), input_port<1>(in_ports));
115 base_type::output_ports_type output_tuple(output_port<0>(gate_fn));
116 base_type::set_external_ports(input_tuple, output_tuple);
117 base_type::add_visible_nodes(in_ports, gate_fn);
118 }
~gate()119 virtual ~gate() {}
operator =(const gate & src)120 gate& operator=(const gate& src) {
121 return *this;
122 }
123
124 protected:
125 oneapi::tbb::flow::graph& my_graph;
126
127 private:
128 input_port_t in_ports;
129 gate_fn_t gate_fn;
130 };
131
132 template <>
133 class gate<3> : public oneapi::tbb::flow::composite_node<std::tuple<signal_t, signal_t, signal_t>,
134 std::tuple<signal_t>> {
135 protected:
136 typedef oneapi::tbb::flow::indexer_node<signal_t, signal_t, signal_t> input_port_t;
137 typedef oneapi::tbb::flow::multifunction_node<input_port_t::output_type, std::tuple<signal_t>>
138 gate_fn_t;
139 typedef gate_fn_t::output_ports_type ports_type;
140 typedef oneapi::tbb::flow::composite_node<std::tuple<signal_t, signal_t, signal_t>,
141 std::tuple<signal_t>>
142 base_type;
143
144 public:
145 template <typename Body>
gate(oneapi::tbb::flow::graph & g,Body b)146 gate(oneapi::tbb::flow::graph& g, Body b)
147 : base_type(g),
148 my_graph(g),
149 in_ports(g),
150 gate_fn(g, 1, b) {
151 make_edge(in_ports, gate_fn);
152 base_type::input_ports_type input_tuple(
153 input_port<0>(in_ports), input_port<1>(in_ports), input_port<2>(in_ports));
154 base_type::output_ports_type output_tuple(output_port<0>(gate_fn));
155 base_type::set_external_ports(input_tuple, output_tuple);
156 base_type::add_visible_nodes(in_ports, gate_fn);
157 }
~gate()158 virtual ~gate() {}
operator =(const gate & src)159 gate& operator=(const gate& src) {
160 return *this;
161 }
162
163 protected:
164 oneapi::tbb::flow::graph& my_graph;
165
166 private:
167 input_port_t in_ports;
168 gate_fn_t gate_fn;
169 };
170
171 template <>
172 class gate<4> : public oneapi::tbb::flow::composite_node<
173 std::tuple<signal_t, signal_t, signal_t, signal_t>,
174 std::tuple<signal_t>> {
175 protected:
176 typedef oneapi::tbb::flow::indexer_node<signal_t, signal_t, signal_t, signal_t> input_port_t;
177 typedef oneapi::tbb::flow::multifunction_node<input_port_t::output_type, std::tuple<signal_t>>
178 gate_fn_t;
179 typedef gate_fn_t::output_ports_type ports_type;
180 typedef oneapi::tbb::flow::composite_node<std::tuple<signal_t, signal_t, signal_t, signal_t>,
181 std::tuple<signal_t>>
182 base_type;
183
184 public:
185 template <typename Body>
gate(oneapi::tbb::flow::graph & g,Body b)186 gate(oneapi::tbb::flow::graph& g, Body b)
187 : base_type(g),
188 my_graph(g),
189 in_ports(g),
190 gate_fn(g, 1, b) {
191 make_edge(in_ports, gate_fn);
192 base_type::input_ports_type input_tuple(input_port<0>(in_ports),
193 input_port<1>(in_ports),
194 input_port<2>(in_ports),
195 input_port<3>(in_ports));
196 base_type::output_ports_type output_tuple(output_port<0>(gate_fn));
197 base_type::set_external_ports(input_tuple, output_tuple);
198 base_type::add_visible_nodes(in_ports, gate_fn);
199 }
~gate()200 virtual ~gate() {}
operator =(const gate & src)201 gate& operator=(const gate& src) {
202 return *this;
203 }
204
205 protected:
206 oneapi::tbb::flow::graph& my_graph;
207
208 private:
209 input_port_t in_ports;
210 gate_fn_t gate_fn;
211 };
212
213 // Input devices
214 class steady_signal {
215 oneapi::tbb::flow::graph& my_graph;
216 signal_t init_signal;
217 oneapi::tbb::flow::write_once_node<signal_t> signal_node;
218
219 public:
steady_signal(oneapi::tbb::flow::graph & g,signal_t v)220 steady_signal(oneapi::tbb::flow::graph& g, signal_t v)
221 : my_graph(g),
222 init_signal(v),
223 signal_node(g) {}
steady_signal(const steady_signal & src)224 steady_signal(const steady_signal& src)
225 : my_graph(src.my_graph),
226 init_signal(src.init_signal),
227 signal_node(src.my_graph) {}
~steady_signal()228 ~steady_signal() {}
229 // Assignment is ignored
operator =(const steady_signal & src)230 steady_signal& operator=(const steady_signal& src) {
231 return *this;
232 }
get_out()233 oneapi::tbb::flow::write_once_node<signal_t>& get_out() {
234 return signal_node;
235 }
activate()236 void activate() {
237 signal_node.try_put(init_signal);
238 }
239 };
240
241 class pulse {
242 class clock_body {
243 std::size_t& ms;
244 int& reps;
245 signal_t val;
246
247 public:
clock_body(std::size_t & _ms,int & _reps)248 clock_body(std::size_t& _ms, int& _reps) : ms(_ms), reps(_reps), val(low) {}
operator ()(oneapi::tbb::flow_control & fc)249 signal_t operator()(oneapi::tbb::flow_control& fc) {
250 rt_sleep((int)ms);
251
252 if (reps > 0)
253 --reps;
254 if (val == low)
255 val = high;
256 else
257 val = low;
258
259 if (!(reps > 0 || reps == -1))
260 fc.stop();
261 return val;
262 }
263 };
264 oneapi::tbb::flow::graph& my_graph;
265 std::size_t ms, init_ms;
266 int reps, init_reps;
267 oneapi::tbb::flow::input_node<signal_t> clock_node;
268
269 public:
pulse(oneapi::tbb::flow::graph & g,std::size_t _ms=1000,int _reps=-1)270 pulse(oneapi::tbb::flow::graph& g, std::size_t _ms = 1000, int _reps = -1)
271 : my_graph(g),
272 ms(_ms),
273 init_ms(_ms),
274 reps(_reps),
275 init_reps(_reps),
276 clock_node(g, clock_body(ms, reps)) {}
pulse(const pulse & src)277 pulse(const pulse& src)
278 : my_graph(src.my_graph),
279 ms(src.init_ms),
280 init_ms(src.init_ms),
281 reps(src.init_reps),
282 init_reps(src.init_reps),
283 clock_node(src.my_graph, clock_body(ms, reps)) {}
~pulse()284 ~pulse() {}
285 // Assignment changes the behavior of LHS to that of the RHS, but doesn't change owning graph
operator =(const pulse & src)286 pulse& operator=(const pulse& src) {
287 ms = src.ms;
288 init_ms = src.init_ms;
289 reps = src.reps;
290 init_reps = src.init_reps;
291 return *this;
292 }
get_out()293 oneapi::tbb::flow::input_node<signal_t>& get_out() {
294 return clock_node;
295 }
activate()296 void activate() {
297 clock_node.activate();
298 }
reset()299 void reset() {
300 reps = init_reps;
301 }
302 };
303
304 class push_button {
305 oneapi::tbb::flow::graph& my_graph;
306 oneapi::tbb::flow::overwrite_node<signal_t> push_button_node;
307
308 public:
push_button(oneapi::tbb::flow::graph & g)309 push_button(oneapi::tbb::flow::graph& g) : my_graph(g), push_button_node(g) {
310 push_button_node.try_put(low);
311 }
push_button(const push_button & src)312 push_button(const push_button& src) : my_graph(src.my_graph), push_button_node(src.my_graph) {
313 push_button_node.try_put(low);
314 }
~push_button()315 ~push_button() {}
316 // Assignment is ignored
operator =(const push_button & src)317 push_button& operator=(const push_button& src) {
318 return *this;
319 }
get_out()320 oneapi::tbb::flow::overwrite_node<signal_t>& get_out() {
321 return push_button_node;
322 }
press()323 void press() {
324 push_button_node.try_put(high);
325 }
release()326 void release() {
327 push_button_node.try_put(low);
328 }
329 };
330
331 class toggle {
332 oneapi::tbb::flow::graph& my_graph;
333 signal_t state;
334 oneapi::tbb::flow::overwrite_node<signal_t> toggle_node;
335
336 public:
toggle(oneapi::tbb::flow::graph & g)337 toggle(oneapi::tbb::flow::graph& g) : my_graph(g), state(undefined), toggle_node(g) {}
toggle(const toggle & src)338 toggle(const toggle& src)
339 : my_graph(src.my_graph),
340 state(undefined),
341 toggle_node(src.my_graph) {}
~toggle()342 ~toggle() {}
343 // Assignment ignored
operator =(const toggle & src)344 toggle& operator=(const toggle& src) {
345 return *this;
346 }
get_out()347 oneapi::tbb::flow::overwrite_node<signal_t>& get_out() {
348 return toggle_node;
349 }
flip()350 void flip() {
351 if (state == high)
352 state = low;
353 else
354 state = high;
355 toggle_node.try_put(state);
356 }
activate()357 void activate() {
358 state = low;
359 toggle_node.try_put(state);
360 }
361 };
362
363 // Basic gates
364 class buffer : public gate<1> {
365 using gate<1>::my_graph;
366 typedef gate<1>::ports_type ports_type;
367 class buffer_body {
368 signal_t state;
369 bool touched;
370
371 public:
buffer_body()372 buffer_body() : state(undefined), touched(false) {}
operator ()(const input_port_t::output_type & v,ports_type & p)373 void operator()(const input_port_t::output_type& v, ports_type& p) {
374 if (!touched || state != cast_to<signal_t>(v)) {
375 state = cast_to<signal_t>(v);
376 std::get<0>(p).try_put(state);
377 touched = true;
378 }
379 }
380 };
381
382 public:
buffer(oneapi::tbb::flow::graph & g)383 buffer(oneapi::tbb::flow::graph& g) : gate<1>(g, buffer_body()) {}
buffer(const buffer & src)384 buffer(const buffer& src) : gate<1>(src.my_graph, buffer_body()) {}
~buffer()385 ~buffer() {}
386 };
387
388 class not_gate : public gate<1> {
389 using gate<1>::my_graph;
390 typedef gate<1>::ports_type ports_type;
391 class not_body {
392 signal_t port;
393 bool touched;
394
395 public:
not_body()396 not_body() : port(undefined), touched(false) {}
operator ()(const input_port_t::output_type & v,ports_type & p)397 void operator()(const input_port_t::output_type& v, ports_type& p) {
398 if (!touched || port != cast_to<signal_t>(v)) {
399 port = cast_to<signal_t>(v);
400 signal_t state = low;
401 if (port == low)
402 state = high;
403 std::get<0>(p).try_put(state);
404 touched = true;
405 }
406 }
407 };
408
409 public:
not_gate(oneapi::tbb::flow::graph & g)410 not_gate(oneapi::tbb::flow::graph& g) : gate<1>(g, not_body()) {}
not_gate(const not_gate & src)411 not_gate(const not_gate& src) : gate<1>(src.my_graph, not_body()) {}
~not_gate()412 ~not_gate() {}
413 };
414
415 template <int N>
416 class and_gate : public gate<N> {
417 using gate<N>::my_graph;
418 typedef typename gate<N>::ports_type ports_type;
419 typedef typename gate<N>::input_port_t::output_type from_input;
420 class and_body {
421 signal_t* ports;
422 signal_t state;
423 bool touched;
424
425 public:
and_body()426 and_body() : state(undefined), touched(false) {
427 ports = new signal_t[N];
428 for (int i = 0; i < N; ++i)
429 ports[i] = undefined;
430 }
operator ()(const from_input & v,ports_type & p)431 void operator()(const from_input& v, ports_type& p) {
432 ports[v.tag()] = cast_to<signal_t>(v);
433 signal_t new_state = high;
434 std::size_t i = 0;
435 while (i < N) {
436 if (ports[i] == low) {
437 new_state = low;
438 break;
439 }
440 else if (ports[i] == undefined && new_state != low) {
441 new_state = undefined;
442 }
443 ++i;
444 }
445 if (!touched || state != new_state) {
446 state = new_state;
447 std::get<0>(p).try_put(state);
448 touched = true;
449 }
450 }
451 };
452
453 public:
and_gate(oneapi::tbb::flow::graph & g)454 and_gate(oneapi::tbb::flow::graph& g) : gate<N>(g, and_body()) {}
and_gate(const and_gate<N> & src)455 and_gate(const and_gate<N>& src) : gate<N>(src.my_graph, and_body()) {}
~and_gate()456 ~and_gate() {}
457 };
458
459 template <int N>
460 class or_gate : public gate<N> {
461 using gate<N>::my_graph;
462 typedef typename gate<N>::ports_type ports_type;
463 typedef typename gate<N>::input_port_t::output_type from_input;
464 class or_body {
465 signal_t* ports;
466 signal_t state;
467 bool touched;
468
469 public:
or_body()470 or_body() : state(undefined), touched(false) {
471 ports = new signal_t[N];
472 for (int i = 0; i < N; ++i)
473 ports[i] = undefined;
474 }
operator ()(const from_input & v,ports_type & p)475 void operator()(const from_input& v, ports_type& p) {
476 ports[v.tag()] = cast_to<signal_t>(v);
477 signal_t new_state = low;
478 std::size_t i = 0;
479 while (i < N) {
480 if (ports[i] == high) {
481 new_state = high;
482 break;
483 }
484 else if (ports[i] == undefined && new_state != high) {
485 new_state = undefined;
486 }
487 ++i;
488 }
489 if (!touched || state != new_state) {
490 state = new_state;
491 std::get<0>(p).try_put(state);
492 touched = true;
493 }
494 }
495 };
496
497 public:
or_gate(oneapi::tbb::flow::graph & g)498 or_gate(oneapi::tbb::flow::graph& g) : gate<N>(g, or_body()) {}
or_gate(const or_gate & src)499 or_gate(const or_gate& src) : gate<N>(src.my_graph, or_body()) {}
~or_gate()500 ~or_gate() {}
501 };
502
503 template <int N>
504 class xor_gate : public gate<N> {
505 using gate<N>::my_graph;
506 typedef typename gate<N>::ports_type ports_type;
507 typedef typename gate<N>::input_port_t input_port_t;
508 class xor_body {
509 signal_t* ports;
510 signal_t state;
511 bool touched;
512
513 public:
xor_body()514 xor_body() : state(undefined), touched(false) {
515 ports = new signal_t[N];
516 for (int i = 0; i < N; ++i)
517 ports[i] = undefined;
518 }
operator ()(const typename input_port_t::output_type & v,ports_type & p)519 void operator()(const typename input_port_t::output_type& v, ports_type& p) {
520 ports[v.tag()] = cast_to<signal_t>(v);
521 signal_t new_state = low;
522 std::size_t i = 0, highs = 0;
523 while (i < N) {
524 if (ports[i] == undefined) {
525 new_state = undefined;
526 }
527 else if (ports[i] == high && new_state == low) {
528 new_state = high;
529 ++highs;
530 }
531 else if (ports[i] == high && highs > 0) {
532 new_state = low;
533 break;
534 }
535 else if (ports[i] == high) {
536 ++highs;
537 }
538 ++i;
539 }
540 if (!touched || state != new_state) {
541 state = new_state;
542 std::get<0>(p).try_put(state);
543 touched = true;
544 }
545 }
546 };
547
548 public:
xor_gate(oneapi::tbb::flow::graph & g)549 xor_gate(oneapi::tbb::flow::graph& g) : gate<N>(g, xor_body()) {}
xor_gate(const xor_gate & src)550 xor_gate(const xor_gate& src) : gate<N>(src.my_graph, xor_body()) {}
~xor_gate()551 ~xor_gate() {}
552 };
553
554 template <int N>
555 class nor_gate : public gate<N> {
556 using gate<N>::my_graph;
557 typedef typename gate<N>::ports_type ports_type;
558 typedef typename gate<N>::input_port_t input_port_t;
559 class nor_body {
560 signal_t* ports;
561 signal_t state;
562 bool touched;
563
564 public:
nor_body()565 nor_body() : state(undefined), touched(false) {
566 ports = new signal_t[N];
567 for (int i = 0; i < N; ++i)
568 ports[i] = undefined;
569 }
operator ()(const typename input_port_t::output_type & v,ports_type & p)570 void operator()(const typename input_port_t::output_type& v, ports_type& p) {
571 ports[v.tag()] = cast_to<signal_t>(v);
572 signal_t new_state = low;
573 std::size_t i = 0;
574 while (i < N) {
575 if (ports[i] == high) {
576 new_state = high;
577 break;
578 }
579 else if (ports[i] == undefined && new_state != high) {
580 new_state = undefined;
581 }
582 ++i;
583 }
584 if (new_state == high)
585 new_state = low;
586 else if (new_state == low)
587 new_state = high;
588 if (!touched || state != new_state) {
589 state = new_state;
590 std::get<0>(p).try_put(state);
591 touched = true;
592 }
593 }
594 };
595
596 public:
nor_gate(oneapi::tbb::flow::graph & g)597 nor_gate(oneapi::tbb::flow::graph& g) : gate<N>(g, nor_body()) {}
nor_gate(const nor_gate & src)598 nor_gate(const nor_gate& src) : gate<N>(src.my_graph, nor_body()) {}
~nor_gate()599 ~nor_gate() {}
600 };
601
602 // Output devices
603 class led {
604 class led_body {
605 signal_t& state;
606 std::string& label;
607 bool report_changes;
608 bool touched;
609
610 public:
led_body(signal_t & s,std::string & l,bool r)611 led_body(signal_t& s, std::string& l, bool r)
612 : state(s),
613 label(l),
614 report_changes(r),
615 touched(false) {}
operator ()(signal_t b)616 oneapi::tbb::flow::continue_msg operator()(signal_t b) {
617 if (!touched || b != state) {
618 state = b;
619 if (state != undefined && report_changes) {
620 if (state)
621 printf("%s: (*)\n", label.c_str());
622 else
623 printf("%s: ( )\n", label.c_str());
624 }
625 touched = false;
626 }
627 return oneapi::tbb::flow::continue_msg();
628 }
629 };
630 oneapi::tbb::flow::graph& my_graph;
631 std::string label;
632 signal_t state;
633 bool report_changes;
634 oneapi::tbb::flow::function_node<signal_t, oneapi::tbb::flow::continue_msg> led_node;
635
636 public:
led(oneapi::tbb::flow::graph & g,std::string l,bool rc=false)637 led(oneapi::tbb::flow::graph& g, std::string l, bool rc = false)
638 : my_graph(g),
639 label(l),
640 state(undefined),
641 report_changes(rc),
642 led_node(g, 1, led_body(state, label, report_changes)) {}
led(const led & src)643 led(const led& src)
644 : my_graph(src.my_graph),
645 label(src.label),
646 state(undefined),
647 report_changes(src.report_changes),
648 led_node(src.my_graph, 1, led_body(state, label, report_changes)) {}
~led()649 ~led() {}
650 // Assignment changes the behavior of LHS to that of the RHS, but doesn't change owning graph
651 // state is set to undefined so that next signal changes it
operator =(const led & src)652 led& operator=(const led& src) {
653 label = src.label;
654 state = undefined;
655 report_changes = src.report_changes;
656 return *this;
657 }
get_in()658 oneapi::tbb::flow::function_node<signal_t, oneapi::tbb::flow::continue_msg>& get_in() {
659 return led_node;
660 }
display()661 void display() {
662 if (state == high)
663 printf("%s: (*)\n", label.c_str());
664 else if (state == low)
665 printf("%s: ( )\n", label.c_str());
666 else
667 printf("%s: (u)\n", label.c_str());
668 }
get_value()669 signal_t get_value() {
670 return state;
671 }
672 };
673
674 class digit : public gate<4> {
675 using gate<4>::my_graph;
676 typedef gate<4>::ports_type ports_type;
677 typedef gate<4>::input_port_t input_port_t;
678 class digit_body {
679 signal_t ports[4];
680 static const int N = 4;
681 unsigned int& state;
682 std::string& label;
683 bool& report_changes;
684
685 public:
digit_body(unsigned int & s,std::string & l,bool & r)686 digit_body(unsigned int& s, std::string& l, bool& r)
687 : state(s),
688 label(l),
689 report_changes(r) {
690 for (int i = 0; i < N; ++i)
691 ports[i] = undefined;
692 }
operator ()(const input_port_t::output_type & v,ports_type & p)693 void operator()(const input_port_t::output_type& v, ports_type& p) {
694 unsigned int new_state = 0;
695 ports[v.tag()] = cast_to<signal_t>(v);
696 if (ports[0] == high)
697 ++new_state;
698 if (ports[1] == high)
699 new_state += 2;
700 if (ports[2] == high)
701 new_state += 4;
702 if (ports[3] == high)
703 new_state += 8;
704 if (state != new_state) {
705 state = new_state;
706 if (report_changes) {
707 printf("%s: %x\n", label.c_str(), state);
708 }
709 }
710 }
711 };
712 std::string label;
713 unsigned int state;
714 bool report_changes;
715
716 public:
digit(oneapi::tbb::flow::graph & g,std::string l,bool rc=false)717 digit(oneapi::tbb::flow::graph& g, std::string l, bool rc = false)
718 : gate<4>(g, digit_body(state, label, report_changes)),
719 label(l),
720 state(0),
721 report_changes(rc) {}
digit(const digit & src)722 digit(const digit& src)
723 : gate<4>(src.my_graph, digit_body(state, label, report_changes)),
724 label(src.label),
725 state(0),
726 report_changes(src.report_changes) {}
~digit()727 ~digit() {}
728 // Assignment changes the behavior of LHS to that of the RHS, but doesn't change owning graph.
729 // state is reset as in constructors
operator =(const digit & src)730 digit& operator=(const digit& src) {
731 label = src.label;
732 state = 0;
733 report_changes = src.report_changes;
734 return *this;
735 }
display()736 void display() {
737 printf("%s: %x\n", label.c_str(), state);
738 }
get_value()739 unsigned int get_value() {
740 return state;
741 }
742 };
743
744 #endif /* TBB_examples_logic_sim_basic_H */
745