logicuit 0.3.0 → 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 -2
  3. data/README.md +161 -14
  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 +6 -4
  19. data/lib/logicuit/dsl.rb +47 -18
  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 +7 -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 +28 -4
  55. data/sig/logicuit.rbs +0 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 51ce3fab568abef949848bf4f1cb8c8dbe3f0f80da773b9f6f48ea374e21c376
4
- data.tar.gz: 787d8ae4a61d770bba76612b5a7ffffbee750dfe0d645dae4a89c57e130ecdc1
3
+ metadata.gz: 7ab72694854386c09ba2b86561b6f71f96ea150cbc75384cac6b367a1ef77678
4
+ data.tar.gz: 033acc2d10c17e90f32dae9af915e92fd81064c88ff8174842821676b5d11fa4
5
5
  SHA512:
6
- metadata.gz: 28dcfd69c6f889c27283f46928dabcf178ba0113609f36895ab4e10642e36eff631070573946b5d5c7dd4ab06180d7b5649e524d855c977ab361d20675ece5b6
7
- data.tar.gz: 4b253121ffffc6d0f06e53f07c23bde1bc371c91b2217ba91cfe46fd134376b0c2c0dac7146afad73d12f02a8a7fc1d0ad1242c85a11888a1b00434a63c5ceaf
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
 
@@ -31,6 +34,4 @@ Metrics:
31
34
 
32
35
  plugins:
33
36
  - rubocop-minitest
34
-
35
- require:
36
37
  - rubocop-rake
data/README.md CHANGED
@@ -1,9 +1,51 @@
1
1
  # Logicuit
2
2
 
3
+ ```
4
+ ******* ******* *******
5
+ ********* ********* *********
6
+ *********** *********** ***********
7
+ ********* ********* *********
8
+ ******* ******* *******
9
+
10
+ +-----------------------------------------------+ OUT 0111
11
+ | | ADD A,0001
12
+ +--->|rg_a|(0111)----->| | | JNC 0001
13
+ | |1000| | | | ADD A,0001
14
+ | | | | > JNC 0011
15
+ +--->|rg_b|(0000)----->| |----------->| |---+ OUT 0110
16
+ | |0000| | | | | ADD A,0001
17
+ | |SEL| |ALU| JNC 0110
18
+ +--->| out| | in|--->| | | | ADD A,0001
19
+ | |0111| |0000| | | | im|--->| |--(0) JNC 1000
20
+ | | | |0011| OUT 0000
21
+ +--->| pc| (0000)--->| | OUT 0100
22
+ |0100| ADD A,0001
23
+ JNC 1010
24
+ OUT 1000
25
+ JMP 1111
26
+
27
+ tick: 48
28
+ input: in0,in1,in2,in3?
29
+ ```
30
+
3
31
  From logic circuit to Logicuit — a playful portmanteau.
4
32
 
5
33
  A Ruby-based logic circuit simulator featuring an internal DSL for building circuits.
6
34
 
