logicuit 0.3.1 → 0.4.0

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 +118 -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: 801a574ecce49e94ff390ae3e648fab2184766c7b3543226fa4d6543146e73f0
4
+ data.tar.gz: 76187c318d7e1b0852e07612ab3692ab9721213b7fb02383222567b03af6063c
5
5
  SHA512:
6
- metadata.gz: 3e942269a9b55dad3f7efff1d68935f431952d0c3276d7d290461dabe84230f6d6d1d0eb2f307b6dd375c2d3b1261c8e2e7c72f1faa17db0de576cee9c37c0da
7
- data.tar.gz: 3f1428cced00eee1798ea56dc9cfb169eb041b40bfc514a729d1cd3d67ce4b05d93ea633a9290c3ac22432aa1bfeb384e8de20cee59a0e463c582bf82be61ea4
6
+ metadata.gz: c43600503050602054a4d9c43db01a645cbd019ae97cfc47db6ba17791fb4dbe10c0b98fe67140e5cfd31a2d855634f363ba735c6caad26cf9fea24b5fdfbab2
7
+ data.tar.gz: 849923282c18476e4cf8dafef57d342f1d8826ea9c5d2814c8d9b4d3d2861cde4a5899b0b4ef1765c0f0212d5bd056e4df0ee3472c88fb7085f42cba4391f325
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)
@@ -67,12 +68,16 @@ You can define inputs, outputs, and even a visual diagram — all within a Ruby
67
68
  Here is an example of a simple 2-input AND gate:
68
69
 
69
70
  ```ruby
71
+ # rbs_inline: enabled
72
+
70
73
  require "logicuit"
71
74
 
72
75
  class MyAndGate < Logicuit::DSL
76
+ attr_reader :a, :b, :y #: Logicuit::Signals::Signal
77
+
73
78
  inputs :a, :b
74
79
 
75
- outputs y: -> { a && b }
80
+ outputs y: -> { a & b }
76
81
 
77
82
  diagram <<~DIAGRAM
78
83
  (A)-| |
@@ -90,6 +95,19 @@ This defines:
90
95
  - one output (`y`) that returns the logical AND of the inputs,
91
96
  - and an ASCII diagram that shows the structure of the gate.
92
97
 
98
+ ### About signals and logical operations
99
+
100
+ Inputs and outputs in Logicuit are not plain booleans — they are instances of the `Logicuit::Signals::Signal` class.
101
+ The `Signal` class provides methods like `&`, `|`, and `!` to represent logical AND, OR, and NOT operations, respectively.
102
+
103
+ For example:
104
+
105
+ ```ruby
106
+ outputs y: -> { (a & b) | !a }
107
+ ```
108
+
109
+ This allows logic expressions to look natural and circuit-like while supporting chaining and composition.
110
+
93
111
  ### Interactive execution
94
112
 
95
113
  When you call `run`, the simulator enters an interactive mode.
@@ -119,9 +137,13 @@ This approach gives you more control and expressiveness when building complex ci
119
137
  Here's an example of a 2-to-1 multiplexer:
120
138
 
121
139
  ```ruby
140
+ # rbs_inline: enabled
141
+
122
142
  require "logicuit"
123
143
 
124
144
  class MyMultiplexer < Logicuit::DSL
145
+ attr_reader :c0, :c1, :a, :y #: Logicuit::Signals::Signal
146
+
125
147
  inputs :c0, :c1, :a
126
148
 
127
149
  outputs :y
@@ -254,9 +276,13 @@ In addition to combinational circuits, Logicuit also supports sequential circuit
254
276
  For example, here’s a D flip-flop:
255
277
 
256
278
  ```ruby
279
+ # rbs_inline: enabled
280
+
257
281
  require "logicuit"
258
282
 
259
283
  class MyDFlipFlop < Logicuit::DSL
284
+ attr_reader :d, :q #: Logicuit::Signals::Signal
285
+
260
286
  inputs :d, clock: :ck
261
287
 
262
288
  outputs q: -> { d }
@@ -325,9 +351,13 @@ You can build sequential circuits out of smaller components using the `assemblin
325
351
  Here’s an example of a 4-bit register that stores its input when the load signal `ld` is not active:
