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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 43a3513f7c19e4125cca8f7ea6d242f06eecdf9bc7e48bc4afa11524f0cbce51
4
- data.tar.gz: 5b301e47822f01ae50798cb40c636e07ef72f2557812451a69fb42327bb48f87
3
+ metadata.gz: 51ce3fab568abef949848bf4f1cb8c8dbe3f0f80da773b9f6f48ea374e21c376
4
+ data.tar.gz: 787d8ae4a61d770bba76612b5a7ffffbee750dfe0d645dae4a89c57e130ecdc1
5
5
  SHA512:
6
- metadata.gz: 546e6f2dd4b6dbb76bf195da77f756391bccfa1e9606790f54a66131b60acae68f4fe1858b5915c03e8bfb47a96aea630d411db388d286b5fa208f862664301f
7
- data.tar.gz: 26a33fc73deda4d50bb9bfd70ba9ddeeb13e83d379c0e97f3eacf4a8761f58c55a25f7d72f2267255d4ab437df676a80b4aea5a62424f9b6cf9315519f473270
6
+ metadata.gz: 28dcfd69c6f889c27283f46928dabcf178ba0113609f36895ab4e10642e36eff631070573946b5d5c7dd4ab06180d7b5649e524d855c977ab361d20675ece5b6
7
+ data.tar.gz: 4b253121ffffc6d0f06e53f07c23bde1bc371c91b2217ba91cfe46fd134376b0c2c0dac7146afad73d12f02a8a7fc1d0ad1242c85a11888a1b00434a63c5ceaf
data/.rubocop.yml CHANGED
@@ -8,6 +8,29 @@ 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
+ Style/OptionalBooleanParameter:
18
+ Enabled: false
19
+
20
+ Style/SymbolProc:
21
+ Enabled: false
22
+
23
+ Style/MultilineBlockChain:
24
+ Enabled: false
25
+
26
+ Naming/MethodParameterName:
27
+ Enabled: false
28
+
29
+ Metrics:
30
+ Enabled: false
31
+
32
+ plugins:
12
33
  - rubocop-minitest
34
+
35
+ require:
13
36
  - rubocop-rake
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # Logicuit
2
2
 
3
- logi(c cir)cuit -> logicuit
3
+ From logic circuit to Logicuit — a playful portmanteau.
4
+
5
+ A Ruby-based logic circuit simulator featuring an internal DSL for building circuits.
4
6
 
5
7
  ## Installation
6
8
 
@@ -16,50 +18,330 @@ If bundler is not being used to manage dependencies, install the gem by executin
16
18
  gem install logicuit
17
19
  ```
18
20
 
19
- ## Usage
21
+ ## DSL
22
+
23
+ This library provides an internal DSL for defining logic circuits in a declarative and readable way.
24
+ You can define inputs, outputs, and even a visual diagram — all within a Ruby class.
25
+
26
+ Here is an example of a simple 2-input AND gate:
27
+
28
+ ```
29
+ require "logicuit"
30
+
31
+ class MyAndGate < Logicuit::DSL
32
+ inputs :a, :b
20
33
 
21
- This is the code to create a Multiplexer with 2 inputs and 1 output:
34
+ outputs y: -> { a && b }
35
+
36
+ diagram <<~DIAGRAM
37
+ (A)-| |
38
+ |AND|-(Y)
39
+ (B)-| |
40
+ DIAGRAM
41
+ end
22
42
 
43
+ MyAndGate.run
23
44
  ```
24
- require 'logicuit'
25
45
 
26
- class Multiplexer2To1 < Logicuit::Base
27
- tag :MY_MUX
46
+ This defines:
47
+
48
+ - two inputs (`a` and `b`),
49
+ - one output (`y`) that returns the logical AND of the inputs,
50
+ - and an ASCII diagram that shows the structure of the gate.
51
+
52
+ ### Interactive execution
53
+
54
+ When you call `run`, the simulator enters an interactive mode.
55
+
56
+ At first, the circuit is evaluated with all inputs set to `0`, and drawn as an ASCII diagram:
57
+
58
+ ```
59
+ (0)-| |
60
+ |AND|-(0)
61
+ (0)-| |
62
+
63
+ input: a,b?
64
+ ```
65
+
66
+ To interact with the circuit, just type the name of an input — for example, `a` — and press Enter.
67
+ That input will toggle its value (`0 → 1` or `1 → 0`), and the diagram will be redrawn to reflect the new state.
68
+ You can keep toggling inputs this way to observe how the circuit reacts in real time.
69
+
70
+ To exit the simulator, simply press `Ctrl+C`.
71
+
72
+ ### Assembling circuits
73
+
74
+ In addition to defining simple gates declaratively, Logicuit also lets you assemble circuits from reusable components using the `assembling` block.
75
+
76
+ This approach gives you more control and expressiveness when building complex circuits.
77
+
78
+ Here's an example of a 2-to-1 multiplexer:
79
+
80
+ ```
81
+ require "logicuit"
82
+
83
+ class MyMultiplexer < Logicuit::DSL
84
+ inputs :c0, :c1, :a
85
+
86
+ outputs :y
87
+
88
+ assembling do
89
+ and_gate1 = Logicuit::Gates::And.new
90
+ and_gate2 = Logicuit::Gates::And.new
91
+ not_gate = Logicuit::Gates::Not.new
92
+ or_gate = Logicuit::Gates::Or.new
93
+
94
+ c0 >> and_gate1.a
95
+ a >> not_gate.a
96
+ not_gate.y >> and_gate1.b
97
+
98
+ c1 >> and_gate2.a
99
+ a >> and_gate2.b
100
+
101
+ and_gate1.y >> or_gate.a
102
+ and_gate2.y >> or_gate.b
103
+ or_gate.y >> y
104
+ end
28
105
 
