logicuit 0.1.5 → 0.3.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.
@@ -4,47 +4,54 @@ module Logicuit
4
4
  module Signals
5
5
  # Signal
6
6
  class Signal
7
- def initialize(current = false) # rubocop:disable Style/OptionalBooleanParameter
7
+ def initialize(current = false)
8
8
  @current = current
9
- @connected_by = nil
10
- @on_change = []
9
+ @downstreams = []
11
10
  end
12
11
 
13
- attr_reader :current, :on_change
14
- attr_accessor :connected_by
12
+ attr_reader :current
15
13
 
16
14
  def on
17
- changed = @current.!
15
+ return if @current
16
+
18
17
  @current = true
19
- @on_change.each(&:evaluate) if changed
18
+ propagate_current
20
19
  end
21
20
 
22
21
  def off
23
- changed = @current
24
- @current = false
25
- @on_change.each(&:evaluate) if changed
26
- end
22
+ return unless @current
27
23
 
28
- def toggle
29
- @current ? off : on
24
+ @current = false
25
+ propagate_current
30
26
  end
31
27
 
32
28
  def connects_to(other)
33
- other.connected_by = self
34
- other.evaluate
35
- on_change << other
29
+ if other.is_a? Array
30
+ @downstreams.concat(other)
31
+ elsif other.is_a? Signals::SignalGroup
32
+ @downstreams.concat(other.signals)
33
+ else
34
+ @downstreams << other
35
+ end
36
+ propagate_current
36
37
  end
37
38
  alias >> connects_to
38
39
 
39
- def evaluate
40
- return if @connected_by.nil?
41
-
42
- @connected_by.current ? on : off
43
- end
44
-
45
40
  def to_s
46
41
  current ? "1" : "0"
47
42
  end
43
+
44
+ private
45
+
46
+ def propagate_current
47
+ @downstreams.each do |downstream|
48
+ if downstream.is_a?(Signal)
49
+ current ? downstream.on : downstream.off
50
+ elsif downstream.respond_to?(:evaluate)
51
+ downstream.evaluate
52
+ end
53
+ end
54
+ end
48
55
  end
49
56
  end
50
57
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Logicuit
4
+ module Signals
5
+ # Signal Group
6
+ class SignalGroup
7
+ def initialize(*signals)
8
+ @signals = signals
9
+ end
10
+
11
+ def signals
12
+ @signals.dup
13
+ end
14
+
15
+ def connects_to(others)
16
+ others = others.signals if others.is_a?(SignalGroup)
17
+ @signals.zip(others).each { _1 >> _2 unless _1.nil? || _2.nil? }
18
+ end
19
+ alias >> connects_to
20
+
21
+ def to_s
22
+ signals.map { it.current ? "1" : "0" }.join
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Logicuit
4
- VERSION = "0.1.5"
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/logicuit.rb CHANGED
@@ -1,16 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "logicuit/version"
4
- require_relative "logicuit/base"
4
+ require_relative "logicuit/dsl"
5
+ require_relative "logicuit/array_as_signal_group"
6
+ require_relative "logicuit/runner"
5
7
  require_relative "logicuit/gates/and"
6
8
  require_relative "logicuit/gates/or"
7
9
  require_relative "logicuit/gates/not"
8
10
  require_relative "logicuit/gates/nand"
9
11
  require_relative "logicuit/gates/xor"
10
12
  require_relative "logicuit/signals/signal"
13
+ require_relative "logicuit/signals/signal_group"
11
14
  require_relative "logicuit/signals/clock"
12
- require_relative "logicuit/circuits/sequential/d_flip_flop"
13
- require_relative "logicuit/circuits/combinational/multiplexer2to1"
14
- require_relative "logicuit/circuits/combinational/multiplexer4to1"
15
+ require_relative "logicuit/circuits/combinational/multiplexer_2to1"
16
+ require_relative "logicuit/circuits/combinational/multiplexer_4to1"
15
17
  require_relative "logicuit/circuits/combinational/half_adder"
16
- require_relative "logicuit/circuits/system_level/one_bit_cpu"
18
+ require_relative "logicuit/circuits/combinational/full_adder"
19
+ require_relative "logicuit/circuits/combinational/full_adder_4bit"
20
+ require_relative "logicuit/circuits/sequential/d_flip_flop"
21
+ require_relative "logicuit/circuits/sequential/register_4bit"
22
+ require_relative "logicuit/circuits/sequential/program_counter"
23
+ require_relative "logicuit/circuits/sequential/one_bit_cpu"
24
+ require_relative "logicuit/circuits/td4/cpu"
25
+ require_relative "logicuit/circuits/td4/decoder"
26
+ require_relative "logicuit/circuits/td4/rom"
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.5
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Koji NAKAMURA
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-03-15 00:00:00.000000000 Z
10
+ date: 2025-04-19 00:00:00.000000000 Z
11
11
  dependencies: []
