Merged logic into master
[Mograsim.git] / era.mi / src / era / mi / logic / wires / Wire.java
index 5eac889..a7b96ee 100644 (file)
@@ -1,13 +1,14 @@
 package era.mi.logic.wires;
 
+import static era.mi.logic.types.Bit.*;
+
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Iterator;
 import java.util.List;
 
-import era.mi.logic.Bit;
 import era.mi.logic.Simulation;
-import era.mi.logic.Util;
+import era.mi.logic.types.Bit;
+import era.mi.logic.types.BitVector;
+import era.mi.logic.types.BitVector.BitVectorMutator;
 
 /**
  * Represents an array of wires that can store n bits of information.
@@ -17,9 +18,9 @@ import era.mi.logic.Util;
  */
 public class Wire
 {
-       private Bit[] values;
+       private BitVector values;
        public final int travelTime;
-       private List<WireArrayObserver> observers = new ArrayList<WireArrayObserver>();
+       private List<WireObserver> observers = new ArrayList<WireObserver>();
        public final int length;
        private List<WireEnd> inputs = new ArrayList<WireEnd>();
 
@@ -35,46 +36,29 @@ public class Wire
 
        private void initValues()
        {
-               values = Bit.U.makeArray(length);
+               values = U.toVector(length);
        }
 
        private void recalculateSingleInput()
        {
-               WireEnd input = inputs.get(0);
-               if (!Arrays.equals(input.getInputValues(), values))
-               {
-                       Bit[] oldValues = values.clone();
-                       System.arraycopy(input.getInputValues(), 0, values, 0, length);
-                       notifyObservers(oldValues);
-               }
+               setNewValues(inputs.get(0).getInputValues());
        }
 
        private void recalculateMultipleInputs()
        {
-               Iterator<WireEnd> it = inputs.iterator();
-               Bit[] newValues = it.next().inputValues.clone();
-
-               while (it.hasNext())
-               {
-                       WireEnd input = it.next();
-                       Bit[] bits = input.getInputValues();
-                       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;
-                       }
-               }
+               BitVectorMutator mutator = BitVectorMutator.empty();
+               for (WireEnd wireArrayEnd : inputs)
+                       mutator.join(wireArrayEnd.getInputValues());
+               setNewValues(mutator.get());
+       }
 
-               if (!Arrays.equals(newValues, values))
-               {
-                       Bit[] oldValues = values;
-                       values = newValues;
-                       notifyObservers(oldValues);
-               }
+       private void setNewValues(BitVector newValues)
+       {
+               if (values.equals(newValues))
+                       return;
+               BitVector oldValues = values;
+               values = newValues;
+               notifyObservers(oldValues);
        }
 
        private void recalculate()
