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.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/README.md +118 -2
- data/Rakefile +12 -1
- data/Steepfile +6 -0
- data/lib/logicuit/array_as_signal_group.rb +1 -1
- data/lib/logicuit/circuits/combinational/full_adder.rb +6 -2
- data/lib/logicuit/circuits/combinational/full_adder_4bit.rb +6 -0
- data/lib/logicuit/circuits/combinational/half_adder.rb +4 -0
- data/lib/logicuit/circuits/combinational/multiplexer_2to1.rb +5 -1
- data/lib/logicuit/circuits/combinational/multiplexer_4to1.rb +5 -1
- data/lib/logicuit/circuits/sequential/d_flip_flop.rb +4 -0
- data/lib/logicuit/circuits/sequential/one_bit_cpu.rb +4 -0
- data/lib/logicuit/circuits/sequential/program_counter.rb +10 -4
- data/lib/logicuit/circuits/sequential/register_4bit.rb +6 -0
- data/lib/logicuit/circuits/td4/cpu.rb +11 -2
- data/lib/logicuit/circuits/td4/decoder.rb +9 -5
- data/lib/logicuit/circuits/td4/rom.rb +4 -0
- data/lib/logicuit/dsl.rb +21 -17
- data/lib/logicuit/gates/and.rb +5 -1
- data/lib/logicuit/gates/nand.rb +5 -1
- data/lib/logicuit/gates/not.rb +4 -0
- data/lib/logicuit/gates/or.rb +5 -1
- data/lib/logicuit/gates/xor.rb +5 -1
- data/lib/logicuit/runner.rb +1 -1
- data/lib/logicuit/signals/clock.rb +1 -1
- data/lib/logicuit/signals/signal.rb +12 -0
- data/lib/logicuit/signals/signal_group.rb +1 -1
- data/lib/logicuit/version.rb +1 -1
- data/sig/generated/logicuit/circuits/combinational/full_adder.rbs +20 -0
- data/sig/generated/logicuit/circuits/combinational/full_adder_4bit.rbs +38 -0
- data/sig/generated/logicuit/circuits/combinational/half_adder.rbs +18 -0
- data/sig/generated/logicuit/circuits/combinational/multiplexer_2to1.rbs +18 -0
- data/sig/generated/logicuit/circuits/combinational/multiplexer_4to1.rbs +24 -0
- data/sig/generated/logicuit/circuits/sequential/d_flip_flop.rbs +14 -0
- data/sig/generated/logicuit/circuits/sequential/one_bit_cpu.rbs +16 -0
- data/sig/generated/logicuit/circuits/sequential/program_counter.rbs +28 -0
- data/sig/generated/logicuit/circuits/sequential/register_4bit.rbs +28 -0
- data/sig/generated/logicuit/circuits/td4/cpu.rbs +28 -0
- data/sig/generated/logicuit/circuits/td4/decoder.rbs +32 -0
- data/sig/generated/logicuit/circuits/td4/rom.rbs +36 -0
- data/sig/generated/logicuit/gates/and.rbs +14 -0
- data/sig/generated/logicuit/gates/nand.rbs +14 -0
- data/sig/generated/logicuit/gates/not.rbs +12 -0
- data/sig/generated/logicuit/gates/or.rbs +14 -0
- data/sig/generated/logicuit/gates/xor.rbs +14 -0
- data/sig/logicuit/array_as_signal_group.rbs +11 -0
- data/sig/logicuit/dsl.rbs +35 -0
- data/sig/logicuit/runner.rbs +4 -0
- data/sig/logicuit/signals/clock.rbs +30 -0
- data/sig/logicuit/signals/signal.rbs +32 -0
- data/sig/logicuit/signals/signal_group.rbs +20 -0
- data/sig/logicuit/version.rbs +3 -0
- metadata +26 -2
- data/sig/logicuit.rbs +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 801a574ecce49e94ff390ae3e648fab2184766c7b3543226fa4d6543146e73f0
|
4
|
+
data.tar.gz: 76187c318d7e1b0852e07612ab3692ab9721213b7fb02383222567b03af6063c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c43600503050602054a4d9c43db01a645cbd019ae97cfc47db6ba17791fb4dbe10c0b98fe67140e5cfd31a2d855634f363ba735c6caad26cf9fea24b5fdfbab2
|
7
|
+
data.tar.gz: 849923282c18476e4cf8dafef57d342f1d8826ea9c5d2814c8d9b4d3d2861cde4a5899b0b4ef1765c0f0212d5bd056e4df0ee3472c88fb7085f42cba4391f325
|
data/.rubocop.yml
CHANGED
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
|
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
|
-
|
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
|
-
|
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
@@ -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
|
49
|
-
c: -> { (!cin
|
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
|
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
|
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,
|
25
|
-
[d, qd,
|
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 >>
|
30
|
-
|
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
|
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
|
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
|
12
|
-
ld0: -> { op3
|
13
|
-
ld1: -> { op3
|
14
|
-
ld2: -> { !op3
|
15
|
-
ld3: -> { !op3
|
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
|
-
|
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
|
-
|
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
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
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
|
data/lib/logicuit/gates/and.rb
CHANGED
@@ -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
|
19
|
+
outputs y: -> { a & b }
|
16
20
|
|
17
21
|
truth_table <<~TRUTH_TABLE
|
18
22
|
| A | B | Y |
|
data/lib/logicuit/gates/nand.rb
CHANGED
@@ -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
|
19
|
+
outputs y: -> { !(a & b) }
|
16
20
|
|
17
21
|
truth_table <<~TRUTH_TABLE
|
18
22
|
| A | B | Y |
|
data/lib/logicuit/gates/not.rb
CHANGED
@@ -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 }
|