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.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -2
- data/README.md +161 -14
- 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 +6 -4
- data/lib/logicuit/dsl.rb +47 -18
- 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 +7 -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 +28 -4
- 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: 7ab72694854386c09ba2b86561b6f71f96ea150cbc75384cac6b367a1ef77678
|
4
|
+
data.tar.gz: 033acc2d10c17e90f32dae9af915e92fd81064c88ff8174842821676b5d11fa4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
-
|
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
|
@@ -12,7 +16,7 @@ module Logicuit
|
|
12
16
|
def evaluate
|
13
17
|
return unless initialized
|
14
18
|
|
15
|
-
output = case
|
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
|
-
|
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
|