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
|