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
1 package net.mograsim.logic.model.snippets.highlevelstatehandlers.standard.atomic;
2
3 import java.math.BigInteger;
4 import java.util.ArrayList;
5 import java.util.Collections;
6 import java.util.HashMap;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.function.Consumer;
10
11 import net.mograsim.logic.core.types.Bit;
12 import net.mograsim.logic.core.types.BitVector;
13 import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
14 import net.mograsim.logic.model.serializing.IdentifyParams;
15 import net.mograsim.logic.model.snippets.SnippetDefinintion;
16 import net.mograsim.logic.model.snippets.highlevelstatehandlers.standard.StandardHighLevelStateHandlerSnippetSuppliers;
17
18 public class BitVectorSplittingAtomicHighLevelStateHandler implements AtomicHighLevelStateHandler
19 {
20         private final SubmodelComponent component;
21         private final List<String> vectorPartTargets;
22         private final List<String> vectorPartTargetsUnmodifiable;
23         private final List<Integer> vectorPartLengthes;
24         private final List<Integer> vectorPartLengthesUnmodifiable;
25         private BitVector minimalValue;
26         private BigInteger minimalValueBigInteger;
27         private BitVector maximalValue;
28         private BigInteger maximalValueBigInteger;
29         private int length;
30
31         private final Map<Consumer<Object>, Consumer<Object>> targetListeners;
32
33         public BitVectorSplittingAtomicHighLevelStateHandler(SubmodelComponent component)
34         {
35                 this(component, null);
36         }
37
38         public BitVectorSplittingAtomicHighLevelStateHandler(SubmodelComponent component,
39                         BitVectorSplittingAtomicHighLevelStateHandlerParams params)
40         {
41                 this.component = component;
42                 this.vectorPartTargets = new ArrayList<>();
43                 this.vectorPartTargetsUnmodifiable = Collections.unmodifiableList(vectorPartTargets);
44                 this.vectorPartLengthes = new ArrayList<>();
45                 this.vectorPartLengthesUnmodifiable = Collections.unmodifiableList(vectorPartLengthes);
46
47                 this.targetListeners = new HashMap<>();
48
49                 if (params != null)
50                 {
51                         setVectorParts(params.vectorPartTargets, params.vectorPartLengthes);
52                         setRange(params.minimalValue, params.maximalValue);
53                 }
54         }
55
56         public void set(List<String> targets, List<Integer> lengthes, BitVector minimalValue, BitVector maximalValue)
57         {
58                 setVectorParts(targets, lengthes);
59                 setRange(minimalValue, maximalValue);
60         }
61
62         public void addVectorPart(String target, int length)
63         {
64                 vectorPartTargets.add(target);
65                 vectorPartLengthes.add(length);
66                 this.length += length;
67         }
68
69         public void clearVectorParts()
70         {
71                 vectorPartTargets.clear();
72                 vectorPartLengthes.clear();
73                 length = 0;
74         }
75
76         private void setVectorParts(List<String> targets, List<Integer> lengthes)
77         {
78                 clearVectorParts();
79                 if (targets.size() != lengthes.size())
80                         throw new IllegalArgumentException("Targets list and lengthes list have different sizes");
81                 vectorPartTargets.addAll(targets);
82                 vectorPartLengthes.addAll(lengthes);
83                 length += lengthes.stream().mapToInt(Integer::intValue).sum();
84         }
85
86         @SuppressWarnings("null") // explicit checks for null are in place
87         public void setRange(BitVector minimalValue, BitVector maximalValue)
88         {
89                 boolean minIsNull = minimalValue == null;
90                 if (minIsNull != (maximalValue == null))
91                         throw new IllegalArgumentException("minimalValue and maximalValue must either both be null or both non-null");
92                 if (!minIsNull)
93                 {
94                         if (!minimalValue.isBinary())
95                                 throw new IllegalArgumentException("minimalValue is not binary");
96                         if (!maximalValue.isBinary())
97                                 throw new IllegalArgumentException("maximalValue is not binary");
98                         this.minimalValueBigInteger = minimalValue.getUnsignedValue();
99                         this.maximalValueBigInteger = maximalValue.getUnsignedValue();
100                 }
101                 this.minimalValue = minimalValue;
102                 this.maximalValue = maximalValue;
103         }
104
105         public BitVector getMinimalValue()
106         {
107                 return minimalValue;
108         }
109
110         public BitVector getMaximalValue()
111         {
112                 return maximalValue;
113         }
114
115         public List<String> getVectorPartTargets()
116         {
117                 return vectorPartTargetsUnmodifiable;
118         }
119
120         public List<Integer> getVectorPartLenghtes()
121         {
122                 return vectorPartLengthesUnmodifiable;
123         }
124
125         @Override
126         public Object getHighLevelState()
127         {
128                 BitVector result = BitVector.of();
129                 for (int partIndex = 0; partIndex < vectorPartTargets.size(); partIndex++)
130                 {
131                         Object subStateUncasted = component.getHighLevelState(vectorPartTargets.get(partIndex));
132                         BitVector vectorPart;
133                         if (subStateUncasted instanceof Bit)
134                                 vectorPart = BitVector.of((Bit) subStateUncasted);
135                         else
136                                 vectorPart = (BitVector) subStateUncasted;
137                         if (vectorPart.length() != vectorPartLengthes.get(partIndex))
138                                 throw new IllegalArgumentException(
139                                                 "Incorrect vector part length: " + vectorPart.length() + "; expected " + vectorPartLengthes.get(partIndex));
140                         result = result.concat(vectorPart);
141                 }
142                 return result;
143         }
144
145         @Override
146         public void setHighLevelState(Object newState)
147         {
148                 BitVector newStateCasted = (BitVector) newState;
149                 if (newStateCasted.length() != length)
150                         throw new IllegalArgumentException("Incorrect vector length: " + newStateCasted.length() + "; expected " + length);
151                 // TODO what for non-binary values?
152                 if (minimalValue != null && newStateCasted.isBinary())
153                 {
154                         BigInteger newStateBigInteger = newStateCasted.getUnsignedValue();
155                         if (newStateBigInteger.compareTo(minimalValueBigInteger) < 0 || newStateBigInteger.compareTo(maximalValueBigInteger) > 0)
156                                 throw new IllegalArgumentException(
157                                                 "Value out of range: should be in " + minimalValue + " - " + maximalValue + "; was " + newState);
158                 }
159                 for (int partIndex = 0, bitIndex = 0; partIndex < vectorPartTargets.size(); partIndex++)
160                 {
161                         int vectorPartLength = vectorPartLengthes.get(partIndex);
162                         BitVector vectorPart = newStateCasted.subVector(bitIndex, bitIndex + vectorPartLength);
163                         component.setHighLevelState(vectorPartTargets.get(partIndex), vectorPart);
164                         bitIndex += vectorPartLength;
165                 }
166         }
167
168         @Override
169         public void addListener(Consumer<Object> stateChanged)
170         {
171                 if (targetListeners.get(stateChanged) != null)
172                         // this listener is/was already registered
173                         return;
174
175                 Consumer<Object> targetListener = o -> stateChanged.accept(getHighLevelState());
176                 targetListeners.put(stateChanged, targetListener);
177
178                 for (String target : vectorPartTargets)
179                         component.addHighLevelStateListener(target, targetListener);
180         }
181
182         @Override
183         public void removeListener(Consumer<Object> stateChanged)
184         {
185                 Consumer<Object> targetListener = targetListeners.get(stateChanged);
186                 if (targetListener == null)
187                         // this listener is/was not registered
188                         return;
189
190                 for (String target : vectorPartTargets)
191                         component.removeHighLevelStateListener(target, targetListener);
192         }
193
194         @Override
195         public String getIDForSerializing(IdentifyParams idParams)
196         {
197                 return "bitVectorSplitting";
198         }
199
200         @Override
201         public BitVectorSplittingAtomicHighLevelStateHandlerParams getParamsForSerializing(IdentifyParams idParams)
202         {
203                 BitVectorSplittingAtomicHighLevelStateHandlerParams params = new BitVectorSplittingAtomicHighLevelStateHandlerParams();
204                 params.vectorPartTargets = new ArrayList<>(vectorPartTargets);
205                 params.vectorPartLengthes = new ArrayList<>(vectorPartLengthes);
206                 params.minimalValue = minimalValue;
207                 params.maximalValue = maximalValue;
208                 return params;
209         }
210
211         public static class BitVectorSplittingAtomicHighLevelStateHandlerParams
212         {
213                 public List<String> vectorPartTargets;
214                 public List<Integer> vectorPartLengthes;
215                 public BitVector minimalValue;
216                 public BitVector maximalValue;
217         }
218
219         static
220         {
221                 StandardHighLevelStateHandlerSnippetSuppliers.atomicHandlerSupplier
222                                 .setSnippetSupplier(BitVectorSplittingAtomicHighLevelStateHandler.class.getCanonicalName(), SnippetDefinintion.create(
223                                                 BitVectorSplittingAtomicHighLevelStateHandlerParams.class, BitVectorSplittingAtomicHighLevelStateHandler::new));
224         }
225 }