From 9ea0dc9cec7c1fd6adba4bb3806e328470416bd9 Mon Sep 17 00:00:00 2001 From: Fabian Stemmler Date: Sun, 12 May 2019 14:27:09 +0200 Subject: [PATCH] added more doc to Timeline; added functionality to Bit --- era.mi/src/era/mi/logic/Bit.java | 201 ++--- era.mi/src/era/mi/logic/Util.java | 9 +- .../src/era/mi/logic/tests/ComponentTest.java | 640 ++++++++-------- era.mi/src/era/mi/logic/tests/Connector.java | 2 +- .../src/era/mi/logic/timeline/Timeline.java | 199 ++--- .../era/mi/logic/timeline/TimelineEvent.java | 42 +- era.mi/src/era/mi/logic/wires/WireArray.java | 718 +++++++++--------- 7 files changed, 916 insertions(+), 895 deletions(-) diff --git a/era.mi/src/era/mi/logic/Bit.java b/era.mi/src/era/mi/logic/Bit.java index e7c93968..58a538a9 100644 --- a/era.mi/src/era/mi/logic/Bit.java +++ b/era.mi/src/era/mi/logic/Bit.java @@ -1,95 +1,106 @@ -package era.mi.logic; - -public enum Bit -{ - ONE, ZERO, Z, X; - - public static Bit and(Bit a, Bit b) - { - return a.and(b); - } - - public Bit and(Bit other) - { - if (equals(Bit.ZERO) || other.equals(Bit.ZERO)) - return Bit.ZERO; - else if (equals(other) && equals(Bit.ONE)) - return Bit.ONE; - else - return Bit.X; - } - - public static Bit or(Bit a, Bit b) - { - return a.or(b); - } - - public Bit or(Bit other) - { - if (equals(Bit.ONE) || other.equals(Bit.ONE)) - return Bit.ONE; - else if (equals(other) && equals(Bit.ZERO)) - return Bit.ZERO; - else - return Bit.X; - } - - public static Bit xor(Bit a, Bit b) - { - return a.xor(b); - } - - public Bit xor(Bit other) - { - // I'm uncertain how this should behave for cases where one value is neither 1 nor 0. - // TODO: Implement xor - return Bit.X; - } - - public Bit not() - { - switch (this) - { - case ONE: - return Bit.ZERO; - case ZERO: - return Bit.ONE; - default: - return Bit.X; - } - } - - /** - * Rules for two bits that get directly connected
- * - * - * - * - * - * - * - * - *
X01Z
XXXXX
0X0X0
1XX11
ZX01Z
- * - * @return the result according to the table - * - * @author Christian Femers - */ - public Bit combineWith(Bit other) - { - if (this == other) - return this; - if (this == X || other == X) - return X; - if (other == Z) - return this; - if (this == Z) - return other; - return X; - } - - public static Bit combine(Bit a, Bit b) - { - return a.combineWith(b); - } -} +package era.mi.logic; + +import java.util.Arrays; + +public enum Bit +{ + ONE, ZERO, Z, X; + + public static Bit and(Bit a, Bit b) + { + return a.and(b); + } + + public Bit and(Bit other) + { + if (equals(Bit.ZERO) || other.equals(Bit.ZERO)) + return Bit.ZERO; + else if (equals(other) && equals(Bit.ONE)) + return Bit.ONE; + else + return Bit.X; + } + + public static Bit or(Bit a, Bit b) + { + return a.or(b); + } + + public Bit or(Bit other) + { + if (equals(Bit.ONE) || other.equals(Bit.ONE)) + return Bit.ONE; + else if (equals(other) && equals(Bit.ZERO)) + return Bit.ZERO; + else + return Bit.X; + } + + public static Bit xor(Bit a, Bit b) + { + return a.xor(b); + } + + public Bit xor(Bit other) + { + if(this == Bit.X || this == Bit.Z + || other == Bit.X || other == Bit.Z) + return Bit.X; + else + return this == other ? Bit.ZERO : Bit.ONE; + } + + public Bit not() + { + switch (this) + { + case ONE: + return Bit.ZERO; + case ZERO: + return Bit.ONE; + default: + return Bit.X; + } + } + + public Bit[] makeArray(int length) + { + Bit[] bits = new Bit[length]; + Arrays.fill(bits, this); + return bits; + } + + /** + * Rules for two bits that get directly connected
+ * + * + * + * + * + * + * + * + *
X01Z
XXXXX
0X0X0
1XX11
ZX01Z
+ * + * @return the result according to the table + * + * @author Christian Femers + */ + public Bit combineWith(Bit other) + { + if (this == other) + return this; + if (this == X || other == X) + return X; + if (other == Z) + return this; + if (this == Z) + return other; + return X; + } + + public static Bit combine(Bit a, Bit b) + { + return a.combineWith(b); + } +} diff --git a/era.mi/src/era/mi/logic/Util.java b/era.mi/src/era/mi/logic/Util.java index 6aec8844..3ca16b7a 100644 --- a/era.mi/src/era/mi/logic/Util.java +++ b/era.mi/src/era/mi/logic/Util.java @@ -85,16 +85,9 @@ public final class Util return out; } - public static Bit[] arrayOfZ(int length) - { - Bit[] out = new Bit[length]; - Arrays.fill(out, Bit.Z); - return out; - } - /** * uses the {@link Bit#combineWith(Bit)} method, does not create a new array, - * the result is stored in the fist array. + * the result is stored in the first array. * * @author Christian Femers */ diff --git a/era.mi/src/era/mi/logic/tests/ComponentTest.java b/era.mi/src/era/mi/logic/tests/ComponentTest.java index a407b8df..c49e0040 100644 --- a/era.mi/src/era/mi/logic/tests/ComponentTest.java +++ b/era.mi/src/era/mi/logic/tests/ComponentTest.java @@ -1,320 +1,320 @@ -package era.mi.logic.tests; - -import static org.junit.jupiter.api.Assertions.*; - -import java.util.Arrays; -import java.util.function.LongConsumer; - -import org.junit.jupiter.api.Test; - -import era.mi.logic.Bit; -import era.mi.logic.Simulation; -import era.mi.logic.components.Merger; -import era.mi.logic.components.Mux; -import era.mi.logic.components.Splitter; -import era.mi.logic.components.TriStateBuffer; -import era.mi.logic.components.gates.AndGate; -import era.mi.logic.components.gates.NotGate; -import era.mi.logic.components.gates.OrGate; -import era.mi.logic.wires.WireArray; -import era.mi.logic.wires.WireArray.WireArrayInput; - -class ComponentTest -{ - - @Test - void circuitExampleTest() - { - Simulation.TIMELINE.reset(); - WireArray a = new WireArray(1, 1), b = new WireArray(1, 1), c = new WireArray(1, 10), d = new WireArray(2, 1), e = new WireArray(1, 1), - f = new WireArray(1, 1), g = new WireArray(1, 1), h = new WireArray(2, 1), i = new WireArray(2, 1), j = new WireArray(1, 1), k = new WireArray(1, 1); - new AndGate(1, a, b, f); - new NotGate(1, f, g); - new Merger(h, c, g); - new Mux(1, i, e, h, d); - new Splitter(i, k, j); - - a.createInput().feedSignals(Bit.ZERO); - b.createInput().feedSignals(Bit.ONE); - c.createInput().feedSignals(Bit.ZERO); - d.createInput().feedSignals(Bit.ONE, Bit.ONE); - e.createInput().feedSignals(Bit.ZERO); - - Simulation.TIMELINE.executeAll(); - - assertEquals(Bit.ONE, j.getValue()); - assertEquals(Bit.ZERO, k.getValue()); - } - - @Test - void splitterTest() - { - Simulation.TIMELINE.reset(); - WireArray a = new WireArray(3, 1), b = new WireArray(2, 1), c = new WireArray(3, 1), in = new WireArray(8, 1); - in.createInput().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE); - new Splitter(in, a, b, c); - - Simulation.TIMELINE.executeAll(); - - assertArrayEquals(new Bit[] { Bit.ZERO, Bit.ONE, Bit.ZERO }, a.getValues()); - assertArrayEquals(new Bit[] { Bit.ONE, Bit.ZERO }, b.getValues()); - assertArrayEquals(new Bit[] { Bit.ONE, Bit.ZERO, Bit.ONE }, c.getValues()); - } - - @Test - void mergerTest() - { - Simulation.TIMELINE.reset(); - WireArray a = new WireArray(3, 1), b = new WireArray(2, 1), c = new WireArray(3, 1), out = new WireArray(8, 1); - a.createInput().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO); - b.createInput().feedSignals(Bit.ONE, Bit.ZERO); - c.createInput().feedSignals(Bit.ONE, Bit.ZERO, Bit.ONE); - - new Merger(out, a, b, c); - - Simulation.TIMELINE.executeAll(); - - assertTrue(Arrays.equals(out.getValues(), - new Bit[] { Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE })); - } - - @Test - void triStateBufferTest() - { - WireArray a = new WireArray(1, 1), b = new WireArray(1, 1), en = new WireArray(1, 1), - notEn = new WireArray(1, 1); - new NotGate(1, en, notEn); - new TriStateBuffer(1, a, b, en); - new TriStateBuffer(1, b, a, notEn); - - WireArrayInput enI = en.createInput(), aI = a.createInput(), bI = b.createInput(); - enI.feedSignals(Bit.ONE); - aI.feedSignals(Bit.ONE); - - Simulation.TIMELINE.executeAll(); - - assertEquals(Bit.ONE, b.getValue()); - - bI.feedSignals(Bit.ZERO); - - Simulation.TIMELINE.executeAll(); - - assertEquals(Bit.X, b.getValue()); - assertEquals(Bit.ONE, a.getValue()); - - aI.clearSignals(); - enI.feedSignals(Bit.ZERO); - - Simulation.TIMELINE.executeAll(); - - assertEquals(Bit.ZERO, a.getValue()); - - } - - @Test - void muxTest() - { - Simulation.TIMELINE.reset(); - WireArray a = new WireArray(4, 3), b = new WireArray(4, 6), c = new WireArray(4, 4), - select = new WireArray(2, 5), out = new WireArray(4, 1); - WireArrayInput selectIn = select.createInput(); - - selectIn.feedSignals(Bit.ZERO, Bit.ZERO); - a.createInput().feedSignals(Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO); - c.createInput().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE); - - new Mux(1, out, select, a, b, c); - Simulation.TIMELINE.executeAll(); - - assertArrayEquals(new Bit[] { Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO }, out.getValues()); - selectIn.feedSignals(Bit.ZERO, Bit.ONE); - Simulation.TIMELINE.executeAll(); - - assertArrayEquals(new Bit[] { Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE }, out.getValues()); - - selectIn.feedSignals(Bit.ONE, Bit.ONE); - Simulation.TIMELINE.executeAll(); - - assertArrayEquals(new Bit[] { Bit.Z, Bit.Z, Bit.Z, Bit.Z }, out.getValues()); - - } - - @Test - void andTest() - { - Simulation.TIMELINE.reset(); - AndGate gate = new AndGate(1, new WireArray(4, 1), new WireArray(4, 1), new WireArray(4, 1)); - gate.getA().createInput().feedSignals(Bit.ONE, Bit.ONE, Bit.ZERO, Bit.ZERO); - gate.getB().createInput().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE); - - Simulation.TIMELINE.executeAll(); - assertArrayEquals(new Bit[] { Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ZERO }, gate.getOut().getValues()); - } - - @Test - void orTest() - { - Simulation.TIMELINE.reset(); - OrGate gate = new OrGate(1, new WireArray(4, 1), new WireArray(4, 1), new WireArray(4, 1)); - gate.getA().createInput().feedSignals(Bit.ONE, Bit.ONE, Bit.ZERO, Bit.ZERO); - gate.getB().createInput().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE); - - Simulation.TIMELINE.executeAll(); - - assertArrayEquals(new Bit[] { Bit.ONE, Bit.ONE, Bit.ZERO, Bit.ONE }, gate.getOut().getValues()); - } - - @Test - void rsLatchCircuitTest() - { - Simulation.TIMELINE.reset(); - WireArray r = new WireArray(1, 1), s = new WireArray(1, 1), t1 = new WireArray(1, 15), t2 = new WireArray(1, 1), - q = new WireArray(1, 1), nq = new WireArray(1, 1); - - new OrGate(1, r, nq, t2); - new OrGate(1, s, q, t1); - new NotGate(1, t2, q); - new NotGate(1, t1, nq); - - WireArrayInput sIn = s.createInput(), rIn = r.createInput(); - - sIn.feedSignals(Bit.ONE); - rIn.feedSignals(Bit.ZERO); - - Simulation.TIMELINE.executeAll(); - - assertEquals(Bit.ONE, q.getValue()); - assertEquals(Bit.ZERO, nq.getValue()); - - sIn.feedSignals(Bit.ZERO); - - Simulation.TIMELINE.executeAll(); - assertEquals(Bit.ONE, q.getValue()); - assertEquals(Bit.ZERO, nq.getValue()); - - rIn.feedSignals(Bit.ONE); - - Simulation.TIMELINE.executeAll(); - - assertEquals(Bit.ZERO, q.getValue()); - assertEquals(Bit.ONE, nq.getValue()); - } - - @Test - void numericValueTest() - { - Simulation.TIMELINE.reset(); - - WireArray a = new WireArray(4, 1); - a.createInput().feedSignals(Bit.ONE, Bit.ONE, Bit.ONE, Bit.ONE); - - Simulation.TIMELINE.executeAll(); - - assertEquals(15, a.getUnsignedValue()); - assertEquals(-1, a.getSignedValue()); - } - - @Test - void multipleInputs() - { - Simulation.TIMELINE.reset(); - WireArray w = new WireArray(2, 1); - WireArrayInput wI1 = w.createInput(), wI2 = w.createInput(); - wI1.feedSignals(Bit.ONE, Bit.Z); - wI2.feedSignals(Bit.Z, Bit.X); - Simulation.TIMELINE.executeAll(); - assertArrayEquals(new Bit[] { Bit.ONE, Bit.X }, w.getValues()); - - wI2.feedSignals(Bit.ZERO, Bit.Z); - Simulation.TIMELINE.executeAll(); - assertArrayEquals(new Bit[] { Bit.X, Bit.Z }, w.getValues()); - - wI2.feedSignals(Bit.Z, Bit.Z); - Simulation.TIMELINE.executeAll(); - assertArrayEquals(new Bit[] { Bit.ONE, Bit.Z }, w.getValues()); - - wI2.feedSignals(Bit.ONE, Bit.Z); - w.addObserver((i) -> fail("WireArray notified observer, although value did not change.")); - Simulation.TIMELINE.executeAll(); - assertArrayEquals(new Bit[] { Bit.ONE, Bit.Z }, w.getValues()); - } - - @Test - void wireConnections() - { - // Nur ein Experiment, was über mehrere 'passive' Bausteine hinweg passieren würde - - Simulation.TIMELINE.reset(); - - WireArray a = new WireArray(1, 2); - WireArray b = new WireArray(1, 2); - WireArray c = new WireArray(1, 2); - WireArrayInput aI = a.createInput(); - WireArrayInput bI = b.createInput(); - WireArrayInput cI = c.createInput(); - - TestBitDisplay test = new TestBitDisplay(c); - TestBitDisplay test2 = new TestBitDisplay(a); - LongConsumer print = time -> System.out.format("Time %2d\n a: %s\n b: %s\n c: %s\n", time, a, b, c); - - cI.feedSignals(Bit.ONE); - test.assertAfterSimulationIs(print, Bit.ONE); - - cI.feedSignals(Bit.X); - test.assertAfterSimulationIs(print, Bit.X); - - cI.feedSignals(Bit.X); - cI.feedSignals(Bit.Z); - test.assertAfterSimulationIs(print, Bit.Z); - - Connector c1 = new Connector(b, c); - test.assertAfterSimulationIs(print, Bit.Z); - System.err.println("ONE"); - bI.feedSignals(Bit.ONE); - test.assertAfterSimulationIs(print, Bit.ONE); - System.err.println("ZERO"); - bI.feedSignals(Bit.ZERO); - test.assertAfterSimulationIs(print, Bit.ZERO); - System.err.println("Z"); - bI.feedSignals(Bit.Z); - test.assertAfterSimulationIs(print, Bit.Z); - - Connector c2 = new Connector(a, b); - System.err.println("Z 2"); - aI.feedSignals(Bit.Z); - test.assertAfterSimulationIs(print, Bit.Z); - test2.assertAfterSimulationIs(Bit.Z); - System.err.println("ONE 2"); - aI.feedSignals(Bit.ONE); - test.assertAfterSimulationIs(print, Bit.ONE); - test2.assertAfterSimulationIs(Bit.ONE); - System.err.println("ZERO 2"); - aI.feedSignals(Bit.ZERO); - test.assertAfterSimulationIs(print, Bit.ZERO); - test2.assertAfterSimulationIs(Bit.ZERO); - System.err.println("Z 2 II"); - aI.feedSignals(Bit.Z); - test.assertAfterSimulationIs(print, Bit.Z); - test2.assertAfterSimulationIs(Bit.Z); - - System.err.println("No Conflict yet"); - bI.feedSignals(Bit.ONE); - test.assertAfterSimulationIs(print, Bit.ONE); - test2.assertAfterSimulationIs(Bit.ONE); - aI.feedSignals(Bit.ONE); - test.assertAfterSimulationIs(print, Bit.ONE); - test2.assertAfterSimulationIs(Bit.ONE); - System.err.println("Conflict"); - aI.feedSignals(Bit.ZERO); - test.assertAfterSimulationIs(print, Bit.X); - test2.assertAfterSimulationIs(Bit.X); - aI.feedSignals(Bit.ONE); - test.assertAfterSimulationIs(print, Bit.ONE); - test2.assertAfterSimulationIs(Bit.ONE); - } - - private static void assertBitArrayEquals(Bit[] actual, Bit... expected) - { - assertArrayEquals(expected, actual); - } -} +package era.mi.logic.tests; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.Arrays; +import java.util.function.LongConsumer; + +import org.junit.jupiter.api.Test; + +import era.mi.logic.Bit; +import era.mi.logic.Simulation; +import era.mi.logic.components.Merger; +import era.mi.logic.components.Mux; +import era.mi.logic.components.Splitter; +import era.mi.logic.components.TriStateBuffer; +import era.mi.logic.components.gates.AndGate; +import era.mi.logic.components.gates.NotGate; +import era.mi.logic.components.gates.OrGate; +import era.mi.logic.wires.WireArray; +import era.mi.logic.wires.WireArray.WireArrayInput; + +class ComponentTest +{ + + @Test + void circuitExampleTest() + { + Simulation.TIMELINE.reset(); + WireArray a = new WireArray(1, 1), b = new WireArray(1, 1), c = new WireArray(1, 10), d = new WireArray(2, 1), e = new WireArray(1, 1), + f = new WireArray(1, 1), g = new WireArray(1, 1), h = new WireArray(2, 1), i = new WireArray(2, 1), j = new WireArray(1, 1), k = new WireArray(1, 1); + new AndGate(1, a, b, f); + new NotGate(1, f, g); + new Merger(h, c, g); + new Mux(1, i, e, h, d); + new Splitter(i, k, j); + + a.createInput().feedSignals(Bit.ZERO); + b.createInput().feedSignals(Bit.ONE); + c.createInput().feedSignals(Bit.ZERO); + d.createInput().feedSignals(Bit.ONE, Bit.ONE); + e.createInput().feedSignals(Bit.ZERO); + + Simulation.TIMELINE.executeAll(); + + assertEquals(Bit.ONE, j.getValue()); + assertEquals(Bit.ZERO, k.getValue()); + } + + @Test + void splitterTest() + { + Simulation.TIMELINE.reset(); + WireArray a = new WireArray(3, 1), b = new WireArray(2, 1), c = new WireArray(3, 1), in = new WireArray(8, 1); + in.createInput().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE); + new Splitter(in, a, b, c); + + Simulation.TIMELINE.executeAll(); + + assertBitArrayEquals(a.getValues(), Bit.ZERO, Bit.ONE, Bit.ZERO); + assertBitArrayEquals(b.getValues(), Bit.ONE, Bit.ZERO); + assertBitArrayEquals(c.getValues(), Bit.ONE, Bit.ZERO, Bit.ONE); + } + + @Test + void mergerTest() + { + Simulation.TIMELINE.reset(); + WireArray a = new WireArray(3, 1), b = new WireArray(2, 1), c = new WireArray(3, 1), out = new WireArray(8, 1); + a.createInput().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO); + b.createInput().feedSignals(Bit.ONE, Bit.ZERO); + c.createInput().feedSignals(Bit.ONE, Bit.ZERO, Bit.ONE); + + new Merger(out, a, b, c); + + Simulation.TIMELINE.executeAll(); + + assertTrue(Arrays.equals(out.getValues(), + new Bit[] { Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE })); + } + + @Test + void triStateBufferTest() + { + WireArray a = new WireArray(1, 1), b = new WireArray(1, 1), en = new WireArray(1, 1), + notEn = new WireArray(1, 1); + new NotGate(1, en, notEn); + new TriStateBuffer(1, a, b, en); + new TriStateBuffer(1, b, a, notEn); + + WireArrayInput enI = en.createInput(), aI = a.createInput(), bI = b.createInput(); + enI.feedSignals(Bit.ONE); + aI.feedSignals(Bit.ONE); + + Simulation.TIMELINE.executeAll(); + + assertEquals(Bit.ONE, b.getValue()); + + bI.feedSignals(Bit.ZERO); + + Simulation.TIMELINE.executeAll(); + + assertEquals(Bit.X, b.getValue()); + assertEquals(Bit.ONE, a.getValue()); + + aI.clearSignals(); + enI.feedSignals(Bit.ZERO); + + Simulation.TIMELINE.executeAll(); + + assertEquals(Bit.ZERO, a.getValue()); + + } + + @Test + void muxTest() + { + Simulation.TIMELINE.reset(); + WireArray a = new WireArray(4, 3), b = new WireArray(4, 6), c = new WireArray(4, 4), + select = new WireArray(2, 5), out = new WireArray(4, 1); + WireArrayInput selectIn = select.createInput(); + + selectIn.feedSignals(Bit.ZERO, Bit.ZERO); + a.createInput().feedSignals(Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO); + c.createInput().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE); + + new Mux(1, out, select, a, b, c); + Simulation.TIMELINE.executeAll(); + + assertBitArrayEquals(out.getValues(), Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO); + selectIn.feedSignals(Bit.ZERO, Bit.ONE); + Simulation.TIMELINE.executeAll(); + + assertBitArrayEquals(out.getValues(), Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE); + + selectIn.feedSignals(Bit.ONE, Bit.ONE); + Simulation.TIMELINE.executeAll(); + + assertBitArrayEquals(out.getValues(), Bit.Z, Bit.Z, Bit.Z, Bit.Z); + + } + + @Test + void andTest() + { + Simulation.TIMELINE.reset(); + AndGate gate = new AndGate(1, new WireArray(4, 1), new WireArray(4, 1), new WireArray(4, 1)); + gate.getA().createInput().feedSignals(Bit.ONE, Bit.ONE, Bit.ZERO, Bit.ZERO); + gate.getB().createInput().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE); + + Simulation.TIMELINE.executeAll(); + assertBitArrayEquals(gate.getOut().getValues(), Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ZERO); + } + + @Test + void orTest() + { + Simulation.TIMELINE.reset(); + OrGate gate = new OrGate(1, new WireArray(4, 1), new WireArray(4, 1), new WireArray(4, 1)); + gate.getA().createInput().feedSignals(Bit.ONE, Bit.ONE, Bit.ZERO, Bit.ZERO); + gate.getB().createInput().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE); + + Simulation.TIMELINE.executeAll(); + + assertBitArrayEquals(gate.getOut().getValues(), Bit.ONE, Bit.ONE, Bit.ZERO, Bit.ONE); + } + + @Test + void rsLatchCircuitTest() + { + Simulation.TIMELINE.reset(); + WireArray r = new WireArray(1, 1), s = new WireArray(1, 1), t1 = new WireArray(1, 15), t2 = new WireArray(1, 1), + q = new WireArray(1, 1), nq = new WireArray(1, 1); + + new OrGate(1, r, nq, t2); + new OrGate(1, s, q, t1); + new NotGate(1, t2, q); + new NotGate(1, t1, nq); + + WireArrayInput sIn = s.createInput(), rIn = r.createInput(); + + sIn.feedSignals(Bit.ONE); + rIn.feedSignals(Bit.ZERO); + + Simulation.TIMELINE.executeAll(); + + assertEquals(Bit.ONE, q.getValue()); + assertEquals(Bit.ZERO, nq.getValue()); + + sIn.feedSignals(Bit.ZERO); + + Simulation.TIMELINE.executeAll(); + assertEquals(Bit.ONE, q.getValue()); + assertEquals(Bit.ZERO, nq.getValue()); + + rIn.feedSignals(Bit.ONE); + + Simulation.TIMELINE.executeAll(); + + assertEquals(Bit.ZERO, q.getValue()); + assertEquals(Bit.ONE, nq.getValue()); + } + + @Test + void numericValueTest() + { + Simulation.TIMELINE.reset(); + + WireArray a = new WireArray(4, 1); + a.createInput().feedSignals(Bit.ONE, Bit.ONE, Bit.ONE, Bit.ONE); + + Simulation.TIMELINE.executeAll(); + + assertEquals(15, a.getUnsignedValue()); + assertEquals(-1, a.getSignedValue()); + } + + @Test + void multipleInputs() + { + Simulation.TIMELINE.reset(); + WireArray w = new WireArray(2, 1); + WireArrayInput wI1 = w.createInput(), wI2 = w.createInput(); + wI1.feedSignals(Bit.ONE, Bit.Z); + wI2.feedSignals(Bit.Z, Bit.X); + Simulation.TIMELINE.executeAll(); + assertBitArrayEquals(w.getValues(), Bit.ONE, Bit.X); + + wI2.feedSignals(Bit.ZERO, Bit.Z); + Simulation.TIMELINE.executeAll(); + assertBitArrayEquals(w.getValues(), Bit.X, Bit.Z); + + wI2.feedSignals(Bit.Z, Bit.Z); + Simulation.TIMELINE.executeAll(); + assertBitArrayEquals(w.getValues(), Bit.ONE, Bit.Z); + + wI2.feedSignals(Bit.ONE, Bit.Z); + w.addObserver((i) -> fail("WireArray notified observer, although value did not change.")); + Simulation.TIMELINE.executeAll(); + assertBitArrayEquals(w.getValues(), Bit.ONE, Bit.Z); + } + + @Test + void wireConnections() + { + // Nur ein Experiment, was über mehrere 'passive' Bausteine hinweg passieren würde + + Simulation.TIMELINE.reset(); + + WireArray a = new WireArray(1, 2); + WireArray b = new WireArray(1, 2); + WireArray c = new WireArray(1, 2); + WireArrayInput aI = a.createInput(); + WireArrayInput bI = b.createInput(); + WireArrayInput cI = c.createInput(); + + TestBitDisplay test = new TestBitDisplay(c); + TestBitDisplay test2 = new TestBitDisplay(a); + LongConsumer print = time -> System.out.format("Time %2d\n a: %s\n b: %s\n c: %s\n", time, a, b, c); + + cI.feedSignals(Bit.ONE); + test.assertAfterSimulationIs(print, Bit.ONE); + + cI.feedSignals(Bit.X); + test.assertAfterSimulationIs(print, Bit.X); + + cI.feedSignals(Bit.X); + cI.feedSignals(Bit.Z); + test.assertAfterSimulationIs(print, Bit.Z); + + Connector c1 = new Connector(b, c); + test.assertAfterSimulationIs(print, Bit.Z); + System.err.println("ONE"); + bI.feedSignals(Bit.ONE); + test.assertAfterSimulationIs(print, Bit.ONE); + System.err.println("ZERO"); + bI.feedSignals(Bit.ZERO); + test.assertAfterSimulationIs(print, Bit.ZERO); + System.err.println("Z"); + bI.feedSignals(Bit.Z); + test.assertAfterSimulationIs(print, Bit.Z); + + Connector c2 = new Connector(a, b); + System.err.println("Z 2"); + aI.feedSignals(Bit.Z); + test.assertAfterSimulationIs(print, Bit.Z); + test2.assertAfterSimulationIs(Bit.Z); + System.err.println("ONE 2"); + aI.feedSignals(Bit.ONE); + test.assertAfterSimulationIs(print, Bit.ONE); + test2.assertAfterSimulationIs(Bit.ONE); + System.err.println("ZERO 2"); + aI.feedSignals(Bit.ZERO); + test.assertAfterSimulationIs(print, Bit.ZERO); + test2.assertAfterSimulationIs(Bit.ZERO); + System.err.println("Z 2 II"); + aI.feedSignals(Bit.Z); + test.assertAfterSimulationIs(print, Bit.Z); + test2.assertAfterSimulationIs(Bit.Z); + + System.err.println("No Conflict yet"); + bI.feedSignals(Bit.ONE); + test.assertAfterSimulationIs(print, Bit.ONE); + test2.assertAfterSimulationIs(Bit.ONE); + aI.feedSignals(Bit.ONE); + test.assertAfterSimulationIs(print, Bit.ONE); + test2.assertAfterSimulationIs(Bit.ONE); + System.err.println("Conflict"); + aI.feedSignals(Bit.ZERO); + test.assertAfterSimulationIs(print, Bit.X); + test2.assertAfterSimulationIs(Bit.X); + aI.feedSignals(Bit.ONE); + test.assertAfterSimulationIs(print, Bit.ONE); + test2.assertAfterSimulationIs(Bit.ONE); + } + + private static void assertBitArrayEquals(Bit[] actual, Bit... expected) + { + assertArrayEquals(expected, actual); + } +} diff --git a/era.mi/src/era/mi/logic/tests/Connector.java b/era.mi/src/era/mi/logic/tests/Connector.java index c8432370..112f6fc7 100644 --- a/era.mi/src/era/mi/logic/tests/Connector.java +++ b/era.mi/src/era/mi/logic/tests/Connector.java @@ -15,7 +15,7 @@ public class Connector implements WireArrayObserver public Connector(WireArray a, WireArray b) { if (a.length != b.length) - throw new IllegalArgumentException("WireArray width does not match: " + a.length + ", " + b.length); + throw new IllegalArgumentException(String.format("WireArray width does not match: %o, %o", a.length, b.length)); this.a = a; this.b = b; a.addObserver(this); diff --git a/era.mi/src/era/mi/logic/timeline/Timeline.java b/era.mi/src/era/mi/logic/timeline/Timeline.java index 2392f4c2..2578a9be 100644 --- a/era.mi/src/era/mi/logic/timeline/Timeline.java +++ b/era.mi/src/era/mi/logic/timeline/Timeline.java @@ -1,95 +1,106 @@ -package era.mi.logic.timeline; - -import java.util.PriorityQueue; - -/** - * Orders Events by the time they are due to be executed. Can execute Events individually. - * @author Fabian Stemmler - * - */ -public class Timeline -{ - private PriorityQueue events; - private long currentTime = 0; - - public Timeline(int initCapacity) - { - events = new PriorityQueue(initCapacity, (a, b) -> { - long difference = a.getTiming() - b.getTiming(); - if(difference == 0) - return 0; - return difference < 0 ? -1 : 1; - }); - } - - public boolean hasNext() - { - return !events.isEmpty(); - } - - public void executeNext() - { - InnerEvent first = events.poll(); - currentTime = first.getTiming(); - first.run(); - } - - public void executeAll() - { - while (hasNext()) - executeNext(); - } - - public long getSimulationTime() - { - return currentTime; - } - - public void reset() - { - events.clear(); - currentTime = 0; - } - - /** - * Adds an Event to the {@link Timeline} - * @param function The {@link TimelineEventHandler} that will be executed, when the {@link InnerEvent} occurs on the timeline. - * @param relativeTiming The amount of MI ticks in which the {@link InnerEvent} is called, starting from the current time. - */ - public void addEvent(TimelineEventHandler function, int relativeTiming) - { - long timing = currentTime + relativeTiming; - events.add(new InnerEvent(function, new TimelineEvent(timing), timing)); - } - - private class InnerEvent - { - - private final long timing; - private final TimelineEventHandler function; - private final TimelineEvent event; - - /** - * Creates an {@link InnerEvent} - * @param function {@link TimelineEventHandler} to be executed when the {@link InnerEvent} occurs - * @param timing Point in the MI simulation {@link Timeline}, at which the {@link InnerEvent} is executed; - */ - InnerEvent(TimelineEventHandler function, TimelineEvent event, long timing) - { - this.function = function; - this.event = event; - this.timing = timing; - } - - public long getTiming() - { - return timing; - } - - public void run() - { - function.handle(event); - } - - } +package era.mi.logic.timeline; + +import java.util.PriorityQueue; + +/** + * Orders Events by the time they are due to be executed. Can execute Events individually. + * @author Fabian Stemmler + * + */ +public class Timeline +{ + private PriorityQueue events; + private long currentTime = 0; + + public Timeline(int initCapacity) + { + events = new PriorityQueue(initCapacity, (a, b) -> { + long difference = a.getTiming() - b.getTiming(); + if(difference == 0) + return 0; + return difference < 0 ? -1 : 1; + }); + } + + public boolean hasNext() + { + return !events.isEmpty(); + } + + public void executeNext() + { + InnerEvent first = events.poll(); + currentTime = first.getTiming(); + first.run(); + } + + public void executeAll() + { + while (hasNext()) + executeNext(); + } + + public long getSimulationTime() + { + return currentTime; + } + + public void reset() + { + events.clear(); + currentTime = 0; + } + + /** + * Adds an Event to the {@link Timeline} + * @param function The {@link TimelineEventHandler} that will be executed, when the {@link InnerEvent} occurs on the timeline. + * @param relativeTiming The amount of MI ticks in which the {@link InnerEvent} is called, starting from the current time. + */ + public void addEvent(TimelineEventHandler function, int relativeTiming) + { + long timing = currentTime + relativeTiming; + events.add(new InnerEvent(function, new TimelineEvent(timing), timing)); + } + + private class InnerEvent + { + + private final long timing; + private final TimelineEventHandler function; + private final TimelineEvent event; + + /** + * Creates an {@link InnerEvent} + * @param function {@link TimelineEventHandler} to be executed when the {@link InnerEvent} occurs + * @param timing Point in the MI simulation {@link Timeline}, at which the {@link InnerEvent} is executed; + */ + InnerEvent(TimelineEventHandler function, TimelineEvent event, long timing) + { + this.function = function; + this.event = event; + this.timing = timing; + } + + public long getTiming() + { + return timing; + } + + public void run() + { + function.handle(event); + } + + @Override + public String toString() + { + return event.toString(); + } + } + + @Override + public String toString() + { + return "simulation time: " + currentTime + ", " + events.toString(); + } } \ No newline at end of file diff --git a/era.mi/src/era/mi/logic/timeline/TimelineEvent.java b/era.mi/src/era/mi/logic/timeline/TimelineEvent.java index 6cec9079..68403499 100644 --- a/era.mi/src/era/mi/logic/timeline/TimelineEvent.java +++ b/era.mi/src/era/mi/logic/timeline/TimelineEvent.java @@ -1,17 +1,27 @@ -package era.mi.logic.timeline; - -public class TimelineEvent -{ - private final long timing; - - TimelineEvent(long timing) - { - super(); - this.timing = timing; - } - - public long getTiming() - { - return timing; - } +package era.mi.logic.timeline; + +/** + * A class that stores all relevant information about an event in the {@link Timeline}. Currently, there is not much relevant information to store. + * @author Fabian Stemmler + * + */ +public class TimelineEvent +{ + private final long timing; + + TimelineEvent(long timing) + { + super(); + this.timing = timing; + } + + public long getTiming() + { + return timing; + } + + public String toString() + { + return "timestamp: " + timing; + } } \ No newline at end of file diff --git a/era.mi/src/era/mi/logic/wires/WireArray.java b/era.mi/src/era/mi/logic/wires/WireArray.java index 370cbbd5..29b35754 100644 --- a/era.mi/src/era/mi/logic/wires/WireArray.java +++ b/era.mi/src/era/mi/logic/wires/WireArray.java @@ -1,362 +1,358 @@ -package era.mi.logic.wires; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; - -import era.mi.logic.Bit; -import era.mi.logic.Simulation; -import era.mi.logic.Util; - -/** - * Represents an array of wires that can store n bits of information. - * - * @author Fabian Stemmler - * - */ -public class WireArray -{ - private Bit[] values; - public final int travelTime; - private List observers = new ArrayList(); - public final int length; - private List inputs = new ArrayList(); - - public WireArray(int length, int travelTime) - { - if (length < 1) - throw new IllegalArgumentException("Tried to create an array of wires with length " + length - + ", but a length of less than 1 makes no sense."); - this.length = length; - this.travelTime = travelTime; - initValues(); - } - - private void initValues() - { - values = new Bit[length]; - for (int i = 0; i < length; i++) - values[i] = Bit.Z; - } - - private void recalculateSingleInput() - { - WireArrayInput input = inputs.get(0); - if (!Arrays.equals(input.getValues(), values)) - { - System.arraycopy(input.getValues(), 0, values, 0, length); - notifyObservers(); - } - } - - private void recalculateMultipleInputs() - { - Iterator it = inputs.iterator(); - Bit[] newValues = it.next().values.clone(); - - while (it.hasNext()) - { - WireArrayInput input = it.next(); - Bit[] bits = input.getValues(); - for (int i = 0; i < length; i++) - { - if (Bit.Z.equals(bits[i]) || newValues[i].equals(bits[i])) - continue; - else if (Bit.Z.equals(newValues[i])) - newValues[i] = bits[i]; - else - newValues[i] = Bit.X; - } - } - - if (!Arrays.equals(newValues, values)) - { - notifyObservers(); - values = newValues; - } - } - - private void recalculate() - { - switch (inputs.size()) - { - case 0: - return; - case 1: - recalculateSingleInput(); - break; - default: - recalculateMultipleInputs(); - } - } - - /** - * The WireArray is interpreted as an unsigned integer with n bits. - * - * @return true if all bits are either Bit.ONE or - * Bit.ZERO (they do not all have to have the same value), - * not Bit.X or Bit.Z. false is - * returned otherwise. - * - * @author Fabian Stemmler - */ - public boolean hasNumericValue() - { - for (Bit b : values) - { - if (b != Bit.ZERO && b != Bit.ONE) - return false; - } - return true; - } - - /** - * The WireArray is interpreted as an unsigned integer with n bits. - * - * @return The unsigned value of the {@link WireArray}'s bits, where value 0 - * corresponds with 2^0, value 1 is 2^1 and so on. - * - * @author Fabian Stemmler - */ - public long getUnsignedValue() - { - long val = 0; - long mask = 1; - for (int i = 0; i < length; i++) - { - switch (values[i]) - { - default: - case Z: - case X: - return 0; // TODO: Proper handling for getUnsignedValue(), if not all bits are 1 or 0; - // Random number? - case ONE: - val |= mask; - break; - case ZERO: - } - mask = mask << 1; - } - return val; - } - - /** - * The WireArray is interpreted as a signed integer with n bits. - * - * @return The signed value of the {@link WireArray}'s bits, where value 0 - * corresponds with 2^0, value 1 is 2^1 and so on. - * - * @author Fabian Stemmler - */ - public long getSignedValue() - { - long val = getUnsignedValue(); - long mask = 1 << (length - 1); - if ((mask & val) != 0) - { - int shifts = 64 - length; - return (val << shifts) >> shifts; - } - return val; - } - - /** - * Included for convenient use on {@link WireArray}s of length 1. - * - * @return The value of bit 0. - * - * @author Fabian Stemmler - */ - public Bit getValue() - { - return getValue(0); - } - - /** - * - * @param index Index of the requested bit. - * @return The value of the indexed bit. - * - * @author Fabian Stemmler - */ - public Bit getValue(int index) - { - return values[index]; - } - - public Bit[] getValues(int start, int end) - { - int length = end - start; - Bit[] bits = new Bit[length]; - System.arraycopy(values, start, bits, 0, length); - return bits; - } - - /** - * @return An array of length n containing the values of the n bits in the - * {@link WireArray}. Can be safely modified. - * - * @author Fabian Stemmler - */ - public Bit[] getValues() - { - return values.clone(); - } - - /** - * Adds an {@link WireArrayObserver}, who will be notified when the value of the - * {@link WireArray} is updated. - * - * @param ob The {@link WireArrayObserver} to be notified of changes. - * @return true if the given {@link WireArrayObserver} was not already - * registered, false otherwise - * - * @author Fabian Stemmler - */ - public boolean addObserver(WireArrayObserver ob) - { - return observers.add(ob); - } - - private void notifyObservers() - { - for (WireArrayObserver o : observers) - o.update(this); - } - - /** - * Create and register a {@link WireArrayInput} object, which is tied to this - * {@link WireArray}. - */ - public WireArrayInput createInput() - { - return new WireArrayInput(this); - } - - private void registerInput(WireArrayInput toRegister) - { - inputs.add(toRegister); - } - - /** - * A {@link WireArrayInput} feeds a constant signal into the {@link WireArray} - * it is tied to. The combination of all inputs determines the - * {@link WireArray}s final value. X dominates all other inputs Z does not - * affect the final value, unless there are no other inputs than Z 0 and 1 turn - * into X when they are mixed - * - * @author Fabian Stemmler - */ - public class WireArrayInput - { - public final WireArray owner; - private Bit[] values; - - private WireArrayInput(WireArray owner) - { - super(); - this.owner = owner; - initValues(); - owner.registerInput(this); - } - - private void initValues() - { - values = new Bit[length]; - for (int i = 0; i < length; i++) - values[i] = Bit.Z; - } - - /** - * Sets the wires values. This takes up time, as specified by the - * {@link WireArray}s travel time. - * - * @param newValues The new values the wires should take on. - * - * @author Fabian Stemmler - */ - public void feedSignals(Bit... newValues) - { - if (newValues.length == length) - { - feedSignals(0, newValues); - } else - throw new IllegalArgumentException( - "Attempted to input " + newValues.length + " bits instead of " + length + " bits."); - } - - /** - * Sets values of a subarray of wires. This takes up time, as specified by the - * {@link WireArray}s travel time. - * - * @param newValues The new values the wires should take on. - * @param startingBit The first index of the subarray of wires. - * - * @author Fabian Stemmler - */ - public void feedSignals(int startingBit, Bit... newValues) - { - Simulation.TIMELINE.addEvent((e) -> setValues(startingBit, newValues), travelTime); - } - - private void setValues(int startingBit, Bit... newValues) - { - int exclLastIndex = startingBit + newValues.length; - if (length < exclLastIndex) - throw new ArrayIndexOutOfBoundsException("Attempted to input bits from index " + startingBit + " to " - + exclLastIndex + " when there are only " + length + "wires."); - if (!Arrays.equals(values, startingBit, exclLastIndex, newValues, 0, newValues.length)) - { - System.arraycopy(newValues, 0, values, startingBit, newValues.length); - owner.recalculate(); - } - } - - public Bit[] getValues() - { - return values.clone(); - } - - public Bit[] wireValuesExcludingMe() - { - Bit[] bits = Util.arrayOfZ(length); - for (WireArrayInput wai : inputs) - { - if(wai == this) - continue; - Util.combineInto(bits, wai.getValues()); - } - return bits; - } - - public void clearSignals() - { - Bit[] bits = new Bit[length]; - for (int i = 0; i < length; i++) - bits[i] = Bit.Z; - feedSignals(bits); - } - - @Override - public String toString() - { - return Arrays.toString(values); - } - } - - @Override - public String toString() - { - return String.format("wire 0x%08x value: %s inputs: %s", hashCode(), Arrays.toString(values), inputs); - } - - public static WireArrayInput[] extractInputs(WireArray[] w) - { - WireArrayInput[] inputs = new WireArrayInput[w.length]; - for(int i = 0; i < w.length; i++) - inputs[i] = w[i].createInput(); - return inputs; - } +package era.mi.logic.wires; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import era.mi.logic.Bit; +import era.mi.logic.Simulation; +import era.mi.logic.Util; + +/** + * Represents an array of wires that can store n bits of information. + * + * @author Fabian Stemmler + * + */ +public class WireArray +{ + private Bit[] values; + public final int travelTime; + private List observers = new ArrayList(); + public final int length; + private List inputs = new ArrayList(); + + public WireArray(int length, int travelTime) + { + if (length < 1) + throw new IllegalArgumentException(String.format("Tried to create an array of wires with length %o, but a length of less than 1 makes no sense.", length)); + this.length = length; + this.travelTime = travelTime; + initValues(); + } + + private void initValues() + { + values = Bit.Z.makeArray(length); + } + + private void recalculateSingleInput() + { + WireArrayInput input = inputs.get(0); + if (!Arrays.equals(input.getValues(), values)) + { + System.arraycopy(input.getValues(), 0, values, 0, length); + notifyObservers(); + } + } + + private void recalculateMultipleInputs() + { + Iterator it = inputs.iterator(); + Bit[] newValues = it.next().inputValues.clone(); + + while (it.hasNext()) + { + WireArrayInput input = it.next(); + Bit[] bits = input.getValues(); + for (int i = 0; i < length; i++) + { + if (Bit.Z.equals(bits[i]) || newValues[i].equals(bits[i])) + continue; + else if (Bit.Z.equals(newValues[i])) + newValues[i] = bits[i]; + else + newValues[i] = Bit.X; + } + } + + if (!Arrays.equals(newValues, values)) + { + notifyObservers(); + values = newValues; + } + } + + private void recalculate() + { + switch (inputs.size()) + { + case 0: + return; + case 1: + recalculateSingleInput(); + break; + default: + recalculateMultipleInputs(); + } + } + + /** + * The WireArray is interpreted as an unsigned integer with n bits. + * + * @return true if all bits are either Bit.ONE or + * Bit.ZERO (they do not all have to have the same value), + * not Bit.X or Bit.Z. false is + * returned otherwise. + * + * @author Fabian Stemmler + */ + public boolean hasNumericValue() + { + for (Bit b : values) + { + if (b != Bit.ZERO && b != Bit.ONE) + return false; + } + return true; + } + + /** + * The WireArray is interpreted as an unsigned integer with n bits. + * + * @return The unsigned value of the {@link WireArray}'s bits, where value 0 + * corresponds with 2^0, value 1 is 2^1 and so on. + * + * @author Fabian Stemmler + */ + public long getUnsignedValue() + { + long val = 0; + long mask = 1; + for (int i = 0; i < length; i++) + { + switch (values[i]) + { + default: + case Z: + case X: + return 0; // TODO: Proper handling for getUnsignedValue(), if not all bits are 1 or 0; + // Random number? + case ONE: + val |= mask; + break; + case ZERO: + } + mask = mask << 1; + } + return val; + } + + /** + * The WireArray is interpreted as a signed integer with n bits. + * + * @return The signed value of the {@link WireArray}'s bits, where value 0 + * corresponds with 2^0, value 1 is 2^1 and so on. + * + * @author Fabian Stemmler + */ + public long getSignedValue() + { + long val = getUnsignedValue(); + long mask = 1 << (length - 1); + if ((mask & val) != 0) + { + int shifts = 64 - length; + return (val << shifts) >> shifts; + } + return val; + } + + /** + * Included for convenient use on {@link WireArray}s of length 1. + * + * @return The value of bit 0. + * + * @author Fabian Stemmler + */ + public Bit getValue() + { + return getValue(0); + } + + /** + * + * @param index Index of the requested bit. + * @return The value of the indexed bit. + * + * @author Fabian Stemmler + */ + public Bit getValue(int index) + { + return values[index]; + } + + public Bit[] getValues(int start, int end) + { + int length = end - start; + Bit[] bits = new Bit[length]; + System.arraycopy(values, start, bits, 0, length); + return bits; + } + + /** + * @return An array of length n containing the values of the n bits in the + * {@link WireArray}. Can be safely modified. + * + * @author Fabian Stemmler + */ + public Bit[] getValues() + { + return values.clone(); + } + + /** + * Adds an {@link WireArrayObserver}, who will be notified when the value of the + * {@link WireArray} is updated. + * + * @param ob The {@link WireArrayObserver} to be notified of changes. + * @return true if the given {@link WireArrayObserver} was not already + * registered, false otherwise + * + * @author Fabian Stemmler + */ + public boolean addObserver(WireArrayObserver ob) + { + return observers.add(ob); + } + + private void notifyObservers() + { + for (WireArrayObserver o : observers) + o.update(this); + } + + /** + * Create and register a {@link WireArrayInput} object, which is tied to this + * {@link WireArray}. + */ + public WireArrayInput createInput() + { + return new WireArrayInput(this); + } + + private void registerInput(WireArrayInput toRegister) + { + inputs.add(toRegister); + } + + /** + * A {@link WireArrayInput} feeds a constant signal into the {@link WireArray} + * it is tied to. The combination of all inputs determines the + * {@link WireArray}s final value. X dominates all other inputs Z does not + * affect the final value, unless there are no other inputs than Z 0 and 1 turn + * into X when they are mixed + * + * @author Fabian Stemmler + */ + public class WireArrayInput + { + public final WireArray owner; + private Bit[] inputValues; + + private WireArrayInput(WireArray owner) + { + super(); + this.owner = owner; + initValues(); + owner.registerInput(this); + } + + private void initValues() + { + inputValues = Bit.Z.makeArray(length); + } + + /** + * Sets the wires values. This takes up time, as specified by the + * {@link WireArray}s travel time. + * + * @param newValues The new values the wires should take on. + * + * @author Fabian Stemmler + */ + public void feedSignals(Bit... newValues) + { + if (newValues.length == length) + { + feedSignals(0, newValues); + } else + throw new IllegalArgumentException(String.format("Attempted to input %o bits instead of %o bits.", newValues.length, length)); + } + + /** + * Sets values of a subarray of wires. This takes up time, as specified by the + * {@link WireArray}s travel time. + * + * @param newValues The new values the wires should take on. + * @param startingBit The first index of the subarray of wires. + * + * @author Fabian Stemmler + */ + public void feedSignals(int startingBit, Bit... newValues) + { + Simulation.TIMELINE.addEvent((e) -> setValues(startingBit, newValues), travelTime); + } + + private void setValues(int startingBit, Bit... newValues) + { + int exclLastIndex = startingBit + newValues.length; + if (length < exclLastIndex) + throw new ArrayIndexOutOfBoundsException(String.format("Attempted to input bits from index %o to %o when there are only %o wires.", startingBit, exclLastIndex - 1, length)); + if (!Arrays.equals(inputValues, startingBit, exclLastIndex, newValues, 0, newValues.length)) + { + System.arraycopy(newValues, 0, inputValues, startingBit, newValues.length); + owner.recalculate(); + } + } + + /** + * Returns a copy (safe to modify) of the values the {@link WireArrayInput} is currently feeding into the associated {@link WireArray}. + */ + public Bit[] getValues() + { + return inputValues.clone(); + } + + /** + * {@link WireArrayInput} now feeds Z into the associated {@link WireArray}. + */ + public void clearSignals() + { + feedSignals(Bit.Z.makeArray(length)); + } + + public Bit[] wireValuesExcludingMe() + { + Bit[] bits = Bit.Z.makeArray(length); + for (WireArrayInput wai : inputs) + { + if(wai == this) + continue; + Util.combineInto(bits, wai.getValues()); + } + return bits; + } + + @Override + public String toString() + { + return Arrays.toString(inputValues); + } + } + + @Override + public String toString() + { + return String.format("wire 0x%08x value: %s inputs: %s", hashCode(), Arrays.toString(values), inputs); + } + + public static WireArrayInput[] extractInputs(WireArray[] w) + { + WireArrayInput[] inputs = new WireArrayInput[w.length]; + for (int i = 0; i < w.length; i++) + inputs[i] = w[i].createInput(); + return inputs; + } } \ No newline at end of file -- 2.17.1