1 | /* |
2 | Copyright (c) 2005-2019 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 __TBBexample_graph_logicsim_basics_H |
18 | #define __TBBexample_graph_logicsim_basics_H 1 |
19 | |
20 | #include <cstdio> |
21 | #include <string> |
22 | #include "tbb/atomic.h" |
23 | #include "tbb/task_scheduler_init.h" |
24 | #include "tbb/tick_count.h" |
25 | #include "tbb/flow_graph.h" |
26 | #include "../../common/utility/utility.h" |
27 | |
28 | #ifndef _WIN32 |
29 | #include <sys/time.h> |
30 | #include <unistd.h> |
31 | |
32 | void rt_sleep(int msec) { |
33 | usleep(msec*1000); |
34 | } |
35 | |
36 | #else //_WIN32 |
37 | |
38 | #undef OLDUNIXTIME |
39 | #undef STDTIME |
40 | |
41 | #include <windows.h> |
42 | |
43 | void rt_sleep(int msec) { |
44 | Sleep(msec); |
45 | } |
46 | #endif /* _WIN32 */ |
47 | |
48 | using namespace std; |
49 | using namespace tbb; |
50 | using namespace tbb::flow; |
51 | |
52 | typedef enum { low=0, high, undefined } signal_t; |
53 | |
54 | template<int N> class gate; |
55 | |
56 | template<> |
57 | class gate<1> : public composite_node< tuple< signal_t >, tuple< signal_t > > { |
58 | protected: |
59 | typedef indexer_node<signal_t> input_port_t; |
60 | typedef multifunction_node< input_port_t::output_type, tuple<signal_t> > gate_fn_t; |
61 | typedef gate_fn_t::output_ports_type ports_type; |
62 | typedef composite_node< tuple< signal_t >, tuple< signal_t > > base_type; |
63 | public: |
64 | template <typename Body> |
65 | gate(graph& g, Body b) : base_type(g), my_graph(g), in_ports(g), gate_fn(g, 1, b) { |
66 | make_edge(in_ports, gate_fn); |
67 | base_type::input_ports_type input_tuple(input_port<0>(in_ports)); |
68 | base_type::output_ports_type output_tuple(output_port<0>(gate_fn)); |
69 | base_type::set_external_ports(input_tuple, output_tuple); |
70 | base_type::add_visible_nodes(in_ports, gate_fn); |
71 | } |
72 | virtual ~gate() {} |
73 | gate& operator=(const gate& src) { return *this; } |
74 | protected: |
75 | graph& my_graph; |
76 | private: |
77 | input_port_t in_ports; |
78 | gate_fn_t gate_fn; |
79 | }; |
80 | |
81 | template<> |
82 | class gate<2> : public composite_node< tuple< signal_t, signal_t >, tuple< signal_t > > { |
83 | protected: |
84 | typedef indexer_node<signal_t,signal_t> input_port_t; |
85 | typedef multifunction_node< input_port_t::output_type, tuple<signal_t> > gate_fn_t; |
86 | typedef gate_fn_t::output_ports_type ports_type; |
87 | typedef composite_node< tuple< signal_t, signal_t >, tuple< signal_t > > base_type; |
88 | public: |
89 | template <typename Body> |
90 | gate(graph& g, Body b) : base_type(g), my_graph(g), in_ports(g), gate_fn(g, 1, b) { |
91 | make_edge(in_ports, gate_fn); |
92 | base_type::input_ports_type input_tuple(input_port<0>(in_ports),input_port<1>(in_ports)); |
93 | base_type::output_ports_type output_tuple(output_port<0>(gate_fn)); |
94 | base_type::set_external_ports(input_tuple, output_tuple); |
95 | base_type::add_visible_nodes(in_ports, gate_fn); |
96 | } |
97 | virtual ~gate() {} |
98 | gate& operator=(const gate& src) { return *this; } |
99 | protected: |
100 | graph& my_graph; |
101 | private: |
102 | input_port_t in_ports; |
103 | gate_fn_t gate_fn; |
104 | }; |
105 | |
106 | template<> |
107 | class gate<3> : public composite_node< tuple< signal_t, signal_t, signal_t >, tuple< signal_t > > { |
108 | protected: |
109 | typedef indexer_node<signal_t, signal_t, signal_t> input_port_t; |
110 | typedef multifunction_node< input_port_t::output_type, tuple<signal_t> > gate_fn_t; |
111 | typedef gate_fn_t::output_ports_type ports_type; |
112 | typedef composite_node< tuple< signal_t, signal_t, signal_t >, tuple< signal_t > > base_type; |
113 | public: |
114 | template <typename Body> |
115 | gate(graph& g, Body b) : base_type(g), my_graph(g), in_ports(g), gate_fn(g, 1, b) { |
116 | make_edge(in_ports, gate_fn); |
117 | base_type::input_ports_type input_tuple(input_port<0>(in_ports),input_port<1>(in_ports),input_port<2>(in_ports)); |
118 | base_type::output_ports_type output_tuple(output_port<0>(gate_fn)); |
119 | base_type::set_external_ports(input_tuple, output_tuple); |
120 | base_type::add_visible_nodes(in_ports, gate_fn); |
121 | } |
122 | virtual ~gate() {} |
123 | gate& operator=(const gate& src) { return *this; } |
124 | protected: |
125 | graph& my_graph; |
126 | private: |
127 | input_port_t in_ports; |
128 | gate_fn_t gate_fn; |
129 | }; |
130 | |
131 | template<> |
132 | class gate<4> : public composite_node< tuple< signal_t, signal_t, signal_t, signal_t >, tuple< signal_t > > { |
133 | protected: |
134 | typedef indexer_node<signal_t, signal_t, signal_t, signal_t> input_port_t; |
135 | typedef multifunction_node< input_port_t::output_type, tuple<signal_t> > gate_fn_t; |
136 | typedef gate_fn_t::output_ports_type ports_type; |
137 | typedef composite_node< tuple< signal_t, signal_t, signal_t, signal_t >, tuple< signal_t > > base_type; |
138 | public: |
139 | template <typename Body> |
140 | gate(graph& g, Body b) : base_type(g), my_graph(g), in_ports(g), gate_fn(g, 1, b) { |
141 | make_edge(in_ports, gate_fn); |
142 | base_type::input_ports_type input_tuple(input_port<0>(in_ports),input_port<1>(in_ports),input_port<2>(in_ports), input_port<3>(in_ports)); |
143 | base_type::output_ports_type output_tuple(output_port<0>(gate_fn)); |
144 | base_type::set_external_ports(input_tuple, output_tuple); |
145 | base_type::add_visible_nodes(in_ports, gate_fn); |
146 | } |
147 | virtual ~gate() {} |
148 | gate& operator=(const gate& src) { return *this; } |
149 | protected: |
150 | graph& my_graph; |
151 | private: |
152 | input_port_t in_ports; |
153 | gate_fn_t gate_fn; |
154 | }; |
155 | |
156 | // Input devices |
157 | class steady_signal { |
158 | graph& my_graph; |
159 | signal_t init_signal; |
160 | write_once_node<signal_t> signal_node; |
161 | public: |
162 | steady_signal(graph& g, signal_t v) : |
163 | my_graph(g), init_signal(v), signal_node(g) {} |
164 | steady_signal(const steady_signal& src) : |
165 | my_graph(src.my_graph), init_signal(src.init_signal), |
166 | signal_node(src.my_graph) {} |
167 | ~steady_signal() {} |
168 | // Assignment is ignored |
169 | steady_signal& operator=(const steady_signal& src) { return *this; } |
170 | sender<signal_t>& get_out() { return signal_node; } |
171 | void activate() { signal_node.try_put(init_signal); } |
172 | }; |
173 | |
174 | class pulse { |
175 | class clock_body { |
176 | size_t& ms; |
177 | int& reps; |
178 | signal_t val; |
179 | public: |
180 | clock_body(size_t& _ms, int& _reps) : ms(_ms), reps(_reps), val(low) {} |
181 | bool operator()(signal_t& out) { |
182 | rt_sleep((int)ms); |
183 | if (reps>0) --reps; |
184 | if (val==low) val = high; |
185 | else val = low; |
186 | out = val; |
187 | return reps>0 || reps == -1; |
188 | } |
189 | }; |
190 | graph& my_graph; |
191 | size_t ms, init_ms; |
192 | int reps, init_reps; |
193 | source_node<signal_t> clock_node; |
194 | |
195 | public: |
196 | pulse(graph& g, size_t _ms=1000, int _reps=-1) : |
197 | my_graph(g), ms(_ms), init_ms(_ms), reps(_reps), init_reps(_reps), |
198 | clock_node(g, clock_body(ms, reps), false) |
199 | {} |
200 | pulse(const pulse& src) : |
201 | my_graph(src.my_graph), ms(src.init_ms), init_ms(src.init_ms), |
202 | reps(src.init_reps), init_reps(src.init_reps), |
203 | clock_node(src.my_graph, clock_body(ms, reps), false) |
204 | {} |
205 | ~pulse() {} |
206 | // Assignment changes the behavior of LHS to that of the RHS, but doesn't change owning graph |
207 | pulse& operator=(const pulse& src) { |
208 | ms = src.ms; init_ms = src.init_ms; reps = src.reps; init_reps = src.init_reps; |
209 | return *this; |
210 | } |
211 | sender<signal_t>& get_out() { return clock_node; } |
212 | void activate() { clock_node.activate(); } |
213 | void reset() { reps = init_reps; } |
214 | }; |
215 | |
216 | class push_button { |
217 | graph& my_graph; |
218 | overwrite_node<signal_t> push_button_node; |
219 | public: |
220 | push_button(graph& g) : my_graph(g), push_button_node(g) { |
221 | push_button_node.try_put(low); |
222 | } |
223 | push_button(const push_button& src) : |
224 | my_graph(src.my_graph), push_button_node(src.my_graph) { |
225 | push_button_node.try_put(low); |
226 | } |
227 | ~push_button() {} |
228 | // Assignment is ignored |
229 | push_button& operator=(const push_button& src) { return *this; } |
230 | sender<signal_t>& get_out() { return push_button_node; } |
231 | void press() { push_button_node.try_put(high); } |
232 | void release() { push_button_node.try_put(low); } |
233 | }; |
234 | |
235 | class toggle { |
236 | graph& my_graph; |
237 | signal_t state; |
238 | overwrite_node<signal_t> toggle_node; |
239 | public: |
240 | toggle(graph& g) : my_graph(g), state(undefined), toggle_node(g) {} |
241 | toggle(const toggle& src) : my_graph(src.my_graph), state(undefined), |
242 | toggle_node(src.my_graph) {} |
243 | ~toggle() {} |
244 | // Assignment ignored |
245 | toggle& operator=(const toggle& src) { return *this; } |
246 | sender<signal_t>& get_out() { return toggle_node; } |
247 | void flip() { |
248 | if (state==high) state = low; |
249 | else state = high; |
250 | toggle_node.try_put(state); |
251 | } |
252 | void activate() { |
253 | state = low; |
254 | toggle_node.try_put(state); |
255 | } |
256 | }; |
257 | |
258 | // Basic gates |
259 | class buffer : public gate<1> { |
260 | using gate<1>::my_graph; |
261 | typedef gate<1>::ports_type ports_type; |
262 | class buffer_body { |
263 | signal_t state; |
264 | bool touched; |
265 | public: |
266 | buffer_body() : state(undefined), touched(false) {} |
267 | void operator()(const input_port_t::output_type &v, ports_type& p) { |
268 | if (!touched || state != cast_to<signal_t>(v)) { |
269 | state = cast_to<signal_t>(v); |
270 | tbb::flow::get<0>(p).try_put(state); |
271 | touched = true; |
272 | } |
273 | } |
274 | }; |
275 | public: |
276 | buffer(graph& g) : gate<1>(g, buffer_body()) {} |
277 | buffer(const buffer& src) : gate<1>(src.my_graph, buffer_body()) {} |
278 | ~buffer() {} |
279 | }; |
280 | |
281 | class not_gate : public gate<1> { |
282 | using gate<1>::my_graph; |
283 | typedef gate<1>::ports_type ports_type; |
284 | class not_body { |
285 | signal_t port; |
286 | bool touched; |
287 | public: |
288 | not_body() : port(undefined), touched(false) {} |
289 | void operator()(const input_port_t::output_type &v, ports_type& p) { |
290 | if (!touched || port != cast_to<signal_t>(v)) { |
291 | port = cast_to<signal_t>(v); |
292 | signal_t state = low; |
293 | if (port==low) state = high; |
294 | tbb::flow::get<0>(p).try_put(state); |
295 | touched = true; |
296 | } |
297 | } |
298 | }; |
299 | public: |
300 | not_gate(graph& g) : gate<1>(g, not_body()) {} |
301 | not_gate(const not_gate& src) : gate<1>(src.my_graph, not_body()) {} |
302 | ~not_gate() {} |
303 | }; |
304 | |
305 | template <int N> |
306 | class and_gate : public gate<N> { |
307 | using gate<N>::my_graph; |
308 | typedef typename gate<N>::ports_type ports_type; |
309 | typedef typename gate<N>::input_port_t::output_type from_input; |
310 | class and_body { |
311 | signal_t *ports; |
312 | signal_t state; |
313 | bool touched; |
314 | public: |
315 | and_body() : state(undefined), touched(false) { |
316 | ports = new signal_t[N]; |
317 | for (int i=0; i<N; ++i) ports[i] = undefined; |
318 | } |
319 | void operator()(const from_input& v, ports_type& p) { |
320 | ports[v.tag()] = cast_to<signal_t>(v); |
321 | signal_t new_state=high; |
322 | size_t i=0; |
323 | while (i<N) { |
324 | if (ports[i] == low) { new_state = low; break; } |
325 | else if (ports[i] == undefined && new_state != low) { new_state = undefined; } |
326 | ++i; |
327 | } |
328 | if (!touched || state != new_state) { |
329 | state = new_state; |
330 | tbb::flow::get<0>(p).try_put(state); |
331 | touched = true; |
332 | } |
333 | } |
334 | }; |
335 | public: |
336 | and_gate(graph& g) : gate<N>(g, and_body()) {} |
337 | and_gate(const and_gate<N>& src) : gate<N>(src.my_graph, and_body()) {} |
338 | ~and_gate() {} |
339 | }; |
340 | |
341 | template<int N> |
342 | class or_gate : public gate<N> { |
343 | using gate<N>::my_graph; |
344 | typedef typename gate<N>::ports_type ports_type; |
345 | typedef typename gate<N>::input_port_t::output_type from_input; |
346 | class or_body { |
347 | signal_t *ports; |
348 | signal_t state; |
349 | bool touched; |
350 | public: |
351 | or_body() : state(undefined), touched(false) { |
352 | ports = new signal_t[N]; |
353 | for (int i=0; i<N; ++i) ports[i] = undefined; |
354 | } |
355 | void operator()(const from_input& v, ports_type& p) { |
356 | ports[v.tag()] = cast_to<signal_t>(v); |
357 | signal_t new_state=low; |
358 | size_t i=0; |
359 | while (i<N) { |
360 | if (ports[i] == high) { new_state = high; break; } |
361 | else if (ports[i] == undefined && new_state != high) { new_state = undefined; } |
362 | ++i; |
363 | } |
364 | if (!touched || state != new_state) { |
365 | state = new_state; |
366 | tbb::flow::get<0>(p).try_put(state); |
367 | touched = true; |
368 | } |
369 | } |
370 | }; |
371 | public: |
372 | or_gate(graph& g) : gate<N>(g, or_body()) {} |
373 | or_gate(const or_gate& src) : gate<N>(src.my_graph, or_body()) {} |
374 | ~or_gate() {} |
375 | }; |
376 | |
377 | template <int N> |
378 | class xor_gate : public gate<N> { |
379 | using gate<N>::my_graph; |
380 | typedef typename gate<N>::ports_type ports_type; |
381 | typedef typename gate<N>::input_port_t input_port_t; |
382 | class xor_body { |
383 | signal_t *ports; |
384 | signal_t state; |
385 | bool touched; |
386 | public: |
387 | xor_body() : state(undefined), touched(false) { |
388 | ports = new signal_t[N]; |
389 | for (int i=0; i<N; ++i) ports[i] = undefined; |
390 | } |
391 | void operator()(const typename input_port_t::output_type &v, ports_type& p) { |
392 | ports[v.tag()] = cast_to<signal_t>(v); |
393 | signal_t new_state=low; |
394 | size_t i=0, highs=0; |
395 | while (i<N) { |
396 | if (ports[i] == undefined) { new_state = undefined; } |
397 | else if (ports[i] == high && new_state == low) { new_state = high; ++highs; } |
398 | else if (ports[i] == high && highs > 0) { new_state = low; break; } |
399 | else if (ports[i] == high ) { ++highs; } |
400 | ++i; |
401 | } |
402 | if (!touched || state != new_state) { |
403 | state = new_state; |
404 | tbb::flow::get<0>(p).try_put(state); |
405 | touched = true; |
406 | } |
407 | } |
408 | }; |
409 | public: |
410 | xor_gate(graph& g) : gate<N>(g, xor_body()) {} |
411 | xor_gate(const xor_gate& src) : gate<N>(src.my_graph, xor_body()) {} |
412 | ~xor_gate() {} |
413 | }; |
414 | |
415 | template <int N> |
416 | class nor_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 input_port_t; |
420 | class nor_body { |
421 | signal_t *ports; |
422 | signal_t state; |
423 | bool touched; |
424 | public: |
425 | nor_body() : state(undefined), touched(false) { |
426 | ports = new signal_t[N]; |
427 | for (int i=0; i<N; ++i) ports[i] = undefined; |
428 | } |
429 | void operator()(const typename input_port_t::output_type &v, ports_type& p) { |
430 | ports[v.tag()] = cast_to<signal_t>(v); |
431 | signal_t new_state=low; |
432 | size_t i=0; |
433 | while (i<N) { |
434 | if (ports[i] == high) { new_state = high; break; } |
435 | else if (ports[i] == undefined && new_state != high) { new_state = undefined; } |
436 | ++i; |
437 | } |
438 | if (new_state == high) new_state = low; |
439 | else if (new_state == low) new_state = high; |
440 | if (!touched || state != new_state) { |
441 | state = new_state; |
442 | tbb::flow::get<0>(p).try_put(state); |
443 | touched = true; |
444 | } |
445 | } |
446 | }; |
447 | public: |
448 | nor_gate(graph& g) : gate<N>(g, nor_body()) {} |
449 | nor_gate(const nor_gate& src) : gate<N>(src.my_graph, nor_body()) {} |
450 | ~nor_gate() {} |
451 | }; |
452 | |
453 | // Output devices |
454 | class led { |
455 | class led_body { |
456 | signal_t &state; |
457 | string &label; |
458 | bool report_changes; |
459 | bool touched; |
460 | public: |
461 | led_body(signal_t &s, string &l, bool r) : |
462 | state(s), label(l), report_changes(r), touched(false) |
463 | {} |
464 | continue_msg operator()(signal_t b) { |
465 | if (!touched || b!=state) { |
466 | state = b; |
467 | if (state != undefined && report_changes) { |
468 | if (state) printf("%s: (*)\n" , label.c_str()); |
469 | else printf("%s: ( )\n" , label.c_str()); |
470 | } |
471 | touched = false; |
472 | } |
473 | return continue_msg(); |
474 | } |
475 | }; |
476 | graph& my_graph; |
477 | string label; |
478 | signal_t state; |
479 | bool report_changes; |
480 | function_node<signal_t, continue_msg> led_node; |
481 | public: |
482 | led(graph& g, string l, bool rc=false) : my_graph(g), label(l), state(undefined), |
483 | report_changes(rc), |
484 | led_node(g, 1, led_body(state, label, report_changes)) |
485 | {} |
486 | led(const led& src) : my_graph(src.my_graph), label(src.label), state(undefined), |
487 | report_changes(src.report_changes), |
488 | led_node(src.my_graph, 1, led_body(state, label, report_changes)) |
489 | {} |
490 | ~led() {} |
491 | // Assignment changes the behavior of LHS to that of the RHS, but doesn't change owning graph |
492 | // state is set to undefined so that next signal changes it |
493 | led& operator=(const led& src) { |
494 | label = src.label; state = undefined; report_changes = src.report_changes; |
495 | return *this; |
496 | } |
497 | receiver<signal_t>& get_in() { return led_node; } |
498 | void display() { |
499 | if (state == high) printf("%s: (*)\n" , label.c_str()); |
500 | else if (state == low) printf("%s: ( )\n" , label.c_str()); |
501 | else printf("%s: (u)\n" , label.c_str()); |
502 | } |
503 | signal_t get_value() { return state; } |
504 | }; |
505 | |
506 | class digit : public gate<4> { |
507 | using gate<4>::my_graph; |
508 | typedef gate<4>::ports_type ports_type; |
509 | typedef gate<4>::input_port_t input_port_t; |
510 | class digit_body { |
511 | signal_t ports[4]; |
512 | static const int N = 4; |
513 | unsigned int &state; |
514 | string &label; |
515 | bool& report_changes; |
516 | public: |
517 | digit_body(unsigned int &s, string &l, bool& r) : state(s), label(l), report_changes(r) { |
518 | for (int i=0; i<N; ++i) ports[i] = undefined; |
519 | } |
520 | void operator()(const input_port_t::output_type& v, ports_type& p) { |
521 | unsigned int new_state = 0; |
522 | ports[v.tag()] = cast_to<signal_t>(v); |
523 | if (ports[0] == high) ++new_state; |
524 | if (ports[1] == high) new_state += 2; |
525 | if (ports[2] == high) new_state += 4; |
526 | if (ports[3] == high) new_state += 8; |
527 | if (state != new_state) { |
528 | state = new_state; |
529 | if (report_changes) { |
530 | printf("%s: %x\n" , label.c_str(), state); |
531 | } |
532 | } |
533 | } |
534 | }; |
535 | string label; |
536 | unsigned int state; |
537 | bool report_changes; |
538 | public: |
539 | digit(graph& g, string l, bool rc=false) : |
540 | gate<4>(g, digit_body(state, label, report_changes)), |
541 | label(l), state(0), report_changes(rc) {} |
542 | digit(const digit& src) : |
543 | gate<4>(src.my_graph, digit_body(state, label, report_changes)), |
544 | label(src.label), state(0), report_changes(src.report_changes) {} |
545 | ~digit() {} |
546 | // Assignment changes the behavior of LHS to that of the RHS, but doesn't change owning graph. |
547 | // state is reset as in constructors |
548 | digit& operator=(const digit& src) { |
549 | label = src.label; state = 0; report_changes = src.report_changes; |
550 | return *this; |
551 | } |
552 | void display() { printf("%s: %x\n" , label.c_str(), state); } |
553 | unsigned int get_value() { return state; } |
554 | }; |
555 | |
556 | #endif /* __TBBexample_graph_logicsim_basics_H */ |
557 | |