logicuit 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/README.md +94 -2
  4. data/Rakefile +12 -1
  5. data/Steepfile +6 -0
  6. data/lib/logicuit/array_as_signal_group.rb +1 -1
  7. data/lib/logicuit/circuits/combinational/full_adder.rb +6 -2
  8. data/lib/logicuit/circuits/combinational/full_adder_4bit.rb +6 -0
  9. data/lib/logicuit/circuits/combinational/half_adder.rb +4 -0
  10. data/lib/logicuit/circuits/combinational/multiplexer_2to1.rb +5 -1
  11. data/lib/logicuit/circuits/combinational/multiplexer_4to1.rb +5 -1
  12. data/lib/logicuit/circuits/sequential/d_flip_flop.rb +4 -0
  13. data/lib/logicuit/circuits/sequential/one_bit_cpu.rb +4 -0
  14. data/lib/logicuit/circuits/sequential/program_counter.rb +10 -4
  15. data/lib/logicuit/circuits/sequential/register_4bit.rb +6 -0
  16. data/lib/logicuit/circuits/td4/cpu.rb +11 -2
  17. data/lib/logicuit/circuits/td4/decoder.rb +9 -5
  18. data/lib/logicuit/circuits/td4/rom.rb +4 -0
  19. data/lib/logicuit/dsl.rb +21 -17
  20. data/lib/logicuit/gates/and.rb +5 -1
  21. data/lib/logicuit/gates/nand.rb +5 -1
  22. data/lib/logicuit/gates/not.rb +4 -0
  23. data/lib/logicuit/gates/or.rb +5 -1
  24. data/lib/logicuit/gates/xor.rb +5 -1
  25. data/lib/logicuit/runner.rb +1 -1
  26. data/lib/logicuit/signals/clock.rb +1 -1
  27. data/lib/logicuit/signals/signal.rb +12 -0
  28. data/lib/logicuit/signals/signal_group.rb +1 -1
  29. data/lib/logicuit/version.rb +1 -1
  30. data/sig/generated/logicuit/circuits/combinational/full_adder.rbs +20 -0
  31. data/sig/generated/logicuit/circuits/combinational/full_adder_4bit.rbs +38 -0
  32. data/sig/generated/logicuit/circuits/combinational/half_adder.rbs +18 -0
  33. data/sig/generated/logicuit/circuits/combinational/multiplexer_2to1.rbs +18 -0
  34. data/sig/generated/logicuit/circuits/combinational/multiplexer_4to1.rbs +24 -0
  35. data/sig/generated/logicuit/circuits/sequential/d_flip_flop.rbs +14 -0
  36. data/sig/generated/logicuit/circuits/sequential/one_bit_cpu.rbs +16 -0
  37. data/sig/generated/logicuit/circuits/sequential/program_counter.rbs +28 -0
  38. data/sig/generated/logicuit/circuits/sequential/register_4bit.rbs +28 -0
  39. data/sig/generated/logicuit/circuits/td4/cpu.rbs +28 -0
  40. data/sig/generated/logicuit/circuits/td4/decoder.rbs +32 -0
  41. data/sig/generated/logicuit/circuits/td4/rom.rbs +36 -0
  42. data/sig/generated/logicuit/gates/and.rbs +14 -0
  43. data/sig/generated/logicuit/gates/nand.rbs +14 -0
  44. data/sig/generated/logicuit/gates/not.rbs +12 -0
  45. data/sig/generated/logicuit/gates/or.rbs +14 -0
  46. data/sig/generated/logicuit/gates/xor.rbs +14 -0
  47. data/sig/logicuit/array_as_signal_group.rbs +11 -0
  48. data/sig/logicuit/dsl.rbs +35 -0
  49. data/sig/logicuit/runner.rbs +4 -0
  50. data/sig/logicuit/signals/clock.rbs +30 -0
  51. data/sig/logicuit/signals/signal.rbs +32 -0
  52. data/sig/logicuit/signals/signal_group.rbs +20 -0
  53. data/sig/logicuit/version.rbs +3 -0
  54. metadata +26 -2
  55. data/sig/logicuit.rbs +0 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1a2841e79a0daf8046710c6bd43d8862a3d9f28f482ab2b9cac2886b271f571f
