From: Fabian Stemmler Date: Fri, 10 May 2019 12:55:46 +0000 (+0200) Subject: Wire concept was changed to accommodate multiple inputs. Not all X-Git-Url: https://mograsim.net/gitweb/?a=commitdiff_plain;h=fa95c348b3b8fb9681e4bf5c8284c5ac8eeed518;p=Mograsim.git Wire concept was changed to accommodate multiple inputs. Not all components have been updated yet. --- diff --git a/era.mi/bin/era/mi/logic/WireArray.class b/era.mi/bin/era/mi/logic/WireArray.class deleted file mode 100644 index 3a5553ae..00000000 Binary files a/era.mi/bin/era/mi/logic/WireArray.class and /dev/null differ diff --git a/era.mi/bin/era/mi/logic/WireArrayObserver.class b/era.mi/bin/era/mi/logic/WireArrayObserver.class deleted file mode 100644 index 51ff213a..00000000 Binary files a/era.mi/bin/era/mi/logic/WireArrayObserver.class and /dev/null differ diff --git a/era.mi/bin/era/mi/logic/components/BasicComponent.class b/era.mi/bin/era/mi/logic/components/BasicComponent.class index 30dad6ea..8ed18388 100644 Binary files a/era.mi/bin/era/mi/logic/components/BasicComponent.class and b/era.mi/bin/era/mi/logic/components/BasicComponent.class differ diff --git a/era.mi/bin/era/mi/logic/components/Clock.class b/era.mi/bin/era/mi/logic/components/Clock.class index e2014fc8..70dfad4c 100644 Binary files a/era.mi/bin/era/mi/logic/components/Clock.class and b/era.mi/bin/era/mi/logic/components/Clock.class differ diff --git a/era.mi/bin/era/mi/logic/components/Mux.class b/era.mi/bin/era/mi/logic/components/Mux.class index 9f6da5f5..ec4740b3 100644 Binary files a/era.mi/bin/era/mi/logic/components/Mux.class and b/era.mi/bin/era/mi/logic/components/Mux.class differ diff --git a/era.mi/bin/era/mi/logic/components/Splitter.class b/era.mi/bin/era/mi/logic/components/Splitter.class index e8faa694..d795f92c 100644 Binary files a/era.mi/bin/era/mi/logic/components/Splitter.class and b/era.mi/bin/era/mi/logic/components/Splitter.class differ diff --git a/era.mi/bin/era/mi/logic/components/gates/AndGate.class b/era.mi/bin/era/mi/logic/components/gates/AndGate.class index f5ca302c..d6ea9f59 100644 Binary files a/era.mi/bin/era/mi/logic/components/gates/AndGate.class and b/era.mi/bin/era/mi/logic/components/gates/AndGate.class differ diff --git a/era.mi/bin/era/mi/logic/components/gates/NotGate.class b/era.mi/bin/era/mi/logic/components/gates/NotGate.class index eb7dda83..addad50e 100644 Binary files a/era.mi/bin/era/mi/logic/components/gates/NotGate.class and b/era.mi/bin/era/mi/logic/components/gates/NotGate.class differ diff --git a/era.mi/bin/era/mi/logic/components/gates/OrGate.class b/era.mi/bin/era/mi/logic/components/gates/OrGate.class index 0cd75d07..ddc06f36 100644 Binary files a/era.mi/bin/era/mi/logic/components/gates/OrGate.class and b/era.mi/bin/era/mi/logic/components/gates/OrGate.class differ diff --git a/era.mi/bin/era/mi/logic/components/gates/XorGate.class b/era.mi/bin/era/mi/logic/components/gates/XorGate.class index d5b5adb6..e2c3f8bd 100644 Binary files a/era.mi/bin/era/mi/logic/components/gates/XorGate.class and b/era.mi/bin/era/mi/logic/components/gates/XorGate.class differ diff --git a/era.mi/bin/era/mi/logic/tests/ComponentTest.class b/era.mi/bin/era/mi/logic/tests/ComponentTest.class index 58535ad9..081de043 100644 Binary files a/era.mi/bin/era/mi/logic/tests/ComponentTest.class and b/era.mi/bin/era/mi/logic/tests/ComponentTest.class differ diff --git a/era.mi/bin/era/mi/logic/timeline/Timeline$InnerEvent.class b/era.mi/bin/era/mi/logic/timeline/Timeline$InnerEvent.class index 41d0ab68..5278183b 100644 Binary files a/era.mi/bin/era/mi/logic/timeline/Timeline$InnerEvent.class and b/era.mi/bin/era/mi/logic/timeline/Timeline$InnerEvent.class differ diff --git a/era.mi/bin/era/mi/logic/timeline/Timeline.class b/era.mi/bin/era/mi/logic/timeline/Timeline.class index 7bdc178c..52329114 100644 Binary files a/era.mi/bin/era/mi/logic/timeline/Timeline.class and b/era.mi/bin/era/mi/logic/timeline/Timeline.class differ diff --git a/era.mi/src/era/mi/logic/WireArray.java b/era.mi/src/era/mi/logic/WireArray.java deleted file mode 100644 index 64d90c17..00000000 --- a/era.mi/src/era/mi/logic/WireArray.java +++ /dev/null @@ -1,208 +0,0 @@ -package era.mi.logic; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * Represents an array of wires that can store n bits of information. - * @author Fabian Stemmler - * - */ -public class WireArray -{ - private Bit[] values; - private final int travelTime; - private List observers = new ArrayList<>();//(); - private final int length; - - 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.X; - } - - /** - * 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) - { - Simulation.TIMELINE.addEvent((e) -> setValues(newValues), travelTime); - } - - private void setValues(Bit... newValues) - { - if(length != newValues.length) - throw new IllegalArgumentException(String.format("Unexpected length for input array. Length was %d but expected %d", newValues.length, length)); //TODO: Proper handling - if(!Arrays.equals(values, newValues)) - { - values = newValues.clone(); - notifyObservers(); - } - } - - /** - * 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) - { - if(length < startingBit + newValues.length) - throw new IllegalArgumentException(); //TODO: Proper handling - if(!Arrays.equals(values, startingBit, startingBit + newValues.length, newValues, 0, newValues.length)) - { - System.arraycopy(newValues, 0, values, startingBit, newValues.length); - notifyObservers(); - } - } - - /** - * 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 int getUnsignedValue() - { - int val = 0; - int 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 int getSignedValue() - { - int val = getUnsignedValue(); - int mask = 1 << (length - 1); - if((mask & val) != 0) - { - int shifts = 32 - 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) - { - //TODO: ArrayIndexOutOfBoundsException handling for accessing single bit in WireArray - 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(); - } - - public int length() - { - return length; - } - - - /** - * 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); - } -} diff --git a/era.mi/src/era/mi/logic/WireArrayObserver.java b/era.mi/src/era/mi/logic/WireArrayObserver.java deleted file mode 100644 index 1b469fa9..00000000 --- a/era.mi/src/era/mi/logic/WireArrayObserver.java +++ /dev/null @@ -1,6 +0,0 @@ -package era.mi.logic; - -public interface WireArrayObserver -{ - public void update(WireArray initiator); -} diff --git a/era.mi/src/era/mi/logic/components/BasicComponent.java b/era.mi/src/era/mi/logic/components/BasicComponent.java index ad93dfe2..ddcf4cea 100644 --- a/era.mi/src/era/mi/logic/components/BasicComponent.java +++ b/era.mi/src/era/mi/logic/components/BasicComponent.java @@ -1,8 +1,8 @@ package era.mi.logic.components; import era.mi.logic.Simulation; -import era.mi.logic.WireArray; -import era.mi.logic.WireArrayObserver; +import era.mi.logic.wires.WireArray; +import era.mi.logic.wires.WireArrayObserver; public abstract class BasicComponent implements WireArrayObserver { diff --git a/era.mi/src/era/mi/logic/components/Clock.java b/era.mi/src/era/mi/logic/components/Clock.java index 3efde15c..9f2ecca6 100644 --- a/era.mi/src/era/mi/logic/components/Clock.java +++ b/era.mi/src/era/mi/logic/components/Clock.java @@ -2,30 +2,31 @@ package era.mi.logic.components; import era.mi.logic.Bit; import era.mi.logic.Simulation; -import era.mi.logic.WireArray; import era.mi.logic.timeline.TimelineEvent; import era.mi.logic.timeline.TimelineEventHandler; +import era.mi.logic.wires.WireArray; +import era.mi.logic.wires.WireArray.WireArrayInput; public class Clock implements TimelineEventHandler { private boolean toggle = false; - private WireArray w; + private WireArrayInput outI; - public Clock(WireArray w) + public Clock(WireArray out) { - this.w = w; + this.outI = out.createInput(); } @Override public void handle(TimelineEvent e) { Simulation.TIMELINE.addEvent(this, 50); - w.feedSignals(new Bit[] { toggle ? Bit.ONE : Bit.ZERO }); + outI.feedSignals(new Bit[] { toggle ? Bit.ONE : Bit.ZERO }); toggle = !toggle; } - public WireArray getW() + public WireArray getOut() { - return w; + return outI.owner; } } diff --git a/era.mi/src/era/mi/logic/components/Mux.java b/era.mi/src/era/mi/logic/components/Mux.java index 29c48146..0b19e7c8 100644 --- a/era.mi/src/era/mi/logic/components/Mux.java +++ b/era.mi/src/era/mi/logic/components/Mux.java @@ -1,7 +1,7 @@ package era.mi.logic.components; import era.mi.logic.Bit; -import era.mi.logic.WireArray; +import era.mi.logic.wires.WireArray; /** * Models a Multiplexer. A is selected when select bit is 1, B when select bit is 0. Outputs X otherwise. @@ -24,8 +24,8 @@ public class Mux extends BasicComponent public Mux(int processTime, WireArray a, WireArray b, WireArray select, WireArray out) { super(processTime); - size = a.length(); - if(b.length() != out.length() || b.length() != size) + size = a.length; + if(b.length != out.length || b.length != size) throw new IllegalArgumentException("All MUX wire arrays must be of uniform length!"); this.a = a; a.addObserver(this); diff --git a/era.mi/src/era/mi/logic/components/Mux2.java b/era.mi/src/era/mi/logic/components/Mux2.java new file mode 100644 index 00000000..c0c4ce32 --- /dev/null +++ b/era.mi/src/era/mi/logic/components/Mux2.java @@ -0,0 +1,101 @@ +package era.mi.logic.components; + +import era.mi.logic.Simulation; +import era.mi.logic.wires.WireArray; +import era.mi.logic.wires.WireArray.WireArrayInput; +import era.mi.logic.wires.WireArrayObserver; + +/** + * Models a Multiplexer. A is selected when select bit is 1, B when select bit is 0. Outputs X otherwise. + * @author Fabian Stemmler + * + */ +public class Mux2 implements WireArrayObserver +{ + private WireArray select; + private WireArrayInput outI; + private WireArrayInput[] inputs; + private final int size; + private final int processTime; + private int selected; + + /** + * {@link WireArray}s a, b and out must be of uniform length, select + * @param out Must be of uniform length with a and b. + * @param select Indexes the input array which is to be mapped to the output + * @param inputs One of these inputs is mapped to the output, depending on the select wires + */ + public Mux2(int processTime, WireArray out, WireArray select, WireArray... inputs) + { + this.processTime = processTime; + size = out.length; + + this.inputs = new WireArrayInput[inputs.length]; + for(int i = 0; i < this.inputs.length; i++) + { + if(inputs[i].length != size) + throw new IllegalArgumentException("All MUX wire arrays must be of uniform length!"); + this.inputs[i] = inputs[i].createInput(); + inputs[i].addObserver(this); + } + + this.select = select; + select.addObserver(this); + selected = -1; + + int maxInputs = 1 << select.length; + if(this.inputs.length > maxInputs) + throw new IllegalArgumentException("There are more inputs (" + + this.inputs.length + ") to the MUX than supported by " + + select.length + " select bits (" + maxInputs + ")."); + + outI = out.createInput(); + out.addObserver(this); + } + + public WireArray getOut() + { + return outI.owner; + } + + public WireArray getSelect() + { + return select; + } + + @Override + public void update(WireArray initiator) { + int selectValue; + if(!select.hasNumericValue() || (selectValue = (int) select.getUnsignedValue()) > size) + { + if(initiator == select) + { + Simulation.TIMELINE.addEvent((e) -> { + if(selected != -1) + { + inputs[selected].clearSignals(); + selected = -1; + outI.clearSignals(); + } + }, processTime); + } + return; + } + + WireArrayInput active = inputs[selectValue]; + Simulation.TIMELINE.addEvent((e) -> { + if(initiator == select) + { + if(selected != -1) + inputs[selected].clearSignals(); + selected = selectValue; + active.feedSignals(outI.owner.getValues()); + outI.feedSignals(active.owner.getValues()); + } + else if(initiator == outI.owner) + active.feedSignals(outI.owner.getValues()); + else if(initiator == active.owner) + outI.feedSignals(active.owner.getValues()); + }, processTime); + } +} diff --git a/era.mi/src/era/mi/logic/components/Splitter.java b/era.mi/src/era/mi/logic/components/Splitter.java index 48db52d9..58d48e7c 100644 --- a/era.mi/src/era/mi/logic/components/Splitter.java +++ b/era.mi/src/era/mi/logic/components/Splitter.java @@ -1,8 +1,8 @@ package era.mi.logic.components; import era.mi.logic.Bit; -import era.mi.logic.WireArray; -import era.mi.logic.WireArrayObserver; +import era.mi.logic.wires.WireArray; +import era.mi.logic.wires.WireArrayObserver; public class Splitter implements WireArrayObserver { @@ -16,9 +16,9 @@ public class Splitter implements WireArrayObserver input.addObserver(this); int length = 0; for(WireArray out : outputs) - length += out.length(); + length += out.length; - if(input.length() != length) + if(input.length != length) throw new IllegalArgumentException("The input of splitting one into n WireArrays must have length = a1.length() + a2.length() + ... + an.length()."); } @@ -28,10 +28,10 @@ public class Splitter implements WireArrayObserver Bit[] inputBits = input.getValues(); for(int i = 0; i < outputs.length; i++) { - Bit[] outputBits = new Bit[outputs[i].length()]; - System.arraycopy(inputBits, startIndex, outputBits, 0, outputs[i].length()); + Bit[] outputBits = new Bit[outputs[i].length]; + System.arraycopy(inputBits, startIndex, outputBits, 0, outputs[i].length); outputs[i].feedSignals(outputBits); - startIndex += outputs[i].length(); + startIndex += outputs[i].length; } } diff --git a/era.mi/src/era/mi/logic/components/TriState.java b/era.mi/src/era/mi/logic/components/TriState.java new file mode 100644 index 00000000..2bddbf1c --- /dev/null +++ b/era.mi/src/era/mi/logic/components/TriState.java @@ -0,0 +1,33 @@ +package era.mi.logic.components; + +import era.mi.logic.Bit; +import era.mi.logic.wires.WireArray; +import era.mi.logic.wires.WireArray.WireArrayInput; + +public class TriState extends BasicComponent{ + WireArray in, enable; + WireArrayInput outI; + + public TriState(int processTime, WireArray in, WireArray out, WireArray enable) { + super(processTime); + if(in.length != out.length) + throw new IllegalArgumentException("Tri-state output must have the same amount of bits as the input. Input: " + in.length + " Output: " + out.length); + if(enable.length != 1) + throw new IllegalArgumentException("Tri-state enable must have exactly one bit, not " + enable.length + "."); + this.in = in; + in.addObserver(this); + this.enable = enable; + enable.addObserver(this); + outI = out.createInput(); + } + + @Override + protected void compute() + { + if(enable.getValue() == Bit.ONE) + outI.feedSignals(in.getValues()); + else + outI.clearSignals(); + } + +} diff --git a/era.mi/src/era/mi/logic/components/gates/AndGate.java b/era.mi/src/era/mi/logic/components/gates/AndGate.java index 762eeef8..b3269cbd 100644 --- a/era.mi/src/era/mi/logic/components/gates/AndGate.java +++ b/era.mi/src/era/mi/logic/components/gates/AndGate.java @@ -1,12 +1,14 @@ package era.mi.logic.components.gates; import era.mi.logic.Util; -import era.mi.logic.WireArray; import era.mi.logic.components.BasicComponent; +import era.mi.logic.wires.WireArray; +import era.mi.logic.wires.WireArray.WireArrayInput; public class AndGate extends BasicComponent { private WireArray a, b, out; + private WireArrayInput outI; public AndGate(int processTime, WireArray a, WireArray b, WireArray out) { @@ -16,11 +18,12 @@ public class AndGate extends BasicComponent this.b = b; b.addObserver(this); this.out = out; + outI = out.createInput(); } protected void compute() { - out.feedSignals(Util.and(a.getValues(), b.getValues())); + outI.feedSignals(Util.and(a.getValues(), b.getValues())); } public WireArray getA() diff --git a/era.mi/src/era/mi/logic/components/gates/NotGate.java b/era.mi/src/era/mi/logic/components/gates/NotGate.java index 55d0cb01..1aba6b86 100644 --- a/era.mi/src/era/mi/logic/components/gates/NotGate.java +++ b/era.mi/src/era/mi/logic/components/gates/NotGate.java @@ -1,12 +1,15 @@ package era.mi.logic.components.gates; import era.mi.logic.Util; -import era.mi.logic.WireArray; import era.mi.logic.components.BasicComponent; +import era.mi.logic.wires.WireArray; +import era.mi.logic.wires.WireArray.WireArrayInput; public class NotGate extends BasicComponent { private WireArray in, out; + private WireArrayInput outI; + public NotGate(int processTime, WireArray in, WireArray out) { @@ -14,11 +17,12 @@ public class NotGate extends BasicComponent this.in = in; in.addObserver(this); this.out = out; + outI = out.createInput(); } public void compute() { - out.feedSignals(Util.not(in.getValues())); + outI.feedSignals(Util.not(in.getValues())); } public WireArray getIn() diff --git a/era.mi/src/era/mi/logic/components/gates/OrGate.java b/era.mi/src/era/mi/logic/components/gates/OrGate.java index 06296bab..c1d95a78 100644 --- a/era.mi/src/era/mi/logic/components/gates/OrGate.java +++ b/era.mi/src/era/mi/logic/components/gates/OrGate.java @@ -1,12 +1,14 @@ package era.mi.logic.components.gates; import era.mi.logic.Util; -import era.mi.logic.WireArray; import era.mi.logic.components.BasicComponent; +import era.mi.logic.wires.WireArray; +import era.mi.logic.wires.WireArray.WireArrayInput; public class OrGate extends BasicComponent { private WireArray a, b, out; + private WireArrayInput outI; public OrGate(int processTime, WireArray a, WireArray b, WireArray out) { @@ -16,11 +18,12 @@ public class OrGate extends BasicComponent this.b = b; b.addObserver(this); this.out = out; + this.outI = out.createInput(); } protected void compute() { - out.feedSignals(Util.or(a.getValues(), b.getValues())); + outI.feedSignals(Util.or(a.getValues(), b.getValues())); } public WireArray getA() diff --git a/era.mi/src/era/mi/logic/components/gates/XorGate.java b/era.mi/src/era/mi/logic/components/gates/XorGate.java index 9287f3fd..c7a94550 100644 --- a/era.mi/src/era/mi/logic/components/gates/XorGate.java +++ b/era.mi/src/era/mi/logic/components/gates/XorGate.java @@ -1,12 +1,14 @@ package era.mi.logic.components.gates; import era.mi.logic.Util; -import era.mi.logic.WireArray; import era.mi.logic.components.BasicComponent; +import era.mi.logic.wires.WireArray; +import era.mi.logic.wires.WireArray.WireArrayInput; public class XorGate extends BasicComponent { private WireArray a, b, out; + private WireArrayInput outI; public XorGate(int processTime, WireArray a, WireArray b, WireArray out) { @@ -20,7 +22,7 @@ public class XorGate extends BasicComponent protected void compute() { - out.feedSignals(Util.xor(a.getValues(), b.getValues())); + outI.feedSignals(Util.xor(a.getValues(), b.getValues())); } public WireArray getA() diff --git a/era.mi/src/era/mi/logic/tests/ComponentTest.java b/era.mi/src/era/mi/logic/tests/ComponentTest.java index f5ec68c0..0638cf8a 100644 --- a/era.mi/src/era/mi/logic/tests/ComponentTest.java +++ b/era.mi/src/era/mi/logic/tests/ComponentTest.java @@ -8,101 +8,104 @@ import org.junit.jupiter.api.Test; import era.mi.logic.Bit; import era.mi.logic.Simulation; -import era.mi.logic.WireArray; import era.mi.logic.components.Merger2; import era.mi.logic.components.Mux; +import era.mi.logic.components.Mux2; import era.mi.logic.components.Splitter; 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 Merger2(h, c, g); - new Mux(1, h, d, e, i); - new Splitter(i, k, j); - - a.feedSignals(Bit.ZERO); - b.feedSignals(Bit.ONE); - c.feedSignals(Bit.ZERO); - d.feedSignals(Bit.ONE, Bit.ONE); - e.feedSignals(Bit.ONE); - - while(Simulation.TIMELINE.hasNext()) - { - Simulation.TIMELINE.executeNext(); - } - - assertEquals(Simulation.TIMELINE.getSimulationTime(), 14); - 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.feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO,Bit.ONE, Bit.ZERO, Bit.ONE); - new Splitter(in, a, b, c); - - while(Simulation.TIMELINE.hasNext()) - { - Simulation.TIMELINE.executeNext(); - } - - assertTrue(Arrays.equals(a.getValues(), new Bit[] { Bit.ZERO, Bit.ONE, Bit.ZERO })); - assertTrue(Arrays.equals(b.getValues(), new Bit[] { Bit.ONE, Bit.ZERO })); - assertTrue(Arrays.equals(c.getValues(), new Bit[] { 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.feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO); - b.feedSignals(Bit.ONE, Bit.ZERO); - c.feedSignals(Bit.ONE, Bit.ZERO, Bit.ONE); - - new Merger2(out, a, b, c); - - while(Simulation.TIMELINE.hasNext()) - { - Simulation.TIMELINE.executeNext(); - } - - 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 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 Merger2(h, c, g); +// new Mux(1, h, d, e, i); +// 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.ONE); +// +// while(Simulation.TIMELINE.hasNext()) +// { +// Simulation.TIMELINE.executeNext(); +// } +// +// assertEquals(Simulation.TIMELINE.getSimulationTime(), 14); +// 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); +// +// while(Simulation.TIMELINE.hasNext()) +// { +// Simulation.TIMELINE.executeNext(); +// } +// +// assertTrue(Arrays.equals(a.getValues(), new Bit[] { Bit.ZERO, Bit.ONE, Bit.ZERO })); +// assertTrue(Arrays.equals(b.getValues(), new Bit[] { Bit.ONE, Bit.ZERO })); +// assertTrue(Arrays.equals(c.getValues(), new Bit[] { 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 Merger2(out, a, b, c); +// +// while(Simulation.TIMELINE.hasNext()) +// { +// Simulation.TIMELINE.executeNext(); +// } +// +// 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 muxTest() { Simulation.TIMELINE.reset(); - WireArray a = new WireArray(1, 1), b = new WireArray(1, 1), select = new WireArray(1, 1), out = new WireArray(1, 1); + WireArray a = new WireArray(1, 3), b = new WireArray(1, 2), select = new WireArray(1, 1), out = new WireArray(1, 1); + WireArrayInput selectIn = select.createInput(); - select.feedSignals(Bit.ONE); - a.feedSignals(Bit.ONE); - b.feedSignals(Bit.ZERO); + selectIn.feedSignals(Bit.ZERO); + a.createInput().feedSignals(Bit.ONE); + b.createInput().feedSignals(Bit.ZERO); - new Mux(1, a, b, select, out); - assertEquals(out.getValue(), Bit.X); + new Mux2(1, out, select, a, b); + assertEquals(Bit.Z, out.getValue()); while(Simulation.TIMELINE.hasNext()) { Simulation.TIMELINE.executeNext(); } - assertEquals(out.getValue(), Bit.ONE); - select.feedSignals(Bit.ZERO); + assertEquals(Bit.ONE, out.getValue()); + selectIn.feedSignals(Bit.ONE); while(Simulation.TIMELINE.hasNext()) { Simulation.TIMELINE.executeNext(); @@ -110,14 +113,14 @@ class ComponentTest assertEquals(out.getValue(), Bit.ZERO); } - + @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().feedSignals(Bit.ONE, Bit.ONE, Bit.ZERO, Bit.ZERO); - gate.getB().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE); + gate.getA().createInput().feedSignals(Bit.ONE, Bit.ONE, Bit.ZERO, Bit.ZERO); + gate.getB().createInput().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE); while(Simulation.TIMELINE.hasNext()) @@ -132,14 +135,14 @@ class ComponentTest { Simulation.TIMELINE.reset(); OrGate gate = new OrGate(1, new WireArray(4, 1), new WireArray(4, 1), new WireArray(4, 1)); - gate.getA().feedSignals(Bit.ONE, Bit.ONE, Bit.ZERO, Bit.ZERO); - gate.getB().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE); - + gate.getA().createInput().feedSignals(Bit.ONE, Bit.ONE, Bit.ZERO, Bit.ZERO); + gate.getB().createInput().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE); while(Simulation.TIMELINE.hasNext()) { Simulation.TIMELINE.executeNext(); } + assertTrue(Arrays.equals(gate.getOut().getValues(), new Bit[] { Bit.ONE, Bit.ONE, Bit.ZERO, Bit.ONE })); } @@ -155,8 +158,10 @@ class ComponentTest new NotGate(1, t2, q); new NotGate(1, t1, nq); - s.feedSignals(Bit.ONE); - r.feedSignals(Bit.ZERO); + WireArrayInput sIn = s.createInput(), rIn = r.createInput(); + + sIn.feedSignals(Bit.ONE); + rIn.feedSignals(Bit.ZERO); while(Simulation.TIMELINE.hasNext()) { @@ -166,7 +171,7 @@ class ComponentTest assertEquals(q.getValue(), Bit.ONE); assertEquals(nq.getValue(), Bit.ZERO); - s.feedSignals(Bit.ZERO); + sIn.feedSignals(Bit.ZERO); while(Simulation.TIMELINE.hasNext()) { @@ -176,7 +181,7 @@ class ComponentTest assertEquals(q.getValue(), Bit.ONE); assertEquals(nq.getValue(), Bit.ZERO); - r.feedSignals(Bit.ONE); + rIn.feedSignals(Bit.ONE); while(Simulation.TIMELINE.hasNext()) { @@ -193,7 +198,7 @@ class ComponentTest Simulation.TIMELINE.reset(); WireArray a = new WireArray(4, 1); - a.feedSignals(Bit.ONE, Bit.ONE, Bit.ONE, Bit.ONE); + a.createInput().feedSignals(Bit.ONE, Bit.ONE, Bit.ONE, Bit.ONE); while(Simulation.TIMELINE.hasNext()) { @@ -203,4 +208,41 @@ class ComponentTest assertEquals(a.getUnsignedValue(), 15); assertEquals(a.getSignedValue(), -1); } + + @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); + while(Simulation.TIMELINE.hasNext()) + { + Simulation.TIMELINE.executeNext(); + } + assertTrue(Arrays.equals(w.getValues(), new Bit[] { Bit.ONE, Bit.X })); + + wI2.feedSignals(Bit.ZERO, Bit.Z); + while(Simulation.TIMELINE.hasNext()) + { + Simulation.TIMELINE.executeNext(); + } + assertTrue(Arrays.equals(w.getValues(), new Bit[] { Bit.X, Bit.Z })); + + wI2.feedSignals(Bit.Z, Bit.Z); + while(Simulation.TIMELINE.hasNext()) + { + Simulation.TIMELINE.executeNext(); + } + assertTrue(Arrays.equals(w.getValues(), new Bit[] { Bit.ONE, Bit.Z })); + + wI2.feedSignals(Bit.ONE, Bit.Z); + w.addObserver((i) -> fail("WireArray notified observer, although value did not change.")); + while(Simulation.TIMELINE.hasNext()) + { + Simulation.TIMELINE.executeNext(); + } + assertTrue(Arrays.equals(w.getValues(), new Bit[] { Bit.ONE, Bit.Z })); + } } diff --git a/era.mi/src/era/mi/logic/timeline/Timeline.java b/era.mi/src/era/mi/logic/timeline/Timeline.java index bdd59476..125b69c3 100644 --- a/era.mi/src/era/mi/logic/timeline/Timeline.java +++ b/era.mi/src/era/mi/logic/timeline/Timeline.java @@ -15,7 +15,6 @@ public class Timeline public Timeline(int initCapacity) { events = new PriorityQueue(initCapacity, (a, b) -> { - //Is this really necessary? If only ints are allowed as relative timing, the difference should always be an int long difference = a.getTiming() - b.getTiming(); if(difference == 0) return 0; diff --git a/era.mi/src/era/mi/logic/wires/WireArray.java b/era.mi/src/era/mi/logic/wires/WireArray.java new file mode 100644 index 00000000..cf960e08 --- /dev/null +++ b/era.mi/src/era/mi/logic/wires/WireArray.java @@ -0,0 +1,295 @@ +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; + +/** + * 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); + } + + public WireArrayInput createInput() + { + return new WireArrayInput(this); + } + + private void registerInput(WireArrayInput toRegister) + { + inputs.add(toRegister); + } + + 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 void clearSignals() + { + Bit[] bits = new Bit[length]; + for(int i = 0; i < length; i++) + bits[i] = Bit.Z; + feedSignals(bits); + } + } +} diff --git a/era.mi/src/era/mi/logic/wires/WireArrayObserver.java b/era.mi/src/era/mi/logic/wires/WireArrayObserver.java new file mode 100644 index 00000000..c0766a2b --- /dev/null +++ b/era.mi/src/era/mi/logic/wires/WireArrayObserver.java @@ -0,0 +1,6 @@ +package era.mi.logic.wires; + +public interface WireArrayObserver +{ + public void update(WireArray initiator); +}