Skip to content

Commit

Permalink
Merge pull request #6 from dopsi/update-status
Browse files Browse the repository at this point in the history
Propagate changes of output value through Updateable::update() and Circuit::tick()
  • Loading branch information
hellow554 authored Aug 19, 2019
2 parents 70da7a8 + 803c1f2 commit 9252b93
Show file tree
Hide file tree
Showing 10 changed files with 98 additions and 23 deletions.
18 changes: 14 additions & 4 deletions examples/fulladder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,17 +110,27 @@ fn main() {
y.replace(triple[1]);
c.replace(triple[2]);

for _ in 0..3 {
circuit.tick();
let mut cycle_count = 1;
while circuit.tick() && cycle_count < 11 {
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();
// }
// ```

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());
Expand Down
44 changes: 40 additions & 4 deletions src/circuit.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,53 @@
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<Box<dyn Updateable>>,
}

impl Circuit {
pub fn tick(&mut self) {
for u in &mut self.updater {
u.update();
}
/// 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.
///
/// ```
/// use logical::{Circuit, Signal};
/// use logical::models::gates::OrGate;
///
/// let mut circuit = Circuit::default();
/// /* Configure updaters */
///
/// 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;
/// }
/// ```
pub fn tick(&mut self) -> bool {
self.updater.iter_mut().fold(false, |acc, u| acc | u.update())
}

/// Add an [`Updateable`](Updateable) to the `Circuit`
///
/// ```
/// use logical::{Circuit, Signal, Ieee1164};
/// use logical::models::gates::OrGate;
///
/// let mut sig: logical::Signal<Ieee1164> = 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<T: Updateable + Clone + 'static>(&mut self, updater: &T) {
self.updater.push(Box::new(updater.clone()))
}
Expand Down
4 changes: 3 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
fn update(&mut self);
///
/// Returns `true` if the output value of the updatable object was changed.
fn update(&mut self) -> bool;
}
12 changes: 8 additions & 4 deletions src/models/gates/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ macro_rules! create_simple_1i1o_gate {
}

impl Updateable for $name {
fn update(&mut self) {
self.z.replace($func(self.a.value()));
fn update(&mut self) -> bool {
let new_value = $func(self.a.value());
let old_value = self.z.replace(new_value);
old_value != new_value
}
}

Expand Down Expand Up @@ -58,8 +60,10 @@ macro_rules! create_simple_2i1o_gate {
}

impl Updateable for $name {
fn update(&mut self) {
self.z.replace($func(self.a.value(), self.b.value()));
fn update(&mut self) -> bool {
let new_value = $func(self.a.value(), self.b.value());
let old_value = self.z.replace(new_value);
old_value != new_value
}
}

Expand Down
10 changes: 7 additions & 3 deletions src/models/gates/mux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,18 @@ pub struct Mux {
}

impl Updateable for Mux {
fn update(&mut self) {
self.z.replace(if self.s.value().is_1H() {
fn update(&mut self) -> bool {
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
});
};

let old_value = self.z.replace(new_value);

old_value != new_value
}
}

Expand Down
9 changes: 6 additions & 3 deletions src/models/gates/tri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,17 @@ pub struct TriBuffer {
}

impl Updateable for TriBuffer {
fn update(&mut self) {
self.z.replace(if self.s.value().is_1H() {
fn update(&mut self) -> bool {
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 != new_value
}
}

Expand Down
6 changes: 5 additions & 1 deletion src/models/rtlib/arithmic/add.rs
Original file line number Diff line number Diff line change
@@ -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.
///
Expand All @@ -17,7 +18,8 @@ pub struct Add {
}

impl Updateable for Add {
fn update(&mut self) {
fn update(&mut self) -> bool {
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()) {
Expand All @@ -26,5 +28,7 @@ impl Updateable for Add {
.unwrap(),
_ => v.set_all_to(Ieee1164::_U),
});

old_value != PortConnector::from(self.s.clone()).value()
}
}
6 changes: 5 additions & 1 deletion src/models/rtlib/arithmic/twoscomplement.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -11,8 +13,10 @@ pub struct TwosComplement {
}

impl Updateable for TwosComplement {
fn update(&mut self) {
fn update(&mut self) -> bool {
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 != PortConnector::from(self.y.clone()).value()
}
}
6 changes: 5 additions & 1 deletion src/models/rtlib/memory/rom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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).
///
Expand Down Expand Up @@ -83,8 +84,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 = 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() {
Expand All @@ -106,6 +108,8 @@ impl Updateable for Rom1kx8 {
f.set_all_to(Ieee1164::_X);
}
});

old_value != PortConnector::from(self.data.clone()).value()
}
}

Expand Down
6 changes: 5 additions & 1 deletion src/signal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand All @@ -229,6 +231,8 @@ where
.iter_mut()
.for_each(|p| p.set_value(r.clone()));
}

old_value != *self.inner.output_ports.read().unwrap()
}
}

Expand Down

0 comments on commit 9252b93

Please sign in to comment.