4
- data.tar.gz: 679b263308e15b0da229573bfd7be5cf02c8e65bd98fb01753874afb3fe56413
3
+ metadata.gz: 7ab72694854386c09ba2b86561b6f71f96ea150cbc75384cac6b367a1ef77678
4
+ data.tar.gz: 033acc2d10c17e90f32dae9af915e92fd81064c88ff8174842821676b5d11fa4
5
5
  SHA512:
6
- metadata.gz: 3e942269a9b55dad3f7efff1d68935f431952d0c3276d7d290461dabe84230f6d6d1d0eb2f307b6dd375c2d3b1261c8e2e7c72f1faa17db0de576cee9c37c0da
7
- data.tar.gz: 3f1428cced00eee1798ea56dc9cfb169eb041b40bfc514a729d1cd3d67ce4b05d93ea633a9290c3ac22432aa1bfeb384e8de20cee59a0e463c582bf82be61ea4
6
+ metadata.gz: f7468f876cf9c462bd2b39b170c309fd9d35408c2dae2d45c7229376254c0d9d8586573fd607f046ddee1d226fb5f6137e8c722dee1e9d36735d204605be5ed2
7
+ data.tar.gz: 021dc78f8bc9bc7f62b12572d9ec553f916ff66fac568268c8502c9de46d9b836ba14c49a042f33ebec517eccea9661489e92628c6c1cbf64d96f90a3b046ce4
data/.rubocop.yml CHANGED
@@ -8,6 +8,9 @@ Style/StringLiterals:
8
8
  Style/StringLiteralsInInterpolation:
9
9
  EnforcedStyle: double_quotes
10
10
 
11
+ Layout/LeadingCommentSpace:
12
+ Enabled: false
13
+
11
14
  Layout/LineLength:
12
15
  Enabled: false
13
16
 
