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