logicuit 0.1.1 → 0.1.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/README.md +8 -0
- data/lib/logicuit/base.rb +110 -0
- data/lib/logicuit/circuits/combinational/multiplexer2to1.rb +35 -0
- data/lib/logicuit/gates/and.rb +16 -27
- data/lib/logicuit/gates/not.rb +12 -20
- data/lib/logicuit/gates/or.rb +16 -27
- data/lib/logicuit/version.rb +1 -1
- data/lib/logicuit.rb +2 -0
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8c670278d5f0547d3b3acdaa0f828731de1351c1d4148c2df2b57bae5a43a199
|
4
|
+
data.tar.gz: f84a271fd5df3767035f77ba196a84638a5214d52b71cd7151c81b18162709a5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 95e3514d3a0327f43becf3066a5a9ad6ecf4dcc51af6af0dfcbf1475fe055faaa715925878422fdc268c261006ea66514b7f6ad90a721c5f0f193cd66104231a
|
7
|
+
data.tar.gz: 39f1237f88d0bcf06d8aed9b08d9e9fd0c7b6f9659c8b6843c8c320382aff5a249f82c2e180a508fb3e9dac14f7eef04d02f6ed2037d14481d6abf2b8fdd3cc6
|
data/README.md
CHANGED
@@ -18,6 +18,8 @@ gem install logicuit
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
+
This is the code to create a 1-bit CPU:
|
22
|
+
|
21
23
|
```
|
22
24
|
require "logicuit"
|
23
25
|
|
@@ -57,6 +59,12 @@ loop do
|
|
57
59
|
end
|
58
60
|
```
|
59
61
|
|
62
|
+
you can execute the following as a one-liner:
|
63
|
+
|
64
|
+
```
|
65
|
+
$ ruby -r logicuit -e 'Logicuit::Circuits::SystemLevel::OneBitCpu.run'
|
66
|
+
```
|
67
|
+
|
60
68
|
## Development
|
61
69
|
|
62
70
|
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.
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Logicuit
|
4
|
+
# base class for all gates and circuits
|
5
|
+
class Base
|
6
|
+
def initialize(*args)
|
7
|
+
@input_targets = []
|
8
|
+
@output_targets = []
|
9
|
+
define_inputs(*args)
|
10
|
+
define_outputs
|
11
|
+
evaluate
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :input_targets, :output_targets
|
15
|
+
|
16
|
+
def self.define_inputs(*inputs) # rubocop:disable Metrics/MethodLength
|
17
|
+
inputs.each do |input|
|
18
|
+
define_method(input) do
|
19
|
+
instance_variable_get("@#{input}")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
define_method(:define_inputs) do |*args|
|
24
|
+
inputs.each_with_index do |input, index|
|
25
|
+
signal = Signals::Signal.new(args[index] == 1)
|
26
|
+
signal.on_change << self
|
27
|
+
instance_variable_set("@#{input}", signal)
|
28
|
+
@input_targets << input
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.define_outputs(**outputs) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
|
34
|
+
outputs.each_key do |output|
|
35
|
+
define_method(output) do
|
36
|
+
instance_variable_get("@#{output}")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
define_method(:define_outputs) do
|
41
|
+
outputs.each_key do |output|
|
42
|
+
instance_variable_set("@#{output}", Signals::Signal.new(false))
|
43
|
+
@output_targets << output
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
define_method(:evaluate) do
|
48
|
+
outputs.each do |output, evaluator|
|
49
|
+
signal = instance_variable_get("@#{output}")
|
50
|
+
if evaluator.call(*@input_targets.map do |input|
|
51
|
+
instance_variable_get("@#{input}").current
|
52
|
+
end)
|
53
|
+
signal.on
|
54
|
+
else
|
55
|
+
signal.off
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.diagram(source)
|
62
|
+
define_method(:to_s) do
|
63
|
+
(@input_targets + @output_targets).reduce(source) do |result, input|
|
64
|
+
result.gsub(/\(#{input}\)/i, "(#{instance_variable_get("@#{input}")})#{"-" * (input.size - 1)}")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.truth_table(source) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
|
70
|
+
define_method(:truth_table) do # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity,Metrics/BlockLength
|
71
|
+
rows = source.strip.split("\n")
|
72
|
+
headers = rows.shift.split("|").map(&:strip).reject(&:empty?).map(&:downcase).map(&:to_sym)
|
73
|
+
rows.shift # devide line
|
74
|
+
table = rows.map do |row|
|
75
|
+
row.split("|").map(&:strip).reject(&:empty?).map(&:downcase).map do |v|
|
76
|
+
case v
|
77
|
+
when "x"
|
78
|
+
:any
|
79
|
+
when "1"
|
80
|
+
true
|
81
|
+
when "0"
|
82
|
+
false
|
83
|
+
else
|
84
|
+
raise "Invalid value in truth table: #{v}"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end.select do |values| # rubocop:disable Style/MultilineBlockChain
|
88
|
+
headers.size == values.size
|
89
|
+
end.map do |values| # rubocop:disable Style/MultilineBlockChain
|
90
|
+
array = [values]
|
91
|
+
while array.any? { |values| values.any? { |v| v == :any } }
|
92
|
+
target_index = array.find_index { |values| values.any? { |v| v == :any } }
|
93
|
+
target = array[target_index]
|
94
|
+
prop_index = target.find_index { |v| v == :any }
|
95
|
+
array.delete_at(target_index)
|
96
|
+
array.insert(target_index, *[true, false].map do |v|
|
97
|
+
target.dup.tap do |a|
|
98
|
+
a[prop_index] = v
|
99
|
+
end
|
100
|
+
end)
|
101
|
+
end
|
102
|
+
array
|
103
|
+
end.flatten!(1).map do |values| # rubocop:disable Style/MultilineBlockChain
|
104
|
+
headers.zip(values).to_h
|
105
|
+
end
|
106
|
+
table
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Logicuit
|
4
|
+
module Circuits
|
5
|
+
module Combinational
|
6
|
+
# A Multiplexer with 2 inputs and 1 output
|
7
|
+
class Multiplexer2To1 < Base
|
8
|
+
define_inputs :c0, :c1, :a
|
9
|
+
|
10
|
+
define_outputs y: lambda { |c0, c1, a|
|
11
|
+
(c0 && !a) || (c1 && a)
|
12
|
+
}
|
13
|
+
|
14
|
+
diagram <<~DIAGRAM
|
15
|
+
(C0)---------|
|
16
|
+
|AND|--+
|
17
|
+
+-|NOT|-| +--|
|
18
|
+
| |OR|--(Y)
|
19
|
+
(C1)---------| +--|
|
20
|
+
| |AND|--+
|
21
|
+
(A)--+-------|
|
22
|
+
DIAGRAM
|
23
|
+
|
24
|
+
truth_table <<~TRUTH_TABLE
|
25
|
+
| C0 | C1 | A | Y |
|
26
|
+
| -- | -- | - | - |
|
27
|
+
| 0 | x | 0 | 0 |
|
28
|
+
| 1 | x | 0 | 1 |
|
29
|
+
| x | 0 | 1 | 0 |
|
30
|
+
| x | 1 | 1 | 1 |
|
31
|
+
TRUTH_TABLE
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/logicuit/gates/and.rb
CHANGED
@@ -3,36 +3,25 @@
|
|
3
3
|
module Logicuit
|
4
4
|
module Gates
|
5
5
|
# AND gate
|
6
|
-
|
7
|
-
|
8
|
-
# |AND|-(Y)
|
9
|
-
# (B)-|
|
10
|
-
#
|
11
|
-
class And
|
12
|
-
def initialize(a = 0, b = 0) # rubocop:disable Naming/MethodParameterName
|
13
|
-
@a = Signals::Signal.new(a == 1)
|
14
|
-
@a.on_change << self
|
6
|
+
class And < Base
|
7
|
+
define_inputs :a, :b
|
15
8
|
|
16
|
-
|
17
|
-
@b.on_change << self
|
9
|
+
define_outputs y: ->(a, b) { a && b }
|
18
10
|
|
19
|
-
|
20
|
-
|
21
|
-
|
11
|
+
diagram <<~DIAGRAM
|
12
|
+
(A)-|
|
13
|
+
|AND|-(Y)
|
14
|
+
(B)-|
|
15
|
+
DIAGRAM
|
22
16
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
(#{a})-|
|
32
|
-
|AND|-(#{y})
|
33
|
-
(#{b})-|
|
34
|
-
CIRCUIT
|
35
|
-
end
|
17
|
+
truth_table <<~TRUTH_TABLE
|
18
|
+
| A | B | Y |
|
19
|
+
| - | - | - |
|
20
|
+
| 0 | 0 | 0 |
|
21
|
+
| 1 | 0 | 0 |
|
22
|
+
| 0 | 1 | 0 |
|
23
|
+
| 1 | 1 | 1 |
|
24
|
+
TRUTH_TABLE
|
36
25
|
end
|
37
26
|
end
|
38
27
|
end
|
data/lib/logicuit/gates/not.rb
CHANGED
@@ -3,29 +3,21 @@
|
|
3
3
|
module Logicuit
|
4
4
|
module Gates
|
5
5
|
# NOT gate
|
6
|
-
|
7
|
-
|
8
|
-
#
|
9
|
-
class Not
|
10
|
-
def initialize(a = 0) # rubocop:disable Naming/MethodParameterName
|
11
|
-
@a = Signals::Signal.new(a == 1)
|
12
|
-
@a.on_change << self
|
6
|
+
class Not < Base
|
7
|
+
define_inputs :a
|
13
8
|
|
14
|
-
|
15
|
-
evaluate
|
16
|
-
end
|
9
|
+
define_outputs y: ->(a) { !a } # rubocop:disable Style/SymbolProc
|
17
10
|
|
18
|
-
|
11
|
+
diagram <<~DIAGRAM
|
12
|
+
(A)-|NOT|-(Y)
|
13
|
+
DIAGRAM
|
19
14
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
(#{a})-|NOT|-(#{y})
|
27
|
-
CIRCUIT
|
28
|
-
end
|
15
|
+
truth_table <<~TRUTH_TABLE
|
16
|
+
| A | Y |
|
17
|
+
| - | - |
|
18
|
+
| 0 | 1 |
|
19
|
+
| 1 | 0 |
|
20
|
+
TRUTH_TABLE
|
29
21
|
end
|
30
22
|
end
|
31
23
|
end
|
data/lib/logicuit/gates/or.rb
CHANGED
@@ -3,36 +3,25 @@
|
|
3
3
|
module Logicuit
|
4
4
|
module Gates
|
5
5
|
# OR gate
|
6
|
-
|
7
|
-
|
8
|
-
# |OR|-(Y)
|
9
|
-
# (B)-|
|
10
|
-
#
|
11
|
-
class Or
|
12
|
-
def initialize(a = 0, b = 0) # rubocop:disable Naming/MethodParameterName
|
13
|
-
@a = Signals::Signal.new(a == 1)
|
14
|
-
@a.on_change << self
|
6
|
+
class Or < Base
|
7
|
+
define_inputs :a, :b
|
15
8
|
|
16
|
-
|
17
|
-
@b.on_change << self
|
9
|
+
define_outputs y: ->(a, b) { a || b }
|
18
10
|
|
19
|
-
|
20
|
-
|
21
|
-
|
11
|
+
diagram <<~DIAGRAM
|
12
|
+
(A)-|
|
13
|
+
|OR|-(Y)
|
14
|
+
(B)-|
|
15
|
+
DIAGRAM
|
22
16
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
(#{a})-|
|
32
|
-
|OR|-(#{y})
|
33
|
-
(#{b})-|
|
34
|
-
CIRCUIT
|
35
|
-
end
|
17
|
+
truth_table <<~TRUTH_TABLE
|
18
|
+
| A | B | Y |
|
19
|
+
| - | - | - |
|
20
|
+
| 0 | 0 | 0 |
|
21
|
+
| 1 | 0 | 1 |
|
22
|
+
| 0 | 1 | 1 |
|
23
|
+
| 1 | 1 | 1 |
|
24
|
+
TRUTH_TABLE
|
36
25
|
end
|
37
26
|
end
|
38
27
|
end
|
data/lib/logicuit/version.rb
CHANGED
data/lib/logicuit.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative "logicuit/version"
|
4
|
+
require_relative "logicuit/base"
|
4
5
|
require_relative "logicuit/gates/and"
|
5
6
|
require_relative "logicuit/gates/or"
|
6
7
|
require_relative "logicuit/gates/not"
|
7
8
|
require_relative "logicuit/signals/signal"
|
8
9
|
require_relative "logicuit/signals/clock"
|
9
10
|
require_relative "logicuit/circuits/sequential/d_flip_flop"
|
11
|
+
require_relative "logicuit/circuits/combinational/multiplexer2to1"
|
10
12
|
require_relative "logicuit/circuits/system_level/one_bit_cpu"
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logicuit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Koji NAKAMURA
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-03-09 00:00:00.000000000 Z
|
11
11
|
dependencies: []
|
12
12
|
description: logi(c cir)cuit -> logicuit
|
13
13
|
email:
|
@@ -21,7 +21,9 @@ files:
|
|
21
21
|
- README.md
|
22
22
|
- Rakefile
|
23
23
|
- lib/logicuit.rb
|
24
|
+
- lib/logicuit/base.rb
|
24
25
|
- lib/logicuit/circuits/combinational/half_adder.rb
|
26
|
+
- lib/logicuit/circuits/combinational/multiplexer2to1.rb
|
25
27
|
- lib/logicuit/circuits/sequential/d_flip_flop.rb
|
26
28
|
- lib/logicuit/circuits/system_level/one_bit_cpu.rb
|
27
29
|
- lib/logicuit/gates/and.rb
|
@@ -53,7 +55,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
53
55
|
- !ruby/object:Gem::Version
|
54
56
|
version: '0'
|
55
57
|
requirements: []
|
56
|
-
rubygems_version: 3.6.
|
58
|
+
rubygems_version: 3.6.5
|
57
59
|
specification_version: 4
|
58
60
|
summary: logi(c cir)cuit -> logicuit
|
59
61
|
test_files: []
|