From 0116e1c7fc1cfe469f24b1c3aa8b964f8b768455 Mon Sep 17 00:00:00 2001 From: Simon Doppler Date: Mon, 19 Aug 2019 11:16:43 +0200 Subject: [PATCH 01/10] return true if the output value was changed See #3 --- src/circuit.rs | 6 ++---- src/lib.rs | 2 +- src/models/gates/mod.rs | 8 ++++++-- src/models/gates/mux.rs | 6 +++++- src/models/gates/tri.rs | 5 ++++- src/models/rtlib/arithmic/add.rs | 5 ++++- src/models/rtlib/arithmic/twoscomplement.rs | 4 +++- src/models/rtlib/memory/rom.rs | 5 ++++- src/port/mod.rs | 2 +- src/signal.rs | 6 +++++- 10 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/circuit.rs b/src/circuit.rs index 115c50f..32d3446 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -6,10 +6,8 @@ pub struct Circuit { } impl Circuit { - pub fn tick(&mut self) { - for u in &mut self.updater { - u.update(); - } + pub fn tick(&mut self) -> bool { + self.updater.iter_mut().fold(false, |acc, u| acc | u.update()) } pub fn add_updater(&mut self, updater: &T) { diff --git a/src/lib.rs b/src/lib.rs index 22d3fe2..8ed5183 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -106,5 +106,5 @@ pub trait Updateable { /// When this trait function is called you should perform any action necessary to update the /// struct, e.g. reading input values and updating output values. These changes should be /// instant. - fn update(&mut self); + fn update(&mut self) -> bool; } diff --git a/src/models/gates/mod.rs b/src/models/gates/mod.rs index f81f9b1..288d86b 100644 --- a/src/models/gates/mod.rs +++ b/src/models/gates/mod.rs @@ -25,8 +25,10 @@ macro_rules! create_simple_1i1o_gate { } impl Updateable for $name { - fn update(&mut self) { + fn update(&mut self) -> bool { + let old_value = self.z.inner.value.read().unwrap().clone(); self.z.replace($func(self.a.value())); + old_value != *self.z.inner.value.read().unwrap() } } @@ -57,8 +59,10 @@ macro_rules! create_simple_2i1o_gate { } impl Updateable for $name { - fn update(&mut self) { + fn update(&mut self) -> bool { + let old_value = self.z.inner.value.read().unwrap().clone(); self.z.replace($func(self.a.value(), self.b.value())); + old_value != *self.z.inner.value.read().unwrap() } } diff --git a/src/models/gates/mux.rs b/src/models/gates/mux.rs index df35f08..20a1290 100644 --- a/src/models/gates/mux.rs +++ b/src/models/gates/mux.rs @@ -67,7 +67,9 @@ pub struct Mux { } impl Updateable for Mux { - fn update(&mut self) { + fn update(&mut self) -> bool { + //let old_value = self.z.inner; + let old_value = self.z.inner.value.read().unwrap().clone(); self.z.replace(if self.s.value().is_1H() { self.b.value() } else if self.s.value().is_0L() { @@ -75,6 +77,8 @@ impl Updateable for Mux { } else { Ieee1164::_X }); + + old_value != *self.z.inner.value.read().unwrap() } } diff --git a/src/models/gates/tri.rs b/src/models/gates/tri.rs index db5e084..15dd446 100644 --- a/src/models/gates/tri.rs +++ b/src/models/gates/tri.rs @@ -19,7 +19,8 @@ pub struct TriBuffer { } impl Updateable for TriBuffer { - fn update(&mut self) { + fn update(&mut self) -> bool { + let old_value = self.z.inner.value.read().unwrap().clone(); self.z.replace(if self.s.value().is_1H() { self.a.value() } else if self.s.value().is_0L() { @@ -27,6 +28,8 @@ impl Updateable for TriBuffer { } else { Ieee1164::_X }); + + old_value != *self.z.inner.value.read().unwrap() } } diff --git a/src/models/rtlib/arithmic/add.rs b/src/models/rtlib/arithmic/add.rs index 6c85a18..f294120 100644 --- a/src/models/rtlib/arithmic/add.rs +++ b/src/models/rtlib/arithmic/add.rs @@ -17,7 +17,8 @@ pub struct Add { } impl Updateable for Add { - fn update(&mut self) { + fn update(&mut self) -> bool { + let old_value = self.s.inner.value.read().unwrap().clone(); let a = self.a.value(); let b = self.b.value(); self.s.with_value_mut(|v| match (a.as_u128(), b.as_u128()) { @@ -26,5 +27,7 @@ impl Updateable for Add { .unwrap(), _ => v.set_all_to(Ieee1164::_U), }); + + old_value != *self.s.inner.value.read().unwrap() } } diff --git a/src/models/rtlib/arithmic/twoscomplement.rs b/src/models/rtlib/arithmic/twoscomplement.rs index dcded09..0cde0a4 100644 --- a/src/models/rtlib/arithmic/twoscomplement.rs +++ b/src/models/rtlib/arithmic/twoscomplement.rs @@ -11,8 +11,10 @@ pub struct TwosComplement { } impl Updateable for TwosComplement { - fn update(&mut self) { + fn update(&mut self) -> bool { + let old_value = self.y.inner.value.read().unwrap().clone(); let a = self.a.value(); self.y.with_value_mut(|y| *y = (!a).incr()); + old_value != *self.y.inner.value.read().unwrap() } } diff --git a/src/models/rtlib/memory/rom.rs b/src/models/rtlib/memory/rom.rs index 385ffd9..f291115 100644 --- a/src/models/rtlib/memory/rom.rs +++ b/src/models/rtlib/memory/rom.rs @@ -82,8 +82,9 @@ impl fmt::Debug for Rom1kx8 { } impl Updateable for Rom1kx8 { - fn update(&mut self) { + fn update(&mut self) -> bool { println!("ROM Update"); + let old_value = self.data.inner.value.read().unwrap().clone(); let ncs = self.n_chip_select.value(); let noe = self.n_output_enable.value(); let data = if let Some(addr) = self.addr.value().as_u128() { @@ -105,6 +106,8 @@ impl Updateable for Rom1kx8 { f.set_all_to(Ieee1164::_X); } }); + + old_value != *self.data.inner.value.read().unwrap() } } diff --git a/src/port/mod.rs b/src/port/mod.rs index da59788..b2c8b37 100644 --- a/src/port/mod.rs +++ b/src/port/mod.rs @@ -13,6 +13,6 @@ pub use self::pport::Port; #[derive(Debug)] pub(crate) struct InnerPort { - value: RwLock, + pub value: RwLock, signal: WeakSignal, } diff --git a/src/signal.rs b/src/signal.rs index c8775f1..4683e23 100644 --- a/src/signal.rs +++ b/src/signal.rs @@ -200,9 +200,11 @@ where for<'a> &'a T: Resolve<&'a T, Output = T>, T: Clone + std::fmt::Debug, { - fn update(&mut self) { + fn update(&mut self) -> bool { self.remove_expired_portconnector(); + let old_value = self.inner.output_ports.read().unwrap().clone(); + let in_guard = self.inner.input_ports.write().unwrap(); let mut iter = in_guard.iter(); @@ -229,6 +231,8 @@ where .iter_mut() .for_each(|p| p.set_value(r.clone())); } + + old_value != *self.inner.output_ports.read().unwrap() } } From 1e5e68bdd495053d07ff0a7fb88e46667dbb045e Mon Sep 17 00:00:00 2001 From: Simon Doppler Date: Mon, 19 Aug 2019 11:19:54 +0200 Subject: [PATCH 02/10] document changes (return true if value changed) --- src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 8ed5183..26bf393 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -106,5 +106,7 @@ pub trait Updateable { /// When this trait function is called you should perform any action necessary to update the /// struct, e.g. reading input values and updating output values. These changes should be /// instant. + /// + /// Returns `true` if the output value of the updatable object was changed. fn update(&mut self) -> bool; } From 5bc1634e2d417c10b3e9343ac4f8b3185d9a53c6 Mon Sep 17 00:00:00 2001 From: Simon Doppler Date: Mon, 19 Aug 2019 13:13:55 +0200 Subject: [PATCH 03/10] reuse old values from replace --- src/models/gates/mod.rs | 6 ++---- src/models/gates/mux.rs | 4 +--- src/models/gates/tri.rs | 3 +-- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/models/gates/mod.rs b/src/models/gates/mod.rs index 288d86b..9a7ab11 100644 --- a/src/models/gates/mod.rs +++ b/src/models/gates/mod.rs @@ -26,8 +26,7 @@ macro_rules! create_simple_1i1o_gate { impl Updateable for $name { fn update(&mut self) -> bool { - let old_value = self.z.inner.value.read().unwrap().clone(); - self.z.replace($func(self.a.value())); + let old_value = self.z.replace($func(self.a.value())); old_value != *self.z.inner.value.read().unwrap() } } @@ -60,8 +59,7 @@ macro_rules! create_simple_2i1o_gate { impl Updateable for $name { fn update(&mut self) -> bool { - let old_value = self.z.inner.value.read().unwrap().clone(); - self.z.replace($func(self.a.value(), self.b.value())); + let old_value = self.z.replace($func(self.a.value(), self.b.value())); old_value != *self.z.inner.value.read().unwrap() } } diff --git a/src/models/gates/mux.rs b/src/models/gates/mux.rs index 20a1290..929d9f8 100644 --- a/src/models/gates/mux.rs +++ b/src/models/gates/mux.rs @@ -68,9 +68,7 @@ pub struct Mux { impl Updateable for Mux { fn update(&mut self) -> bool { - //let old_value = self.z.inner; - let old_value = self.z.inner.value.read().unwrap().clone(); - self.z.replace(if self.s.value().is_1H() { + let old_value = self.z.replace(if self.s.value().is_1H() { self.b.value() } else if self.s.value().is_0L() { self.a.value() diff --git a/src/models/gates/tri.rs b/src/models/gates/tri.rs index 15dd446..408e9c2 100644 --- a/src/models/gates/tri.rs +++ b/src/models/gates/tri.rs @@ -20,8 +20,7 @@ pub struct TriBuffer { impl Updateable for TriBuffer { fn update(&mut self) -> bool { - let old_value = self.z.inner.value.read().unwrap().clone(); - self.z.replace(if self.s.value().is_1H() { + let old_value = self.z.replace(if self.s.value().is_1H() { self.a.value() } else if self.s.value().is_0L() { Ieee1164::_Z From 7abd8b576ea7385162c90b74209a5c4ea9ebe3e1 Mon Sep 17 00:00:00 2001 From: Simon Doppler Date: Mon, 19 Aug 2019 12:47:50 +0200 Subject: [PATCH 04/10] document circuit --- src/circuit.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/circuit.rs b/src/circuit.rs index 32d3446..b70c017 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -1,15 +1,47 @@ use crate::Updateable; +/// A `Circuit` is a combination of connected logic elements +/// +/// A `Circuit` holds references of [`Updateable`](Updateable) structs +/// ([`Port`](crate::port::Port), ...), which are updated on every call of +/// tick. #[derive(Default)] pub struct Circuit { updater: Vec>, } impl Circuit { + /// The clock tick function + /// This function propagates the logic values by one Updateable element. + /// + /// Returns `true` as long as at least one element's output value has changed in the circuit. + /// + /// ``` + /// let mut circuit = Circuit::default(); + /// /* Configure updaters */ + /// + /// let mut clock_cycles = 0_u32; + /// while circuit.tick() && clock_cycles < 100 { // 100 is a arbitrary value, to avoid looping if we have an oscillating circuit + /// clock_cycles += 1; + /// } + /// ``` pub fn tick(&mut self) -> bool { self.updater.iter_mut().fold(false, |acc, u| acc | u.update()) } + /// Add an [`Updateable`](Updateable) to the `Circuit` + /// + /// ``` + /// let mut sig = Signal::default(); + /// // Configure signal here + /// + /// let or = OrGate::default(); // Gates do not need to be mutable + /// // Connect gate here + /// + /// let mut circuit = Circuit::default(); + /// circuit.add_updater(&sig); + /// circuit.add_updater(&or); + /// ``` pub fn add_updater(&mut self, updater: &T) { self.updater.push(Box::new(updater.clone())) } From f94cdf9cc06605aa0d917e7111a39432a80c3b16 Mon Sep 17 00:00:00 2001 From: Simon Doppler Date: Mon, 19 Aug 2019 13:39:10 +0200 Subject: [PATCH 05/10] Circuit::tick() is not a clock tick --- src/circuit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/circuit.rs b/src/circuit.rs index b70c017..510d66f 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -11,7 +11,7 @@ pub struct Circuit { } impl Circuit { - /// The clock tick function + /// The update tick function /// This function propagates the logic values by one Updateable element. /// /// Returns `true` as long as at least one element's output value has changed in the circuit. From c37724593052f04355962fdfd677ff0a454c5cb9 Mon Sep 17 00:00:00 2001 From: Simon Doppler Date: Mon, 19 Aug 2019 13:39:42 +0200 Subject: [PATCH 06/10] update fulladder example to use the tick return value --- examples/fulladder.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/examples/fulladder.rs b/examples/fulladder.rs index b89e775..51ea16e 100644 --- a/examples/fulladder.rs +++ b/examples/fulladder.rs @@ -110,17 +110,29 @@ fn main() { y.replace(triple[1]); c.replace(triple[2]); - for _ in 0..3 { - circuit.tick(); + let mut cycle_count = 0_u32; + while circuit.tick() && cycle_count < 10_u32 { + cycle_count += 1; } + // If the number of required ticks is known, it is possible to use + // a loop with a fixed number of iterations + // ``` + // for _ in 0..3 { + // circuit.tick(); + // } + // ``` + + cycle_count += 1; // To get the correct number of cycles + println!( - "{} + {} + {} = {}{}", + "{} + {} + {} = {}{} (used {} cycles to reach a stable circuit)", triple[0], triple[1], triple[2], cout.value(), - s.value() + s.value(), + cycle_count ); assert_eq!(triple[3], s.value()); assert_eq!(triple[4], cout.value()); From 40ae49c442b3c363644fdfdea1468aa8a1df9240 Mon Sep 17 00:00:00 2001 From: Simon Doppler Date: Mon, 19 Aug 2019 14:01:33 +0200 Subject: [PATCH 07/10] add missing imports --- src/circuit.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/circuit.rs b/src/circuit.rs index 510d66f..1b983b0 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -17,6 +17,9 @@ impl Circuit { /// Returns `true` as long as at least one element's output value has changed in the circuit. /// /// ``` + /// use logical::{Circuit, Signal}; + /// use logical::models::gates::OrGate; + /// /// let mut circuit = Circuit::default(); /// /* Configure updaters */ /// @@ -32,7 +35,10 @@ impl Circuit { /// Add an [`Updateable`](Updateable) to the `Circuit` /// /// ``` - /// let mut sig = Signal::default(); + /// use logical::{Circuit, Signal, Ieee1164}; + /// use logical::models::gates::OrGate; + /// + /// let mut sig: logical::Signal = Signal::default(); /// // Configure signal here /// /// let or = OrGate::default(); // Gates do not need to be mutable From 9b5e9aadedd2dabe34e038aa99e057c9c22d93eb Mon Sep 17 00:00:00 2001 From: Simon Doppler Date: Mon, 19 Aug 2019 16:45:14 +0200 Subject: [PATCH 08/10] use PortConnector instead of exposing inner port --- src/models/gates/mod.rs | 10 ++++++---- src/models/gates/mux.rs | 8 +++++--- src/models/gates/tri.rs | 7 ++++--- src/models/rtlib/arithmic/add.rs | 5 +++-- src/models/rtlib/arithmic/twoscomplement.rs | 6 ++++-- src/models/rtlib/memory/rom.rs | 5 +++-- src/port/mod.rs | 2 +- 7 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/models/gates/mod.rs b/src/models/gates/mod.rs index 9a7ab11..85b69cf 100644 --- a/src/models/gates/mod.rs +++ b/src/models/gates/mod.rs @@ -26,8 +26,9 @@ macro_rules! create_simple_1i1o_gate { impl Updateable for $name { fn update(&mut self) -> bool { - let old_value = self.z.replace($func(self.a.value())); - old_value != *self.z.inner.value.read().unwrap() + let new_value = $func(self.a.value()); + let old_value = self.z.replace(new_value); + old_value != new_value } } @@ -59,8 +60,9 @@ macro_rules! create_simple_2i1o_gate { impl Updateable for $name { fn update(&mut self) -> bool { - let old_value = self.z.replace($func(self.a.value(), self.b.value())); - old_value != *self.z.inner.value.read().unwrap() + let new_value = $func(self.a.value(), self.b.value()); + let old_value = self.z.replace(new_value); + old_value != new_value } } diff --git a/src/models/gates/mux.rs b/src/models/gates/mux.rs index 929d9f8..ef76e0a 100644 --- a/src/models/gates/mux.rs +++ b/src/models/gates/mux.rs @@ -68,15 +68,17 @@ pub struct Mux { impl Updateable for Mux { fn update(&mut self) -> bool { - let old_value = self.z.replace(if self.s.value().is_1H() { + let new_value = if self.s.value().is_1H() { self.b.value() } else if self.s.value().is_0L() { self.a.value() } else { Ieee1164::_X - }); + }; - old_value != *self.z.inner.value.read().unwrap() + let old_value = self.z.replace(new_value); + + old_value != new_value } } diff --git a/src/models/gates/tri.rs b/src/models/gates/tri.rs index 408e9c2..165873e 100644 --- a/src/models/gates/tri.rs +++ b/src/models/gates/tri.rs @@ -20,15 +20,16 @@ pub struct TriBuffer { impl Updateable for TriBuffer { fn update(&mut self) -> bool { - let old_value = self.z.replace(if self.s.value().is_1H() { + let new_value = if self.s.value().is_1H() { self.a.value() } else if self.s.value().is_0L() { Ieee1164::_Z } else { Ieee1164::_X - }); + }; + let old_value = self.z.replace(new_value); - old_value != *self.z.inner.value.read().unwrap() + old_value != new_value } } diff --git a/src/models/rtlib/arithmic/add.rs b/src/models/rtlib/arithmic/add.rs index f294120..b2da060 100644 --- a/src/models/rtlib/arithmic/add.rs +++ b/src/models/rtlib/arithmic/add.rs @@ -1,6 +1,7 @@ use crate::direction::{Input, Output}; use crate::logicbit::mask_from_width; use crate::{Ieee1164, LogicVector, Port, Updateable}; +use crate::port::PortConnector; /// This models an actual adder that will add up both inputs. /// @@ -18,7 +19,7 @@ pub struct Add { impl Updateable for Add { fn update(&mut self) -> bool { - let old_value = self.s.inner.value.read().unwrap().clone(); + let old_value = PortConnector::from(self.s.clone()).value(); let a = self.a.value(); let b = self.b.value(); self.s.with_value_mut(|v| match (a.as_u128(), b.as_u128()) { @@ -28,6 +29,6 @@ impl Updateable for Add { _ => v.set_all_to(Ieee1164::_U), }); - old_value != *self.s.inner.value.read().unwrap() + old_value != PortConnector::from(self.s.clone()).value() } } diff --git a/src/models/rtlib/arithmic/twoscomplement.rs b/src/models/rtlib/arithmic/twoscomplement.rs index 0cde0a4..7ca51c4 100644 --- a/src/models/rtlib/arithmic/twoscomplement.rs +++ b/src/models/rtlib/arithmic/twoscomplement.rs @@ -1,6 +1,8 @@ use crate::direction::{Input, Output}; use crate::{LogicVector, Port, Updateable}; +use crate::port::PortConnector; + /// Computes the two's complement of the applied value. #[derive(Debug)] pub struct TwosComplement { @@ -12,9 +14,9 @@ pub struct TwosComplement { impl Updateable for TwosComplement { fn update(&mut self) -> bool { - let old_value = self.y.inner.value.read().unwrap().clone(); + let old_value = PortConnector::from(self.y.clone()).value(); let a = self.a.value(); self.y.with_value_mut(|y| *y = (!a).incr()); - old_value != *self.y.inner.value.read().unwrap() + old_value != PortConnector::from(self.y.clone()).value() } } diff --git a/src/models/rtlib/memory/rom.rs b/src/models/rtlib/memory/rom.rs index f291115..5c4d220 100644 --- a/src/models/rtlib/memory/rom.rs +++ b/src/models/rtlib/memory/rom.rs @@ -3,6 +3,7 @@ use std::iter::FromIterator; use crate::direction::{Input, Output}; use crate::{Ieee1164, LogicVector, Port, Updateable}; +use crate::port::PortConnector; /// This struct represents a Read-only-memory with a size of 1kB (1024 bytes). /// @@ -84,7 +85,7 @@ impl fmt::Debug for Rom1kx8 { impl Updateable for Rom1kx8 { fn update(&mut self) -> bool { println!("ROM Update"); - let old_value = self.data.inner.value.read().unwrap().clone(); + let old_value = PortConnector::from(self.data.clone()).value(); let ncs = self.n_chip_select.value(); let noe = self.n_output_enable.value(); let data = if let Some(addr) = self.addr.value().as_u128() { @@ -107,7 +108,7 @@ impl Updateable for Rom1kx8 { } }); - old_value != *self.data.inner.value.read().unwrap() + old_value != PortConnector::from(self.data.clone()).value() } } diff --git a/src/port/mod.rs b/src/port/mod.rs index b2c8b37..da59788 100644 --- a/src/port/mod.rs +++ b/src/port/mod.rs @@ -13,6 +13,6 @@ pub use self::pport::Port; #[derive(Debug)] pub(crate) struct InnerPort { - pub value: RwLock, + value: RwLock, signal: WeakSignal, } From 64432d175bc739f94cf53a6b27722adf39982141 Mon Sep 17 00:00:00 2001 From: Simon Doppler Date: Mon, 19 Aug 2019 16:45:38 +0200 Subject: [PATCH 09/10] clear up example --- examples/fulladder.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/fulladder.rs b/examples/fulladder.rs index 51ea16e..c31b741 100644 --- a/examples/fulladder.rs +++ b/examples/fulladder.rs @@ -110,8 +110,8 @@ fn main() { y.replace(triple[1]); c.replace(triple[2]); - let mut cycle_count = 0_u32; - while circuit.tick() && cycle_count < 10_u32 { + let mut cycle_count = 1; + while circuit.tick() && cycle_count < 11 { cycle_count += 1; } @@ -123,8 +123,6 @@ fn main() { // } // ``` - cycle_count += 1; // To get the correct number of cycles - println!( "{} + {} + {} = {}{} (used {} cycles to reach a stable circuit)", triple[0], From 803c1f297efd59060dc93e1c76af7777fa66db0e Mon Sep 17 00:00:00 2001 From: Simon Doppler Date: Mon, 19 Aug 2019 16:49:03 +0200 Subject: [PATCH 10/10] remove suffix in documentation --- src/circuit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/circuit.rs b/src/circuit.rs index 1b983b0..d99dbc0 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -23,7 +23,7 @@ impl Circuit { /// let mut circuit = Circuit::default(); /// /* Configure updaters */ /// - /// let mut clock_cycles = 0_u32; + /// let mut clock_cycles = 0; /// while circuit.tick() && clock_cycles < 100 { // 100 is a arbitrary value, to avoid looping if we have an oscillating circuit /// clock_cycles += 1; /// }