logicuit 0.2.0 → 0.3.1

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.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +12 -2
  3. data/README.md +355 -18
  4. data/lib/logicuit/array_as_signal_group.rb +13 -0
  5. data/lib/logicuit/circuits/combinational/full_adder.rb +28 -30
  6. data/lib/logicuit/circuits/combinational/full_adder_4bit.rb +13 -28
  7. data/lib/logicuit/circuits/combinational/half_adder.rb +8 -10
  8. data/lib/logicuit/circuits/combinational/multiplexer_2to1.rb +7 -9
  9. data/lib/logicuit/circuits/combinational/multiplexer_4to1.rb +11 -15
  10. data/lib/logicuit/circuits/sequential/d_flip_flop.rb +3 -5
  11. data/lib/logicuit/circuits/{system_level/one_bit_cpu2.rb → sequential/one_bit_cpu.rb} +13 -15
  12. data/lib/logicuit/circuits/sequential/program_counter.rb +6 -8
  13. data/lib/logicuit/circuits/sequential/register_4bit.rb +12 -14
  14. data/lib/logicuit/circuits/{system_level/cpu_td4.rb → td4/cpu.rb} +34 -59
  15. data/lib/logicuit/circuits/{combinational → td4}/decoder.rb +9 -11
  16. data/lib/logicuit/circuits/{rom/timer.rb → td4/rom.rb} +9 -9
  17. data/lib/logicuit/{base.rb → dsl.rb} +63 -105
  18. data/lib/logicuit/gates/and.rb +5 -7
  19. data/lib/logicuit/gates/nand.rb +5 -7
  20. data/lib/logicuit/gates/not.rb +3 -5
  21. data/lib/logicuit/gates/or.rb +5 -7
  22. data/lib/logicuit/gates/xor.rb +5 -7
  23. data/lib/logicuit/runner.rb +45 -0
  24. data/lib/logicuit/signals/clock.rb +18 -15
  25. data/lib/logicuit/signals/signal.rb +29 -24
  26. data/lib/logicuit/signals/signal_group.rb +32 -0
  27. data/lib/logicuit/version.rb +1 -1
  28. data/lib/logicuit.rb +8 -6
  29. metadata +11 -9
  30. data/lib/logicuit/circuits/system_level/one_bit_cpu.rb +0 -41
@@ -4,36 +4,32 @@ module Logicuit
4
4
  module Circuits
5
5
  module Combinational
6
6
  # A Multiplexer with 4 inputs and 1 output
7
- class Multiplexer4to1 < Base
8
- tag :MUX4, :MUX4TO1
9
-
7
+ class Multiplexer4to1 < DSL
10
8
  diagram <<~DIAGRAM
11
- (C0)---------------|
9
+ (C0)---------------| |
12
10
  +---|AND|---+
13
- | +-| |
11
+ | +-| | |
14
12
  | | |
15
- (C1)---------------| +-|
13
+ (C1)---------------| | +-|
16
14
  +---|AND|-+ |
17
- +-----------| +---|
15
+ +-----------| | +---|
18
16
  | | | |OR|--(Y)
19
- (C2)---------------| +---|
17
+ (C2)---------------| | +---|
20
18
  +-------------|AND|-+ |
21
- | | | +-| +-|
19
+ | | | +-| | +-|
22
20
  | | | | |
23
- (C3)---------------| |
21
+ (C3)---------------| | |
24
22
  +-------------|AND|---+
25
- | +-----------|
23
+ | +-----------| |
26
24
  | | | |
27
25
  (B)--+---|NOT|-+ |
28
26
  | |
29
27
  (A)----+-|NOT|---+
30
28
  DIAGRAM
31
29
 
32
- define_inputs :c0, :c1, :c2, :c3, :b, :a
30
+ inputs :c0, :c1, :c2, :c3, :b, :a
33
31
 
34
- define_outputs y: lambda { |c0, c1, c2, c3, b, a|
35
- (c0 && !b && !a) || (c1 && !b && a) || (c2 && b && !a) || (c3 && b && a)
36
- }
32
+ outputs y: -> { (c0 && !b && !a) || (c1 && !b && a) || (c2 && b && !a) || (c3 && b && a) }
37
33
 