29
106
  diagram <<~DIAGRAM
30
- (C0)---------|
107
+ (C0)---------| |
31
108
  |AND|--+
32
- +-|NOT|-| +--|
109
+ +-|NOT|-| | +--| |
33
110
  | |OR|--(Y)
34
- (C1)---------| +--|
111
+ (C1)---------| | +--| |
35
112
  | |AND|--+
36
- (A)--+-------|
113
+ (A)--+-------| |
37
114
  DIAGRAM
115
+ end
116
+
117
+ MyMultiplexer.run
118
+ ```
119
+
120
+ ### Connection syntax
121
+
122
+ The `>>` operator is used to connect outputs to inputs, mimicking the direction of signal flow.
123
+
124
+ This allows the code to resemble the actual structure of the circuit, making it more intuitive to follow.
125
+
126
+ For example:
127
+
128
+ ```
129
+ a >> not_gate.a
130
+ not_gate.y >> and_gate1.b
131
+ ```
132
+
133
+ can be read as:
134
+
135
+ *"Connect input `a` to the NOT gate's input. Then connect the NOT gate's output to one of the AND gate's inputs."*
136
+
137
+ ### Built-in gates
138
+
139
+ Logicuit includes several built-in logic gates, which you can use as components:
140
+
141
+ - `Logicuit::Gates::And`
142
+ - `Logicuit::Gates::Or`
143
+ - `Logicuit::Gates::Not`
144
+ - `Logicuit::Gates::Nand`
145
+ - `Logicuit::Gates::Xor`
146
+
147
+ These gates expose their input and output pins as attributes (`a`, `b`, `y`, etc.), which can be freely connected using `>>`.
148
+
149
+ ### Signal groups
150
+
151
+ When building larger circuits, it's common to connect one output to multiple inputs, or to connect multiple outputs to multiple inputs.
152
+
153
+ Logicuit provides a convenient way to express these kinds of connections using signal groups.
154
+
155
+ #### One-to-many connections
156
+
157
+ These two lines:
158
+
159
+ ```
160
+ a >> xor_gate.a
161
+ a >> and_gate.a
162
+ ```
163
+
164
+ can be written more concisely as:
165
+
166
+ ```
167
+ a >> [xor_gate.a, and_gate.a]
168
+ ```
169
+
170
+ The array on the right-hand side is treated as a signal group, and the connection is applied to each element.
171
+
172
+ #### Many-to-many connections
38
173
 
39
- define_inputs :c0, :c1, :a
174
+ You can also connect multiple outputs to multiple inputs at once by using the [] method to access signals by name:
40
175
 
41
- define_outputs y: ->(c0, c1, a) { (c0 && !a) || (c1 && a) }
176
+ ```
177
+ pc.qa >> rom.a0
178
+ pc.qb >> rom.a1
179
+ pc.qc >> rom.a2
180
+ pc.qd >> rom.a3
181
+ ```
182
+
183
+ is equivalent to:
184
+
185
+ ```
186
+ pc[:qa, :qb, :qc, :qd] >> rom[:a0, :a1, :a2, :a3]
187
+ ```
188
+
189
+ This `#[](*keys)` method returns a `SignalGroup` object — a Logicuit abstraction that makes it easier to handle groups of signals together.
190
+
191
+ > Note: The number of signals on both sides must match.
192
+
193
+ #### Connecting from different sources
194
+
195
+ What if you want to connect signals from multiple different components as a single group?
196
+
197
+ You can use `Logicuit::ArrayAsSignalGroup`, which adds signal group behavior to arrays:
198
+
199
+ ```
200
+ using Logicuit::ArrayAsSignalGroup
201
+
202
+ assembling do
203
+ [register_a.qa, register_b.qa, in0] >> mux0[:c0, :c1, :c2]
42
204
  end
205
+ ```
206
+
207
+ This lets you treat a plain Ruby array as a `SignalGroup` and connect it to another group of inputs in one line.
208
+
209
+ ### Sequential circuits
210
+
211
+ In addition to combinational circuits, Logicuit also supports sequential circuits — circuits whose output depends not only on the current inputs, but also on past inputs.
212
+
213
+ For example, here’s a D flip-flop:
43
214
 