35
+ ## Table of Contents
36
+
37
+ - [Installation](#installation)
38
+ - [DSL](#dsl)
39
+ - [Interactive Execution](#interactive-execution)
40
+ - [Assembling](#assembling)
41
+ - [SignalGroup](#signalgroup)
42
+ - [Sequential Circuits](#sequential-circuits)
43
+ - [Truth Table Verification](#truth-table-verification)
44
+ - [Demo: Ramen Timer](#demo-ramen-timer)
45
+ - [Development](#development)
46
+ - [Contributing](#contributing)
47
+ - [License](#license)
48
+
7
49
  ## Installation
8
50
 
9
51
  Install the gem and add to the application's Gemfile by executing:
@@ -25,13 +67,13 @@ You can define inputs, outputs, and even a visual diagram — all within a Ruby
25
67
 
26
68
  Here is an example of a simple 2-input AND gate:
27
69
 
28
- ```
70
+ ```ruby
29
71
  require "logicuit"
30
72
 
31
73
  class MyAndGate < Logicuit::DSL
32
74
  inputs :a, :b
33
75
 
34
- outputs y: -> { a && b }
76
+ outputs y: -> { a & b }
35
77
 
36
78
  diagram <<~DIAGRAM
37
79
  (A)-| |
@@ -49,6 +91,19 @@ This defines:
49
91
  - one output (`y`) that returns the logical AND of the inputs,
50
92
  - and an ASCII diagram that shows the structure of the gate.
51
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
+
52
107
  ### Interactive execution
53
108
 
54
109
  When you call `run`, the simulator enters an interactive mode.
@@ -77,7 +132,7 @@ This approach gives you more control and expressiveness when building complex ci
77
132
 
78
133
  Here's an example of a 2-to-1 multiplexer:
79
134
 
80
- ```
135
+ ```ruby
81
136
  require "logicuit"
82
137
 
83
138
  class MyMultiplexer < Logicuit::DSL
@@ -125,7 +180,7 @@ This allows the code to resemble the actual structure of the circuit, making it
125
180
 
126
181
  For example:
127
182
 
128
- ```
183
+ ```ruby
129
184
  a >> not_gate.a
130
185
  not_gate.y >> and_gate1.b
131
186
  ```
@@ -156,14 +211,14 @@ Logicuit provides a convenient way to express these kinds of connections using s
156
211
 
157
212
  These two lines:
158
213
 
159
- ```
214
+ ```ruby
160
215
  a >> xor_gate.a
161
216
  a >> and_gate.a
162
217
  ```
163
218
 
164
219
  can be written more concisely as:
165
220
 
166
- ```
221
+ ```ruby
167
222
  a >> [xor_gate.a, and_gate.a]
168
223
  ```
169
224
 
@@ -173,7 +228,7 @@ The array on the right-hand side is treated as a signal group, and the connectio
173
228
 
174
229
  You can also connect multiple outputs to multiple inputs at once by using the [] method to access signals by name:
175
230
 
176
- ```
231
+ ```ruby
177
232
  pc.qa >> rom.a0
178
233
  pc.qb >> rom.a1
179
234
  pc.qc >> rom.a2
@@ -182,7 +237,7 @@ pc.qd >> rom.a3
182
237
 
183
238
  is equivalent to:
184
239
 
185
- ```
240
+ ```ruby
186
241
  pc[:qa, :qb, :qc, :qd] >> rom[:a0, :a1, :a2, :a3]
187
242
  ```
188
243
 
@@ -196,7 +251,7 @@ What if you want to connect signals from multiple different components as a sing
196
251
 
197
252
  You can use `Logicuit::ArrayAsSignalGroup`, which adds signal group behavior to arrays:
198
253
 
199
- ```
254
+ ```ruby
200
255
  using Logicuit::ArrayAsSignalGroup
201
256
 
202
257
  assembling do
@@ -212,7 +267,7 @@ In addition to combinational circuits, Logicuit also supports sequential circuit
212
267
 
213
268
  For example, here’s a D flip-flop:
214
269
 
215
- ```
270
+ ```ruby
216
271
  require "logicuit"
217
272
 
218
273
  class MyDFlipFlop < Logicuit::DSL
@@ -261,7 +316,7 @@ The number of elapsed ticks is shown as `tick: N`.
261
316
 
262
317
  By default, the clock ticks at 1 Hz (once per second). You can change the frequency by passing the `hz:` option to `run`:
263
318
 
264
- ```
319
+ ```ruby
265
320
  MyDFlipFlop.run(hz: 10)
266
321
  ```
267
322
 
@@ -271,7 +326,7 @@ If you want full control, you can set `hz: 0` to disable automatic ticking.
271
326
 
272
327
  In this mode, the clock only ticks when you press Enter, allowing you to step through the simulation manually:
273
328
 
274
- ```
329
+ ```ruby
275
330
  MyDFlipFlop.run(hz: 0)
276
331
  ```
277
332
 
@@ -283,7 +338,7 @@ You can build sequential circuits out of smaller components using the `assemblin
283
338
 
284
339
  Here’s an example of a 4-bit register that stores its input when the load signal `ld` is not active:
285
340
 
286
- ```
341
+ ```ruby
287
342
  require "logicuit"
288
343
 
289
344
  class MyRegister4bit < Logicuit::DSL
@@ -336,12 +391,104 @@ If your circuit contains one or more sequential components (such as D flip-flops
336
391
 
337
392
  The clock signal is automatically connected to all internal sequential components. You don't need to wire it manually — just declare it at the top level:
338
393
 
339
- ```
394
+ ```ruby
340
395
  inputs ..., clock: :ck
341
396
  ```
342
397
 
343
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.
344
399
 
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
479
+
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).
481
+
482
+ You can try it out by running:
483
+
484
+ ```
485
+ ruby -r logicuit -e 'Logicuit::Circuits::Td4::Cpu.run'
486
+ ```
487
+
488
+ This launches a fully functional CPU simulation that counts down from a programmed value — perfect for timing your instant ramen 🍜
489
+
490
+ The TD4 CPU is built entirely from logic gates and flip-flops, assembled using Logicuit’s DSL. It’s a great demonstration of how small components can be combined to create a complete digital system.
491
+
345
492
  ## Development
346
493
 
347
494
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
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
@@ -12,7 +16,7 @@ module Logicuit
12
16
  def evaluate
13
17
  return unless initialized
14
18
 
15
- output = case "#{a3}#{a2}#{a1}#{a0}"
19
+ output = case self[:a3, :a2, :a1, :a0].to_s
16
20
  in "0000" then "10110111"
17
21
  in "0001" then "00000001"
18
22
  in "0010" then "11100001"
@@ -30,9 +34,7 @@ module Logicuit
30
34
  in "1110" then "10111000"
31
35
  in "1111" then "11111111"
32
36
  end
33
- output.split("").zip([d7, d6, d5, d4, d3, d2, d1, d0]).each do |v, o|
34
- v == "1" ? o.on : o.off
35
- end
37
+ self[:d7, :d6, :d5, :d4, :d3, :d2, :d1, :d0].set output
36
38
  end
37
39
 
38
40
  truth_table <<~TRUTH_TABLE