38
34
  truth_table <<~TRUTH_TABLE
39
35
  | B | A | C0 | C1 | C2 | C3 | Y |
@@ -4,18 +4,16 @@ module Logicuit
4
4
  module Circuits
5
5
  module Sequential
6
6
  # D Flip-Flop
7
- class DFlipFlop < Base
8
- tag :DFF
9
-
7
+ class DFlipFlop < DSL
10
8
  diagram <<~DIAGRAM
11
9
  (D)--| |--(Q)
12
10
  |DFF|
13
11
  (CK)-|> |
14
12
  DIAGRAM
15
13
 
16
- define_inputs :d, clock: :ck
14
+ inputs :d, clock: :ck
17
15
 
18
- define_outputs q: ->(d) { d }
16
+ outputs q: -> { d }
19
17
 
20
18
  truth_table <<~TRUTH_TABLE
21
19
  | CK | D | Q |
@@ -2,38 +2,36 @@
2
2
 
3
3
  module Logicuit
4
4
  module Circuits
5
- module SystemLevel
5
+ module Sequential
6
6
  # 1 bit CPU with a Multiplexer
7
7
  # Input A is H, MOV A,A
8
8
  # Input A is L, NOT A
9
- class OneBitCpu2 < Base
10
- tag :ONE_BIT_CPU2
11
-
9
+ class OneBitCpu < DSL
12
10
  diagram <<~DIAGRAM
13
- +------------------------+
14
- | +-------------(Y)
15
- +----| |-+---+---| |
16
- |DFF| | | |
17
- (CK)-|> | +-|NOT|-|MUX|-+
18
- |
19
- (A)---|
11
+ +-----------------------------+
12
+ | |
13
+ +----| |---+---------| | |
14
+ |DFF| | | | |
15
+ (CK)-|> | +--|NOT|--|MUX|--+--(Y)
16
+ | |
17
+ (A)--| |
20
18
  DIAGRAM
21
19
 
22
- define_inputs :a, clock: :ck
20
+ inputs :a, clock: :ck
23
21
 
24
- define_outputs :y
22
+ outputs :y
25
23
 
26
- assembling do |a, y|
24
+ assembling do
27
25
  dff = Sequential::DFlipFlop.new
28
26
  not_gate = Gates::Not.new
29
27
  mux = Combinational::Multiplexer2to1.new
30
28
 
31
- dff.q >> y
32
29
  dff.q >> mux.c0
33
30
  dff.q >> not_gate.a
34
31
  not_gate.y >> mux.c1
35
32
  a >> mux.a
36
33
  mux.y >> dff.d
34
+ mux.y >> y
37
35
  end
38
36
  end
39
37
  end
@@ -4,23 +4,21 @@ module Logicuit
4
4
  module Circuits
5
5
  module Sequential
6
6
  # Program Counter
7
- class ProgramCounter < Base
8
- tag :PC
9
-
7
+ class ProgramCounter < DSL
10
8
  diagram <<~DIAGRAM
11
9
  (A)---| |---(QA)
12
10
  (B)---| |---(QB)
13
11
  (C)---|PC|---(QC)
14
12
  (D)---| |---(QD)
15
- (LD)--|
13
+ (LD)--| |
16
14
  DIAGRAM
17
15
 
18
- define_inputs :a, :b, :c, :d, :ld, clock: :ck
16
+ inputs :a, :b, :c, :d, :ld, clock: :ck
19
17
 
20
- define_outputs :qa, :qb, :qc, :qd
18
+ outputs :qa, :qb, :qc, :qd
21
19
 
22
- assembling do |a, b, c, d, ld, qa, qb, qc, qd|
23
- # define_inputs :cin, :a0, :b0, :a1, :b1, :a2, :b2, :a3, :b3
20
+ assembling do
21
+ # inputs :cin, :a0, :b0, :a1, :b1, :a2, :b2, :a3, :b3
24
22
  fadd = Combinational::FullAdder4bit.new(0, 0, 1, 0, 0, 0, 0, 0, 0)
25
23
 