326
352
 
327
353
  ```ruby
354
+ # rbs_inline: enabled
355
+
328
356
  require "logicuit"
329
357
 
330
358
  class MyRegister4bit < Logicuit::DSL
359
+ attr_reader :a, :b, :c, :d, :ld, :qa, :qb, :qc, :qd #: Logicuit::Signals::Signal
360
+
331
361
  inputs :a, :b, :c, :d, :ld, clock: :ck
332
362
 
333
363
  outputs :qa, :qb, :qc, :qd
@@ -383,7 +413,93 @@ inputs ..., clock: :ck
383
413
 
384
414
  > 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
415
 
386
- ### Demo: Ramen Timer
416
+ ## Truth Table Verification
417
+
418
+ You can attach a truth table to your circuit class using the `#truth_table`. The truth table should be written in Markdown table format.
419
+
420
+ ```ruby
421
+ # rbs_inline: enabled
422
+
423
+ require "logicuit"
424
+
425
+ class MyAndGate < Logicuit::DSL
426
+ attr_reader :a, :b, :y #: Logicuit::Signals::Signal
427
+
428
+ inputs :a, :b
429
+
430
+ outputs y: -> { a & b }
431
+
432
+ diagram <<~DIAGRAM
433
+ (A)-| |
434
+ |AND|-(Y)
435
+ (B)-| |
436
+ DIAGRAM
437
+
438
+ truth_table <<~TRUTH_TABLE
439
+ | A | B | Y |
440
+ | - | - | - |
441
+ | 0 | 0 | 0 |
442
+ | 1 | 0 | 0 |
443
+ | 0 | 1 | 0 |
444
+ | 1 | 1 | 1 |
445
+ TRUTH_TABLE
446
+ end
447
+
448
+ MyAndGate.verify_against_truth_table
449
+ ```
450
+
451
+ 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.
452
+
453
+ If the behavior of the circuit doesn't match the truth table, you'll see an error like this:
454
+
455
+ ```
456
+ MyAndGate.new(0, 1).y should be 0 (RuntimeError)
457
+ ```
458
+
459
+ This feature is useful for validating your logic circuits against formal truth tables as part of development or testing workflows.
460
+
461
+ ### Verifying sequential circuits
462
+
463
+ Sequential circuits can also be verified using truth tables. When verifying a sequential circuit, the symbol `^` represents the rising edge of the clock.
464
+
465
+ Here’s an example for a D flip-flop:
466
+
467
+ ```ruby
468
+ # rbs_inline: enabled
469
+
470
+ class MyDFlipFlop < Logicuit::DSL
471
+ attr_reader :d, :q #: Logicuit::Signals::Signal
472
+
473
+ inputs :d, clock: :ck
474
+
475
+ outputs q: -> { d }
476
+
477
+ diagram <<~DIAGRAM
478
+ (D)--| |--(Q)
479
+ |DFF|
480
+ (CK)-|> |
481
+ DIAGRAM
482
+
483
+ truth_table <<~TRUTH_TABLE
484
+ | CK | D | Q |
485
+ | -- | - | - |
486
+ | ^ | 0 | 0 |
487
+ | ^ | 1 | 1 |
488
+ TRUTH_TABLE
489
+ end
490
+
491
+ MyDFlipFlop.verify_against_truth_table
492
+ ```
493
+
494
+ In this table:
495
+
496
+ - The `CK` column uses `^` to indicate a clock tick.
497
+ - The circuit is initialized with the given inputs, then the clock is ticked once.
498
+ - The outputs are evaluated immediately after the tick and compared against the expected values.
499
+
500
+ This mechanism makes it easy to specify and verify the behavior of memory elements and registers.
501
+
502
+ ## Demo: Ramen Timer
387
503
 
388
504
  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
505
 
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 }