12
12
  description: logi(c cir)cuit -> logicuit
13
13
  email:
@@ -21,19 +21,29 @@ files:
21
21
  - README.md
22
22
  - Rakefile
23
23
  - lib/logicuit.rb
24
- - lib/logicuit/base.rb
24
+ - lib/logicuit/array_as_signal_group.rb
25
+ - lib/logicuit/circuits/combinational/full_adder.rb
26
+ - lib/logicuit/circuits/combinational/full_adder_4bit.rb
25
27
  - lib/logicuit/circuits/combinational/half_adder.rb
26
- - lib/logicuit/circuits/combinational/multiplexer2to1.rb
27
- - lib/logicuit/circuits/combinational/multiplexer4to1.rb
28
+ - lib/logicuit/circuits/combinational/multiplexer_2to1.rb
29
+ - lib/logicuit/circuits/combinational/multiplexer_4to1.rb
28
30
  - lib/logicuit/circuits/sequential/d_flip_flop.rb
29
- - lib/logicuit/circuits/system_level/one_bit_cpu.rb
31
+ - lib/logicuit/circuits/sequential/one_bit_cpu.rb
32
+ - lib/logicuit/circuits/sequential/program_counter.rb
33
+ - lib/logicuit/circuits/sequential/register_4bit.rb
34
+ - lib/logicuit/circuits/td4/cpu.rb
35
+ - lib/logicuit/circuits/td4/decoder.rb
36
+ - lib/logicuit/circuits/td4/rom.rb
37
+ - lib/logicuit/dsl.rb
30
38
  - lib/logicuit/gates/and.rb
31
39
  - lib/logicuit/gates/nand.rb
32
40
  - lib/logicuit/gates/not.rb
33
41
  - lib/logicuit/gates/or.rb
34
42
  - lib/logicuit/gates/xor.rb
43
+ - lib/logicuit/runner.rb
35
44
  - lib/logicuit/signals/clock.rb
36
45
  - lib/logicuit/signals/signal.rb
46
+ - lib/logicuit/signals/signal_group.rb
37
47
  - lib/logicuit/version.rb
38
48
  - sig/logicuit.rbs
39
49
  homepage: https://github.com/kozy4324/logicuit