26
24
  [[a, qa, :a0, :s0], [b, qb, :a1, :s1], [c, qc, :a2, :s2],
@@ -4,37 +4,35 @@ module Logicuit
4
4
  module Circuits
5
5
  module Sequential
6
6
  # 4 bit register
7
- class Register4bit < Base
8
- tag :REG4
9
-
7
+ class Register4bit < DSL
10
8
  diagram <<~DIAGRAM
11
9
  +---------------------+
12
- +-| |
10
+ +-| | |
13
11
  (A)-------|MUX|-------|DFF|---+---(QA)
14
- +---| +---|
12
+ +---| | +---| |
15
13
  | |
16
14
  | +---------------------+
17
- | +-| | |
15
+ | +-| | | |
18
16
  (B)-------|MUX|-------|DFF|---+---(QB)
19
- +---| +---|
17
+ +---| | +---| |
20
18
  | |
21
19
  | +---------------------+
22
- | +-| | |
20
+ | +-| | | |
23
21
  (C)-------|MUX|-------|DFF|---+---(QC)
24
- +---| +---|
22
+ +---| | +---| |
25
23
  | |
26
24
  | +---------------------+
27
- | +-| | |
25
+ | +-| | | |
28
26
  (D)-------|MUX|-------|DFF|---+---(QD)
29
- +---| +---|
27
+ +---| | +---| |
30
28
  (LD)--+ (CK)--+
31
29
  DIAGRAM
32
30
 
33
- define_inputs :a, :b, :c, :d, :ld, clock: :ck
31
+ inputs :a, :b, :c, :d, :ld, clock: :ck
34
32
 
35
- define_outputs :qa, :qb, :qc, :qd
33
+ outputs :qa, :qb, :qc, :qd
36
34
 
37
- assembling do |a, b, c, d, ld, qa, qb, qc, qd|
35
+ assembling do
38
36
  [[a, qa], [b, qb], [c, qc], [d, qd]].each do |input, output|
39
37
  dff = Sequential::DFlipFlop.new
40
38
  mux = Combinational::Multiplexer2to1.new
@@ -2,68 +2,43 @@
2
2
 
3
3
  module Logicuit
4
4
  module Circuits
5
- module SystemLevel
6
- # TD4
7
- class CpuTd4 < Base
8
- tag :TD4
5
+ module Td4
6
+ # TD4 CPU
7
+ class Cpu < DSL
8
+ using Logicuit::ArrayAsSignalGroup
9
9
 
10
- define_inputs :in0, :in1, :in2, :in3, clock: :ck
10
+ inputs :in0, :in1, :in2, :in3, clock: :ck
11
11
 
12
- define_outputs :led1, :led2, :led3, :led4
12
+ outputs :led1, :led2, :led3, :led4
13
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
14
+ assembling do
15
+ register_a, register_b, register_c = (:a..:c).map { Sequential::Register4bit.new }
18
16
  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
17
+ rom = Rom.new
18
+ dec = Decoder.new
19
+ mux0, mux1, mux2, mux3 = (0..3).map { Combinational::Multiplexer4to1.new }
25
20
  alu = Combinational::FullAdder4bit.new
26
21
  dff = Sequential::DFlipFlop.new
27
22
 
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
23
+ alu.s0 >> [register_a.a, register_b.a, register_c.a, pc.a]
24
+ alu.s1 >> [register_a.b, register_b.b, register_c.b, pc.b]
25
+ alu.s2 >> [register_a.c, register_b.c, register_c.c, pc.c]
26
+ alu.s3 >> [register_a.d, register_b.d, register_c.d, pc.d]
34
27
  alu.c >> dff.d
35
28
 
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
29
+ [register_a.qa, register_b.qa, in0] >> mux0[:c0, :c1, :c2]
30
+ [register_a.qb, register_b.qb, in1] >> mux1[:c0, :c1, :c2]
31
+ [register_a.qc, register_b.qc, in2] >> mux2[:c0, :c1, :c2]
32
+ [register_a.qd, register_b.qd, in3] >> mux3[:c0, :c1, :c2]
33
+ dec.sel_a >> [mux0.a, mux1.a, mux2.a, mux3.a]
34
+ dec.sel_b >> [mux0.b, mux1.b, mux2.b, mux3.b]
35
+ [mux0.y, mux1.y, mux2.y, mux3.y] >> [alu.a0, alu.a1, alu.a2, alu.a3]
45
36
 
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
37
+ register_c[:qa, :qb, :qc, :qd] >> [led4, led3, led2, led1]
38
+ pc[:qa, :qb, :qc, :qd] >> rom[:a0, :a1, :a2, :a3]
39
+ rom[:d0, :d1, :d2, :d3] >> alu[:b0, :b1, :b2, :b3]
40
+ rom[:d4, :d5, :d6, :d7] >> dec[:op0, :op1, :op2, :op3]
41
+ dec[:ld0, :ld1, :ld2, :ld3] >> [register_a.ld, register_b.ld, register_c.ld, pc.ld]
67
42
  dff.q >> dec.c_flag
68
43
 
69
44
  [register_a, register_b, pc, rom, dec]
@@ -74,14 +49,14 @@ module Logicuit
74
49
  p_b = "(#{@b || "0000"})"
75
50
 
76
51
  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}"
