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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 43a3513f7c19e4125cca8f7ea6d242f06eecdf9bc7e48bc4afa11524f0cbce51
4
- data.tar.gz: 5b301e47822f01ae50798cb40c636e07ef72f2557812451a69fb42327bb48f87
3
+ metadata.gz: a6288d2da83c42993610ba8212db59a1296ebf4724355c83f0c63f8605a228b6
4
+ data.tar.gz: 7fcc0e76b0142332d46e93a8a841004de7943e8520ec196cf61c97253ab4321a
5
5
  SHA512:
6
- metadata.gz: 546e6f2dd4b6dbb76bf195da77f756391bccfa1e9606790f54a66131b60acae68f4fe1858b5915c03e8bfb47a96aea630d411db388d286b5fa208f862664301f
7
- data.tar.gz: 26a33fc73deda4d50bb9bfd70ba9ddeeb13e83d379c0e97f3eacf4a8761f58c55a25f7d72f2267255d4ab437df676a80b4aea5a62424f9b6cf9315519f473270
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
- require:
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
@@ -23,7 +23,7 @@ This is the code to create a Multiplexer with 2 inputs and 1 output:
23
23
  ```
24
24
  require 'logicuit'
25
25
 
26
- class Multiplexer2To1 < Logicuit::Base
26
+ class Multiplexer2to1 < Logicuit::Base
27
27
  tag :MY_MUX
28
28
 
29
29
  diagram <<~DIAGRAM
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 # rubocop:disable Metrics/ClassLength
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
- attr_reader :input_targets, :output_targets, :clock
30
+ def evaluate(*args); end
30
31
 
31
- def self.define_inputs(*args, **kwargs) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
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) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
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
- define_method(:evaluate) do
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 evaluator.call(*@input_targets.map do |input|
68
- instance_variable_get("@#{input}").current
69
- end)
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 { |target| instance_variable_get("@#{target}") })
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
- (@input_targets + @output_targets).reduce(source) do |result, input|
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) # 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")
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? { |values| values.any? { |v| v == :any } }
117
- target_index = array.find_index { |values| values.any? { |v| v == :any } }
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 Metrics/AbcSize,Metrics/MethodLength,Metrics/PerceivedComplexity
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
- puts "input: #{circuit.input_targets.join ","}?" if circuit.input_targets.any?
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
- 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
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
- signal.on
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
@@ -10,7 +10,7 @@ module Logicuit
10
10
  diagram <<~DIAGRAM
11
11
  (A)---+-|
12
12
  | |XOR|-(S)
13
- (B)-+---+
13
+ (B)-+---|
14
14
  | |
15
15
  | +-|
16
16
  | |AND|-(C)
@@ -4,7 +4,7 @@ module Logicuit
4
4
  module Circuits
5
5
  module Combinational
6
6
  # A Multiplexer with 2 inputs and 1 output
7
- class Multiplexer2To1 < Base
7
+ class Multiplexer2to1 < Base
8
8
  tag :MUX, :MUX2, :MUX2to1
9
9
 
10
10
  diagram <<~DIAGRAM
@@ -4,7 +4,7 @@ module Logicuit
4
4
  module Circuits
5
5
  module Combinational
6
6
  # A Multiplexer with 4 inputs and 1 output
7
- class Multiplexer4To1 < Base
7
+ class Multiplexer4to1 < Base
8
8
  tag :MUX4, :MUX4TO1
9
9
 
10
10
  diagram <<~DIAGRAM
@@ -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
- @on_tick.each(&:evaluate)
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Logicuit
4
- VERSION = "0.1.5"
4
+ VERSION = "0.2.0"
5
5
  end
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/sequential/d_flip_flop"
13
- require_relative "logicuit/circuits/combinational/multiplexer2to1"
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.1.5
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-03-15 00:00:00.000000000 Z
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/multiplexer2to1.rb
27
- - lib/logicuit/circuits/combinational/multiplexer4to1.rb
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