| 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 | |