44
- Logicuit.run(:MY_MUX)
45
215
  ```
216
+ require "logicuit"
217
+
218
+ class MyDFlipFlop < Logicuit::DSL
219
+ inputs :d, clock: :ck
46
220
 
47
- you can execute a same circuit by the following as a one-liner:
221
+ outputs q: -> { d }
222
+
223
+ diagram <<~DIAGRAM
224
+ (D)--| |--(Q)
225
+ |DFF|
226
+ (CK)-|> |
227
+ DIAGRAM
228
+ end
48
229
 
230
+ MyDFlipFlop.run
49
231
  ```
50
- ruby -r ./lib/logicuit -e 'Logicuit.run(:mux)'
232
+
233
+ #### Defining a sequential circuit
234
+
235
+ A circuit becomes sequential when the `inputs` declaration includes a keyword argument named `clock:`.
236
+ You can assign any name to the clock signal — in the above example, it's `:ck` — but the presence of the `clock:` keyword is what tells Logicuit to treat the circuit as sequential.
237
+
238
+ Once a clock is defined:
239
+
240
+ - The `outputs` lambdas will be evaluated on each clock tick, not continuously.
241
+ - A global singleton clock will drive the timing — you don’t need to define or manage the clock yourself.
242
+
243
+ #### Interactive execution with a clock
244
+
245
+ When a sequential circuit is run interactively, Logicuit enters clock mode. The clock ticks periodically, and the circuit is redrawn after each tick.
246
+
51
247
  ```
248
+ (0)--| |--(0)
249
+ |DFF|
250
+ (CK)-|> |
52
251
 
53
- you can similarly execute other circuits with the following commands:
252
+ tick: 2
253
+ input: d?
254
+ ```
255
+
256
+ You can still toggle inputs as before (e.g., type `d` and press Enter), but updates take effect on the next tick.
257
+
258
+ The number of elapsed ticks is shown as `tick: N`.
259
+
260
+ #### Clock speed
261
+
262
+ By default, the clock ticks at 1 Hz (once per second). You can change the frequency by passing the `hz:` option to `run`:
263
+
264
+ ```
265
+ MyDFlipFlop.run(hz: 10)
266
+ ```
267
+
268
+ This will run the clock at 10 ticks per second — useful when simulating more complex circuits.
269
+
270
+ If you want full control, you can set `hz: 0` to disable automatic ticking.
271
+
272
+ In this mode, the clock only ticks when you press Enter, allowing you to step through the simulation manually:
273
+
274
+ ```
275
+ MyDFlipFlop.run(hz: 0)
276
+ ```
277
+
278
+ This is useful for debugging or analyzing a circuit’s behavior step by step.
279
+
280
+ #### Combining sequential circuits with `assembling`
281
+
282
+ You can build sequential circuits out of smaller components using the `assembling` block, just like with combinational circuits.
283
+
284
+ Here’s an example of a 4-bit register that stores its input when the load signal `ld` is not active:
54
285
 
55
286
  ```
56
- ruby -r ./lib/logicuit -e 'Logicuit.run(:dff)'
287
+ require "logicuit"
288
+
289
+ class MyRegister4bit < Logicuit::DSL
290
+ inputs :a, :b, :c, :d, :ld, clock: :ck
291
+
292
+ outputs :qa, :qb, :qc, :qd
293
+
294
+ assembling do
295
+ [[a, qa], [b, qb], [c, qc], [d, qd]].each do |input, output|
296
+ dff = Logicuit::Circuits::Sequential::DFlipFlop.new
297
+ mux = Logicuit::Circuits::Combinational::Multiplexer2to1.new
298
+ input >> mux.c0
299
+ dff.q >> mux.c1
300
+ ld >> mux.a
301
+ mux.y >> dff.d
302
+ dff.q >> output
303
+ end
304
+ end
305
+
306
+ diagram <<~DIAGRAM
307
+ +---------------------+
308
+ +-| | |
309
+ (A)-------|MUX|-------|DFF|---+---(QA)
310
+ +---| | +---| |
311
+ | |
312
+ | +---------------------+
313
+ | +-| | | |
314
+ (B)-------|MUX|-------|DFF|---+---(QB)
315
+ +---| | +---| |
316
+ | |
317
+ | +---------------------+
318
+ | +-| | | |
319
+ (C)-------|MUX|-------|DFF|---+---(QC)
320
+ +---| | +---| |
321
+ | |
322
+ | +---------------------+
323
+ | +-| | | |
324
+ (D)-------|MUX|-------|DFF|---+---(QD)
325
+ +---| | +---| |
326
+ (LD)--+ (CK)--+
327
+ DIAGRAM
328
+ end
329
+
330
+ MyRegister4bit.run
57
331
  ```
