MPROMEditor now calls its columns "Opcode" and "muPC"
[Mograsim.git] / plugins / net.mograsim.logic.model / src / net / mograsim / logic / model / snippets / highlevelstatehandlers / standard / atomic / BitVectorSplittingAtomicHighLevelStateHandler.java
index 7ae2912..bc8b966 100644 (file)
@@ -1,8 +1,12 @@
 package net.mograsim.logic.model.snippets.highlevelstatehandlers.standard.atomic;
 
+import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
 
 import net.mograsim.logic.core.types.Bit;
 import net.mograsim.logic.core.types.BitVector;
@@ -18,8 +22,14 @@ public class BitVectorSplittingAtomicHighLevelStateHandler implements AtomicHigh
        private final List<String> vectorPartTargetsUnmodifiable;
        private final List<Integer> vectorPartLengthes;
        private final List<Integer> vectorPartLengthesUnmodifiable;
+       private BitVector minimalValue;
+       private BigInteger minimalValueBigInteger;
+       private BitVector maximalValue;
+       private BigInteger maximalValueBigInteger;
        private int length;
 
+       private final Map<Consumer<Object>, Consumer<Object>> targetListeners;
+
        public BitVectorSplittingAtomicHighLevelStateHandler(SubmodelComponent component)
        {
                this(component, null);
@@ -33,13 +43,20 @@ public class BitVectorSplittingAtomicHighLevelStateHandler implements AtomicHigh
                this.vectorPartTargetsUnmodifiable = Collections.unmodifiableList(vectorPartTargets);
                this.vectorPartLengthes = new ArrayList<>();
                this.vectorPartLengthesUnmodifiable = Collections.unmodifiableList(vectorPartLengthes);
+
+               this.targetListeners = new HashMap<>();
+
                if (params != null)
+               {
                        setVectorParts(params.vectorPartTargets, params.vectorPartLengthes);
+                       setRange(params.minimalValue, params.maximalValue);
+               }
        }
 
-       public void set(List<String> targets, List<Integer> lengthes)
+       public void set(List<String> targets, List<Integer> lengthes, BitVector minimalValue, BitVector maximalValue)
        {
                setVectorParts(targets, lengthes);
+               setRange(minimalValue, maximalValue);
        }
 
        public void addVectorPart(String target, int length)
@@ -66,6 +83,35 @@ public class BitVectorSplittingAtomicHighLevelStateHandler implements AtomicHigh
                length += lengthes.stream().mapToInt(Integer::intValue).sum();
        }
 
+       @SuppressWarnings("null") // explicit checks for null are in place
+       public void setRange(BitVector minimalValue, BitVector maximalValue)
+       {
+               boolean minIsNull = minimalValue == null;
+               if (minIsNull != (maximalValue == null))
+                       throw new IllegalArgumentException("minimalValue and maximalValue must either both be null or both non-null");
+               if (!minIsNull)
+               {
+                       if (!minimalValue.isBinary())
+                               throw new IllegalArgumentException("minimalValue is not binary");
+                       if (!maximalValue.isBinary())
+                               throw new IllegalArgumentException("maximalValue is not binary");
+                       this.minimalValueBigInteger = minimalValue.getUnsignedValue();
+                       this.maximalValueBigInteger = maximalValue.getUnsignedValue();
+               }
+               this.minimalValue = minimalValue;
+               this.maximalValue = maximalValue;
+       }
+
+       public BitVector getMinimalValue()
+       {
+               return minimalValue;
+       }
+
+       public BitVector getMaximalValue()
+       {
+               return maximalValue;
+       }
+
        public List<String> getVectorPartTargets()
        {
                return vectorPartTargetsUnmodifiable;
@@ -102,6 +148,14 @@ public class BitVectorSplittingAtomicHighLevelStateHandler implements AtomicHigh
                BitVector newStateCasted = (BitVector) newState;
                if (newStateCasted.length() != length)
                        throw new IllegalArgumentException("Incorrect vector length: " + newStateCasted.length() + "; expected " + length);
+               // TODO what for non-binary values?
+               if (minimalValue != null && newStateCasted.isBinary())
+               {
+                       BigInteger newStateBigInteger = newStateCasted.getUnsignedValue();
+                       if (newStateBigInteger.compareTo(minimalValueBigInteger) < 0 || newStateBigInteger.compareTo(maximalValueBigInteger) > 0)
+                               throw new IllegalArgumentException(
+                                               "Value out of range: should be in " + minimalValue + " - " + maximalValue + "; was " + newState);
+               }
                for (int partIndex = 0, bitIndex = 0; partIndex < vectorPartTargets.size(); partIndex++)
                {
                        int vectorPartLength = vectorPartLengthes.get(partIndex);
@@ -111,6 +165,32 @@ public class BitVectorSplittingAtomicHighLevelStateHandler implements AtomicHigh
                }
        }
 
+       @Override
+       public void addListener(Consumer<Object> stateChanged)
+       {
+               if (targetListeners.get(stateChanged) != null)
+                       // this listener is/was already registered
+                       return;
+
+               Consumer<Object> targetListener = o -> stateChanged.accept(getHighLevelState());
+               targetListeners.put(stateChanged, targetListener);
+
+               for (String target : vectorPartTargets)
+                       component.addHighLevelStateListener(target, targetListener);
+       }
+
+       @Override
+       public void removeListener(Consumer<Object> stateChanged)
+       {
+               Consumer<Object> targetListener = targetListeners.get(stateChanged);
+               if (targetListener == null)
+                       // this listener is/was not registered
+                       return;
+
+               for (String target : vectorPartTargets)
+                       component.removeHighLevelStateListener(target, targetListener);
+       }
+
        @Override
        public String getIDForSerializing(IdentifyParams idParams)
        {
@@ -123,6 +203,8 @@ public class BitVectorSplittingAtomicHighLevelStateHandler implements AtomicHigh
                BitVectorSplittingAtomicHighLevelStateHandlerParams params = new BitVectorSplittingAtomicHighLevelStateHandlerParams();
                params.vectorPartTargets = new ArrayList<>(vectorPartTargets);
                params.vectorPartLengthes = new ArrayList<>(vectorPartLengthes);
+               params.minimalValue = minimalValue;
+               params.maximalValue = maximalValue;
                return params;
        }
 
@@ -130,6 +212,8 @@ public class BitVectorSplittingAtomicHighLevelStateHandler implements AtomicHigh
        {
                public List<String> vectorPartTargets;
                public List<Integer> vectorPartLengthes;
+               public BitVector minimalValue;
+               public BitVector maximalValue;
        }
 
        static