Merge logic of origin into logic
[Mograsim.git] / era.mi / src / era / mi / logic / wires / Wire.java
1 package era.mi.logic.wires;
2
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.Iterator;
6 import java.util.List;
7
8 import era.mi.logic.Bit;
9 import era.mi.logic.Simulation;
10 import era.mi.logic.Util;
11
12 /**
13  * Represents an array of wires that can store n bits of information.
14  * 
15  * @author Fabian Stemmler
16  *
17  */
18 public class Wire
19 {
20         private Bit[] values;
21         public final int travelTime;
22         private List<WireObserver> observers = new ArrayList<WireObserver>();
23         public final int length;
24         private List<WireEnd> inputs = new ArrayList<WireEnd>();
25
26         public Wire(int length, int travelTime)
27         {
28                 if (length < 1)
29                         throw new IllegalArgumentException(
30                                         String.format("Tried to create an array of wires with length %d, but a length of less than 1 makes no sense.", length));
31                 this.length = length;
32                 this.travelTime = travelTime;
33                 initValues();
34         }
35
36         private void initValues()
37         {
38                 values = Bit.U.makeArray(length);
39         }
40
41         private void recalculateSingleInput()
42         {
43                 WireEnd input = inputs.get(0);
44                 if (!Arrays.equals(input.getInputValues(), values))
45                 {
46                         Bit[] oldValues = values.clone();
47                         System.arraycopy(input.getInputValues(), 0, values, 0, length);
48                         notifyObservers(oldValues);
49                 }
50         }
51
52         private void recalculateMultipleInputs()
53         {
54                 Iterator<WireEnd> it = inputs.iterator();
55                 Bit[] newValues = it.next().inputValues.clone();
56
57                 while (it.hasNext())
58                 {
59                         WireEnd input = it.next();
60                         Bit[] bits = input.getInputValues();
61                         for (int i = 0; i < length; i++)
62                         {
63                                 if (Bit.Z.equals(bits[i]) || newValues[i].equals(bits[i]))
64                                         continue;
65                                 else if (Bit.Z.equals(newValues[i]))
66                                         newValues[i] = bits[i];
67                                 else
68                                         newValues[i] = Bit.X;
69                         }
70                 }
71
72                 if (!Arrays.equals(newValues, values))
73                 {
74                         Bit[] oldValues = values;
75                         values = newValues;
76                         notifyObservers(oldValues);
77                 }
78         }
79
80         private void recalculate()
81         {
82                 switch (inputs.size())
83                 {
84                 case 0:
85                         return;
86                 case 1:
87                         recalculateSingleInput();
88                         break;
89                 default:
90                         recalculateMultipleInputs();
91                 }
92         }
93
94         /**
95          * The {@link Wire} is interpreted as an unsigned integer with n bits.
96          * 
97          * @return <code>true</code> if all bits are either <code>Bit.ONE</code> or <code>Bit.ZERO</code> (they do not all have to have the same
98          *         value), not <code>Bit.X</code> or <code>Bit.Z</code>. <code>false</code> is returned otherwise.
99          * 
100          * @author Fabian Stemmler
101          */
102         public boolean hasNumericValue()
103         {
104                 for (Bit b : values)
105                 {
106                         if (b != Bit.ZERO && b != Bit.ONE)
107                                 return false;
108                 }
109                 return true;
110         }
111
112         /**
113          * The {@link Wire} is interpreted as an unsigned integer with n bits.
114          * 
115          * @return The unsigned value of the {@link Wire}'s bits, where value 0 corresponds with 2^0, value 1 is 2^1 and so on.
116          * 
117          * @author Fabian Stemmler
118          */
119         public long getUnsignedValue()
120         {
121                 long val = 0;
122                 long mask = 1;
123                 for (int i = 0; i < length; i++)
124                 {
125                         switch (values[i])
126                         {
127                         default:
128                         case Z:
129                         case X:
130                                 return 0; // TODO: Proper handling for getUnsignedValue(), if not all bits are 1 or 0;
131                         // Random number?
132                         case ONE:
133                                 val |= mask;
134                                 break;
135                         case ZERO:
136                         }
137                         mask = mask << 1;
138                 }
139                 return val;
140         }
141
142         /**
143          * The {@link Wire} is interpreted as a signed integer with n bits.
144          * 
145          * @return The signed value of the {@link Wire}'s bits, where value 0 corresponds with 2^0, value 1 is 2^1 and so on.
146          * 
147          * @author Fabian Stemmler
148          */
149         public long getSignedValue()
150         {
151                 long val = getUnsignedValue();
152                 long mask = 1 << (length - 1);
153                 if ((mask & val) != 0)
154                 {
155                         int shifts = 64 - length;
156                         return (val << shifts) >> shifts;
157                 }
158                 return val;
159         }
160
161         public Bit getValue()
162         {
163                 return getValue(0);
164         }
165
166         public Bit getValue(int index)
167         {
168                 return values[index];
169         }
170
171         public Bit[] getValues(int start, int end)
172         {
173                 int length = end - start;
174                 Bit[] bits = new Bit[length];
175                 System.arraycopy(values, start, bits, 0, length);
176                 return bits;
177         }
178
179         public Bit[] getValues()
180         {
181                 return values.clone();
182         }
183
184         /**
185          * Adds an {@link WireObserver}, who will be notified when the value of the {@link Wire} is updated.
186          * 
187          * @param ob The {@link WireObserver} to be notified of changes.
188          * @return true if the given {@link WireObserver} was not already registered, false otherwise
189          * 
190          * @author Fabian Stemmler
191          */
192         public boolean addObserver(WireObserver ob)
193         {
194                 return observers.add(ob);
195         }
196
197         private void notifyObservers(Bit[] oldValues)
198         {
199                 for (WireObserver o : observers)
200                         o.update(this, oldValues);
201         }
202
203         /**
204          * Create and register a {@link WireEnd} object, which is tied to this {@link Wire}.
205          */
206         public WireEnd createEnd()
207         {
208                 return new WireEnd();
209         }
210
211         private void registerInput(WireEnd toRegister)
212         {
213                 inputs.add(toRegister);
214         }
215
216         /**
217          * A {@link WireEnd} feeds a constant signal into the {@link Wire} it is tied to. The combination of all inputs determines the
218          * {@link Wire}s final value. X dominates all other inputs Z does not affect the final value, unless there are no other inputs than Z 0
219          * and 1 turn into X when they are mixed
220          * 
221          * @author Fabian Stemmler
222          */
223         public class WireEnd
224         {
225                 private boolean open;
226                 private Bit[] inputValues;
227
228                 private WireEnd()
229                 {
230                         super();
231                         open = true;
232                         initValues();
233                         registerInput(this);
234                 }
235
236                 private void initValues()
237                 {
238                         inputValues = Bit.Z.makeArray(length);
239                 }
240
241                 /**
242                  * Sets the wires values. This takes up time, as specified by the {@link Wire}s travel time.
243                  * 
244                  * @param newValues The new values the wires should take on.
245                  * 
246                  * @author Fabian Stemmler
247                  */
248                 public void feedSignals(Bit... newValues)
249                 {
250                         if (newValues.length == length)
251                         {
252                                 feedSignals(0, newValues);
253                         } else
254                                 throw new IllegalArgumentException(
255                                                 String.format("Attempted to input %d bits instead of %d bits.", newValues.length, length));
256                 }
257
258                 /**
259                  * Sets values of a subarray of wires. This takes up time, as specified by the {@link Wire}s travel time.
260                  * 
261                  * @param newValues   The new values the wires should take on.
262                  * @param startingBit The first index of the subarray of wires.
263                  * 
264                  * @author Fabian Stemmler
265                  */
266                 public void feedSignals(int startingBit, Bit... newValues)
267                 {
268                         if (!open)
269                                 throw new RuntimeException("Attempted to write to closed WireArrayEnd.");
270                         Simulation.TIMELINE.addEvent((e) -> setValues(startingBit, newValues), travelTime);
271                 }
272
273                 private void setValues(int startingBit, Bit... newValues)
274                 {
275                         int exclLastIndex = startingBit + newValues.length;
276                         if (length < exclLastIndex)
277                                 throw new ArrayIndexOutOfBoundsException(
278                                                 String.format("Attempted to input bits from index %d to %d when there are only %d wires.", startingBit,
279                                                                 exclLastIndex - 1, length));
280                         if (!Arrays.equals(inputValues, startingBit, exclLastIndex, newValues, 0, newValues.length))
281                         {
282                                 System.arraycopy(newValues, 0, inputValues, startingBit, newValues.length);
283                                 Wire.this.recalculate();
284                         }
285                 }
286
287                 /**
288                  * @return The value (of bit 0) the {@link WireEnd} is currently feeding into the associated {@link Wire}.
289                  */
290                 public Bit getInputValue()
291                 {
292                         return getInputValue(0);
293                 }
294
295                 /**
296                  * @return The value which the {@link WireEnd} is currently feeding into the associated {@link Wire} at the indexed {@link Bit}.
297                  */
298                 public Bit getInputValue(int index)
299                 {
300                         return inputValues[index];
301                 }
302
303                 /**
304                  * @return A copy (safe to modify) of the values the {@link WireEnd} is currently feeding into the associated {@link Wire}.
305                  */
306                 public Bit[] getInputValues()
307                 {
308                         return getInputValues(0, length);
309                 }
310
311                 public Bit[] getInputValues(int start, int end)
312                 {
313                         int length = end - start;
314                         Bit[] bits = new Bit[length];
315                         System.arraycopy(inputValues, start, bits, 0, length);
316                         return bits;
317                 }
318
319                 /**
320                  * {@link WireEnd} now feeds Z into the associated {@link Wire}.
321                  */
322                 public void clearSignals()
323                 {
324                         feedSignals(Bit.Z.makeArray(length));
325                 }
326
327                 public Bit[] wireValuesExcludingMe()
328                 {
329                         Bit[] bits = Bit.Z.makeArray(length);
330                         for (WireEnd wai : inputs)
331                         {
332                                 if (wai == this)
333                                         continue;
334                                 Util.combineInto(bits, wai.getInputValues());
335                         }
336                         return bits;
337                 }
338
339                 /**
340                  * Included for convenient use on {@link Wire}s of length 1.
341                  * 
342                  * @return The value of bit 0.
343                  * 
344                  * @author Fabian Stemmler
345                  */
346                 public Bit getValue()
347                 {
348                         return Wire.this.getValue();
349                 }
350
351                 /**
352                  * @param index Index of the requested bit.
353                  * @return The value of the indexed bit.
354                  * 
355                  * @author Fabian Stemmler
356                  */
357                 public Bit getValue(int index)
358                 {
359                         return Wire.this.getValue(index);
360                 }
361
362                 /**
363                  * @param index Index of the requested bit.
364                  * @return The value of the indexed bit.
365                  * 
366                  * @author Fabian Stemmler
367                  */
368                 public Bit[] getValues()
369                 {
370                         return Wire.this.getValues();
371                 }
372
373                 /**
374                  * @param start Start of the wanted segment. (inclusive)
375                  * @param end   End of the wanted segment. (exclusive)
376                  * @return The values of the segment of {@link Bit}s indexed.
377                  * 
378                  * @author Fabian Stemmler
379                  */
380                 public Bit[] getValues(int start, int end)
381                 {
382                         return Wire.this.getValues(start, end);
383                 }
384
385                 /**
386                  * The {@link Wire} is interpreted as an unsigned integer with n bits.
387                  * 
388                  * @return <code>true</code> if all bits are either <code>Bit.ONE</code> or <code>Bit.ZERO</code> (they do not all have to have the
389                  *         same value), not <code>Bit.X</code> or <code>Bit.Z</code>. <code>false</code> is returned otherwise.
390                  * 
391                  * @author Fabian Stemmler
392                  */
393                 public boolean hasNumericValue()
394                 {
395                         return Wire.this.hasNumericValue();
396                 }
397
398                 /**
399                  * The {@link Wire} is interpreted as an unsigned integer with n bits.
400                  * 
401                  * @return The unsigned value of the {@link Wire}'s bits, where value 0 corresponds with 2^0, value 1 is 2^1 and so on.
402                  * 
403                  * @author Fabian Stemmler
404                  */
405                 public long getUnsignedValue()
406                 {
407                         return Wire.this.getUnsignedValue();
408                 }
409
410                 /**
411                  * The {@link Wire} is interpreted as a signed integer with n bits.
412                  * 
413                  * @return The signed value of the {@link Wire}'s bits, where value 0 corresponds with 2^0, value 1 is 2^1 and so on.
414                  * 
415                  * @author Fabian Stemmler
416                  */
417                 public long getSignedValue()
418                 {
419                         return Wire.this.getSignedValue();
420                 }
421
422                 @Override
423                 public String toString()
424                 {
425                         return Arrays.toString(values);
426                         // return String.format("%s \nFeeding: %s", WireArray.this.toString(), Arrays.toString(inputValues));
427                 }
428
429                 public void disconnect()
430                 {
431                         inputs.remove(this);
432                         open = false;
433                 }
434
435                 public int length()
436                 {
437                         return length;
438                 }
439
440                 public boolean addObserver(WireObserver ob)
441                 {
442                         return Wire.this.addObserver(ob);
443                 }
444
445                 public Wire getWire()
446                 {
447                         return Wire.this;
448                 }
449         }
450
451         @Override
452         public String toString()
453         {
454                 return String.format("wire 0x%08x value: %s inputs: %s", hashCode(), Arrays.toString(values), inputs);
455                 // Arrays.toString(values), inputs.stream().map(i -> Arrays.toString(i.inputValues)).reduce((s1, s2) -> s1 + s2)
456         }
457
458         public static WireEnd[] extractEnds(Wire[] w)
459         {
460                 WireEnd[] inputs = new WireEnd[w.length];
461                 for (int i = 0; i < w.length; i++)
462                         inputs[i] = w[i].createEnd();
463                 return inputs;
464         }
465 }