58
332
 
333
+ #### Sequential detection
334
+
335
+ If your circuit contains one or more sequential components (such as D flip-flops), Logicuit will treat the entire circuit as sequential, as long as you declare a clock input using the `clock:` keyword in `inputs`.
336
+
337
+ The clock signal is automatically connected to all internal sequential components. You don't need to wire it manually — just declare it at the top level:
338
+
59
339
  ```
60
- ruby -r ./lib/logicuit -e 'Logicuit.run(:one_bit_cpu)'
340
+ inputs ..., clock: :ck
61
341
  ```
62
342
 
343
+ > Note: If you forget to declare a clock input, Logicuit won't know it's a sequential circuit — even if you include flip-flops internally. Always include `clock:` to enable timing.
344
+
63
345
  ## Development
64
346
 
65
347
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Logicuit module
4
+ module Logicuit
5
+ # Treats Array#>> as SignalGroup#>> for the purpose of connecting signals
6
+ module ArrayAsSignalGroup
7
+ refine Array do
8
+ def >>(other)
9
+ Signals::SignalGroup.new(*self).connects_to(other)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Logicuit
4
+ module Circuits
5
+ module Combinational
6
+ # FullAdder class
7
+ class FullAdder < DSL
8
+ diagram <<~DIAGRAM
9
+ (Cin)---+-|NOT|-----+
10
+ | |
11
+ (A)---+---|NOT|---+ |
12
+ | | | |
13
+ (B)-+-----|NOT|-+ | +-| |
14
+ | | | | +---|AND|---+
15
+ +-----------------| | |
16
+ | | | | | | +-| |
17
+ | | | | | +-| | | |
18
+ | +---------------|AND|-----| |
19
+ | | | +-----| | | |
20
+ | | | | | | |OR|-(S)
21
+ | | +-------------| | | |
22
+ | | | | +---|AND|-----| |
23
+ | | | +-----| | | |
24
+ | | | | | | +-| |
25
+ | | +-------------| | |
26
+ | +---------------|AND|---+
27
+ +-----------------| |
28
+ | | | | | |
29
+ | | | | | +-| |
30
+ | +---------------|AND|---+
31
+ +-----------------| | |
32
+ | | | | | +-| |
33
+ | | +-------------| | | |
34
+ | | | | +---|AND|-----| |
35
+ +-----------------| | | |
36
+ | | | | |OR|-(C)
37
+ | | +-------------| | | |
38
+ | +---------------|AND|-----| |
39
+ | | | +-----| | | |
40
+ | | | +-| |
41
+ | | +-------------| | |
42
+ | +---------------|AND|---+
43
+ +-----------------| |
44
+ DIAGRAM
45
+
46
+ inputs :cin, :a, :b
47
+
48
+ outputs s: -> { (!cin && !a && b) || (!cin && a && !b) || (cin && !a && !b) || (cin && a && b) },
49
+ c: -> { (!cin && a && b) || (cin && !a && b) || (cin && a && !b) || (cin && a && b) }
50
+
51
+ truth_table <<~TRUTH_TABLE
52
+ | Cin | A | B | C | S |
53
+ | --- | - | - | - | - |
54
+ | 0 | 0 | 0 | 0 | 0 |
55
+ | 0 | 0 | 1 | 0 | 1 |
56
+ | 0 | 1 | 0 | 0 | 1 |
57
+ | 0 | 1 | 1 | 1 | 0 |
58
+ | 1 | 0 | 0 | 0 | 1 |
59
+ | 1 | 0 | 1 | 1 | 0 |
60
+ | 1 | 1 | 0 | 1 | 0 |
61
+ | 1 | 1 | 1 | 1 | 1 |
62
+ TRUTH_TABLE
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Logicuit
4
+ module Circuits
5
+ module Combinational
6
+ # FullAdder class
7
+ class FullAdder4bit < DSL
8
+ diagram <<~DIAGRAM
9
+ (Cin)-| |--(S0) +--------| |--(S1)
10
+ (A0)--|FADD| | (A1)--|FADD|
11
+ (B0)--| |--------+ (B1)--| |--+
12
+ |
13
+ +---------------------------------+
14
+ |
15
+ +--| |--(S2) +--------| |--(S3)
16
+ (A2)--|FADD| | (A3)--|FADD|
17
+ (B2)--| |--------+ (B3)--| |---(C)
18
+ DIAGRAM
19
+
20
+ inputs :cin, :a0, :b0, :a1, :b1, :a2, :b2, :a3, :b3
21
+
22
+ outputs :s0, :s1, :s2, :s3, :c
23
+
24
+ assembling do
25
+ [[a0, b0, s0], [a1, b1, s1], [a2, b2, s2], [a3, b3, s3]].reduce(cin) do |c, sigs|
26
+ a, b, s = sigs
27
+ full_addr = Combinational::FullAdder.new
28
+ c >> full_addr.cin
29
+ a >> full_addr.a
30
+ b >> full_addr.b
31
+ full_addr.s >> s
32
+ full_addr.c
33
+ end >> c
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -4,24 +4,22 @@ module Logicuit
4
4
  module Circuits
