Merge branch 'wire_array_inputs_update'
authorDaniel Kirschten <daniel.kirschten@gmx.de>
Fri, 10 May 2019 13:01:41 +0000 (15:01 +0200)
committerDaniel Kirschten <daniel.kirschten@gmx.de>
Fri, 10 May 2019 13:01:41 +0000 (15:01 +0200)
43 files changed:
era.mi/.classpath [new file with mode: 0644]
era.mi/.project [new file with mode: 0644]
era.mi/.settings/org.eclipse.jdt.core.prefs [new file with mode: 0644]
era.mi/bin/era/mi/logic/Bit.class [new file with mode: 0644]
era.mi/bin/era/mi/logic/Simulation.class [new file with mode: 0644]
era.mi/bin/era/mi/logic/Util$BitOp.class [new file with mode: 0644]
era.mi/bin/era/mi/logic/Util.class [new file with mode: 0644]
era.mi/bin/era/mi/logic/components/BasicComponent.class [new file with mode: 0644]
era.mi/bin/era/mi/logic/components/Clock.class [new file with mode: 0644]
era.mi/bin/era/mi/logic/components/Merger.class [new file with mode: 0644]
era.mi/bin/era/mi/logic/components/Merger2.class [new file with mode: 0644]
era.mi/bin/era/mi/logic/components/Mux.class [new file with mode: 0644]
era.mi/bin/era/mi/logic/components/Splitter.class [new file with mode: 0644]
era.mi/bin/era/mi/logic/components/gates/AndGate.class [new file with mode: 0644]
era.mi/bin/era/mi/logic/components/gates/NotGate.class [new file with mode: 0644]
era.mi/bin/era/mi/logic/components/gates/OrGate.class [new file with mode: 0644]
era.mi/bin/era/mi/logic/components/gates/XorGate.class [new file with mode: 0644]
era.mi/bin/era/mi/logic/tests/ComponentTest.class [new file with mode: 0644]
era.mi/bin/era/mi/logic/timeline/Timeline$InnerEvent.class [new file with mode: 0644]
era.mi/bin/era/mi/logic/timeline/Timeline.class [new file with mode: 0644]
era.mi/bin/era/mi/logic/timeline/TimelineEvent.class [new file with mode: 0644]
era.mi/bin/era/mi/logic/timeline/TimelineEventHandler.class [new file with mode: 0644]
era.mi/src/era/mi/logic/Bit.java [new file with mode: 0644]
era.mi/src/era/mi/logic/Simulation.java [new file with mode: 0644]
era.mi/src/era/mi/logic/Util.java [new file with mode: 0644]
era.mi/src/era/mi/logic/components/BasicComponent.java [new file with mode: 0644]
era.mi/src/era/mi/logic/components/Clock.java [new file with mode: 0644]
era.mi/src/era/mi/logic/components/Merger.java [new file with mode: 0644]
era.mi/src/era/mi/logic/components/Merger2.java [new file with mode: 0644]
era.mi/src/era/mi/logic/components/Mux.java [new file with mode: 0644]
era.mi/src/era/mi/logic/components/Mux2.java [new file with mode: 0644]
era.mi/src/era/mi/logic/components/Splitter.java [new file with mode: 0644]
era.mi/src/era/mi/logic/components/TriState.java [new file with mode: 0644]
era.mi/src/era/mi/logic/components/gates/AndGate.java [new file with mode: 0644]
era.mi/src/era/mi/logic/components/gates/NotGate.java [new file with mode: 0644]
era.mi/src/era/mi/logic/components/gates/OrGate.java [new file with mode: 0644]
era.mi/src/era/mi/logic/components/gates/XorGate.java [new file with mode: 0644]
era.mi/src/era/mi/logic/tests/ComponentTest.java [new file with mode: 0644]
era.mi/src/era/mi/logic/timeline/Timeline.java [new file with mode: 0644]
era.mi/src/era/mi/logic/timeline/TimelineEvent.java [new file with mode: 0644]
era.mi/src/era/mi/logic/timeline/TimelineEventHandler.java [new file with mode: 0644]
era.mi/src/era/mi/logic/wires/WireArray.java [new file with mode: 0644]
era.mi/src/era/mi/logic/wires/WireArrayObserver.java [new file with mode: 0644]