52
+ @a = a = register_a[:qd, :qc, :qb, :qa].to_s
53
+ @b = b = register_b[:qd, :qc, :qb, :qa].to_s
54
+ p = pc[:qd, :qc, :qb, :qa]
55
+ o = self[:led1, :led2, :led3, :led4]
56
+ i = self[:in3, :in2, :in1, :in0]
57
+ m = rom[:d3, :d2, :d1, :d0]
83
58
  c = "-(#{dec.c_flag})"
84
- loc = p.to_i(2)
59
+ loc = p.to_s.to_i(2)
85
60
 
86
61
  l1 = led1.current ? "*" : " "
87
62
  l2 = led2.current ? "*" : " "
@@ -2,19 +2,17 @@
2
2
 
3
3
  module Logicuit
4
4
  module Circuits
5
- module Combinational
5
+ module Td4
6
6
  # Decoder class
7
- class Decoder < Base
8
- tag :DEC
7
+ class Decoder < DSL
8
+ inputs :op3, :op2, :op1, :op0, :c_flag
9
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) }
10
+ outputs sel_b: -> { op1 },
11
+ sel_a: -> { op3 || op0 },
12
+ ld0: -> { op3 || op2 },
13
+ ld1: -> { op3 || !op2 },
14
+ ld2: -> { !op3 || op2 },
15
+ ld3: -> { !op3 || !op2 || (!op0 && c_flag) }
18
16
 
19
17
  truth_table <<~TRUTH_TABLE
20
18
  | OP3 | OP2 | OP1 | OP0 | C_FLAG | SEL_B | SEL_A | LD0 | LD1 | LD2 | LD3 |
@@ -2,15 +2,17 @@
2
2
 
3
3
  module Logicuit
4
4
  module Circuits
5
- module Rom
6
- # TImer
7
- class Timer < Base
8
- define_inputs :a3, :a2, :a1, :a0
5
+ module Td4
6
+ # Timer
7
+ class Rom < DSL
8
+ inputs :a3, :a2, :a1, :a0
9
9
 
10
- define_outputs :d7, :d6, :d5, :d4, :d3, :d2, :d1, :d0
10
+ outputs :d7, :d6, :d5, :d4, :d3, :d2, :d1, :d0
11
11
 
12
12
  def evaluate
13
- output = case "#{a3}#{a2}#{a1}#{a0}"
13
+ return unless initialized
14
+
15
+ output = case self[:a3, :a2, :a1, :a0].to_s
14
16
  in "0000" then "10110111"
15
17
  in "0001" then "00000001"
16
18
  in "0010" then "11100001"
@@ -28,9 +30,7 @@ module Logicuit
28
30
  in "1110" then "10111000"
29
31
  in "1111" then "11111111"
30
32
  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
33
+ self[:d7, :d6, :d5, :d4, :d3, :d2, :d1, :d0].set output
34
34
  end
35
35
 
36
36
  truth_table <<~TRUTH_TABLE
@@ -3,79 +3,61 @@
3
3
  # Logicuit module
4
4
  module Logicuit
5
5
  # base class for all gates and circuits