data/README.md CHANGED
@@ -40,6 +40,7 @@ A Ruby-based logic circuit simulator featuring an internal DSL for building circ
40
40
  - [Assembling](#assembling)
41
41
  - [SignalGroup](#signalgroup)
42
42
  - [Sequential Circuits](#sequential-circuits)
43
+ - [Truth Table Verification](#truth-table-verification)
43
44
  - [Demo: Ramen Timer](#demo-ramen-timer)
44
45
  - [Development](#development)
45
46
  - [Contributing](#contributing)
@@ -72,7 +73,7 @@ require "logicuit"
72
73
  class MyAndGate < Logicuit::DSL
73
74
  inputs :a, :b
74
75
 
75
- outputs y: -> { a && b }
76
+ outputs y: -> { a & b }
76
77
 
77
78
  diagram <<~DIAGRAM
78
79
  (A)-| |
@@ -90,6 +91,19 @@ This defines:
90
91
  - one output (`y`) that returns the logical AND of the inputs,
91
92
  - and an ASCII diagram that shows the structure of the gate.
92
93
 
94
+ ### About signals and logical operations
95
+
96
+ Inputs and outputs in Logicuit are not plain booleans — they are instances of the `Logicuit::Signals::Signal` class.
97
+ The `Signal` class provides methods like `&`, `|`, and `!` to represent logical AND, OR, and NOT operations, respectively.
98
+
99
+ For example:
100
+
101
+ ```ruby
102
+ outputs y: -> { (a & b) | !a }
103
+ ```
104
+
105
+ This allows logic expressions to look natural and circuit-like while supporting chaining and composition.
106
+
93
107
  ### Interactive execution
94
108
 
95
109
  When you call `run`, the simulator enters an interactive mode.
@@ -383,7 +397,85 @@ inputs ..., clock: :ck
383
397
 
384
398
  > Note: If you forget to declare a clock input, Logicuit won't know it's a sequential circuit — even if you include flip-flops internally. Always include `clock:` to enable timing.
385
399
 
386
- ### Demo: Ramen Timer
400
+ ## Truth Table Verification
401
+
402
+ You can attach a truth table to your circuit class using the `#truth_table`. The truth table should be written in Markdown table format.
403
+
404
+ ```ruby
405
+ require "logicuit"
406
+
407
+ class MyAndGate < Logicuit::DSL
408
+ inputs :a, :b
409
+
410
+ outputs y: -> { a & b }
411
+
412
+ diagram <<~DIAGRAM
413
+ (A)-| |
414
+ |AND|-(Y)
415
+ (B)-| |
416
+ DIAGRAM
417
+
418
+ truth_table <<~TRUTH_TABLE
419
+ | A | B | Y |
420
+ | - | - | - |
421
+ | 0 | 0 | 0 |
422
+ | 1 | 0 | 0 |
423
+ | 0 | 1 | 0 |
424
+ | 1 | 1 | 1 |
425
+ TRUTH_TABLE
426
+ end
427
+
428
+ MyAndGate.verify_against_truth_table
429
+ ```
430
+
431
+ The `#verify_against_truth_table` method evaluates the circuit for each row of the truth table and checks whether the outputs match the expected values.
432
+
433
+ If the behavior of the circuit doesn't match the truth table, you'll see an error like this:
434
+
435
+ ```
436
+ MyAndGate.new(0, 1).y should be 0 (RuntimeError)
437
+ ```
438
+
439
+ This feature is useful for validating your logic circuits against formal truth tables as part of development or testing workflows.
440
+
441
+ ### Verifying sequential circuits
442
+
443
+ Sequential circuits can also be verified using truth tables. When verifying a sequential circuit, the symbol `^` represents the rising edge of the clock.
444
+
445
+ Here’s an example for a D flip-flop:
446
+
447
+ ```ruby
448
+ class MyDFlipFlop < Logicuit::DSL
449
+ inputs :d, clock: :ck
450
+
451
+ outputs q: -> { d }
452
+
453
+ diagram <<~DIAGRAM
454
+ (D)--| |--(Q)
455
+ |DFF|
456
+ (CK)-|> |
457
+ DIAGRAM
458
+
459
+ truth_table <<~TRUTH_TABLE
460
+ | CK | D | Q |
461
+ | -- | - | - |
462
+ | ^ | 0 | 0 |
463
+ | ^ | 1 | 1 |
464
+ TRUTH_TABLE
465
+ end
466
+
467
+ MyDFlipFlop.verify_against_truth_table
468
+ ```
469
+
470
+ In this table:
471
+
472
+ - The `CK` column uses `^` to indicate a clock tick.
473
+ - The circuit is initialized with the given inputs, then the clock is ticked once.
474
+ - The outputs are evaluated immediately after the tick and compared against the expected values.
475
+
476
+ This mechanism makes it easy to specify and verify the behavior of memory elements and registers.
477
+
478
+ ## Demo: Ramen Timer
387
479
 
388
480
  Logicuit comes with a simple demo circuit — a working 4-bit CPU based on the TD4 architecture described in the book [CPUの創りかた](https://www.amazon.co.jp/dp/4839909865).
389
481
 
data/Rakefile CHANGED
@@ -9,4 +9,15 @@ require "rubocop/rake_task"
9
9
 
10
10
  RuboCop::RakeTask.new
11
11
 
12
- task default: %i[test rubocop]
12
+ require "steep/rake_task"
13
+ Steep::RakeTask.new do |t|
14
+ t.check.severity_level = :error
15
+ t.watch.verbose
16
+ end
17
+
18
+ desc "Generate rbs files from inline comments"
19
+ task "rbs-inline" do
20
+ sh "rbs-inline --output lib"
21
+ end
22
+
23
+ task default: %i[test rubocop rbs-inline steep]
data/Steepfile ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ target :app do
4
+ check "lib"
5
+ signature "sig"
6
+ end
@@ -6,7 +6,7 @@ module Logicuit
6
6
  module ArrayAsSignalGroup
7
7
  refine Array do
8
8
  def >>(other)
9
- Signals::SignalGroup.new(*self).connects_to(other)
9
+ Signals::SignalGroup.new(*self).connects_to(other) # steep:ignore
10
10
  end
11
11
  end
12
12
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # rbs_inline: enabled
4
+
3
5
  module Logicuit
4
6
  module Circuits
5
7
  module Combinational
@@ -43,10 +45,12 @@ module Logicuit
43
45
  +-----------------| |
44
46
  DIAGRAM
45
47
 
48
+ attr_reader :cin, :a, :b, :s, :c #: Signals::Signal
49
+
46
50
  inputs :cin, :a, :b
47
51
 
48
- outputs s: -> { (!cin && !a && b) || (!cin && a && !b) || (cin && !a && !b) || (cin && a && b) },
49
- c: -> { (!cin && a && b) || (cin && !a && b) || (cin && a && !b) || (cin && a && b) }
52
+ outputs s: -> { (!cin & !a & b) | (!cin & a & !b) | (cin & !a & !b) | (cin & a & b) },
53
+ c: -> { (!cin & a & b) | (cin & !a & b) | (cin & a & !b) | (cin & a & b) }
50
54
 
51
55
  truth_table <<~TRUTH_TABLE
52
56
  | Cin | A | B | C | S |
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # rbs_inline: enabled
4
+
3
5
  module Logicuit
4
6
  module Circuits
5
7
  module Combinational
@@ -17,6 +19,8 @@ module Logicuit
17
19
  (B2)--| |--------+ (B3)--| |---(C)
18
20
  DIAGRAM
19
21
 
22
+ attr_reader :cin, :a0, :b0, :a1, :b1, :a2, :b2, :a3, :b3, :s0, :s1, :s2, :s3, :c #: Signals::Signal
23
+
20
24
  inputs :cin, :a0, :b0, :a1, :b1, :a2, :b2, :a3, :b3
21
25
 
22
26
  outputs :s0, :s1, :s2, :s3, :c
@@ -25,6 +29,8 @@ module Logicuit
25
29
  [[a0, b0, s0], [a1, b1, s1], [a2, b2, s2], [a3, b3, s3]].reduce(cin) do |c, sigs|
26
30
  a, b, s = sigs
27
31
  full_addr = Combinational::FullAdder.new
32
+ next full_addr.c if a.nil? || b.nil? || s.nil? # avoid rbs error and rubocop error...
33
+
28
34
  c >> full_addr.cin
29
35
  a >> full_addr.a
30
36
  b >> full_addr.b
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # rbs_inline: enabled
4
+
3
5
  module Logicuit
4
6
  module Circuits
5
7
  module Combinational
@@ -15,6 +17,8 @@ module Logicuit
15
17
  +---| |
16
18
  DIAGRAM
17
19
 
20
+ attr_reader :a, :b, :c, :s #: Signals::Signal
21
+
18
22
  inputs :a, :b
19
23
 
20
24
  outputs :c, :s
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # rbs_inline: enabled
4
+
3
5
  module Logicuit
4
6
  module Circuits
5
7
  module Combinational
@@ -15,9 +17,11 @@ module Logicuit
15
17
  (A)--+-------| |
16
18
  DIAGRAM
17
19
 
20
+ attr_reader :c0, :c1, :a, :y #: Signals::Signal
21
+
18
22
  inputs :c0, :c1, :a
19
23
 
20
- outputs y: -> { (c0 && !a) || (c1 && a) }
24
+ outputs y: -> { (c0 & !a) | (c1 & a) }
21
25
 
22
26
  truth_table <<~TRUTH_TABLE
23
27
  | C0 | C1 | A | Y |
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # rbs_inline: enabled
4
+
3
5
  module Logicuit
4
6
  module Circuits
5
7
  module Combinational
@@ -27,9 +29,11 @@ module Logicuit
27
29
  (A)----+-|NOT|---+
28
30
  DIAGRAM
29
31
 
32
+ attr_reader :c0, :c1, :c2, :c3, :b, :a, :y #: Signals::Signal
33
+
30
34
  inputs :c0, :c1, :c2, :c3, :b, :a
31
35
 
32
- outputs y: -> { (c0 && !b && !a) || (c1 && !b && a) || (c2 && b && !a) || (c3 && b && a) }
36
+ outputs y: -> { (c0 & !b & !a) | (c1 & !b & a) | (c2 & b & !a) | (c3 & b & a) }
33
37
 
34
38
  truth_table <<~TRUTH_TABLE
35
39
  | B | A | C0 | C1 | C2 | C3 | Y |
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # rbs_inline: enabled
4
+
3
5
  module Logicuit
4
6
  module Circuits
5
7
  module Sequential
@@ -11,6 +13,8 @@ module Logicuit
11
13
  (CK)-|> |
12
14
  DIAGRAM
13
15
 
16
+ attr_reader :d, :q #: Signals::Signal
17
+
14
18
  inputs :d, clock: :ck
15
19
 
16
20
  outputs q: -> { d }
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # rbs_inline: enabled
4
+
3
5
  module Logicuit
4
6
  module Circuits
5
7
  module Sequential
@@ -17,6 +19,8 @@ module Logicuit
17
19
  (A)--| |
18
20
  DIAGRAM
19
21
 
22
+ attr_reader :a, :y #: Signals::Signal
23
+
20
24
  inputs :a, clock: :ck
21
25
 
22
26
  outputs :y
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # rbs_inline: enabled
4
+
3
5
  module Logicuit
4
6
  module Circuits
5
7
  module Sequential
@@ -13,6 +15,8 @@ module Logicuit
13
15
  (LD)--| |
14
16
  DIAGRAM
15
17
 
18
+ attr_reader :a, :b, :c, :d, :ld, :qa, :qb, :qc, :qd #: Signals::Signal
19
+
16
20
  inputs :a, :b, :c, :d, :ld, clock: :ck
17
21
 
18
22
  outputs :qa, :qb, :qc, :qd
@@ -21,13 +25,15 @@ module Logicuit
21
25
  # inputs :cin, :a0, :b0, :a1, :b1, :a2, :b2, :a3, :b3
22
26
  fadd = Combinational::FullAdder4bit.new(0, 0, 1, 0, 0, 0, 0, 0, 0)
23
27
 
24
- [[a, qa, :a0, :s0], [b, qb, :a1, :s1], [c, qc, :a2, :s2],
25
- [d, qd, :a3, :s3]].each do |input, output, fadd_in, fadd_out|
28
+ [[a, qa, fadd.a0, fadd.s0], [b, qb, fadd.a1, fadd.s1], [c, qc, fadd.a2, fadd.s2],
29
+ [d, qd, fadd.a3, fadd.s3]].each do |input, output, fadd_in, fadd_out|
30
+ next if input.nil? || output.nil? || fadd_in.nil? || fadd_out.nil?
31
+
26
32
  dff = Sequential::DFlipFlop.new
27
33
  mux = Combinational::Multiplexer2to1.new
28
34
  input >> mux.c0
29
- dff.q >> fadd.send(fadd_in)
30
- fadd.send(fadd_out) >> mux.c1
35
+ dff.q >> fadd_in
36
+ fadd_out >> mux.c1
31
37
  ld >> mux.a
32
38
  mux.y >> dff.d
33
39
  dff.q >> output
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # rbs_inline: enabled
4
+
3
5
  module Logicuit
4
6
  module Circuits
5
7
  module Sequential
@@ -28,12 +30,16 @@ module Logicuit
28
30
  (LD)--+ (CK)--+
29
31
  DIAGRAM
30
32
 
33
+ attr_reader :a, :b, :c, :d, :ld, :qa, :qb, :qc, :qd #: Signals::Signal
34
+
31
35
  inputs :a, :b, :c, :d, :ld, clock: :ck
32
36
 
33
37
  outputs :qa, :qb, :qc, :qd
34
38
 
35
39
  assembling do
36
40
  [[a, qa], [b, qb], [c, qc], [d, qd]].each do |input, output|
41
+ next if input.nil? || output.nil?
42
+
37
43
  dff = Sequential::DFlipFlop.new
38
44
  mux = Combinational::Multiplexer2to1.new
39
45
  input >> mux.c0
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # rbs_inline: enabled
4
+
3
5
  module Logicuit
4
6
  module Circuits
5
7
  module Td4
@@ -7,16 +9,23 @@ module Logicuit
7
9
  class Cpu < DSL
8
10
  using Logicuit::ArrayAsSignalGroup
9
11
 
12
+ attr_reader :in0, :in1, :in2, :in3, :led1, :led2, :led3, :led4
13
+
10
14
  inputs :in0, :in1, :in2, :in3, clock: :ck
11
15
 
12
16
  outputs :led1, :led2, :led3, :led4
13
17
 
14
18
  assembling do
15
- register_a, register_b, register_c = (:a..:c).map { Sequential::Register4bit.new }
19
+ register_a = Sequential::Register4bit.new
20
+ register_b = Sequential::Register4bit.new
21
+ register_c = Sequential::Register4bit.new
16
22
  pc = Sequential::ProgramCounter.new
17
23
  rom = Rom.new
18
24
  dec = Decoder.new
19
- mux0, mux1, mux2, mux3 = (0..3).map { Combinational::Multiplexer4to1.new }
25
+ mux0 = Combinational::Multiplexer4to1.new
26
+ mux1 = Combinational::Multiplexer4to1.new
27
+ mux2 = Combinational::Multiplexer4to1.new
28
+ mux3 = Combinational::Multiplexer4to1.new
20
29
  alu = Combinational::FullAdder4bit.new
21
30
  dff = Sequential::DFlipFlop.new
22
31
 
@@ -1,18 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # rbs_inline: enabled
4
+
3
5
  module Logicuit
4
6
  module Circuits
5
7
  module Td4
6
8
  # Decoder class
7
9
  class Decoder < DSL
10
+ attr_reader :op3, :op2, :op1, :op0, :c_flag, :sel_b, :sel_a, :ld0, :ld1, :ld2, :ld3 #: Signals::Signal
11
+
8
12
  inputs :op3, :op2, :op1, :op0, :c_flag
9
13
 
10
14
  outputs sel_b: -> { op1 },
11
- sel_a: -> { op3 || op0 },
12
- ld0: -> { op3 || op2 },
13
- ld1: -> { op3 || !op2 },
14
- ld2: -> { !op3 || op2 },
15
- ld3: -> { !op3 || !op2 || (!op0 && c_flag) }
15
+ sel_a: -> { op3 | op0 },
16
+ ld0: -> { op3 | op2 },
17
+ ld1: -> { op3 | !op2 },
18
+ ld2: -> { !op3 | op2 },
19
+ ld3: -> { !op3 | !op2 | (!op0 & c_flag) }
16
20
 
17
21
  truth_table <<~TRUTH_TABLE
18
22
  | OP3 | OP2 | OP1 | OP0 | C_FLAG | SEL_B | SEL_A | LD0 | LD1 | LD2 | LD3 |
@@ -1,10 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # rbs_inline: enabled
4
+
3
5
  module Logicuit
4
6
  module Circuits
5
7
  module Td4
6
8
  # Timer
7
9
  class Rom < DSL
10
+ attr_reader :a3, :a2, :a1, :a0, :d7, :d6, :d5, :d4, :d3, :d2, :d1, :d0 #: Signals::Signal
11
+
8
12
  inputs :a3, :a2, :a1, :a0
9
13
 
10
14
  outputs :d7, :d6, :d5, :d4, :d3, :d2, :d1, :d0
data/lib/logicuit/dsl.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # steep:ignore:start
4
+
3
5
  # Logicuit module
4
6
  module Logicuit
5
7
  # base class for all gates and circuits
@@ -26,7 +28,9 @@ module Logicuit
26
28
 
27
29
  def self.inputs(*args, **kwargs)
28
30
  # define getter methods for inputs
29
- attr_reader(*args)
31
+ args.each do |arg|
32
+ attr_reader(arg) unless instance_methods.include?(arg)
33
+ end
30
34
 
31
35
  # define initializer for inputs
32
36
  define_method(:inputs) do |*instance_method_args|
@@ -54,7 +58,9 @@ module Logicuit
54
58
 
55
59
  def self.outputs(*args, **kwargs)
56
60
  # define getter methods for outputs
57
- attr_reader(*(args + kwargs.keys))
61
+ (args + kwargs.keys).each do |arg|
62
+ attr_reader(arg) unless instance_methods.include?(arg)
63
+ end
58
64
 
59
65
  # define initializer for outputs
60
66
  define_method(:outputs) do
@@ -71,19 +77,13 @@ module Logicuit
71
77
  return unless initialized
72
78
 
73
79
  kwargs.each do |output, evaluator|
74
- signal = instance_variable_get("@#{output}")
75
- e_args = if override_args.empty?
76
- @input_targets.map do |input|
77
- instance_variable_get("@#{input}").current
78
- end
79
- else
80
- override_args
81
- end
82
- if @inputs_as_bool_struct.new(*e_args).instance_exec(&evaluator)
83
- signal.on
84
- else
85
- signal.off
86
- end
80
+ ret = if override_args.empty?
81
+ instance_exec(&evaluator)
82
+ else
83
+ o = @inputs_as_bool_struct.new(*override_args)
84
+ o.instance_exec(&evaluator)
85
+ end
86
+ send(output).send(ret.current ? :on : :off)
87
87
  end
88
88
  end
89
89
  end
@@ -134,6 +134,8 @@ module Logicuit
134
134
  array = [values]
135
135
  while array.any? { _1.any? { |v| v == :any } }
136
136
  target_index = array.find_index { _1.any? { |v| v == :any } }
137
+ next if target_index.nil? # avoid rbs error...
138
+
137
139
  target = array[target_index]
138
140
  prop_index = target.find_index { |v| v == :any }
139
141
  array.delete_at(target_index)
@@ -168,9 +170,9 @@ module Logicuit
168
170
  if value.is_a?(Array) && value.first == :ref
169
171
  expected = previous_values[value.last]
170
172
 
171
- raise "#{self}.new(#{args.join(", ")}).#{key} should be #{expected}" unless expected == subject.send(key).current
173
+ raise "#{self}.new(#{args.join(", ")}).#{key} should be #{expected ? 1 : 0}" unless expected == subject.send(key).current
172
174
  else
173
- raise "#{self}.new(#{args.join(", ")}).#{key} should be #{value}" unless value == subject.send(key).current
175
+ raise "#{self}.new(#{args.join(", ")}).#{key} should be #{value ? 1 : 0}" unless value == subject.send(key).current
174
176
  end
175
177
  end
176
178
  end
@@ -181,3 +183,5 @@ module Logicuit
181
183
  end
182
184
  end
183
185
  end
186
+
187
+ # steep:ignore:end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # rbs_inline: enabled
4
+
3
5
  module Logicuit
4
6
  module Gates
5
7
  # AND gate
@@ -10,9 +12,11 @@ module Logicuit
10
12
  (B)-| |
11
13
  DIAGRAM
12
14
 
15
+ attr_reader :a, :b, :y #: Signals::Signal
16
+
13
17
  inputs :a, :b
14
18
 
15
- outputs y: -> { a && b }
19
+ outputs y: -> { a & b }
16
20
 
17
21
  truth_table <<~TRUTH_TABLE
18
22
  | A | B | Y |
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # rbs_inline: enabled
4
+
3
5
  module Logicuit
4
6
  module Gates
5
7
  # NAND gate
@@ -10,9 +12,11 @@ module Logicuit
10
12
  (B)-| |
11
13
  DIAGRAM
12
14
 
15
+ attr_reader :a, :b, :y #: Signals::Signal
16
+
13
17
  inputs :a, :b
14
18
 
15
- outputs y: -> { !(a && b) }
19
+ outputs y: -> { !(a & b) }
16
20
 
17
21
  truth_table <<~TRUTH_TABLE
18
22
  | A | B | Y |
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # rbs_inline: enabled
4
+
3
5
  module Logicuit
4
6
  module Gates
5
7
  # NOT gate
@@ -8,6 +10,8 @@ module Logicuit
8
10
  (A)-|NOT|-(Y)
9
11
  DIAGRAM
10
12
 
13
+ attr_reader :a, :y #: Signals::Signal
14
+
11
15
  inputs :a
12
16
 
13
17
  outputs y: -> { !a }
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # rbs_inline: enabled
4
+
3
5
  module Logicuit
4
6
  module Gates
5
7
  # OR gate
@@ -10,9 +12,11 @@ module Logicuit
10
12
  (B)-| |
11
13
  DIAGRAM
12
14
 
15
+ attr_reader :a, :b, :y #: Signals::Signal
16
+
13
17
  inputs :a, :b
14
18
 
15
- outputs y: -> { a || b }
19
+ outputs y: -> { a | b }
16
20
 
17
21
  truth_table <<~TRUTH_TABLE
18
22
  | A | B | Y |
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # rbs_inline: enabled
4
+
3
5
  module Logicuit
4
6
  module Gates
5
7
  # XOR gate
@@ -10,9 +12,11 @@ module Logicuit
10
12
  (B)-| |
11
13
  DIAGRAM
12
14
 
15
+ attr_reader :a, :b, :y #: Signals::Signal
16
+
13
17
  inputs :a, :b
14
18
 
15
- outputs y: -> { (a && !b) || (!a && b) }
19
+ outputs y: -> { (a & !b) | (!a & b) }
16
20
 
17
21
  truth_table <<~TRUTH_TABLE
18
22
  | A | B | Y |
@@ -23,7 +23,7 @@ module Logicuit
23
23
  render.call
24
24
  end
25
25
 
26
- while (input = gets.chomp)
26
+ while (input = gets&.chomp)
27
27
  key = input.to_sym
28
28
  unless circuit.respond_to? key
29
29
  if circuit.clock && hz.zero?
@@ -16,7 +16,7 @@ module Logicuit
16
16
  # Call the `evaluate` method for all components.
17
17
  # However, the input argument values should be bound to the values at the time `tick` is called.
18
18
  @downstreams.map do |component|
19
- args = component.input_targets.map { |input| component.instance_variable_get("@#{input}").current }
19
+ args = component.input_targets.map { |input| Signal.new(component.send(input).current) }
20
20
  -> { component.evaluate(*args) }
21
21
  end.each(&:call)
22
22
  end