data/lib/logicuit/base.rb DELETED
@@ -1,172 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Logicuit module
4
- module Logicuit
5
- # base class for all gates and circuits
6
- class Base # rubocop:disable Metrics/ClassLength
7
- def self.tag(*tags)
8
- tags.each do |tag|
9
- registry[tag] = self
10
- end
11
- end
12
-
13
- @@registry = {} # rubocop:disable Style/ClassVars
14
-
15
- def self.registry
16
- @@registry
17
- end
18
-
19
- def initialize(*args)
20
- @input_targets = []
21
- @output_targets = []
22
- @clock = false
23
- define_inputs(*args) if respond_to?(:define_inputs)
24
- define_outputs if respond_to?(:define_outputs)
25
- assembling if respond_to?(:assembling)
26
- evaluate if respond_to?(:evaluate)
27
- end
28
-
29
- attr_reader :input_targets, :output_targets, :clock
30
-
31
- def self.define_inputs(*args, **kwargs) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
32
- args.each do |input|
33
- define_method(input) do
34
- instance_variable_get("@#{input}")
35
- end
36
- end
37
-
38
- define_method(:define_inputs) do |*instance_method_args|
39
- instance_variable_set("@clock", true) if kwargs&.key?(:clock)
40
- args.each_with_index do |input, index|
41
- signal = Signals::Signal.new(instance_method_args[index] == 1)
42
- signal.on_change << self unless clock
43
- instance_variable_set("@#{input}", signal)
44
- @input_targets << input
45
- end
46
- Signals::Clock.on_tick << self if clock
47
- end
48
- end
49
-
50
- def self.define_outputs(*args, **kwargs) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
51
- (args + kwargs.keys).each do |output|
52
- define_method(output) do
53
- instance_variable_get("@#{output}")
54
- end
55
- end
56
-
57
- define_method(:define_outputs) do
58
- (args + kwargs.keys).each do |output|
59
- instance_variable_set("@#{output}", Signals::Signal.new(false))
60
- @output_targets << output
61
- end
62
- end
63
-
64
- define_method(:evaluate) do
65
- kwargs.each do |output, evaluator|
66
- signal = instance_variable_get("@#{output}")
67
- if evaluator.call(*@input_targets.map do |input|
68
- instance_variable_get("@#{input}").current
69
- end)
70
- signal.on
71
- else
72
- signal.off
73
- end
74
- end
75
- end
76
- end
77
-
78
- def self.assembling
79
- define_method(:assembling) do
80
- yield(*(@input_targets + @output_targets).map { |target| instance_variable_get("@#{target}") })
81
- end
82
- end
83
-
84
- def self.diagram(source)
85
- define_method(:to_s) do
86
- (@input_targets + @output_targets).reduce(source) do |result, input|
87
- result.gsub(/\(#{input}\)/i, "(#{instance_variable_get("@#{input}")})#{"-" * (input.size - 1)}")
88
- end
89
- end
90
- end
91
-
92
- def self.truth_table(source) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
93
- define_method(:truth_table) do # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity,Metrics/BlockLength
94
- rows = source.strip.split("\n")
95
- headers = rows.shift.split("|").map(&:strip).reject(&:empty?).map(&:downcase).map(&:to_sym)
96
- rows.shift # devide line
97
- table = rows.map do |row|
98
- row.split("|").map(&:strip).reject(&:empty?).map(&:downcase).map do |v|
99
- case v
100
- when "^"
101
- :clock
102
- when "x"
103
- :any
104
- when "1"
105
- true
106
- when "0"
107
- false
108
- else
109
- raise "Invalid value in truth table: #{v}"
110
- end
111
- end
112
- end.select do |values| # rubocop:disable Style/MultilineBlockChain
113
- headers.size == values.size
114
- end.map do |values| # rubocop:disable Style/MultilineBlockChain
115
- array = [values]
116
- while array.any? { |values| values.any? { |v| v == :any } }
117
- target_index = array.find_index { |values| values.any? { |v| v == :any } }
118
- target = array[target_index]
119
- prop_index = target.find_index { |v| v == :any }
120
- array.delete_at(target_index)
121
- array.insert(target_index, *[true, false].map do |v|
122
- target.dup.tap do |a|
123
- a[prop_index] = v
124
- end
125
- end)
126
- end
127
- array
128
- end.flatten!(1).map do |values| # rubocop:disable Style/MultilineBlockChain
129
- headers.zip(values).to_h
130
- end
131
- table
132
- end
133
- end
134
- end
135
-
136
- def self.run(sym) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength,Metrics/PerceivedComplexity
137
- circuit = Base.registry[sym.upcase.to_sym].new
138
-
139
- render = lambda {
140
- system("clear")
141
- puts circuit
142
- puts
143
- puts "tick: #{Signals::Clock.tick_count}" if circuit.clock
144
- puts "input: #{circuit.input_targets.join ","}?" if circuit.input_targets.any?
145
- }
146
-
147
- if circuit.clock
148
- Thread.new do
149
- loop do
150
- render.call
151
- sleep 1
152
- Signals::Clock.tick
153
- end
154
- end
155
- else
156
- render.call
157
- end
158
-
159
- while (input = gets)
160
- key = input.chomp.to_sym
161
- next unless circuit.respond_to? key
162
-
163
- signal = circuit.send(key)
164
- if signal.current
165
- signal.off
166
- else
167
- signal.on
168
- end
169
- render.call
170
- end
171
- end
172
- end
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Logicuit
4
- module Circuits
5
- module SystemLevel
6
- # 1 bit CPU
7
- class OneBitCpu < Base
8
- tag :ONE_BIT_CPU
9
-
10
- diagram <<~DIAGRAM
11
- +-------------+
12
- | |
13
- +-|NOT|-| |-+-(Y)
14
- |DFF|
15
- (CK)-|> |
16
- DIAGRAM
17
-
18
- define_inputs clock: :ck
19
-
20
- define_outputs :y
21
-
22
- assembling do |y|
23
- dff = Sequential::DFlipFlop.new
24
- not_gate = Gates::Not.new
25
-
26
- dff.q >> not_gate.a
27
- not_gate.y >> dff.d
28
-
29
- dff.q >> y
30
- end
31
-
32
- truth_table <<~TRUTH_TABLE
33
- | CK | prev Y | Y |
34
- | -- | ------ | - |
35
- | ^ | 0 | 1 |
36
- | ^ | 1 | 0 |
37
- TRUTH_TABLE
38
- end
39
- end
40
- end
41
- end