6
- class Base
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
-
6
+ class DSL
19
7
  def initialize(*args)
20
8
  @input_targets = []
9
+ @inputs_as_bool_struct = nil
21
10
  @output_targets = []
22
11
  @clock = false
23
12
  @components = []
24
- define_inputs(*args) if respond_to?(:define_inputs)
25
- define_outputs if respond_to?(:define_outputs)
26
- assembling if respond_to?(:assembling)
27
- evaluate if respond_to?(:evaluate)
13
+ inputs(*args)
14
+ outputs
15
+ assembling
16
+ @initialized = true
17
+ evaluate
28
18
  end
29
19
 
20
+ def inputs(*args); end
21
+ def outputs; end
22
+ def assembling; end
30
23
  def evaluate(*args); end
31
24
 
32
- attr_reader :input_targets, :output_targets, :clock, :components
25
+ attr_reader :input_targets, :output_targets, :clock, :components, :initialized
33
26
 
34
- def self.define_inputs(*args, **kwargs)
27
+ def self.inputs(*args, **kwargs)
35
28
  # define getter methods for inputs
36
- args.each do |input|
37
- define_method(input) do
38
- instance_variable_get("@#{input}")
39
- end
40
- end
29
+ attr_reader(*args)
41
30
 
42
31
  # define initializer for inputs
43
- define_method(:define_inputs) do |*instance_method_args|
44
- instance_variable_set("@clock", true) if kwargs&.key?(:clock)
32
+ define_method(:inputs) do |*instance_method_args|
33
+ @clock = true if kwargs&.key?(:clock)
45
34
  args.each_with_index do |input, index|
46
35
  signal = Signals::Signal.new(instance_method_args[index] == 1)
47
- signal.on_change << self unless clock
36
+ signal >> self unless clock
48
37
  instance_variable_set("@#{input}", signal)
49
38
  @input_targets << input
50
39
  end
51
- Signals::Clock.on_tick << self if clock
40
+ Signals::Clock >> self if clock
41
+ @inputs_as_bool_struct = Struct.new(*@input_targets)
52
42
  end
43
+ end
53
44
 
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
45
+ def [](*keys)
46
+ if keys.size == 1
47
+ send(keys.first)
48
+ elsif keys.size > 1
49
+ Signals::SignalGroup.new(*(keys.map { |key| send(key) }))
50
+ else
51
+ raise ArgumentError, "Invalid number of arguments"
66
52
  end
67
53
  end
68
54
 
69
- def self.define_outputs(*args, **kwargs)
55
+ def self.outputs(*args, **kwargs)
70
56
  # define getter methods for outputs
71
- (args + kwargs.keys).each do |output|
72
- define_method(output) do
73
- instance_variable_get("@#{output}")
74
- end
75
- end
57
+ attr_reader(*(args + kwargs.keys))
76
58
 
77
59
  # define initializer for outputs
78
- define_method(:define_outputs) do
60
+ define_method(:outputs) do
79
61
  (args + kwargs.keys).each do |output|
80
62
  instance_variable_set("@#{output}", Signals::Signal.new(false))
81
63
  @output_targets << output
@@ -86,6 +68,8 @@ module Logicuit
86
68
  return if kwargs.empty?
87
69
 
88
70
  define_method(:evaluate) do |*override_args|
71
+ return unless initialized
72
+
89
73
  kwargs.each do |output, evaluator|
90
74
  signal = instance_variable_get("@#{output}")
91
75
  e_args = if override_args.empty?
@@ -95,7 +79,7 @@ module Logicuit
95
79
  else
96
80
  override_args
97
81
  end
98
- if evaluator.call(*e_args)
82
+ if @inputs_as_bool_struct.new(*e_args).instance_exec(&evaluator)
99
83
  signal.on
100
84
  else
101
85
  signal.off
@@ -104,13 +88,10 @@ module Logicuit
104
88
  end
105
89
  end
106
90
 
107
- def self.assembling
91
+ def self.assembling(&block)
108
92
  define_method(:assembling) do
109
- (yield(*(@input_targets + @output_targets).map do |target|
110
- instance_variable_get("@#{target}")
111
- end) || []).each do |component|
112
- @components << component
113
- end
93
+ ret = instance_eval(&block)
94
+ ret.each { @components << _1 } if ret.is_a?(Array)
114
95
  end
