Fixed a bug in Am2900; created dlatch8/80; relayouted some components
[Mograsim.git] / net.mograsim.logic.core / src / net / mograsim / logic / core / types / BitVector.java
index 4d5365a..1346694 100644 (file)
@@ -2,6 +2,7 @@ package net.mograsim.logic.core.types;
 
 import static java.lang.String.format;
 
+import java.math.BigInteger;
 import java.util.Arrays;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
@@ -13,17 +14,30 @@ import java.util.function.UnaryOperator;
 /**
  * Immutable class representing a {@link Bit}Vector
  *
- *
  * @author Christian Femers
  *
  */
 public final class BitVector implements StrictLogicType<BitVector>, Iterable<Bit>, RandomAccess
 {
+       public static final BitVector SINGLE_U = new BitVector(Bit.U);
+       public static final BitVector SINGLE_X = new BitVector(Bit.X);
+       public static final BitVector SINGLE_0 = new BitVector(Bit.ZERO);
+       public static final BitVector SINGLE_1 = new BitVector(Bit.ONE);
+       public static final BitVector SINGLE_Z = new BitVector(Bit.Z);
+
+       private static final BitVector[] SINGLE_BIT_MAPPING = { SINGLE_U, SINGLE_X, SINGLE_0, SINGLE_1, SINGLE_Z };
+
        private final Bit[] bits;
 
+       private BitVector(Bit single)
+       {
+               Objects.requireNonNull(single);
+               bits = new Bit[] { single };
+       }
+
        private BitVector(Bit[] bits)
        {
-               this.bits = Objects.requireNonNull(bits);// do this first to "catch" bits==null before the foreach loop
+               this.bits = Objects.requireNonNull(bits); // do this first to "catch" bits==null before the foreach loop
                for (Bit bit : bits)
                        if (bit == null)
                                throw new NullPointerException();
@@ -31,33 +45,78 @@ public final class BitVector implements StrictLogicType<BitVector>, Iterable<Bit
 
        public static BitVector of(Bit... bits)
        {
+               if (bits.length == 1)
+                       return SINGLE_BIT_MAPPING[bits[0].ordinal()];
                return new BitVector(bits.clone());
        }
 
        public static BitVector of(Bit bit, int length)
        {
+               if (length == 1)
+                       return SINGLE_BIT_MAPPING[bit.ordinal()];
                return new BitVector(bit.makeArray(length));
        }
 
+       public static BitVector from(long value, int bits)
+       {
+               return from(BigInteger.valueOf(value), bits);
+       }
+
+       public static BitVector from(BigInteger value, int bits)
+       {
+               Bit[] values = new Bit[bits];
+               for (int i = 0; i < bits; i++)
+                       values[bits - i - 1] = Bit.of(value.testBit(i));
+               return new BitVector(values);
+       }
+
        public BitVectorMutator mutator()
        {
                return BitVectorMutator.of(this);
        }
 
-       public Bit getBit(int bitIndex)
+       /**
+        * Returns the most significant bit at <code>bitIndex</code>. (leftmost bit of a binary number at the given index)
+        */
+       public Bit getMSBit(int bitIndex)
        {
                return bits[bitIndex];
        }
 
+       /**
+        * Returns the least significant bit at <code>bitIndex</code>. (rightmost bit of a binary number at the given index)
+        */
+       public Bit getLSBit(int bitIndex)
+       {
+               return bits[bits.length - bitIndex - 1];
+       }
+
        public Bit[] getBits()
        {
                return bits.clone();
        }
 
+       /**
+        * Checks if all bits are {@link Bit#isBinary() binary}.
+        * 
+        * @see Bit#isBinary()
+        */
+       public boolean isBinary()
+       {
+               for (int i = 0; i < bits.length; i++)
+               {
+                       if (!bits[i].isBinary())
+                               return false;
+               }
+               return true;
+       }
+
        @Override
        public BitVector join(BitVector t)
        {
                checkCompatibility(t);
+               if (bits.length == 1)
+                       return SINGLE_BIT_MAPPING[bits[0].join(t.bits[0]).ordinal()];
                return new BitVector(binOp(bits.clone(), t.bits, Bit::join));
        }
 
@@ -65,6 +124,8 @@ public final class BitVector implements StrictLogicType<BitVector>, Iterable<Bit
        public BitVector and(BitVector t)
        {
                checkCompatibility(t);
+               if (bits.length == 1)
+                       return SINGLE_BIT_MAPPING[bits[0].and(t.bits[0]).ordinal()];
                return new BitVector(binOp(bits.clone(), t.bits, Bit::and));
        }
 
@@ -72,6 +133,8 @@ public final class BitVector implements StrictLogicType<BitVector>, Iterable<Bit
        public BitVector or(BitVector t)
        {
                checkCompatibility(t);
+               if (bits.length == 1)
+                       return SINGLE_BIT_MAPPING[bits[0].or(t.bits[0]).ordinal()];
                return new BitVector(binOp(bits.clone(), t.bits, Bit::or));
        }
 
@@ -79,12 +142,16 @@ public final class BitVector implements StrictLogicType<BitVector>, Iterable<Bit
        public BitVector xor(BitVector t)
        {
                checkCompatibility(t);
+               if (bits.length == 1)
+                       return SINGLE_BIT_MAPPING[bits[0].xor(t.bits[0]).ordinal()];
                return new BitVector(binOp(bits.clone(), t.bits, Bit::xor));
        }
 
        @Override
        public BitVector not()
        {
+               if (bits.length == 1)
+                       return SINGLE_BIT_MAPPING[bits[0].not().ordinal()];
                return new BitVector(unOp(bits.clone(), Bit::not));
        }
 
@@ -167,12 +234,23 @@ public final class BitVector implements StrictLogicType<BitVector>, Iterable<Bit
 
                /**
                 * Returns an empty mutator which has no bits set and will simply copy the values from the first binary operation performed.
+                * <p>
+                * An empty BitVectorMutator <b>must not</b> be converted to BitVector or used to manipulate single bits until at least one two
+                * operand logic operation is performed.
                 */
                public static BitVectorMutator empty()
                {
                        return new BitVectorMutator(null);
                }
 
+               /**
+                * @see #empty()
+                */
+               public boolean isEmpty()
+               {
+                       return bits == null;
+               }
+
                /**
                 * Produces the resulting, immutable {@link BitVector}<br>
                 * 
@@ -224,18 +302,50 @@ public final class BitVector implements StrictLogicType<BitVector>, Iterable<Bit
                        return this;
                }
 
-               public void setBit(int bitIndex, Bit bit)
+               /**
+                * Set the most significant bit at <code>bitIndex</code>. (leftmost bit of a binary number at the given index)
+                */
+               public void setMSBit(int bitIndex, Bit bit)
                {
+                       if (bits == null)
+                               throw new IllegalStateException("cannot set a bit of an empty mutator");
                        bits[bitIndex] = bit;
                }
 
-               public Bit getBit(int bitIndex)
+               /**
+                * Set the least significant bit at <code>bitIndex</code>. (rightmost bit of a binary number at the given index)
+                */
+               public void setLSBit(int bitIndex, Bit bit)
                {
+                       if (bits == null)
+                               throw new IllegalStateException("cannot set a bit of an empty mutator");
+                       bits[bits.length - bitIndex - 1] = bit;
+               }
+
+               /**
+                * Returns the most significant bit at <code>bitIndex</code>. (leftmost bit of a binary number at the given index)
+                */
+               public Bit getMSBit(int bitIndex)
+               {
+                       if (bits == null)
+                               throw new IllegalStateException("cannot get a bit of an empty mutator");
                        return bits[bitIndex];
                }
 
+               /**
+                * Returns the least significant bit at <code>bitIndex</code>. (rightmost bit of a binary number at the given index)
+                */
+               public Bit getLSBit(int bitIndex)
+               {
+                       if (bits == null)
+                               throw new IllegalStateException("cannot get a bit of an empty mutator");
+                       return bits[bits.length - bitIndex - 1];
+               }
+
                public int length()
                {
+                       if (bits == null)
+                               throw new IllegalStateException("cannot obtain a length of an empty mutator");
                        return bits.length;
                }
 
@@ -273,7 +383,7 @@ public final class BitVector implements StrictLogicType<BitVector>, Iterable<Bit
 
        /**
         * Does test for equality of values/content, shifting the other BitVector by <code>offset</code> to the right.<br>
-        * Therefore <code>offset + other.length() <= this.length()</code> needs to be true.
+        * Therefore <code>offset + other.length() <= this.wdith()</code> needs to be true.
         * 
         * @throws ArrayIndexOutOfBoundsException if <code>offset + other.length() > this.length()</code>
         * 
@@ -287,7 +397,7 @@ public final class BitVector implements StrictLogicType<BitVector>, Iterable<Bit
        }
 
        /**
-        * All {@link Bit}s symbols concatenated together
+        * All {@link Bit}s symbols concatenated together (MSB first)
         * 
         * @see #parse(String)
         */
@@ -301,7 +411,59 @@ public final class BitVector implements StrictLogicType<BitVector>, Iterable<Bit
        }
 
        /**
-        * Parses a String containing solely {@link Bit} symbols
+        * Returns the value of the BitVector as BigInteger.
+        * 
+        * @throws NumberFormatException if the BitVector is not {@link #isBinary() binary}.
+        */
+       public BigInteger getUnsignedValue()
+       {
+               if (!isBinary())
+                       throw new NumberFormatException(this + " is not binary");
+               byte[] bytes = new byte[(bits.length / 8 + (bits.length % 8 == 0 ? 0 : 1)) + 1];
+               for (int i = bits.length - 1; i >= 0; i--)
+               {
+                       if (Bit.ONE == bits[bits.length - i - 1])
+                       {
+                               try
+                               {
+                                       bytes[bytes.length - (i / 8) - 1] |= 1 << (i % 8);
+                               }
+                               catch (IndexOutOfBoundsException e)
+                               {
+                                       e.printStackTrace();
+                               }
+                       }
+               }
+               return new BigInteger(bytes);
+       }
+
+       public long getUnsignedValueLong()
+       {
+               return getUnsignedValue().longValue();
+       }
+
+       /**
+        * Returns the value of the BitVector as BigInteger interpreted as a two's complement number.
+        * 
+        * @throws NumberFormatException if the BitVector is not {@link #isBinary() binary}.
+        * 
+        * @author Daniel Kirschten
+        */
+       public BigInteger getSignedValue()
+       {
+               BigInteger unsignedValue = getUnsignedValue();
+               if (bits[bits.length - 1] == Bit.ZERO)
+                       return unsignedValue;
+               return unsignedValue.subtract(BitVector.of(Bit.ONE, bits.length).getUnsignedValue()).subtract(BigInteger.ONE);// TODO speed this up!
+       }
+
+       public long getSignedValueLong()
+       {
+               return getSignedValue().longValue();
+       }
+
+       /**
+        * Parses a String containing solely {@link Bit} symbols (MSB first)
         * 
         * @see #toString()
         */
@@ -315,6 +477,23 @@ public final class BitVector implements StrictLogicType<BitVector>, Iterable<Bit
                return new BitVector(values);
        }
 