@@ -120,9 +104,9 @@ public class Wire
        {
                long val = 0;
                long mask = 1;
-               for (int i = 0; i < length; i++)
+               for (Bit bit : values)
                {
-                       switch (values[i])
+                       switch (bit)
                        {
                        default:
                        case Z:
@@ -165,38 +149,35 @@ public class Wire
 
        public Bit getValue(int index)
        {
-               return values[index];
+               return values.getBit(index);
        }
 
-       public Bit[] getValues(int start, int end)
+       public BitVector getValues(int start, int end)
        {
-               int length = end - start;
-               Bit[] bits = new Bit[length];
-               System.arraycopy(values, start, bits, 0, length);
-               return bits;
+               return values.subVector(start, end);
        }
 
-       public Bit[] getValues()
+       public BitVector getValues()
        {
-               return values.clone();
+               return values;
        }
 
        /**
-        * Adds an {@link WireArrayObserver}, who will be notified when the value of the {@link Wire} is updated.
+        * Adds an {@link WireObserver}, who will be notified when the value of the {@link Wire} 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
+        * @param ob The {@link WireObserver} to be notified of changes.
+        * @return true if the given {@link WireObserver} was not already registered, false otherwise
         * 
         * @author Fabian Stemmler
         */
-       public boolean addObserver(WireArrayObserver ob)
+       public boolean addObserver(WireObserver ob)
        {
                return observers.add(ob);
        }
 
-       private void notifyObservers(Bit[] oldValues)
+       private void notifyObservers(BitVector oldValues)
        {
-               for (WireArrayObserver o : observers)
+               for (WireObserver o : observers)
                        o.update(this, oldValues);
        }
 
@@ -205,7 +186,15 @@ public class Wire
         */
        public WireEnd createEnd()
        {
-               return new WireEnd();
+               return new WireEnd(false);
+       }
+
+       /**
+        * Create a {@link WireEnd} object, which is tied to this {@link Wire}. This {@link WireEnd} cannot written to.
+        */
+       public WireEnd createReadOnlyEnd()
+       {
+               return new WireEnd(true);
        }
 
        private void registerInput(WireEnd toRegister)
@@ -215,27 +204,28 @@ public class Wire
 
        /**
         * A {@link WireEnd} feeds a constant signal into the {@link Wire} it is tied to. The combination of all inputs determines the
-        * {@link Wire}s final value. X dominates all other inputs Z does not affect the final value, unless there are no other inputs than
-        * Z 0 and 1 turn into X when they are mixed
+        * {@link Wire}s final value. X dominates all other inputs Z does not affect the final value, unless there are no other inputs than Z 0
+        * and 1 turn into X when they are mixed
         * 
         * @author Fabian Stemmler
         */
        public class WireEnd
        {
                private boolean open;
-               private Bit[] inputValues;
+               private BitVector inputValues;
 
-               private WireEnd()
+               private WireEnd(boolean readOnly)
                {
                        super();
-                       open = true;
+                       open = !readOnly; // TODO: that makes sense, doesn't it?
                        initValues();
-                       registerInput(this);
+                       if (!readOnly)
+                               registerInput(this);
                }
 
                private void initValues()
                {
-                       inputValues = Bit.Z.makeArray(length);
+                       inputValues = U.toVector(length);
                }
 
                /**
@@ -247,43 +237,54 @@ public class Wire
                 */
                public void feedSignals(Bit... newValues)
                {
-                       if (newValues.length == length)
-                       {
-                               feedSignals(0, newValues);
-                       } else
+                       feedSignals(BitVector.of(newValues));
+               }
+
+               public void feedSignals(BitVector newValues)
+               {
+                       if (newValues.length() != length)
                                throw new IllegalArgumentException(
-                                               String.format("Attempted to input %d bits instead of %d bits.", newValues.length, length));
+                                               String.format("Attempted to input %d bits instead of %d bits.", newValues.length(), length));
+                       if (!open)
+                               throw new RuntimeException("Attempted to write to closed WireArrayEnd.");
+                       Simulation.TIMELINE.addEvent(e -> setValues(newValues), travelTime);
                }
 
                /**
                 * Sets values of a subarray of wires. This takes up time, as specified by the {@link Wire}s travel time.
                 * 
-                * @param newValues   The new values the wires should take on.
+                * @param bitVector   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)
+               public void feedSignals(int startingBit, BitVector bitVector)
                {
                        if (!open)
                                throw new RuntimeException("Attempted to write to closed WireArrayEnd.");
-                       Simulation.TIMELINE.addEvent((e) -> setValues(startingBit, newValues), travelTime);
+                       Simulation.TIMELINE.addEvent(e -> setValues(startingBit, bitVector), travelTime);
                }
 
-               private void setValues(int startingBit, Bit... newValues)
+               private void setValues(int startingBit, BitVector newValues)
                {
-                       int exclLastIndex = startingBit + newValues.length;
-                       if (length < exclLastIndex)
-                               throw new ArrayIndexOutOfBoundsException(
-                                               String.format("Attempted to input bits from index %d to %d when there are only %d wires.", startingBit,
-                                                               exclLastIndex - 1, length));
-                       if (!Arrays.equals(inputValues, startingBit, exclLastIndex, newValues, 0, newValues.length))
+                       // index check covered in equals
+                       if (!inputValues.equalsWithOffset(newValues, startingBit))
                        {
-                               System.arraycopy(newValues, 0, inputValues, startingBit, newValues.length);
+                               Bit[] vals = inputValues.getBits();
+                               System.arraycopy(newValues.getBits(), 0, vals, startingBit, newValues.length());
+                               inputValues = BitVector.of(vals);
                                Wire.this.recalculate();
                        }
                }
 
+               private void setValues(BitVector newValues)
+               {
+                       if (inputValues.equals(newValues))
+                               return;
+                       inputValues = newValues;
+                       Wire.this.recalculate();
+               }
+
                /**
                 * @return The value (of bit 0) the {@link WireEnd} is currently feeding into the associated {@link Wire}.
                 */
@@ -297,24 +298,20 @@ public class Wire
                 */
                public Bit getInputValue(int index)
                {
-                       return inputValues[index];
+                       return inputValues.getBit(index);
                }
-               
+
                /**
-                * @return A copy (safe to modify) of the values the {@link WireEnd} is currently feeding into the associated
-                * {@link Wire}.
+                * @return A copy (safe to modify) of the values the {@link WireEnd} is currently feeding into the associated {@link Wire}.
                 */
-               public Bit[] getInputValues()
+               public BitVector getInputValues()
                {
                        return getInputValues(0, length);
                }
-               
-               public Bit[] getInputValues(int start, int end)
+
+               public BitVector getInputValues(int start, int end)
                {
-                       int length = end - start;
-                       Bit[] bits = new Bit[length];
-                       System.arraycopy(inputValues, start, bits, 0, length);
-                       return bits;
+                       return inputValues.subVector(start, end);
                }
 
                /**
@@ -322,19 +319,19 @@ public class Wire
                 */
                public void clearSignals()
                {
-                       feedSignals(Bit.Z.makeArray(length));
+                       feedSignals(Z.toVector(length));
                }
 
-               public Bit[] wireValuesExcludingMe()
+               public BitVector wireValuesExcludingMe()
                {
-                       Bit[] bits = Bit.Z.makeArray(length);
-                       for (WireEnd wai : inputs)
+                       BitVectorMutator mutator = BitVectorMutator.empty();
+                       for (WireEnd wireEnd : inputs)
                        {
-                               if (wai == this)
+                               if (wireEnd == this)
                                        continue;
-                               Util.combineInto(bits, wai.getInputValues());
+                               mutator.join(wireEnd.inputValues);
                        }
-                       return bits;
+                       return mutator.get();
                }
 
                /**
@@ -359,36 +356,35 @@ public class Wire
                {
                        return Wire.this.getValue(index);
                }
-               
+
                /**
                 * @param index Index of the requested bit.
                 * @return The value of the indexed bit.
                 * 
                 * @author Fabian Stemmler
                 */
-               public Bit[] getValues()
+               public BitVector getValues()
                {
                        return Wire.this.getValues();
                }
 
                /**
                 * @param start Start of the wanted segment. (inclusive)
-                * @param end End of the wanted segment. (exclusive)
-                * @return The values of the segment of {@link Bit}s indexed. 
+                * @param end   End of the wanted segment. (exclusive)
+                * @return The values of the segment of {@link Bit}s indexed.
                 * 
                 * @author Fabian Stemmler
                 */
-               public Bit[] getValues(int start, int end)
+               public BitVector getValues(int start, int end)
                {
                        return Wire.this.getValues(start, end);
                }
-               
 
                /**
                 * The {@link Wire} 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.
+                * @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
                 */
@@ -420,15 +416,15 @@ public class Wire
                {
                        return Wire.this.getSignedValue();
                }
-               
+
                @Override
                public String toString()
                {
-                       return Arrays.toString(values);
-                       //return String.format("%s \nFeeding: %s", WireArray.this.toString(), Arrays.toString(inputValues));
+                       return inputValues.toString();
+                       // return String.format("%s \nFeeding: %s", WireArray.this.toString(), Arrays.toString(inputValues));
                }
 
-               public void disconnect()
+               public void close()
                {
                        inputs.remove(this);
                        open = false;
@@ -439,22 +435,22 @@ public class Wire
                        return length;
                }
 
-               public boolean addObserver(WireArrayObserver ob)
+               public boolean addObserver(WireObserver ob)
                {
                        return Wire.this.addObserver(ob);
                }
-               
+
                public Wire getWire()
                {
                        return Wire.this;
                }
        }
-       
+
        @Override
        public String toString()
        {
-               return String.format("wire 0x%08x value: %s inputs: %s", hashCode(), Arrays.toString(values), inputs);
-               //Arrays.toString(values), inputs.stream().map(i -> Arrays.toString(i.inputValues)).reduce((s1, s2) -> s1 + s2)
+               return String.format("wire 0x%08x value: %s inputs: %s", hashCode(), values, inputs);
+               // Arrays.toString(values), inputs.stream().map(i -> Arrays.toString(i.inputValues)).reduce((s1, s2) -> s1 + s2)
        }
 
        public static WireEnd[] extractEnds(Wire[] w)