Created
February 14, 2018 20:57
-
-
Save Badel2/df93c98138901f065d43c1eb57afabe2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#[derive(Debug, Copy, Clone, PartialEq)] | |
enum Bit { | |
L, // Low, false, 0 | |
H, // High, true, 1 | |
X, // Undefined | |
} | |
trait Component: std::fmt::Debug { | |
fn update(&mut self, input: &[Bit]) -> Vec<Bit>; | |
fn num_inputs(&self) -> usize; | |
fn num_outputs(&self) -> usize; | |
fn name(&self) -> &str; | |
} | |
#[derive(Debug, Copy, Clone)] | |
struct Nand { | |
num_inputs: usize, | |
} | |
impl Nand { | |
fn new(num_inputs: usize) -> Nand { | |
Nand { num_inputs } | |
} | |
} | |
impl Component for Nand { | |
fn update(&mut self, input: &[Bit]) -> Vec<Bit> { | |
assert_eq!(self.num_inputs, input.len()); | |
let mut x = Bit::L; | |
for a in input { | |
match *a { | |
// If any input is 0, the output is 1 | |
Bit::L => return vec![Bit::H], | |
// X NAND L = H, but X NAND H = X | |
Bit::X => x = Bit::X, | |
Bit::H => {}, | |
} | |
} | |
vec![x] | |
} | |
fn num_inputs(&self) -> usize { | |
self.num_inputs | |
} | |
fn num_outputs(&self) -> usize { | |
1 | |
} | |
fn name(&self) -> &str { | |
"NAND" | |
} | |
} | |
#[derive(Debug, Copy, Clone)] | |
struct Or2 { | |
nand_a: Nand, | |
nand_b: Nand, | |
nand_c: Nand, | |
} | |
impl Or2 { | |
fn new() -> Or2 { | |
Or2 { | |
nand_a: Nand::new(1), | |
nand_b: Nand::new(1), | |
nand_c: Nand::new(2), | |
} | |
} | |
} | |
impl Component for Or2 { | |
fn update(&mut self, input: &[Bit]) -> Vec<Bit> { | |
assert_eq!(input.len(), 2); | |
let a = input[0]; | |
let b = input[1]; | |
let not_a = self.nand_a.update(&[a])[0]; | |
let not_b = self.nand_b.update(&[b])[0]; | |
// not_a nand not_b == not (not_a or not_b) == a or b | |
self.nand_c.update(&[not_a, not_b]) | |
} | |
fn num_inputs(&self) -> usize { | |
2 | |
} | |
fn num_outputs(&self) -> usize { | |
1 | |
} | |
fn name(&self) -> &str { | |
"Old_OR" | |
} | |
} | |
#[derive(Debug)] | |
struct Structural { | |
components: Vec<CompIo>, | |
num_inputs: usize, | |
num_outputs: usize, | |
name: String, | |
} | |
impl Structural { | |
fn new(components: Vec<CompIo>, num_inputs: usize, num_outputs: usize, | |
name: &str) -> Structural { | |
// Component 0 must have been created using CompIo::c_zero | |
assert_eq!(components[0].input.len(), num_outputs); | |
assert_eq!(components[0].output.len(), num_inputs); | |
assert_eq!(components[0].connections.len(), num_inputs); | |
// TODO: check that all the connections are valid | |
let name = name.to_string(); | |
Structural { components, num_inputs, num_outputs, name } | |
} | |
fn propagate(&mut self, c_id: usize) { | |
// TODO: avoid this clone | |
let connections = self.components[c_id].connections.clone(); | |
for (out_id, to) in connections.iter().enumerate() { | |
for i in to { | |
self.components[i.comp_id] | |
.input[i.input_id] = self.components[c_id].output[out_id]; | |
} | |
} | |
} | |
fn propagate_input(&mut self, input: &[Bit]) { | |
// The input is an output when seen from inside | |
self.components[0].output = input.to_vec(); | |
self.propagate(0); | |
} | |
fn output(&self) -> Vec<Bit> { | |
self.components[0].input.clone() | |
} | |
fn update_components(&mut self) { | |
for c in 1..self.components.len() { | |
// Magic pattern matching to make the borrow checker happy | |
let CompIo { | |
ref mut comp, | |
ref input, | |
ref mut output, | |
connections: _ | |
} = self.components[c]; | |
*output = comp.update(input); | |
} | |
} | |
fn propagate_signals(&mut self) { | |
for c in 1..self.components.len() { | |
self.propagate(c); | |
} | |
} | |
} | |
impl Component for Structural { | |
fn update(&mut self, input: &[Bit]) -> Vec<Bit> { | |
assert_eq!(input.len(), self.num_inputs()); | |
// Propagate input | |
self.propagate_input(input); | |
// Update components | |
self.update_components(); | |
// Propagate internal signals | |
self.propagate_signals(); | |
// Return the component output | |
self.output() | |
} | |
fn num_inputs(&self) -> usize { | |
self.num_inputs | |
} | |
fn num_outputs(&self) -> usize { | |
self.num_outputs | |
} | |
fn name(&self) -> &str { | |
&self.name | |
} | |
} | |
#[derive(Debug)] | |
struct CompIo { | |
comp: Box<Component>, | |
input: Vec<Bit>, | |
output: Vec<Bit>, | |
connections: Vec<Vec<Index>>, | |
} | |
impl CompIo { | |
fn new(comp: Box<Component>) -> CompIo { | |
let input = vec![Bit::X; comp.num_inputs()]; | |
let output = vec![Bit::X; comp.num_outputs()]; | |
let connections = vec![vec![]; comp.num_outputs()]; | |
CompIo { | |
comp, | |
input, | |
output, | |
connections, | |
} | |
} | |
fn c_zero(num_inputs: usize, num_outputs: usize) -> CompIo { | |
let comp = Box::new(Nand::new(0)); | |
let input = vec![Bit::X; num_outputs]; | |
let output = vec![Bit::X; num_inputs]; | |
let connections = vec![vec![]; num_inputs]; | |
CompIo { | |
comp, | |
input, | |
output, | |
connections, | |
} | |
} | |
fn add_connection(&mut self, output_id: usize, to: Index) { | |
self.connections[output_id].push(to); | |
} | |
} | |
#[derive(Debug, Clone)] | |
struct Index { | |
comp_id: usize, | |
input_id: usize | |
} | |
impl Index { | |
fn new(comp_id: usize, input_id: usize) -> Index { | |
Index { comp_id, input_id } | |
} | |
} | |
fn nand_short() { | |
let mut c = vec![]; | |
let mut c_zero = CompIo::c_zero(1, 1); // c_id: 0 | |
let mut nand_a = CompIo::new(Box::new(Nand::new(2))); // c_id: 1 | |
c_zero.add_connection(0, Index::new(1, 0)); // input 0 -> nand_a | |
nand_a.add_connection(0, Index::new(1, 1)); // nand_a -> nand_a | |
nand_a.add_connection(0, Index::new(0, 0)); // nand_a -> out | |
c.push(c_zero); | |
c.push(nand_a); | |
let mut nand_short = Structural::new(c, 1, 1, "NAND short"); | |
truth_table(&mut nand_short); | |
} | |
fn boxed_or_gate() -> Box<Component> { | |
let mut c = vec![]; | |
let mut c_zero = CompIo::c_zero(2, 1); // c_id: 0 | |
let mut nand_a = CompIo::new(Box::new(Nand::new(1))); // c_id: 1 | |
let mut nand_b = CompIo::new(Box::new(Nand::new(1))); // c_id: 2 | |
let mut nand_c = CompIo::new(Box::new(Nand::new(2))); // c_id: 3 | |
c_zero.add_connection(0, Index::new(1, 0)); // input 0 -> nand_a | |
c_zero.add_connection(1, Index::new(2, 0)); // input 1 -> nand_b | |
nand_a.add_connection(0, Index::new(3, 0)); // nand_a -> nand_c | |
nand_b.add_connection(0, Index::new(3, 1)); // nand_b -> nand_c | |
nand_c.add_connection(0, Index::new(0, 0)); // output of nand_c == output of or | |
c.push(c_zero); | |
c.push(nand_a); | |
c.push(nand_b); | |
c.push(nand_c); | |
Box::new(Structural::new(c, 2, 1, "OR2")) | |
} | |
fn or_gate() { | |
let mut or_gate = boxed_or_gate(); | |
truth_table(&mut *or_gate); | |
} | |
fn old_or_gate() { | |
let mut or_gate = Or2::new(); | |
truth_table(&mut or_gate); | |
} | |
fn triple_or() { | |
let mut c = vec![]; | |
let mut c_zero = CompIo::c_zero(1, 1); // c_id: 0 | |
let mut or_a = CompIo::new(boxed_or_gate()); // c_id: 1 | |
let mut or_b = CompIo::new(boxed_or_gate()); // c_id: 2 | |
let mut or_c = CompIo::new(boxed_or_gate()); // c_id: 3 | |
c_zero.add_connection(0, Index::new(1, 0)); // input 0 -> or_a | |
c_zero.add_connection(0, Index::new(1, 1)); // input 0 -> or_a | |
or_a.add_connection(0, Index::new(2, 0)); // or_a -> or_b | |
or_a.add_connection(0, Index::new(2, 1)); // or_a -> or_b | |
or_b.add_connection(0, Index::new(3, 0)); // or_b -> or_c | |
or_b.add_connection(0, Index::new(3, 1)); // or_b -> or_c | |
or_c.add_connection(0, Index::new(0, 0)); // output | |
c.push(c_zero); | |
c.push(or_a); | |
c.push(or_b); | |
c.push(or_c); | |
let mut or_gate = Structural::new(c, 1, 1, "OR-OR-OR"); | |
truth_table(&mut or_gate); | |
} | |
fn truth_table(or_gate: &mut Component) { | |
let n = or_gate.num_inputs(); | |
println!("{} truth table:", or_gate.name()); | |
let mut i = vec![Bit::L, Bit::L]; | |
println!("{:?} = {:?}", &i[0..n], or_gate.update(&i[0..n])); | |
println!("{:?} = {:?}", &i[0..n], or_gate.update(&i[0..n])); | |
println!("{:?} = {:?}", &i[0..n], or_gate.update(&i[0..n])); | |
//println!("{:#?}", or_gate); | |
i = vec![Bit::L, Bit::H]; | |
println!("{:?} = {:?}", &i[0..n], or_gate.update(&i[0..n])); | |
println!("{:?} = {:?}", &i[0..n], or_gate.update(&i[0..n])); | |
println!("{:?} = {:?}", &i[0..n], or_gate.update(&i[0..n])); | |
i = vec![Bit::H, Bit::L]; | |
println!("{:?} = {:?}", &i[0..n], or_gate.update(&i[0..n])); | |
println!("{:?} = {:?}", &i[0..n], or_gate.update(&i[0..n])); | |
println!("{:?} = {:?}", &i[0..n], or_gate.update(&i[0..n])); | |
i = vec![Bit::H, Bit::H]; | |
println!("{:?} = {:?}", &i[0..n], or_gate.update(&i[0..n])); | |
println!("{:?} = {:?}", &i[0..n], or_gate.update(&i[0..n])); | |
println!("{:?} = {:?}", &i[0..n], or_gate.update(&i[0..n])); | |
} | |
fn main(){ | |
old_or_gate(); | |
or_gate(); | |
nand_short(); | |
triple_or(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment