logicsim/lib.rs
1/*!
2Create and simulate digital circuits with Rust abstractions!
3
4In logicsim you use a [GateGraphBuilder][GateGraphBuilder] to create and connect logic gates,
5conceptually the logic gates are represented as nodes in a graph with dependency edges to other nodes.
6
7Inputs are represented by constants([ON][ON], [OFF][OFF]) and [levers][lever].
8
9Outputs are represented by [OutputHandles][OutputHandle] which allow you to query the state of gates and
10are created by calling [GateGraphBuilder::output][output].
11
12Once the graph is initialized, it transforms into an [InitializedGateGraph][InitializedGateGraph] which cannot be modified.
13The initialization process optimizes the gate graph so that expressive abstractions
14that potentially generate lots of constants or useless gates can be used without fear.
15All constants and dead gates will be optimized away and the remaining graph simplified very aggressively.
16
17**Zero overhead abstractions!**
18
19# Examples
20Simple gates.
21```
22# use logicsim::graph::{GateGraphBuilder,ON,OFF};
23let mut g = GateGraphBuilder::new();
24
25// Providing each gate with a string name allows for great debugging.
26// If you don't want them affecting performance, you can disable
27// feature "debug_gates" and all of the strings will be optimized away.
28let or = g.or2(ON, OFF, "or");
29let or_output = g.output1(or, "or_output");
30
31let and = g.and2(ON, OFF, "and");
32let and_output = g.output1(and, "and_output");
33
34let ig = &g.init();
35
36// `b0()` accesses the 0th bit of the output.
37// Outputs can have as many bits as you want
38// and be accessed with methods like `u8()`, `char()` or `i128()`.
39assert_eq!(or_output.b0(ig), true);
40assert_eq!(and_output.b0(ig), false);
41```
42
43Levers!
44```
45# use logicsim::graph::{GateGraphBuilder,ON,OFF};
46# let mut g = GateGraphBuilder::new();
47let l1 = g.lever("l1");
48let l2 = g.lever("l2");
49
50let or = g.or2(l1.bit(), l2.bit(), "or");
51let or_output = g.output1(or, "or_output");
52
53let and = g.and2(l1.bit(), l2.bit(), "and");
54let and_output = g.output1(and, "and_output");
55
56let ig = &mut g.init();
57
58assert_eq!(or_output.b0(ig), false);
59assert_eq!(and_output.b0(ig), false);
60
61// `_stable` means that the graph will run until gate states
62// have stopped changing. This might not be what you want
63// if you have a circuit that never stabilizes like 3 not gates
64// connected in a loop!
65// See [InitializedGateGraph::run_until_stable].
66ig.flip_lever_stable(l1);
67assert_eq!(or_output.b0(ig), true);
68assert_eq!(and_output.b0(ig), false);
69
70ig.flip_lever_stable(l2);
71assert_eq!(or_output.b0(ig), true);
72assert_eq!(and_output.b0(ig), true);
73```
74
75[SR Latch!](https://en.wikipedia.org/wiki/Flip-flop_(electronics)#SR_NOR_latch)
76```
77# use logicsim::graph::{GateGraphBuilder,ON,OFF};
78# let mut g = GateGraphBuilder::new();
79let r = g.lever("l1");
80let s = g.lever("l2");
81
82let q = g.nor2(r.bit(), OFF, "q");
83let nq = g.nor2(s.bit(), q, "nq");
84
85let q_output = g.output1(q, "q");
86let nq_output = g.output1(nq, "nq");
87
88// `d1()` replaces the dependency at index 1 with nq.
89// We used OFF as a placeholder above.
90g.d1(q, nq);
91
92let ig = &mut g.init();
93// With latches, the initial state should be treated as undefined,
94// so remember to always reset your latches at the beginning
95// of the simulation.
96ig.pulse_lever_stable(r);
97assert_eq!(q_output.b0(ig), false);
98assert_eq!(nq_output.b0(ig), true);
99
100ig.pulse_lever_stable(s);
101assert_eq!(q_output.b0(ig), true);
102assert_eq!(nq_output.b0(ig), false);
103
104ig.pulse_lever_stable(r);
105assert_eq!(q_output.b0(ig), false);
106assert_eq!(nq_output.b0(ig), true);
107```
108
109# The 8 bit computer
110
111In the examples folder you'll find a very simple 8 bit computer, it's a great showcase of what you can achieve by using Rust's constructs
112to create modular circuit abstractions.
113
114You can play with it in only 3 shell commands! ([Assuming you have cargo installed](https://rustup.rs/)).
115```sh
116git clone https://github.com/raycar5/logicsim
117cd logicsim
118cargo run --release --example computer greeter
119```
120
121# Built in circuits
122
123The `circuits` module features a lot of useful pre-built generic components like:
124
125- [WordInput][WordInput]
126- [Bus][Bus]
127- [Wire][Wire]
128- [d_flip_flop][d_flip_flop]
129- [rom][rom]
130
131[and many more!][circuits]
132
133# Debugging
134
135Currently there are 2 debugging tools:
136
137## Probes
138
139Calling [GateGraphBuilder::probe][probe] allows you to create probes, which will print the value of all of the bits provided
140along with their name whenever any of the bits change state within a [tick][tick].
141
142## Example:
143```
144# use logicsim::graph::{GateGraphBuilder,ON,OFF};
145let mut g = GateGraphBuilder::new();
146
147let l1 = g.lever("l1");
148let l2 = g.lever("l2");
149
150
151let or = g.xor2(l1.bit(), l2.bit(), "or");
152let xor = g.xor2(l1.bit(), l2.bit(), "xor");
153g.probe(&[or,xor],"or_xor");
154let xor_output = g.output1(xor, "xor_output");
155
156
157let ig = &mut g.init();
158assert_eq!(xor_output.b0(ig), false);
159
160ig.set_lever_stable(l1);
161assert_eq!(xor_output.b0(ig), true);
162
163ig.set_lever_stable(l2);
164assert_eq!(xor_output.b0(ig), false);
165
166ig.reset_lever_stable(l1);
167assert_eq!(xor_output.b0(ig), true);
168
169ig.reset_lever_stable(l2);
170assert_eq!(xor_output.b0(ig), false);
171```
172In the terminal you'll see:
173```sh
174or_xor: 3
175or_xor: 1
176or_xor: 3
177or_xor: 0
178```
179
180## .dot files
181
182Using the method [InitializedGateGraph::dump_dot][dump_dot] you can generate [.dot](https://en.wikipedia.org/wiki/DOT_(graph_description_language))
183files which can be viewed in many different graph viewers. I recommend [gephi](https://gephi.org/), many others can't handle the size of the graphs
184generated by logicsim.
185
186For example here is the graph representation of the [8 bit computer](#the-8-bit-computer):
187
188<img src="https://i.imgur.com/kOiiAKa.png" width="400px" height="271px">
189
190If we zoom in a bit we can see each node is labeled with its name which can help debug really weird bugs.
191
192<img src="https://i.imgur.com/4Y5SOx0.png" width="400px" height="271px">
193
194# Next steps
195
196- Better debugging: I want a gui where I can see many outputs at once with logic-analyzer-like features, probably web based.
197- More thorough optimization testing and documentation: I have documented and tested a lot of the public API surface but the optimizations folder
198needs some love.
199- RISC-V: I want to test out the limits of logicsim by implementing a RISC-V core and running Rust programs in it!
200- Compiling: Right now logicsim is just an interpreter, I might try making it compile circuits to either Rust or x86_64 directly.
201- Synthesizing: I have a nice fpga dev kit next to me and it would be pretty cool if I could synthesize circuits built in logicsim into it.
202
203[GateGraphBuilder]: https://docs.rs/logicsim/0.1.7/logicsim/graph/struct.GateGraphBuilder.html
204[ON]: https://docs.rs/logicsim/0.1.7/logicsim/graph/constant.ON.html
205[OFF]: https://docs.rs/logicsim/0.1.7/logicsim/graph/constant.OFF.html
206[lever]: https://docs.rs/logicsim/0.1.7/logicsim/graph/struct.GateGraphBuilder.html#method.lever
207[OutputHandle]: https://docs.rs/logicsim/0.1.7/logicsim/graph/struct.OutputHandle.html
208[output]: https://docs.rs/logicsim/0.1.7/logicsim/graph/struct.GateGraphBuilder.html#method.output
209[InitializedGateGraph]: https://docs.rs/logicsim/0.1.7/logicsim/graph/struct.InitializedGateGraph.html
210[WordInput]: https://docs.rs/logicsim/0.1.7/logicsim/circuits/struct.WordInput.html
211[Bus]: https://docs.rs/logicsim/0.1.7/logicsim/circuits/struct.Bus.html
212[Wire]: https://docs.rs/logicsim/0.1.7/logicsim/circuits/struct.Wire.html
213[d_flip_flop]: https://docs.rs/logicsim/0.1.7/logicsim/circuits/fn.d_flip_flop.html
214[rom]: https://docs.rs/logicsim/0.1.7/logicsim/circuits/fn.rom.html
215[circuits]: https://docs.rs/logicsim/0.1.7/logicsim/circuits/index.html
216[probe]: https://docs.rs/logicsim/0.1.7/logicsim/graph/struct.GateGraphBuilder.html#method.probe
217[tick]: https://docs.rs/logicsim/0.1.7/logicsim/graph/struct.InitializedGateGraph.html#method.tick
218[dump_dot]: https://docs.rs/logicsim/0.1.7/logicsim/graph/struct.InitializedGateGraph.html#method.dump_dot
219*/
220#[macro_use]
221pub mod graph;
222pub mod data_structures;
223pub extern crate concat_idents;
224pub mod circuits;
225pub use circuits::*;
226pub use graph::*;