115
96
  end
116
97
 
@@ -147,12 +128,12 @@ module Logicuit
147
128
  [:ref, v.to_sym]
148
129
  end
149
130
  end
150
- end.select do |values| # rubocop:disable Style/MultilineBlockChain
131
+ end.select do |values|
151
132
  headers.size == values.size
152
- end.map do |values| # rubocop:disable Style/MultilineBlockChain
133
+ end.map do |values|
153
134
  array = [values]
154
- while array.any? { it.any? { |v| v == :any } }
155
- target_index = array.find_index { it.any? { |v| v == :any } }
135
+ while array.any? { _1.any? { |v| v == :any } }
136
+ target_index = array.find_index { _1.any? { |v| v == :any } }
156
137
  target = array[target_index]
157
138
  prop_index = target.find_index { |v| v == :any }
158
139
  array.delete_at(target_index)
@@ -163,63 +144,40 @@ module Logicuit
163
144
  end)
164
145
  end
165
146
  array
166
- end.flatten!(1).map do |values| # rubocop:disable Style/MultilineBlockChain
147
+ end.flatten!(1).map do |values|
167
148
  headers.zip(values).to_h
168
149
  end
169
150
  table
170
151
  end
171
152
  end
172
- end
173
153
 
174
- def self.run(sym, hz: 1, noclear: false) # rubocop:disable Naming/MethodParameterName
175
- circuit = Base.registry[sym.upcase.to_sym].new
176
-
177
- render = lambda {
178
- system("clear") unless noclear
179
- puts circuit
180
- puts
181
- puts "tick: #{Signals::Clock.tick_count}" if circuit.clock
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
187
- }
188
-
189
- if circuit.clock && hz.nonzero?
190
- Thread.new do
191
- loop do
192
- render.call
193
- sleep 1.0 / hz
194
- Signals::Clock.tick
195
- end
196
- end
197
- else
198
- render.call
199
- end
154
+ def self.verify_against_truth_table
155
+ new.truth_table.each do |row|
156
+ args = row.values_at(*new.input_targets).map { _1 ? 1 : 0 }
157
+ subject = new(*args)
200
158
 
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
205
- else
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
159
+ previous_values = row.reject do |_k, v|
160
+ v == :clock
161
+ end.keys.reduce({}) { |acc, key| acc.merge(key => subject.send(key).current) }
162
+
163
+ Signals::Clock.tick if row.values.find :clock
164
+
165
+ row.each do |key, value|
166
+ next if value == :clock
167
+
168
+ if value.is_a?(Array) && value.first == :ref
169
+ expected = previous_values[value.last]
214
170
 
215
- signal = circuit.send(key)
216
- if signal.current
217
- signal.off
218
- else
219
- signal.on
171
+ raise "#{self}.new(#{args.join(", ")}).#{key} should be #{expected}" unless expected == subject.send(key).current
172
+ else
173
+ raise "#{self}.new(#{args.join(", ")}).#{key} should be #{value}" unless value == subject.send(key).current
174
+ end
220
175
  end
221
- render.call # rubocop:disable Style/IdenticalConditionalBranches
222
176
  end
223
177
  end
178
+
179
+ def self.run(opts = {})
180
+ ::Logicuit.run(new, **opts)
181
+ end
224
182
  end
225
183
  end
@@ -3,18 +3,16 @@
3
3
  module Logicuit
4
4
  module Gates
5
5
  # AND gate
6
- class And < Base
7
- tag :AND
8
-
6
+ class And < DSL
9
7
  diagram <<~DIAGRAM
10
- (A)-|
8
+ (A)-| |
11
9
  |AND|-(Y)
12
- (B)-|
10
+ (B)-| |
13
11
  DIAGRAM
14
12
 
15
- define_inputs :a, :b
13
+ inputs :a, :b
16
14
 
17
- define_outputs y: ->(a, b) { a && b }
15
+ outputs y: -> { a && b }
18
16
 
19
17
  truth_table <<~TRUTH_TABLE
20
18
  | A | B | Y |