diff --git a/era.mi/.classpath b/era.mi/.classpath
new file mode 100644 (file)
index 0000000..bc8d71b
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="src" path="src"/>
+       <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/5"/>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-10">
+               <attributes>
+                       <attribute name="module" value="true"/>
+               </attributes>
+       </classpathentry>
+       <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/era.mi/.project b/era.mi/.project
new file mode 100644 (file)
index 0000000..9a89f37
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>era.mi</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+       </natures>
+</projectDescription>
diff --git a/era.mi/.settings/org.eclipse.jdt.core.prefs b/era.mi/.settings/org.eclipse.jdt.core.prefs
new file mode 100644 (file)
index 0000000..a54bb93
--- /dev/null
@@ -0,0 +1,12 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=10
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=10
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=10
diff --git a/era.mi/bin/era/mi/logic/Bit.class b/era.mi/bin/era/mi/logic/Bit.class
new file mode 100644 (file)
index 0000000..9bba9f0
Binary files /dev/null and b/era.mi/bin/era/mi/logic/Bit.class differ
diff --git a/era.mi/bin/era/mi/logic/Simulation.class b/era.mi/bin/era/mi/logic/Simulation.class
new file mode 100644 (file)
index 0000000..7cfc043
Binary files /dev/null and b/era.mi/bin/era/mi/logic/Simulation.class differ
diff --git a/era.mi/bin/era/mi/logic/Util$BitOp.class b/era.mi/bin/era/mi/logic/Util$BitOp.class
new file mode 100644 (file)
index 0000000..6e5fd47
Binary files /dev/null and b/era.mi/bin/era/mi/logic/Util$BitOp.class differ
diff --git a/era.mi/bin/era/mi/logic/Util.class b/era.mi/bin/era/mi/logic/Util.class
new file mode 100644 (file)
index 0000000..09b21b7
Binary files /dev/null and b/era.mi/bin/era/mi/logic/Util.class differ
diff --git a/era.mi/bin/era/mi/logic/components/BasicComponent.class b/era.mi/bin/era/mi/logic/components/BasicComponent.class
new file mode 100644 (file)
index 0000000..8ed1838
Binary files /dev/null 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
new file mode 100644 (file)
index 0000000..70dfad4
Binary files /dev/null and b/era.mi/bin/era/mi/logic/components/Clock.class differ
diff --git a/era.mi/bin/era/mi/logic/components/Merger.class b/era.mi/bin/era/mi/logic/components/Merger.class
new file mode 100644 (file)
index 0000000..e76a7d2
Binary files /dev/null and b/era.mi/bin/era/mi/logic/components/Merger.class differ
diff --git a/era.mi/bin/era/mi/logic/components/Merger2.class b/era.mi/bin/era/mi/logic/components/Merger2.class
new file mode 100644 (file)
index 0000000..08869fa
Binary files /dev/null and b/era.mi/bin/era/mi/logic/components/Merger2.class differ
diff --git a/era.mi/bin/era/mi/logic/components/Mux.class b/era.mi/bin/era/mi/logic/components/Mux.class
new file mode 100644 (file)
index 0000000..ec4740b
Binary files /dev/null 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
new file mode 100644 (file)
index 0000000..d795f92
Binary files /dev/null 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
new file mode 100644 (file)
index 0000000..d6ea9f5
Binary files /dev/null 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
new file mode 100644 (file)
index 0000000..addad50
Binary files /dev/null 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
new file mode 100644 (file)
index 0000000..ddc06f3
Binary files /dev/null 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
new file mode 100644 (file)
index 0000000..e2c3f8b
Binary files /dev/null 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
new file mode 100644 (file)
index 0000000..081de04
Binary files /dev/null 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
new file mode 100644 (file)
index 0000000..5278183
Binary files /dev/null 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
new file mode 100644 (file)
index 0000000..5232911
Binary files /dev/null and b/era.mi/bin/era/mi/logic/timeline/Timeline.class differ
diff --git a/era.mi/bin/era/mi/logic/timeline/TimelineEvent.class b/era.mi/bin/era/mi/logic/timeline/TimelineEvent.class
new file mode 100644 (file)
index 0000000..7eac32e
Binary files /dev/null and b/era.mi/bin/era/mi/logic/timeline/TimelineEvent.class differ
diff --git a/era.mi/bin/era/mi/logic/timeline/TimelineEventHandler.class b/era.mi/bin/era/mi/logic/timeline/TimelineEventHandler.class
new file mode 100644 (file)
index 0000000..7a4a6f7
Binary files /dev/null and b/era.mi/bin/era/mi/logic/timeline/TimelineEventHandler.class differ
diff --git a/era.mi/src/era/mi/logic/Bit.java b/era.mi/src/era/mi/logic/Bit.java
new file mode 100644 (file)
index 0000000..b18c597
--- /dev/null
@@ -0,0 +1,62 @@
+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;
+               }
+       }
+}
diff --git a/era.mi/src/era/mi/logic/Simulation.java b/era.mi/src/era/mi/logic/Simulation.java
new file mode 100644 (file)
index 0000000..6a63e15
--- /dev/null
@@ -0,0 +1,12 @@
+package era.mi.logic;
+
+import era.mi.logic.timeline.Timeline;
+
+public class Simulation
+{
+       public final static Timeline TIMELINE = new Timeline(11);
+       
+       public static void main(String[] args)
+       {
+       }
+}
\ No newline at end of file
diff --git a/era.mi/src/era/mi/logic/Util.java b/era.mi/src/era/mi/logic/Util.java
new file mode 100644 (file)
index 0000000..6f1b93f
--- /dev/null
@@ -0,0 +1,92 @@
+package era.mi.logic;
+
+import java.util.Arrays;
+
+public final class Util
+{
+       
+       @SuppressWarnings("unchecked")
+       public static <T> T[] concat(T[]... arrays)
+       {
+               if(arrays.length == 0)
+                       throw new IllegalArgumentException("Cannot concatenate 0 arrays.");
+               
+               int length = 0;
+               for(T[] array : arrays)
+                       length += array.length;
+               
+               T[] newArray = Arrays.copyOf(arrays[0], length);
+               int appendIndex = arrays[0].length;
+               for(int i = 1; i < arrays.length; i++)
+               {
+                       System.arraycopy(arrays[i], 0, newArray, appendIndex, arrays[i].length);
+                       appendIndex += arrays[i].length;
+               }
+               
+               return newArray;
+       }
+
+//     @SuppressWarnings("unchecked")
+//     public static <T> T[][] split(T[] array, int... lengths)
+//     {
+//             //TODO: implement array split again; This version contains an illegal cast
+//             int totalLength = 0;
+//             for(int length : lengths)
+//                     totalLength += length;
+//             
+//             if(totalLength != array.length)
+//                     throw new IllegalArgumentException(); //TODO: add proper error message
+//             
+//             Object[][] newArray = new Object[lengths.length][];
+//             int splitIndex = 0;
+//             for(int i = 0; i < lengths.length; i++)
+//             {
+//                     System.arraycopy(array, splitIndex, newArray, 0, lengths[i]);
+//                     splitIndex += lengths[i];
+//             }
+//             
+//             return (T[][]) newArray;
+//     }
+       
+       public static Bit[] and(Bit[] a, Bit[] b)
+       {
+               return binBitOp(a, b, (bA, bB) -> Bit.and(bA, bB));
+       }
+       
+       public static Bit[] or(Bit[] a, Bit[] b)
+       {
+               return binBitOp(a, b, (bA, bB) -> Bit.or(bA, bB));
+       }
+       
+       public static Bit[] xor(Bit[] a, Bit[] b)
+       {
+               return binBitOp(a, b, (bA, bB) -> Bit.xor(bA, bB));
+       }
+       
+       private static Bit[] binBitOp(Bit[] a, Bit[] b, BitOp op)
+       {
+               if(a.length != b.length)
+                       throw new IllegalArgumentException("Bit Arrays were not of equal length.");
+               Bit[] out = new Bit[a.length];
+               for(int i = 0; i < a.length; i++)
+               {
+                       out[i] = op.execute(a[i], b[i]);
+               }
+               return out;
+       }
+       
+       public static Bit[] not(Bit[] a)
+       {
+               Bit[] out = new Bit[a.length];
+               for(int i = 0; i < a.length; i++)
+               {
+                       out[i] = a[i].not();
+               }
+               return out;
+       }
+       
+       interface BitOp
+       {
+               Bit execute(Bit a, Bit b);
+       }
+}
diff --git a/era.mi/src/era/mi/logic/components/BasicComponent.java b/era.mi/src/era/mi/logic/components/BasicComponent.java
new file mode 100644 (file)
index 0000000..ddcf4ce
--- /dev/null
@@ -0,0 +1,29 @@
+package era.mi.logic.components;
+
+import era.mi.logic.Simulation;
+import era.mi.logic.wires.WireArray;
+import era.mi.logic.wires.WireArrayObserver;
+
+public abstract class BasicComponent implements WireArrayObserver
+{
+       private int processTime;
+       
+       /**
+        * 
+        * @param processTime Amount of time this component takes to update its outputs. Must be more than 0, otherwise 1 is assumed.
+        * 
+        * @author Fabian Stemmler
+        */
+       public BasicComponent(int processTime)
+       {
+               this.processTime = processTime > 0 ? processTime : 1;
+       }
+       
+       @Override
+       public void update(WireArray initiator)
+       {
+               Simulation.TIMELINE.addEvent((e) -> {compute();}, processTime);
+       }
+       
+       protected abstract void compute();
+}
diff --git a/era.mi/src/era/mi/logic/components/Clock.java b/era.mi/src/era/mi/logic/components/Clock.java
new file mode 100644 (file)
index 0000000..9f2ecca
--- /dev/null
@@ -0,0 +1,32 @@
+package era.mi.logic.components;
+
+import era.mi.logic.Bit;
+import era.mi.logic.Simulation;
+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 WireArrayInput outI;
+       
+       public Clock(WireArray out)
+       {
+               this.outI = out.createInput();
+       }
+
+       @Override
+       public void handle(TimelineEvent e)
+       {
+               Simulation.TIMELINE.addEvent(this, 50);
+               outI.feedSignals(new Bit[] { toggle ? Bit.ONE : Bit.ZERO });
+               toggle = !toggle;
+       }
+
+       public WireArray getOut()
+       {
+               return outI.owner;
+       }
+}
diff --git a/era.mi/src/era/mi/logic/components/Merger.java b/era.mi/src/era/mi/logic/components/Merger.java
new file mode 100644 (file)
index 0000000..eb910a4
--- /dev/null
@@ -0,0 +1,61 @@
+package era.mi.logic.components;
+
+import era.mi.logic.Util;
+import era.mi.logic.Bit;
+import era.mi.logic.WireArray;
+import era.mi.logic.WireArrayObserver;
+
+@Deprecated
+public class Merger implements WireArrayObserver
+{
+       private WireArray out;
+       private WireArray[] inputs;
+       
+       //TODO: General problem with this concept; New inputs coming in at the same time override each other
+       
+       /**
+        * 
+        * @param union The output of merging n {@link WireArray}s into one. Must have length = a1.length() + a2.length() + ... + an.length().
+        * @param inputs The inputs to be merged into the union
+        */
+       public Merger(WireArray union, WireArray... inputs)
+       {
+               this.inputs = inputs;
+               this.out = union;
+               
+               int length = 0;
+               for(WireArray input : inputs)
+               {
+                       length += input.length();
+                       input.addObserver(this);
+               }
+                       
+               if(length != union.length())
+                       throw new IllegalArgumentException("The output of merging n WireArrays into one must have length = a1.length() + a2.length() + ... + an.length().");
+       }
+
+       protected void compute()
+       {
+               Bit[][] bits = new Bit[inputs.length][];
+               for(int i = 0; i < inputs.length; i++)
+                       bits[i] = inputs[i].getValues();
+               Bit[] newOut = Util.concat(bits);
+               out.feedSignals(newOut);
+       }
+
+       public WireArray getInput(int index)
+       {
+               return inputs[index];
+       }
+       
+       public WireArray getUnion()
+       {
+               return out;
+       }
+       
+       @Override
+       public void update(WireArray initiator)
+       {
+               compute(); //No inner delay
+       }
+}
diff --git a/era.mi/src/era/mi/logic/components/Merger2.java b/era.mi/src/era/mi/logic/components/Merger2.java
new file mode 100644 (file)
index 0000000..ca24254
--- /dev/null
@@ -0,0 +1,70 @@
+package era.mi.logic.components;
+
+import era.mi.logic.WireArray;
+import era.mi.logic.WireArrayObserver;
+
+public class Merger2 implements WireArrayObserver
+{
+       private WireArray out;
+       private WireArray[] inputs;
+       private int[] beginningIndex;
+       
+       /**
+        * 
+        * @param union The output of merging n {@link WireArray}s into one. Must have length = a1.length() + a2.length() + ... + an.length().
+        * @param inputs The inputs to be merged into the union
+        */
+       public Merger2(WireArray union, WireArray... inputs)
+       {
+               this.inputs = inputs;
+               this.out = union;
+               this.beginningIndex = new int[inputs.length];
+               
+               int length = 0;
+               for(int i = 0; i < inputs.length; i++)
+               {
+                       beginningIndex[i] = length;
+                       length += inputs[i].length();
+                       inputs[i].addObserver(this);
+               }
+                       
+               if(length != union.length())
+                       throw new IllegalArgumentException("The output of merging n WireArrays into one must have length = a1.length() + a2.length() + ... + an.length().");
+       }
+
+       public WireArray getInput(int index)
+       {
+               return inputs[index];
+       }
+       
+       public WireArray getUnion()
+       {
+               return out;
+       }
+       
+       @Override
+       public void update(WireArray initiator)
+       {
+               int index = find(initiator);
+               int beginning = beginningIndex[index];
+               out.feedSignals(beginning, initiator.getValues());
+       }
+       
+       private int find(WireArray w)
+       {
+               for(int i = 0; i < inputs.length; i++)
+                       if(inputs[i] == w)
+                               return i;
+               return -1;
+       }
+
+       public WireArray getOut()
+       {
+               return out;
+       }
+
+       public WireArray[] getInputs()
+       {
+               return inputs.clone();
+       }
+}
diff --git a/era.mi/src/era/mi/logic/components/Mux.java b/era.mi/src/era/mi/logic/components/Mux.java
new file mode 100644 (file)
index 0000000..0b19e7c
--- /dev/null
@@ -0,0 +1,77 @@
+package era.mi.logic.components;
+
+import era.mi.logic.Bit;
+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.
+ * @author Fabian
+ *
+ */
+public class Mux extends BasicComponent
+{
+       private WireArray a, b, out;
+       private WireArray select;
+       private final int size;
+       
+       /**
+        * {@link WireArray}s a, b and out must be of uniform length, select
+        * @param a Must be of uniform length with b and out.
+        * @param b Must be of uniform length with a and out.
+        * @param select C
+        * @param out Must be of uniform length with a and b.
+        */
+       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)
+                       throw new IllegalArgumentException("All MUX wire arrays must be of uniform length!");
+               this.a = a;
+               a.addObserver(this);
+               this.b = b;
+               b.addObserver(this);
+               this.select = select;
+               select.addObserver(this);
+               this.out = out;
+       }
+
+       @Override
+       protected void compute()
+       {
+               WireArray active = b;
+               switch(select.getValue())
+               {
+               case ONE:
+                       active = a;
+               case ZERO:
+                       out.feedSignals(active.getValues());
+                       break;
+               default:
+                       Bit[] newValues = new Bit[size];
+                       for(int i = 0; i < size; i++)
+                               newValues[i] = Bit.X;
+                       out.feedSignals(newValues);
+               }
+       }
+
+       public WireArray getA()
+       {
+               return a;
+       }
+
+       public WireArray getB()
+       {
+               return b;
+       }
+
+       public WireArray getOut()
+       {
+               return out;
+       }
+
+       public WireArray getSelect()
+       {
+               return select;
+       }
+}
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 (file)
index 0000000..c0c4ce3
--- /dev/null
@@ -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
new file mode 100644 (file)
index 0000000..58d48e7
--- /dev/null
@@ -0,0 +1,53 @@
+package era.mi.logic.components;
+
+import era.mi.logic.Bit;
+import era.mi.logic.wires.WireArray;
+import era.mi.logic.wires.WireArrayObserver;
+
+public class Splitter implements WireArrayObserver
+{
+       private WireArray input;
+       private WireArray[] outputs;
+       
+       public Splitter(WireArray input, WireArray... outputs)
+       {
+               this.input = input;
+               this.outputs = outputs;
+               input.addObserver(this);
+               int length = 0;
+               for(WireArray out : outputs)
+                       length += out.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().");
+       }
+
+       protected void compute()
+       {
+               int startIndex = 0;
+               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);
+                       outputs[i].feedSignals(outputBits);
+                       startIndex += outputs[i].length;
+               }
+       }
+
+       public WireArray getInput()
+       {
+               return input;
+       }
+       
+       public WireArray[] getOutputs()
+       {
+               return outputs.clone();
+       }
+       
+       @Override
+       public void update(WireArray initiator)
+       {
+               compute();
+       }
+}
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 (file)
index 0000000..2bddbf1
--- /dev/null
@@ -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
new file mode 100644 (file)
index 0000000..b3269cb
--- /dev/null
@@ -0,0 +1,43 @@
+package era.mi.logic.components.gates;
+
+import era.mi.logic.Util;
+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)
+       {
+               super(processTime);
+               this.a = a;
+               a.addObserver(this);
+               this.b = b;
+               b.addObserver(this);
+               this.out = out;
+               outI = out.createInput();
+       }
+
+       protected void compute()
+       {
+               outI.feedSignals(Util.and(a.getValues(), b.getValues()));
+       }
+
+       public WireArray getA()
+       {
+               return a;
+       }
+
+       public WireArray getB()
+       {
+               return b;
+       }
+
+       public WireArray getOut()
+       {
+               return out;
+       }
+}
diff --git a/era.mi/src/era/mi/logic/components/gates/NotGate.java b/era.mi/src/era/mi/logic/components/gates/NotGate.java
new file mode 100644 (file)
index 0000000..1aba6b8
--- /dev/null
@@ -0,0 +1,37 @@
+package era.mi.logic.components.gates;
+
+import era.mi.logic.Util;
+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)
+       {
+               super(processTime);
+               this.in = in;
+               in.addObserver(this);
+               this.out = out;
+               outI = out.createInput();
+       }
+       
+       public void compute()
+       {
+               outI.feedSignals(Util.not(in.getValues()));
+       }
+
+       public WireArray getIn()
+       {
+               return in;
+       }
+
+       public WireArray getOut()
+       {
+               return out;
+       }
+}
diff --git a/era.mi/src/era/mi/logic/components/gates/OrGate.java b/era.mi/src/era/mi/logic/components/gates/OrGate.java
new file mode 100644 (file)
index 0000000..c1d95a7
--- /dev/null
@@ -0,0 +1,43 @@
+package era.mi.logic.components.gates;
+
+import era.mi.logic.Util;
+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)
+       {
+               super(processTime);
+               this.a = a;
+               a.addObserver(this);
+               this.b = b;
+               b.addObserver(this);
+               this.out = out;
+               this.outI = out.createInput();
+       }
+
+       protected void compute()
+       {
+               outI.feedSignals(Util.or(a.getValues(), b.getValues()));
+       }
+
+       public WireArray getA()
+       {
+               return a;
+       }
+
+       public WireArray getB()
+       {
+               return b;
+       }
+
+       public WireArray getOut()
+       {
+               return out;
+       }
+}
diff --git a/era.mi/src/era/mi/logic/components/gates/XorGate.java b/era.mi/src/era/mi/logic/components/gates/XorGate.java
new file mode 100644 (file)
index 0000000..c7a9455
--- /dev/null
@@ -0,0 +1,42 @@
+package era.mi.logic.components.gates;
+
+import era.mi.logic.Util;
+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)
+       {
+               super(processTime);
+               this.a = a;
+               a.addObserver(this);
+               this.b = b;
+               b.addObserver(this);
+               this.out = out;
+       }
+
+       protected void compute()
+       {
+               outI.feedSignals(Util.xor(a.getValues(), b.getValues()));
+       }
+
+       public WireArray getA()
+       {
+               return a;
+       }
+
+       public WireArray getB()
+       {
+               return b;
+       }
+
+       public WireArray getOut()
+       {
+               return out;
+       }
+}
diff --git a/era.mi/src/era/mi/logic/tests/ComponentTest.java b/era.mi/src/era/mi/logic/tests/ComponentTest.java
new file mode 100644 (file)
index 0000000..0638cf8
--- /dev/null
@@ -0,0 +1,248 @@
+package era.mi.logic.tests;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.util.Arrays;
+
+import org.junit.jupiter.api.Test;
+
+import era.mi.logic.Bit;
+import era.mi.logic.Simulation;
+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.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, 3), b = new WireArray(1, 2), select = new WireArray(1, 1), out = new WireArray(1, 1);
+               WireArrayInput selectIn = select.createInput();
+               
+               selectIn.feedSignals(Bit.ZERO);
+               a.createInput().feedSignals(Bit.ONE);
+               b.createInput().feedSignals(Bit.ZERO);
+               
+               new Mux2(1, out, select, a, b);
+               assertEquals(Bit.Z, out.getValue());
+               while(Simulation.TIMELINE.hasNext())
+               {
+                       Simulation.TIMELINE.executeNext();
+               }
+
+               assertEquals(Bit.ONE, out.getValue());
+               selectIn.feedSignals(Bit.ONE);
+               while(Simulation.TIMELINE.hasNext())
+               {
+                       Simulation.TIMELINE.executeNext();
+               }
+               
+               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().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.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);
+               
+               while(Simulation.TIMELINE.hasNext())
+               {
+                       Simulation.TIMELINE.executeNext();
+               }
+               
+               assertTrue(Arrays.equals(gate.getOut().getValues(), new Bit[] { 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);
+               
+               while(Simulation.TIMELINE.hasNext())
+               {
+                       Simulation.TIMELINE.executeNext();
+               }
+               
+               assertEquals(q.getValue(), Bit.ONE);
+               assertEquals(nq.getValue(), Bit.ZERO);
+               
+               sIn.feedSignals(Bit.ZERO);
+               
+               while(Simulation.TIMELINE.hasNext())
+               {
+                       Simulation.TIMELINE.executeNext();
+               }
+               
+               assertEquals(q.getValue(), Bit.ONE);
+               assertEquals(nq.getValue(), Bit.ZERO);
+               
+               rIn.feedSignals(Bit.ONE);
+               
+               while(Simulation.TIMELINE.hasNext())
+               {
+                       Simulation.TIMELINE.executeNext();
+               }
+               
+               assertEquals(q.getValue(), Bit.ZERO);
+               assertEquals(nq.getValue(), Bit.ONE);
+       }
+       
+       @Test
+       void numericValueTest()
+       {
+               Simulation.TIMELINE.reset();
+               
+               WireArray a = new WireArray(4, 1);
+               a.createInput().feedSignals(Bit.ONE, Bit.ONE, Bit.ONE, Bit.ONE);
+               
+               while(Simulation.TIMELINE.hasNext())
+               {
+                       Simulation.TIMELINE.executeNext();
+               }
+               
+               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
new file mode 100644 (file)
index 0000000..125b69c
--- /dev/null
@@ -0,0 +1,89 @@
+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<InnerEvent> events;
+       private long currentTime = 0;
+       
+       public Timeline(int initCapacity)
+       {
+               events = new PriorityQueue<InnerEvent>(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 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);
+               }
+               
+       }
+}
\ 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
new file mode 100644 (file)
index 0000000..6cec907
--- /dev/null
@@ -0,0 +1,17 @@
+package era.mi.logic.timeline;
+
+public class TimelineEvent
+{
+       private final long timing;
+       
+       TimelineEvent(long timing)
+       {
+               super();
+               this.timing = timing;
+       }
+
+       public long getTiming()
+       {
+               return timing;
+       }
+}
\ No newline at end of file
diff --git a/era.mi/src/era/mi/logic/timeline/TimelineEventHandler.java b/era.mi/src/era/mi/logic/timeline/TimelineEventHandler.java
new file mode 100644 (file)
index 0000000..59a91c9
--- /dev/null
@@ -0,0 +1,6 @@
+package era.mi.logic.timeline;
+
+public interface TimelineEventHandler
+{
+       public void handle(TimelineEvent e);
+}
\ 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
new file mode 100644 (file)
index 0000000..cf960e0
--- /dev/null
@@ -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<WireArrayObserver> observers = new ArrayList<WireArrayObserver>();
+       public final int length;
+       private List<WireArrayInput> inputs = new ArrayList<WireArrayInput>();
+       
+       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<WireArrayInput> 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 <code>true</code> if all bits are either <code>Bit.ONE</code> or <code>Bit.ZERO</code> (they do not all have to have the same value), not <code>Bit.X</code> or <code>Bit.Z</code>. <code>false</code> 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 (file)
index 0000000..c0766a2
--- /dev/null
@@ -0,0 +1,6 @@
+package era.mi.logic.wires;
+
+public interface WireArrayObserver
+{
+       public void update(WireArray initiator);
+}