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