logicuit 0.1.5 → 0.2.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 +12 -1
- data/README.md +1 -1
- data/lib/logicuit/base.rb +83 -30
- data/lib/logicuit/circuits/combinational/decoder.rb +39 -0
- data/lib/logicuit/circuits/combinational/full_adder.rb +68 -0
- data/lib/logicuit/circuits/combinational/full_adder_4bit.rb +53 -0
- data/lib/logicuit/circuits/combinational/half_adder.rb +1 -1
- data/lib/logicuit/circuits/combinational/{multiplexer2to1.rb → multiplexer_2to1.rb} +1 -1
- data/lib/logicuit/circuits/combinational/{multiplexer4to1.rb → multiplexer_4to1.rb} +1 -1
- data/lib/logicuit/circuits/rom/timer.rb +59 -0
- data/lib/logicuit/circuits/sequential/program_counter.rb +41 -0
- data/lib/logicuit/circuits/sequential/register_4bit.rb +58 -0
- data/lib/logicuit/circuits/system_level/cpu_td4.rb +120 -0
- data/lib/logicuit/circuits/system_level/one_bit_cpu2.rb +41 -0
- data/lib/logicuit/signals/clock.rb +6 -1
- data/lib/logicuit/signals/signal.rb +2 -0
- data/lib/logicuit/version.rb +1 -1
- data/lib/logicuit.rb +11 -3
- metadata +12 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a6288d2da83c42993610ba8212db59a1296ebf4724355c83f0c63f8605a228b6
|
4
|
+
data.tar.gz: 7fcc0e76b0142332d46e93a8a841004de7943e8520ec196cf61c97253ab4321a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6208894fad9df2006468189d4285e4d1be8b0ce46b0cc8419dbe26dc22c25baab5a9901faf0d29f592fc36cdb3888144e7ff55ca640be6c00e7c9780e56f2748
|
7
|
+
data.tar.gz: 8050593dceea458a6275c9a90c638a4d01cbf23467103ea79756ff08a272585889e09a9beb802cae47b96158d8173744165311adfe671caf555f97d0d86d62a1
|
data/.rubocop.yml
CHANGED
@@ -8,6 +8,17 @@ Style/StringLiterals:
|
|
8
8
|
Style/StringLiteralsInInterpolation:
|
9
9
|
EnforcedStyle: double_quotes
|
10
10
|
|
11
|
-
|
11
|
+
Layout/LineLength:
|
12
|
+
Enabled: false
|
13
|
+
|
14
|
+
Style/NumericPredicate:
|
15
|
+
Enabled: false
|
16
|
+
|
17
|
+
Metrics:
|
18
|
+
Enabled: false
|
19
|
+
|
20
|
+
plugins:
|
12
21
|
- rubocop-minitest
|
22
|
+
|
23
|
+
require:
|
13
24
|
- rubocop-rake
|
data/README.md
CHANGED
data/lib/logicuit/base.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
# Logicuit module
|
4
4
|
module Logicuit
|
5
5
|
# base class for all gates and circuits
|
6
|
-
class Base
|
6
|
+
class Base
|
7
7
|
def self.tag(*tags)
|
8
8
|
tags.each do |tag|
|
9
9
|
registry[tag] = self
|
@@ -20,21 +20,26 @@ module Logicuit
|
|
20
20
|
@input_targets = []
|
21
21
|
@output_targets = []
|
22
22
|
@clock = false
|
23
|
+
@components = []
|
23
24
|
define_inputs(*args) if respond_to?(:define_inputs)
|
24
25
|
define_outputs if respond_to?(:define_outputs)
|
25
26
|
assembling if respond_to?(:assembling)
|
26
27
|
evaluate if respond_to?(:evaluate)
|
27
28
|
end
|
28
29
|
|
29
|
-
|
30
|
+
def evaluate(*args); end
|
30
31
|
|
31
|
-
|
32
|
+
attr_reader :input_targets, :output_targets, :clock, :components
|
33
|
+
|
34
|
+
def self.define_inputs(*args, **kwargs)
|
35
|
+
# define getter methods for inputs
|
32
36
|
args.each do |input|
|
33
37
|
define_method(input) do
|
34
38
|
instance_variable_get("@#{input}")
|
35
39
|
end
|
36
40
|
end
|
37
41
|
|
42
|
+
# define initializer for inputs
|
38
43
|
define_method(:define_inputs) do |*instance_method_args|
|
39
44
|
instance_variable_set("@clock", true) if kwargs&.key?(:clock)
|
40
45
|
args.each_with_index do |input, index|
|
@@ -45,15 +50,31 @@ module Logicuit
|
|
45
50
|
end
|
46
51
|
Signals::Clock.on_tick << self if clock
|
47
52
|
end
|
53
|
+
|
54
|
+
# define bulk_setter for inputs
|
55
|
+
define_method(:bulk_set) do |str|
|
56
|
+
args.zip(str.gsub(/\s/, "").split("")).each do |input, value|
|
57
|
+
next if value.nil?
|
58
|
+
|
59
|
+
signal = send(input)
|
60
|
+
if value == "1"
|
61
|
+
signal.on
|
62
|
+
else
|
63
|
+
signal.off
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
48
67
|
end
|
49
68
|
|
50
|
-
def self.define_outputs(*args, **kwargs)
|
69
|
+
def self.define_outputs(*args, **kwargs)
|
70
|
+
# define getter methods for outputs
|
51
71
|
(args + kwargs.keys).each do |output|
|
52
72
|
define_method(output) do
|
53
73
|
instance_variable_get("@#{output}")
|
54
74
|
end
|
55
75
|
end
|
56
76
|
|
77
|
+
# define initializer for outputs
|
57
78
|
define_method(:define_outputs) do
|
58
79
|
(args + kwargs.keys).each do |output|
|
59
80
|
instance_variable_set("@#{output}", Signals::Signal.new(false))
|
@@ -61,12 +82,20 @@ module Logicuit
|
|
61
82
|
end
|
62
83
|
end
|
63
84
|
|
64
|
-
|
85
|
+
# define evaluate method
|
86
|
+
return if kwargs.empty?
|
87
|
+
|
88
|
+
define_method(:evaluate) do |*override_args|
|
65
89
|
kwargs.each do |output, evaluator|
|
66
90
|
signal = instance_variable_get("@#{output}")
|
67
|
-
if
|
68
|
-
|
69
|
-
|
91
|
+
e_args = if override_args.empty?
|
92
|
+
@input_targets.map do |input|
|
93
|
+
instance_variable_get("@#{input}").current
|
94
|
+
end
|
95
|
+
else
|
96
|
+
override_args
|
97
|
+
end
|
98
|
+
if evaluator.call(*e_args)
|
70
99
|
signal.on
|
71
100
|
else
|
72
101
|
signal.off
|
@@ -77,21 +106,28 @@ module Logicuit
|
|
77
106
|
|
78
107
|
def self.assembling
|
79
108
|
define_method(:assembling) do
|
80
|
-
yield(*(@input_targets + @output_targets).map
|
109
|
+
(yield(*(@input_targets + @output_targets).map do |target|
|
110
|
+
instance_variable_get("@#{target}")
|
111
|
+
end) || []).each do |component|
|
112
|
+
@components << component
|
113
|
+
end
|
81
114
|
end
|
82
115
|
end
|
83
116
|
|
84
117
|
def self.diagram(source)
|
85
118
|
define_method(:to_s) do
|
86
|
-
|
119
|
+
source_ = @input_targets.reduce(source) do |result, input|
|
87
120
|
result.gsub(/\(#{input}\)/i, "(#{instance_variable_get("@#{input}")})#{"-" * (input.size - 1)}")
|
88
121
|
end
|
122
|
+
@output_targets.reduce(source_) do |result, output|
|
123
|
+
result.gsub(/\(#{output}\)/i, "#{"-" * (output.size - 1)}(#{instance_variable_get("@#{output}")})")
|
124
|
+
end
|
89
125
|
end
|
90
126
|
end
|
91
127
|
|
92
|
-
def self.truth_table(source)
|
93
|
-
define_method(:truth_table) do
|
94
|
-
rows = source.strip.split("\n")
|
128
|
+
def self.truth_table(source)
|
129
|
+
define_method(:truth_table) do
|
130
|
+
rows = source.strip.split("\n").map { |row| row.gsub(/#.*$/, "") }
|
95
131
|
headers = rows.shift.split("|").map(&:strip).reject(&:empty?).map(&:downcase).map(&:to_sym)
|
96
132
|
rows.shift # devide line
|
97
133
|
table = rows.map do |row|
|
@@ -106,15 +142,17 @@ module Logicuit
|
|
106
142
|
when "0"
|
107
143
|
false
|
108
144
|
else
|
109
|
-
raise "Invalid value in truth table: #{v}"
|
145
|
+
raise "Invalid value in truth table: #{v}" unless headers.include?(v.to_sym)
|
146
|
+
|
147
|
+
[:ref, v.to_sym]
|
110
148
|
end
|
111
149
|
end
|
112
150
|
end.select do |values| # rubocop:disable Style/MultilineBlockChain
|
113
151
|
headers.size == values.size
|
114
152
|
end.map do |values| # rubocop:disable Style/MultilineBlockChain
|
115
153
|
array = [values]
|
116
|
-
while array.any? {
|
117
|
-
target_index = array.find_index {
|
154
|
+
while array.any? { it.any? { |v| v == :any } }
|
155
|
+
target_index = array.find_index { it.any? { |v| v == :any } }
|
118
156
|
target = array[target_index]
|
119
157
|
prop_index = target.find_index { |v| v == :any }
|
120
158
|
array.delete_at(target_index)
|
@@ -133,22 +171,26 @@ module Logicuit
|
|
133
171
|
end
|
134
172
|
end
|
135
173
|
|
136
|
-
def self.run(sym) # rubocop:disable
|
174
|
+
def self.run(sym, hz: 1, noclear: false) # rubocop:disable Naming/MethodParameterName
|
137
175
|
circuit = Base.registry[sym.upcase.to_sym].new
|
138
176
|
|
139
177
|
render = lambda {
|
140
|
-
system("clear")
|
178
|
+
system("clear") unless noclear
|
141
179
|
puts circuit
|
142
180
|
puts
|
143
181
|
puts "tick: #{Signals::Clock.tick_count}" if circuit.clock
|
144
|
-
|
182
|
+
if circuit.respond_to?(:instructions)
|
183
|
+
puts "instructions: #{circuit.instructions.join "|"}"
|
184
|
+
elsif circuit.input_targets.any?
|
185
|
+
puts "input: #{circuit.input_targets.join ","}?"
|
186
|
+
end
|
145
187
|
}
|
146
188
|
|
147
|
-
if circuit.clock
|
189
|
+
if circuit.clock && hz.nonzero?
|
148
190
|
Thread.new do
|
149
191
|
loop do
|
150
192
|
render.call
|
151
|
-
sleep 1
|
193
|
+
sleep 1.0 / hz
|
152
194
|
Signals::Clock.tick
|
153
195
|
end
|
154
196
|
end
|
@@ -156,17 +198,28 @@ module Logicuit
|
|
156
198
|
render.call
|
157
199
|
end
|
158
200
|
|
159
|
-
while (input = gets)
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
signal = circuit.send(key)
|
164
|
-
if signal.current
|
165
|
-
signal.off
|
201
|
+
while (input = gets.chomp)
|
202
|
+
if circuit.respond_to?(:execute) && circuit.execute(input)
|
203
|
+
Signals::Clock.tick
|
204
|
+
render.call # rubocop:disable Style/IdenticalConditionalBranches
|
166
205
|
else
|
167
|
-
|
206
|
+
key = input.to_sym
|
207
|
+
unless circuit.respond_to? key
|
208
|
+
if circuit.clock && hz.zero?
|
209
|
+
Signals::Clock.tick
|
210
|
+
render.call
|
211
|
+
end
|
212
|
+
next
|
213
|
+
end
|
214
|
+
|
215
|
+
signal = circuit.send(key)
|
216
|
+
if signal.current
|
217
|
+
signal.off
|
218
|
+
else
|
219
|
+
signal.on
|
220
|
+
end
|
221
|
+
render.call # rubocop:disable Style/IdenticalConditionalBranches
|
168
222
|
end
|
169
|
-
render.call
|
170
223
|
end
|
171
224
|
end
|
172
225
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Logicuit
|
4
|
+
module Circuits
|
5
|
+
module Combinational
|
6
|
+
# Decoder class
|
7
|
+
class Decoder < Base
|
8
|
+
tag :DEC
|
9
|
+
|
10
|
+
define_inputs :op3, :op2, :op1, :op0, :c_flag
|
11
|
+
|
12
|
+
define_outputs sel_b: ->(_, _, op1, _, _) { op1 },
|
13
|
+
sel_a: ->(op3, _, _, op0, _) { op3 || op0 },
|
14
|
+
ld0: ->(op3, op2, _, _, _) { op3 || op2 },
|
15
|
+
ld1: ->(op3, op2, _, _, _) { op3 || !op2 },
|
16
|
+
ld2: ->(op3, op2, _, _, _) { !op3 || op2 },
|
17
|
+
ld3: ->(op3, op2, _, op0, c_flag) { !op3 || !op2 || (!op0 && c_flag) }
|
18
|
+
|
19
|
+
truth_table <<~TRUTH_TABLE
|
20
|
+
| OP3 | OP2 | OP1 | OP0 | C_FLAG | SEL_B | SEL_A | LD0 | LD1 | LD2 | LD3 |
|
21
|
+
| --- | --- | --- | --- | ------ | ----- | ----- | --- | --- | --- | --- |
|
22
|
+
| 0 | 0 | 0 | 0 | x | 0 | 0 | 0 | 1 | 1 | 1 | # ADD A,Im
|
23
|
+
| 0 | 0 | 0 | 1 | x | 0 | 1 | 0 | 1 | 1 | 1 | # MOV A,B
|
24
|
+
| 0 | 0 | 1 | 0 | x | 1 | 0 | 0 | 1 | 1 | 1 | # IN A
|
25
|
+
| 0 | 0 | 1 | 1 | x | 1 | 1 | 0 | 1 | 1 | 1 | # MOV A,Im
|
26
|
+
| 0 | 1 | 0 | 0 | x | 0 | 0 | 1 | 0 | 1 | 1 | # MOV B,A
|
27
|
+
| 0 | 1 | 0 | 1 | x | 0 | 1 | 1 | 0 | 1 | 1 | # ADD B,Im
|
28
|
+
| 0 | 1 | 1 | 0 | x | 1 | 0 | 1 | 0 | 1 | 1 | # IN B
|
29
|
+
| 0 | 1 | 1 | 1 | x | 1 | 1 | 1 | 0 | 1 | 1 | # MOV B,Im
|
30
|
+
| 1 | 0 | 0 | 1 | x | 0 | 1 | 1 | 1 | 0 | 1 | # OUT B
|
31
|
+
| 1 | 0 | 1 | 1 | x | 1 | 1 | 1 | 1 | 0 | 1 | # OUT Im
|
32
|
+
| 1 | 1 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 0 | # JNC(C=0)
|
33
|
+
| 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | # JNC(C=1)
|
34
|
+
| 1 | 1 | 1 | 1 | x | 1 | 1 | 1 | 1 | 1 | 0 | # JMP
|
35
|
+
TRUTH_TABLE
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Logicuit
|
4
|
+
module Circuits
|
5
|
+
module Combinational
|
6
|
+
# FullAdder class
|
7
|
+
class FullAdder < Base
|
8
|
+
tag :FADD
|
9
|
+
|
10
|
+
diagram <<~DIAGRAM
|
11
|
+
(Cin)---+-|NOT|-----+
|
12
|
+
| |
|
13
|
+
(A)---+---|NOT|---+ |
|
14
|
+
| | | |
|
15
|
+
(B)-+-----|NOT|-+ | +-|
|
16
|
+
| | | | +---|AND|---+
|
17
|
+
+-----------------| |
|
18
|
+
| | | | | | +-|
|
19
|
+
| | | | | +-| |
|
20
|
+
| +---------------|AND|-----|
|
21
|
+
| | | +-----| |
|
22
|
+
| | | | | | |OR|-(S)
|
23
|
+
| | +-------------| |
|
24
|
+
| | | | +---|AND|-----|
|
25
|
+
| | | +-----| |
|
26
|
+
| | | | | | +-|
|
27
|
+
| | +-------------| |
|
28
|
+
| +---------------|AND|---+
|
29
|
+
+-----------------|
|
30
|
+
| | | | | |
|
31
|
+
| | | | | +-|
|
32
|
+
| +---------------|AND|---+
|
33
|
+
+-----------------| |
|
34
|
+
| | | | | +-|
|
35
|
+
| | +-------------| |
|
36
|
+
| | | | +---|AND|-----|
|
37
|
+
+-----------------| |
|
38
|
+
| | | | |OR|-(C)
|
39
|
+
| | +-------------| |
|
40
|
+
| +---------------|AND|-----|
|
41
|
+
| | | +-----| |
|
42
|
+
| | | +-|
|
43
|
+
| | +-------------| |
|
44
|
+
| +---------------|AND|---+
|
45
|
+
+-----------------|
|
46
|
+
DIAGRAM
|
47
|
+
|
48
|
+
define_inputs :cin, :a, :b
|
49
|
+
|
50
|
+
define_outputs s: ->(cin, a, b) { (!cin && !a && b) || (!cin && a && !b) || (cin && !a && !b) || (cin && a && b) },
|
51
|
+
c: ->(cin, a, b) { (!cin && a && b) || (cin && !a && b) || (cin && a && !b) || (cin && a && b) }
|
52
|
+
|
53
|
+
truth_table <<~TRUTH_TABLE
|
54
|
+
| Cin | A | B | C | S |
|
55
|
+
| --- | - | - | - | - |
|
56
|
+
| 0 | 0 | 0 | 0 | 0 |
|
57
|
+
| 0 | 0 | 1 | 0 | 1 |
|
58
|
+
| 0 | 1 | 0 | 0 | 1 |
|
59
|
+
| 0 | 1 | 1 | 1 | 0 |
|
60
|
+
| 1 | 0 | 0 | 0 | 1 |
|
61
|
+
| 1 | 0 | 1 | 1 | 0 |
|
62
|
+
| 1 | 1 | 0 | 1 | 0 |
|
63
|
+
| 1 | 1 | 1 | 1 | 1 |
|
64
|
+
TRUTH_TABLE
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Logicuit
|
4
|
+
module Circuits
|
5
|
+
module Combinational
|
6
|
+
# FullAdder class
|
7
|
+
class FullAdder4bit < Base
|
8
|
+
tag :FADD4
|
9
|
+
|
10
|
+
diagram <<~DIAGRAM
|
11
|
+
(Cin)-| |--(S0)
|
12
|
+
(A0)--|FADD|
|
13
|
+
(B0)--| |--+
|
14
|
+
|
|
15
|
+
+----------+
|
16
|
+
|
|
17
|
+
+--| |--(S1)
|
18
|
+
(A1)--|FADD|
|
19
|
+
(B1)--| |--+
|
20
|
+
|
|
21
|
+
+----------+
|
22
|
+
|
|
23
|
+
+--| |--(S2)
|
24
|
+
(A2)--|FADD|
|
25
|
+
(B2)--| |--+
|
26
|
+
|
|
27
|
+
+----------+
|
28
|
+
|
|
29
|
+
+--| |--(S3)
|
30
|
+
(A3)--|FADD|
|
31
|
+
(B3)--| |---(C)
|
32
|
+
|
33
|
+
DIAGRAM
|
34
|
+
|
35
|
+
define_inputs :cin, :a0, :b0, :a1, :b1, :a2, :b2, :a3, :b3
|
36
|
+
|
37
|
+
define_outputs :s0, :s1, :s2, :s3, :c
|
38
|
+
|
39
|
+
assembling do |cin, a0, b0, a1, b1, a2, b2, a3, b3, s0, s1, s2, s3, cout|
|
40
|
+
[[a0, b0, s0], [a1, b1, s1], [a2, b2, s2], [a3, b3, s3]].reduce(cin) do |c, sigs|
|
41
|
+
a, b, s = sigs
|
42
|
+
full_addr = Combinational::FullAdder.new
|
43
|
+
c >> full_addr.cin
|
44
|
+
a >> full_addr.a
|
45
|
+
b >> full_addr.b
|
46
|
+
full_addr.s >> s
|
47
|
+
full_addr.c
|
48
|
+
end >> cout
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Logicuit
|
4
|
+
module Circuits
|
5
|
+
module Rom
|
6
|
+
# TImer
|
7
|
+
class Timer < Base
|
8
|
+
define_inputs :a3, :a2, :a1, :a0
|
9
|
+
|
10
|
+
define_outputs :d7, :d6, :d5, :d4, :d3, :d2, :d1, :d0
|
11
|
+
|
12
|
+
def evaluate
|
13
|
+
output = case "#{a3}#{a2}#{a1}#{a0}"
|
14
|
+
in "0000" then "10110111"
|
15
|
+
in "0001" then "00000001"
|
16
|
+
in "0010" then "11100001"
|
17
|
+
in "0011" then "00000001"
|
18
|
+
in "0100" then "11100011"
|
19
|
+
in "0101" then "10110110"
|
20
|
+
in "0110" then "00000001"
|
21
|
+
in "0111" then "11100110"
|
22
|
+
in "1000" then "00000001"
|
23
|
+
in "1001" then "11101000"
|
24
|
+
in "1010" then "10110000"
|
25
|
+
in "1011" then "10110100"
|
26
|
+
in "1100" then "00000001"
|
27
|
+
in "1101" then "11101010"
|
28
|
+
in "1110" then "10111000"
|
29
|
+
in "1111" then "11111111"
|
30
|
+
end
|
31
|
+
output.split("").zip([d7, d6, d5, d4, d3, d2, d1, d0]).each do |v, o|
|
32
|
+
v == "1" ? o.on : o.off
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
truth_table <<~TRUTH_TABLE
|
37
|
+
| A3 | A2 | A1 | A0 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
|
38
|
+
| -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- |
|
39
|
+
| 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 1 | 1 | # OUT 0111
|
40
|
+
| 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | # ADD A,0001
|
41
|
+
| 0 | 0 | 1 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 1 | # JNC 0001
|
42
|
+
| 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | # ADD A,0001
|
43
|
+
| 0 | 1 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | 1 | # JNC 0011
|
44
|
+
| 0 | 1 | 0 | 1 | 1 | 0 | 1 | 1 | 0 | 1 | 1 | 0 | # OUT 0110
|
45
|
+
| 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | # ADD A,0001
|
46
|
+
| 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | # JNC 0110
|
47
|
+
| 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | # ADD A,0001
|
48
|
+
| 1 | 0 | 0 | 1 | 1 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | # JNC 1000
|
49
|
+
| 1 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | # OUT 0000
|
50
|
+
| 1 | 0 | 1 | 1 | 1 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | # OUT 0100
|
51
|
+
| 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | # ADD A,0001
|
52
|
+
| 1 | 1 | 0 | 1 | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | # JNC 1010
|
53
|
+
| 1 | 1 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | # OUT 1000
|
54
|
+
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | # JMP 1111
|
55
|
+
TRUTH_TABLE
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Logicuit
|
4
|
+
module Circuits
|
5
|
+
module Sequential
|
6
|
+
# Program Counter
|
7
|
+
class ProgramCounter < Base
|
8
|
+
tag :PC
|
9
|
+
|
10
|
+
diagram <<~DIAGRAM
|
11
|
+
(A)---| |---(QA)
|
12
|
+
(B)---| |---(QB)
|
13
|
+
(C)---|PC|---(QC)
|
14
|
+
(D)---| |---(QD)
|
15
|
+
(LD)--|
|
16
|
+
DIAGRAM
|
17
|
+
|
18
|
+
define_inputs :a, :b, :c, :d, :ld, clock: :ck
|
19
|
+
|
20
|
+
define_outputs :qa, :qb, :qc, :qd
|
21
|
+
|
22
|
+
assembling do |a, b, c, d, ld, qa, qb, qc, qd|
|
23
|
+
# define_inputs :cin, :a0, :b0, :a1, :b1, :a2, :b2, :a3, :b3
|
24
|
+
fadd = Combinational::FullAdder4bit.new(0, 0, 1, 0, 0, 0, 0, 0, 0)
|
25
|
+
|
26
|
+
[[a, qa, :a0, :s0], [b, qb, :a1, :s1], [c, qc, :a2, :s2],
|
27
|
+
[d, qd, :a3, :s3]].each do |input, output, fadd_in, fadd_out|
|
28
|
+
dff = Sequential::DFlipFlop.new
|
29
|
+
mux = Combinational::Multiplexer2to1.new
|
30
|
+
input >> mux.c0
|
31
|
+
dff.q >> fadd.send(fadd_in)
|
32
|
+
fadd.send(fadd_out) >> mux.c1
|
33
|
+
ld >> mux.a
|
34
|
+
mux.y >> dff.d
|
35
|
+
dff.q >> output
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Logicuit
|
4
|
+
module Circuits
|
5
|
+
module Sequential
|
6
|
+
# 4 bit register
|
7
|
+
class Register4bit < Base
|
8
|
+
tag :REG4
|
9
|
+
|
10
|
+
diagram <<~DIAGRAM
|
11
|
+
+---------------------+
|
12
|
+
+-| |
|
13
|
+
(A)-------|MUX|-------|DFF|---+---(QA)
|
14
|
+
+---| +---|
|
15
|
+
| |
|
16
|
+
| +---------------------+
|
17
|
+
| +-| | |
|
18
|
+
(B)-------|MUX|-------|DFF|---+---(QB)
|
19
|
+
+---| +---|
|
20
|
+
| |
|
21
|
+
| +---------------------+
|
22
|
+
| +-| | |
|
23
|
+
(C)-------|MUX|-------|DFF|---+---(QC)
|
24
|
+
+---| +---|
|
25
|
+
| |
|
26
|
+
| +---------------------+
|
27
|
+
| +-| | |
|
28
|
+
(D)-------|MUX|-------|DFF|---+---(QD)
|
29
|
+
+---| +---|
|
30
|
+
(LD)--+ (CK)--+
|
31
|
+
DIAGRAM
|
32
|
+
|
33
|
+
define_inputs :a, :b, :c, :d, :ld, clock: :ck
|
34
|
+
|
35
|
+
define_outputs :qa, :qb, :qc, :qd
|
36
|
+
|
37
|
+
assembling do |a, b, c, d, ld, qa, qb, qc, qd|
|
38
|
+
[[a, qa], [b, qb], [c, qc], [d, qd]].each do |input, output|
|
39
|
+
dff = Sequential::DFlipFlop.new
|
40
|
+
mux = Combinational::Multiplexer2to1.new
|
41
|
+
input >> mux.c0
|
42
|
+
dff.q >> mux.c1
|
43
|
+
ld >> mux.a
|
44
|
+
mux.y >> dff.d
|
45
|
+
dff.q >> output
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
truth_table <<~TRUTH_TABLE
|
50
|
+
| CK | A | B | C | D | LD | QA | QB | QC | QD |
|
51
|
+
| -- | - | - | - | - | -- | -- | -- | -- | -- |
|
52
|
+
| ^ | x | x | x | x | 0 | A | B | C | D |
|
53
|
+
| ^ | x | x | x | x | 1 | QA | QB | QC | QD |
|
54
|
+
TRUTH_TABLE
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Logicuit
|
4
|
+
module Circuits
|
5
|
+
module SystemLevel
|
6
|
+
# TD4
|
7
|
+
class CpuTd4 < Base
|
8
|
+
tag :TD4
|
9
|
+
|
10
|
+
define_inputs :in0, :in1, :in2, :in3, clock: :ck
|
11
|
+
|
12
|
+
define_outputs :led1, :led2, :led3, :led4
|
13
|
+
|
14
|
+
assembling do |in0, in1, in2, in3, led1, led2, led3, led4|
|
15
|
+
register_a = Sequential::Register4bit.new
|
16
|
+
register_b = Sequential::Register4bit.new
|
17
|
+
register_c = Sequential::Register4bit.new
|
18
|
+
pc = Sequential::ProgramCounter.new
|
19
|
+
rom = Rom::Timer.new
|
20
|
+
dec = Combinational::Decoder.new
|
21
|
+
mux0 = Combinational::Multiplexer4to1.new
|
22
|
+
mux1 = Combinational::Multiplexer4to1.new
|
23
|
+
mux2 = Combinational::Multiplexer4to1.new
|
24
|
+
mux3 = Combinational::Multiplexer4to1.new
|
25
|
+
alu = Combinational::FullAdder4bit.new
|
26
|
+
dff = Sequential::DFlipFlop.new
|
27
|
+
|
28
|
+
[%i[s0 a], %i[s1 b], %i[s2 c], %i[s3 d]].each do |sel, reg|
|
29
|
+
alu.send(sel) >> register_a.send(reg)
|
30
|
+
alu.send(sel) >> register_b.send(reg)
|
31
|
+
alu.send(sel) >> register_c.send(reg)
|
32
|
+
alu.send(sel) >> pc.send(reg)
|
33
|
+
end
|
34
|
+
alu.c >> dff.d
|
35
|
+
|
36
|
+
[[:qa, in0, mux0, :a0], [:qb, in1, mux1, :a1], [:qc, in2, mux2, :a2], [:qd, in3, mux3, :a3]].each do |reg_out, in_port, mux, alu_in|
|
37
|
+
register_a.send(reg_out) >> mux.c0
|
38
|
+
register_b.send(reg_out) >> mux.c1
|
39
|
+
in_port >> mux.c2
|
40
|
+
Signals::Signal.new.off >> mux.c3
|
41
|
+
dec.sel_a >> mux.a
|
42
|
+
dec.sel_b >> mux.b
|
43
|
+
mux.y >> alu.send(alu_in)
|
44
|
+
end
|
45
|
+
|
46
|
+
register_c.qa >> led4
|
47
|
+
register_c.qb >> led3
|
48
|
+
register_c.qc >> led2
|
49
|
+
register_c.qd >> led1
|
50
|
+
|
51
|
+
pc.qa >> rom.a0
|
52
|
+
pc.qb >> rom.a1
|
53
|
+
pc.qc >> rom.a2
|
54
|
+
pc.qd >> rom.a3
|
55
|
+
rom.d0 >> alu.b0
|
56
|
+
rom.d1 >> alu.b1
|
57
|
+
rom.d2 >> alu.b2
|
58
|
+
rom.d3 >> alu.b3
|
59
|
+
rom.d4 >> dec.op0
|
60
|
+
rom.d5 >> dec.op1
|
61
|
+
rom.d6 >> dec.op2
|
62
|
+
rom.d7 >> dec.op3
|
63
|
+
dec.ld0 >> register_a.ld
|
64
|
+
dec.ld1 >> register_b.ld
|
65
|
+
dec.ld2 >> register_c.ld
|
66
|
+
dec.ld3 >> pc.ld
|
67
|
+
dff.q >> dec.c_flag
|
68
|
+
|
69
|
+
[register_a, register_b, pc, rom, dec]
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_s
|
73
|
+
p_a = "(#{@a || "0000"})"
|
74
|
+
p_b = "(#{@b || "0000"})"
|
75
|
+
|
76
|
+
register_a, register_b, pc, rom, dec = components
|
77
|
+
@a = a = "#{register_a.qd}#{register_a.qc}#{register_a.qb}#{register_a.qa}"
|
78
|
+
@b = b = "#{register_b.qd}#{register_b.qc}#{register_b.qb}#{register_b.qa}"
|
79
|
+
p = "#{pc.qd}#{pc.qc}#{pc.qb}#{pc.qa}"
|
80
|
+
o = "#{led1}#{led2}#{led3}#{led4}"
|
81
|
+
i = "#{in3}#{in2}#{in1}#{in0}"
|
82
|
+
m = "#{rom.d3}#{rom.d2}#{rom.d1}#{rom.d0}"
|
83
|
+
c = "-(#{dec.c_flag})"
|
84
|
+
loc = p.to_i(2)
|
85
|
+
|
86
|
+
l1 = led1.current ? "*" : " "
|
87
|
+
l2 = led2.current ? "*" : " "
|
88
|
+
l3 = led3.current ? "*" : " "
|
89
|
+
l4 = led4.current ? "*" : " "
|
90
|
+
|
91
|
+
<<~OUTPUT
|
92
|
+
|
93
|
+
#{l1 * 7}#{" " * 7}#{l2 * 7}#{" " * 7}#{l3 * 7}#{" " * 7}#{l4 * 7}
|
94
|
+
#{l1 * 9}#{" " * 5}#{l2 * 9}#{" " * 5}#{l3 * 9}#{" " * 5}#{l4 * 9}
|
95
|
+
#{l1 * 11}#{" " * 3}#{l2 * 11}#{" " * 3}#{l3 * 11}#{" " * 3}#{l4 * 11}
|
96
|
+
#{l1 * 9}#{" " * 5}#{l2 * 9}#{" " * 5}#{l3 * 9}#{" " * 5}#{l4 * 9}
|
97
|
+
#{l1 * 7}#{" " * 7}#{l2 * 7}#{" " * 7}#{l3 * 7}#{" " * 7}#{l4 * 7}
|
98
|
+
|
99
|
+
+-----------------------------------------------+ #{loc == 0 ? ">" : " "} OUT 0111
|
100
|
+
| | #{loc == 1 ? ">" : " "} ADD A,0001
|
101
|
+
+--->|rg_a|#{p_a}----->| | | #{loc == 2 ? ">" : " "} JNC 0001
|
102
|
+
| |#{a}| | | | #{loc == 3 ? ">" : " "} ADD A,0001
|
103
|
+
| | | | #{loc == 4 ? ">" : " "} JNC 0011
|
104
|
+
+--->|rg_b|#{p_b}----->| |----------->| |---+ #{loc == 5 ? ">" : " "} OUT 0110
|
105
|
+
| |#{b}| | | | | #{loc == 6 ? ">" : " "} ADD A,0001
|
106
|
+
| |SEL| |ALU| #{loc == 7 ? ">" : " "} JNC 0110
|
107
|
+
+--->| out| | in|--->| | | | #{loc == 8 ? ">" : " "} ADD A,0001
|
108
|
+
| |#{o}| |#{i}| | | | im|--->| |-#{c} #{loc == 9 ? ">" : " "} JNC 1000
|
109
|
+
| | | |#{m}| #{loc == 10 ? ">" : " "} OUT 0000
|
110
|
+
+--->| pc| (0000)--->| | #{loc == 11 ? ">" : " "} OUT 0100
|
111
|
+
|#{p}| #{loc == 12 ? ">" : " "} ADD A,0001
|
112
|
+
#{loc == 13 ? ">" : " "} JNC 1010
|
113
|
+
#{loc == 14 ? ">" : " "} OUT 1000
|
114
|
+
#{loc == 15 ? ">" : " "} JMP 1111
|
115
|
+
OUTPUT
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Logicuit
|
4
|
+
module Circuits
|
5
|
+
module SystemLevel
|
6
|
+
# 1 bit CPU with a Multiplexer
|
7
|
+
# Input A is H, MOV A,A
|
8
|
+
# Input A is L, NOT A
|
9
|
+
class OneBitCpu2 < Base
|
10
|
+
tag :ONE_BIT_CPU2
|
11
|
+
|
12
|
+
diagram <<~DIAGRAM
|
13
|
+
+------------------------+
|
14
|
+
| +-------------(Y)
|
15
|
+
+----| |-+---+---| |
|
16
|
+
|DFF| | | |
|
17
|
+
(CK)-|> | +-|NOT|-|MUX|-+
|
18
|
+
|
|
19
|
+
(A)---|
|
20
|
+
DIAGRAM
|
21
|
+
|
22
|
+
define_inputs :a, clock: :ck
|
23
|
+
|
24
|
+
define_outputs :y
|
25
|
+
|
26
|
+
assembling do |a, y|
|
27
|
+
dff = Sequential::DFlipFlop.new
|
28
|
+
not_gate = Gates::Not.new
|
29
|
+
mux = Combinational::Multiplexer2to1.new
|
30
|
+
|
31
|
+
dff.q >> y
|
32
|
+
dff.q >> mux.c0
|
33
|
+
dff.q >> not_gate.a
|
34
|
+
not_gate.y >> mux.c1
|
35
|
+
a >> mux.a
|
36
|
+
mux.y >> dff.d
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -13,7 +13,12 @@ module Logicuit
|
|
13
13
|
|
14
14
|
def tick
|
15
15
|
@tick_count += 1
|
16
|
-
|
16
|
+
# Call the `evaluate` method for all components.
|
17
|
+
# However, the input argument values should be bound to the values at the time `on_tick` is called.
|
18
|
+
@on_tick.map do |component|
|
19
|
+
args = component.input_targets.map { |input| component.instance_variable_get("@#{input}").current }
|
20
|
+
-> { component.evaluate(*args) }
|
21
|
+
end.each(&:call)
|
17
22
|
end
|
18
23
|
|
19
24
|
def self.instance
|
@@ -17,12 +17,14 @@ module Logicuit
|
|
17
17
|
changed = @current.!
|
18
18
|
@current = true
|
19
19
|
@on_change.each(&:evaluate) if changed
|
20
|
+
self
|
20
21
|
end
|
21
22
|
|
22
23
|
def off
|
23
24
|
changed = @current
|
24
25
|
@current = false
|
25
26
|
@on_change.each(&:evaluate) if changed
|
27
|
+
self
|
26
28
|
end
|
27
29
|
|
28
30
|
def toggle
|
data/lib/logicuit/version.rb
CHANGED
data/lib/logicuit.rb
CHANGED
@@ -9,8 +9,16 @@ require_relative "logicuit/gates/nand"
|
|
9
9
|
require_relative "logicuit/gates/xor"
|
10
10
|
require_relative "logicuit/signals/signal"
|
11
11
|
require_relative "logicuit/signals/clock"
|
12
|
-
require_relative "logicuit/circuits/
|
13
|
-
require_relative "logicuit/circuits/combinational/
|
14
|
-
require_relative "logicuit/circuits/combinational/multiplexer4to1"
|
12
|
+
require_relative "logicuit/circuits/combinational/multiplexer_2to1"
|
13
|
+
require_relative "logicuit/circuits/combinational/multiplexer_4to1"
|
15
14
|
require_relative "logicuit/circuits/combinational/half_adder"
|
15
|
+
require_relative "logicuit/circuits/combinational/full_adder"
|
16
|
+
require_relative "logicuit/circuits/combinational/full_adder_4bit"
|
17
|
+
require_relative "logicuit/circuits/combinational/decoder"
|
18
|
+
require_relative "logicuit/circuits/rom/timer"
|
19
|
+
require_relative "logicuit/circuits/sequential/d_flip_flop"
|
20
|
+
require_relative "logicuit/circuits/sequential/register_4bit"
|
21
|
+
require_relative "logicuit/circuits/sequential/program_counter"
|
16
22
|
require_relative "logicuit/circuits/system_level/one_bit_cpu"
|
23
|
+
require_relative "logicuit/circuits/system_level/one_bit_cpu2"
|
24
|
+
require_relative "logicuit/circuits/system_level/cpu_td4"
|
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.2.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-10 00:00:00.000000000 Z
|
11
11
|
dependencies: []
|
12
12
|
description: logi(c cir)cuit -> logicuit
|
13
13
|
email:
|
@@ -22,11 +22,19 @@ files:
|
|
22
22
|
- Rakefile
|
23
23
|
- lib/logicuit.rb
|
24
24
|
- lib/logicuit/base.rb
|
25
|
+
- lib/logicuit/circuits/combinational/decoder.rb
|
26
|
+
- lib/logicuit/circuits/combinational/full_adder.rb
|
27
|
+
- lib/logicuit/circuits/combinational/full_adder_4bit.rb
|
25
28
|
- lib/logicuit/circuits/combinational/half_adder.rb
|
26
|
-
- lib/logicuit/circuits/combinational/
|
27
|
-
- lib/logicuit/circuits/combinational/
|
29
|
+
- lib/logicuit/circuits/combinational/multiplexer_2to1.rb
|
30
|
+
- lib/logicuit/circuits/combinational/multiplexer_4to1.rb
|
31
|
+
- lib/logicuit/circuits/rom/timer.rb
|
28
32
|
- lib/logicuit/circuits/sequential/d_flip_flop.rb
|
33
|
+
- lib/logicuit/circuits/sequential/program_counter.rb
|
34
|
+
- lib/logicuit/circuits/sequential/register_4bit.rb
|
35
|
+
- lib/logicuit/circuits/system_level/cpu_td4.rb
|
29
36
|
- lib/logicuit/circuits/system_level/one_bit_cpu.rb
|
37
|
+
- lib/logicuit/circuits/system_level/one_bit_cpu2.rb
|
30
38
|
- lib/logicuit/gates/and.rb
|
31
39
|
- lib/logicuit/gates/nand.rb
|
32
40
|
- lib/logicuit/gates/not.rb
|