Changed mnemonic X to use BitVector X; added X for integer immediates
[Mograsim.git] / plugins / net.mograsim.machine / src / net / mograsim / machine / mi / parameters / MnemonicFamily.java
1 package net.mograsim.machine.mi.parameters;
2
3 import static net.mograsim.logic.core.types.Bit.X;
4
5 import java.util.Arrays;
6 import java.util.LinkedList;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.stream.Collectors;
10
11 import net.mograsim.logic.core.types.BitVector;
12 import net.mograsim.machine.MachineException;
13 import net.mograsim.machine.mi.parameters.MicroInstructionParameter.ParameterType;
14
15 public class MnemonicFamily implements ParameterClassification
16 {
17         private final Mnemonic[] values;
18         private final Mnemonic defaultValue;
19         private final String[] stringValues;
20         private Map<String, Mnemonic> byText;
21         private int vectorLength;
22
23         MnemonicFamily(String defaultValueName, MnemonicPair... values)
24         {
25                 if (values.length == 0)
26                         throw new MachineException("Mnemonics must not be empty!");
27                 this.values = new Mnemonic[values.length];
28                 this.stringValues = new String[values.length];
29
30                 setup(values);
31
32                 // if no valid defaultValue is specified, pick first value as default
33                 int defaultValueIndex = 0;
34                 for (int i = 0; i < values.length; i++)
35                         if (stringValues[i].equals(defaultValueName))
36                         {
37                                 defaultValueIndex = i;
38                                 break;
39                         }
40                 this.defaultValue = this.values[defaultValueIndex];
41         }
42
43         private void setup(MnemonicPair[] values)
44         {
45                 for (int i = 0; i < values.length; i++)
46                 {
47                         this.values[i] = createMnemonic(values[i], i);
48                         this.stringValues[i] = values[i].name;
49                 }
50                 if (values.length == 0)
51                         vectorLength = 0;
52                 else
53                 {
54                         vectorLength = values[0].value.length();
55                         for (int i = 1; i < values.length; i++)
56                                 if (values[i].value.length() != vectorLength)
57                                         throw new IllegalArgumentException("MnemonicFamily is not of uniform vector length!");
58                 }
59                 byText = Arrays.stream(this.values).collect(Collectors.toMap(m -> m.getText(), m -> m));
60                 if (values.length != byText.keySet().size())
61                         throw new IllegalArgumentException("MnemonicFamily contains multiple Mnemonics with the same name!");
62         }
63
64         private Mnemonic createMnemonic(MnemonicPair mnemonicPair, int ordinal)
65         {
66                 return new Mnemonic(mnemonicPair.name, mnemonicPair.value, this, ordinal);
67         }
68
69         public Mnemonic[] values()
70         {
71                 return values.clone();
72         }
73
74         public Mnemonic get(int ordinal)
75         {
76                 return values[ordinal];
77         }
78
79         public Mnemonic get(String text)
80         {
81                 return byText.get(text);
82         }
83
84         @Override
85         public MicroInstructionParameter getDefault()
86         {
87                 return defaultValue;
88         }
89
90         public boolean contains(Mnemonic m)
91         {
92                 if (m != null)
93                         return m.owner == this;
94                 return false;
95         }
96
97         public boolean contains(String value)
98         {
99                 return byText.keySet().contains(value);
100         }
101
102         public int size()
103         {
104                 return values.length;
105         }
106
107         public int getVectorLength()
108         {
109                 return vectorLength;
110         }
111
112         @Override
113         public boolean conforms(MicroInstructionParameter param)
114         {
115                 return ParameterClassification.super.conforms(param) && (param instanceof Mnemonic ? contains((Mnemonic) param) : false);
116         }
117
118         @Override
119         public ParameterType getExpectedType()
120         {
121                 return ParameterType.MNEMONIC;
122         }
123
124         @Override
125         public int getExpectedBits()
126         {
127                 return vectorLength;
128         }
129
130         public String[] getStringValues()
131         {
132                 return stringValues.clone();
133         }
134
135         @Override
136         public int hashCode()
137         {
138                 final int prime = 31;
139                 int result = 1;
140                 result = prime * result + Arrays.hashCode(values);
141                 return result;
142         }
143
144         @Override
145         public boolean equals(Object obj)
146         {
147                 return this == obj;
148         }
149
150         @Override
151         public Mnemonic parse(String toParse)
152         {
153                 Mnemonic parsed = get(toParse);
154                 if (parsed == null)
155                         throw new UnknownMnemonicException(toParse);
156                 return parsed;
157         }
158
159         public static class MnemonicPair
160         {
161                 public final String name;
162                 public final BitVector value;
163
164                 public MnemonicPair(String name, BitVector value)
165                 {
166                         this.name = name;
167                         this.value = value;
168                 }
169         }
170
171         public static class MnemonicFamilyBuilder
172         {
173                 private final List<MnemonicPair> pairs;
174                 private final int bits;
175                 private String defaultValue;
176
177                 public MnemonicFamilyBuilder(int bits)
178                 {
179                         this.pairs = new LinkedList<>();
180                         this.bits = bits;
181                 }
182
183                 public MnemonicFamilyBuilder addX()
184                 {
185                         pairs.add(new MnemonicPair("X", BitVector.of(X, bits)));
186                         return this;
187                 }
188
189                 public MnemonicFamilyBuilder add(MnemonicPair... pairs)
190                 {
191                         this.pairs.addAll(List.of(pairs));
192                         return this;
193                 }
194
195                 /**
196                  * Adds a name with its corresponding value to the {@link MnemonicFamily}
197                  * 
198                  * @return this {@link MnemonicFamilyBuilder}
199                  */
200                 public MnemonicFamilyBuilder add(String name, BitVector value)
201                 {
202                         add(new MnemonicPair(name, value));
203                         return this;
204                 }
205
206                 /**
207                  * Adds names with their corresponding values to the {@link MnemonicFamily}
208                  * 
209                  * @param names  The names to be added to the {@link MnemonicFamily}
210                  * @param values The values as {@link BitVector}s
211                  * @return this {@link MnemonicFamilyBuilder}
212                  */
213                 public MnemonicFamilyBuilder add(String name, long value)
214                 {
215                         add(new MnemonicPair(name, BitVector.from(value, bits)));
216                         return this;
217                 }
218
219                 /**
220                  * Adds names with their corresponding values to the {@link MnemonicFamily}
221                  * 
222                  * @param names  The names to be added to the {@link MnemonicFamily}
223                  * @param values The values as {@link BitVector}s
224                  * @return this {@link MnemonicFamilyBuilder}
225                  */
226                 public MnemonicFamilyBuilder add(String names[], BitVector[] values)
227                 {
228                         if (names.length != values.length)
229                                 throw new IllegalArgumentException("Cannot add Mnemonics! Amount of names does not match amount of values!");
230                         for (int i = 0; i < names.length; i++)
231                                 add(new MnemonicPair(names[i], values[i]));
232                         return this;
233                 }
234
235                 /**
236                  * Adds names with their corresponding values (converted to a BitVector) to the {@link MnemonicFamily}
237                  * 
238                  * @param names  The names to be added to the {@link MnemonicFamily}
239                  * @param values The values to be converted to {@link BitVector}s with a given amount of {@link MnemonicFamilyBuilder#bits}
240                  * @return this {@link MnemonicFamilyBuilder}
241                  */
242                 public MnemonicFamilyBuilder add(String names[], long values[])
243                 {
244                         if (names.length != values.length)
245                                 throw new IllegalArgumentException("Cannot add Mnemonics! Amount of names does not match amount of values!");
246                         for (int i = 0; i < names.length; i++)
247                                 add(new MnemonicPair(names[i], BitVector.from(values[i], bits)));
248                         return this;
249                 }
250
251                 /**
252                  * Adds names to the {@link MnemonicFamily}; The corresponding {@link BitVector} value to a name is the value of its index
253                  * 
254                  * @param names The names to be added to the {@link MnemonicFamily}
255                  * @return this {@link MnemonicFamilyBuilder}
256                  */
257                 public MnemonicFamilyBuilder add(String... names)
258                 {
259                         for (int i = 0; i < names.length; i++)
260                                 add(names[i], i);
261                         return this;
262                 }
263
264                 /**
265                  * Sets the name of the default {@link Mnemonic} of this {@link MnemonicFamily}
266                  */
267                 public MnemonicFamilyBuilder setDefault(String defaultValue)
268                 {
269                         this.defaultValue = defaultValue;
270                         return this;
271                 }
272
273                 /**
274                  * Sets the name of the default {@link Mnemonic} of this {@link MnemonicFamily} to "X"
275                  */
276                 public MnemonicFamilyBuilder setXDefault()
277                 {
278                         this.defaultValue = "X";
279                         return this;
280                 }
281
282                 public MnemonicFamily build()
283                 {
284                         return new MnemonicFamily(defaultValue, pairs.toArray(new MnemonicPair[pairs.size()]));
285                 }
286         }
287 }