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.
- checksums.yaml +4 -4
- data/.rubocop.yml +24 -1
- data/README.md +300 -18
- data/lib/logicuit/array_as_signal_group.rb +13 -0
- data/lib/logicuit/circuits/combinational/full_adder.rb +66 -0
- data/lib/logicuit/circuits/combinational/full_adder_4bit.rb +38 -0
- data/lib/logicuit/circuits/combinational/half_adder.rb +8 -10
- data/lib/logicuit/circuits/combinational/{multiplexer2to1.rb → multiplexer_2to1.rb} +7 -9
- data/lib/logicuit/circuits/combinational/{multiplexer4to1.rb → multiplexer_4to1.rb} +11 -15
- data/lib/logicuit/circuits/sequential/d_flip_flop.rb +3 -5
- data/lib/logicuit/circuits/sequential/one_bit_cpu.rb +39 -0
- data/lib/logicuit/circuits/sequential/program_counter.rb +39 -0
- data/lib/logicuit/circuits/sequential/register_4bit.rb +56 -0
- data/lib/logicuit/circuits/td4/cpu.rb +95 -0
- data/lib/logicuit/circuits/td4/decoder.rb +37 -0
- data/lib/logicuit/circuits/td4/rom.rb +61 -0
- data/lib/logicuit/dsl.rb +158 -0
- data/lib/logicuit/gates/and.rb +5 -7
- data/lib/logicuit/gates/nand.rb +5 -7
- data/lib/logicuit/gates/not.rb +3 -5
- data/lib/logicuit/gates/or.rb +5 -7
- data/lib/logicuit/gates/xor.rb +5 -7
- data/lib/logicuit/runner.rb +45 -0
- data/lib/logicuit/signals/clock.rb +22 -14
- data/lib/logicuit/signals/signal.rb +29 -22
- data/lib/logicuit/signals/signal_group.rb +26 -0
- data/lib/logicuit/version.rb +1 -1
- data/lib/logicuit.rb +15 -5
- metadata +16 -6
- data/lib/logicuit/base.rb +0 -172
- data/lib/logicuit/circuits/system_level/one_bit_cpu.rb +0 -41
|
@@ -4,47 +4,54 @@ module Logicuit
|
|
|
4
4
|
module Signals
|
|
5
5
|
# Signal
|
|
6
6
|
class Signal
|
|
7
|
-
def initialize(current = false)
|
|
7
|
+
def initialize(current = false)
|
|
8
8
|
@current = current
|
|
9
|
-
@
|
|
10
|
-
@on_change = []
|
|
9
|
+
@downstreams = []
|
|
11
10
|
end
|
|
12
11
|
|
|
13
|
-
attr_reader :current
|
|
14
|
-
attr_accessor :connected_by
|
|
12
|
+
attr_reader :current
|
|
15
13
|
|
|
16
14
|
def on
|
|
17
|
-
|
|
15
|
+
return if @current
|
|
16
|
+
|
|
18
17
|
@current = true
|
|
19
|
-
|
|
18
|
+
propagate_current
|
|
20
19
|
end
|
|
21
20
|
|
|
22
21
|
def off
|
|
23
|
-
|
|
24
|
-
@current = false
|
|
25
|
-
@on_change.each(&:evaluate) if changed
|
|
26
|
-
end
|
|
22
|
+
return unless @current
|
|
27
23
|
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
@current = false
|
|
25
|
+
propagate_current
|
|
30
26
|
end
|
|
31
27
|
|
|
32
28
|
def connects_to(other)
|
|
33
|
-
other.
|
|
34
|
-
|
|
35
|
-
|
|
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
|
data/lib/logicuit/version.rb
CHANGED
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/
|
|
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/
|
|
13
|
-
require_relative "logicuit/circuits/combinational/
|
|
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/
|
|
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.
|
|
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-
|
|
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/
|
|
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/
|
|
27
|
-
- lib/logicuit/circuits/combinational/
|
|
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/
|
|
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
|