Skip to content

Instantly share code, notes, and snippets.

@Badel2
Created February 14, 2018 20:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Badel2/df93c98138901f065d43c1eb57afabe2 to your computer and use it in GitHub Desktop.
Save Badel2/df93c98138901f065d43c1eb57afabe2 to your computer and use it in GitHub Desktop.
#[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