5
5
  module Combinational
6
6
  # HalfAdder class
7
- class HalfAdder < Base
8
- tag :HADD
9
-
7
+ class HalfAdder < DSL
10
8
  diagram <<~DIAGRAM
11
- (A)---+-|
9
+ (A)---+-| |
12
10
  | |XOR|-(S)
13
- (B)-+---+
11
+ (B)-+---| |
14
12
  | |
15
- | +-|
13
+ | +-| |
16
14
  | |AND|-(C)
17
- +---|
15
+ +---| |
18
16
  DIAGRAM
19
17
 
20
- define_inputs :a, :b
18
+ inputs :a, :b
21
19
 
22
- define_outputs :c, :s
20
+ outputs :c, :s
23
21
 
24
- assembling do |a, b, c, s|
22
+ assembling do
25
23
  xor_gate = Gates::Xor.new
26
24
  and_gate = Gates::And.new
27
25
 
@@ -4,22 +4,20 @@ module Logicuit
4
4
  module Circuits
5
5
  module Combinational
6
6
  # A Multiplexer with 2 inputs and 1 output
7
- class Multiplexer2To1 < Base
8
- tag :MUX, :MUX2, :MUX2to1
9
-
7
+ class Multiplexer2to1 < DSL
10
8
  diagram <<~DIAGRAM
11
- (C0)---------|
9
+ (C0)---------| |
12
10
  |AND|--+
13
- +-|NOT|-| +--|
11
+ +-|NOT|-| | +--| |
14
12
  | |OR|--(Y)
15
- (C1)---------| +--|
13
+ (C1)---------| | +--| |
16
14
  | |AND|--+
17
- (A)--+-------|
15
+ (A)--+-------| |
18
16
  DIAGRAM
19
17
 
20
- define_inputs :c0, :c1, :a
18
+ inputs :c0, :c1, :a
21
19
 
22
- define_outputs y: ->(c0, c1, a) { (c0 && !a) || (c1 && a) }
20
+ outputs y: -> { (c0 && !a) || (c1 && a) }
23
21
 
24
22
  truth_table <<~TRUTH_TABLE
25
23
  | C0 | C1 | A | Y |
@@ -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 |
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Logicuit
4
+ module Circuits
5
+ module Sequential
6
+ # 1 bit CPU with a Multiplexer
7
+ # Input A is H, MOV A,A
8
+ # Input A is L, NOT A
9
+ class OneBitCpu < DSL
10
+ diagram <<~DIAGRAM
11
+ +-----------------------------+
12
+ | |
13
+ +----| |---+---------| | |
14
+ |DFF| | | | |
15
+ (CK)-|> | +--|NOT|--|MUX|--+--(Y)
16
+ | |
17
+ (A)--| |
18
+ DIAGRAM
19
+
20
+ inputs :a, clock: :ck
21
+
22
+ outputs :y
23
+
24
+ assembling do
25
+ dff = Sequential::DFlipFlop.new
26
+ not_gate = Gates::Not.new
27
+ mux = Combinational::Multiplexer2to1.new
28
+
29
+ dff.q >> mux.c0
30
+ dff.q >> not_gate.a
31
+ not_gate.y >> mux.c1
32
+ a >> mux.a
33
+ mux.y >> dff.d
34
+ mux.y >> y
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end