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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 26c6eb8e9b1845c097a5e64604ca2c71632c8d0f98f19e0df1d642e57ad6ee7a
4
- data.tar.gz: 9e470fdd05e968fd46829a2df9a57015f40cd9460a2cef769e210d1e720c9144
3
+ metadata.gz: 8c670278d5f0547d3b3acdaa0f828731de1351c1d4148c2df2b57bae5a43a199
4
+ data.tar.gz: f84a271fd5df3767035f77ba196a84638a5214d52b71cd7151c81b18162709a5
5
5
  SHA512:
6
- metadata.gz: beb747fa8ea167b01d3a765564f1ffcf546072afe315e8c8a9bb37601409204b002011d68a737302090e5f2808c54e75fa80de87ea4d02e66037d2c2a8792b74
7
- data.tar.gz: dc144486811fc58d4ba1cda48f6fce95ed7776e7b3b059950388d3e41d8459c90e3d4500c4e0b97e9d9158654952fc1041e801c24a9b13c690f8d7c238bb5647
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
@@ -3,36 +3,25 @@
3
3
  module Logicuit
4
4
  module Gates
5
5
  # AND gate
6
- #
7
- # (A)-|
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
- @b = Signals::Signal.new(b == 1)
17
- @b.on_change << self
9
+ define_outputs y: ->(a, b) { a && b }
18
10
 
19
- @y = Signals::Signal.new(false)
20
- evaluate
21
- end
11
+ diagram <<~DIAGRAM
12
+ (A)-|
13
+ |AND|-(Y)
14
+ (B)-|
15
+ DIAGRAM
22
16
 
23
- attr_reader :a, :b, :y
24
-
25
- def evaluate
26
- a.current && b.current ? y.on : y.off
27
- end
28
-
29
- def to_s
30
- <<~CIRCUIT
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
@@ -3,29 +3,21 @@
3
3
  module Logicuit
4
4
  module Gates
5
5
  # NOT gate
6
- #
7
- # (A)-|NOT|-(Y)
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
- @y = Signals::Signal.new(false)
15
- evaluate
16
- end
9
+ define_outputs y: ->(a) { !a } # rubocop:disable Style/SymbolProc
17
10
 
18
- attr_reader :a, :y
11
+ diagram <<~DIAGRAM
12
+ (A)-|NOT|-(Y)
13
+ DIAGRAM
19
14
 
20
- def evaluate
21
- a.current ? y.off : y.on
22
- end
23
-
24
- def to_s
25
- <<~CIRCUIT
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
@@ -3,36 +3,25 @@
3
3
  module Logicuit
4
4
  module Gates
5
5
  # OR gate
6
- #
7
- # (A)-|
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
- @b = Signals::Signal.new(b == 1)
17
- @b.on_change << self
9
+ define_outputs y: ->(a, b) { a || b }
18
10
 
19
- @y = Signals::Signal.new(false)
20
- evaluate
21
- end
11
+ diagram <<~DIAGRAM
12
+ (A)-|
13
+ |OR|-(Y)
14
+ (B)-|
15
+ DIAGRAM
22
16
 
23
- attr_reader :a, :b, :y
24
-
25
- def evaluate
26
- a.current || b.current ? y.on : y.off
27
- end
28
-
29
- def to_s
30
- <<~CIRCUIT
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Logicuit
4
- VERSION = "0.1.1"
4
+ VERSION = "0.1.2"
5
5
  end
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.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-02-26 00:00:00.000000000 Z
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.2
58
+ rubygems_version: 3.6.5
57
59
  specification_version: 4
58
60
  summary: logi(c cir)cuit -> logicuit
59
61
  test_files: []