+       /**
+        * Changes a single Bit using the given operation. This can be used to set, clear or flip bits.
+        * 
+        * @param msbIndex           index of the MSB to be changed
+        * @param singleBitOperation the operation to perform on that Bit
+        * @return the resulting, new BitVektor
+        */
+       public BitVector withBitChanged(int msbIndex, UnaryOperator<Bit> singleBitOperation)
+       {
+               Bit[] newBits = bits.clone();
+               newBits[msbIndex] = singleBitOperation.apply(newBits[msbIndex]);
+               return new BitVector(newBits);
+       }
+
+       /**
+        * Iterate over the {@link Bit}s of the BitVector <b>from MSB to LSB</b> (left to right).
+        */
        @Override
        public Iterator<Bit> iterator()
        {
@@ -327,7 +506,7 @@ public final class BitVector implements StrictLogicType<BitVector>, Iterable<Bit
                        {
                                if (!hasNext())
                                        throw new NoSuchElementException();
-                               return getBit(pos++);
+                               return getMSBit(pos++);
                        }
 
                        @Override
@@ -337,4 +516,15 @@ public final class BitVector implements StrictLogicType<BitVector>, Iterable<Bit
                        }
                };
        }
+
+       public BitVector reverse()
+       {
+               int length = length();
+               Bit[] other = new Bit[length];
+               for (int i = 0, j = length - 1; i < length; i++, j--)
+               {
+                       other[i] = bits[j];
+               }
+               return new BitVector(other);
+       }
 }