new WireEnds as in/outputs are now initialized with U again
[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(false);
204         }
205
206         /**
207          * Create a {@link WireEnd} object, which is tied to this {@link Wire}. This {@link WireEnd} cannot written to.
208          */
209         public WireEnd createReadOnlyEnd()
210         {
211                 return new WireEnd(true);
212         }
213
214         private void registerInput(WireEnd toRegister)
215         {
216                 inputs.add(toRegister);
217         }
218
219         /**
220          * A {@link WireEnd} feeds a constant signal into the {@link Wire} it is tied to. The combination of all inputs determines the
221          * {@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
222          * and 1 turn into X when they are mixed
223          * 
224          * @author Fabian Stemmler
225          */
226         public class WireEnd
227         {
228                 private boolean open;
229                 private Bit[] inputValues;
230
231                 private WireEnd(boolean readOnly)
232                 {
233                         super();
234                         open = true;
235                         initValues();
236                         if (!readOnly)
237                                 registerInput(this);
238                 }
239
240                 private void initValues()
241                 {
242                         inputValues = Bit.U.makeArray(length);
243                 }
244
245                 /**
246                  * Sets the wires values. This takes up time, as specified by the {@link Wire}s travel time.
247                  * 
248                  * @param newValues The new values the wires should take on.
249                  * 
250                  * @author Fabian Stemmler
251                  */
252                 public void feedSignals(Bit... newValues)
253                 {
254                         if (newValues.length != length)
255                                 throw new IllegalArgumentException(
256                                                 String.format("Attempted to input %d bits instead of %d bits.", newValues.length, length));
257                         feedSignals(0, newValues);
258                 }
259
260                 /**
261                  * Sets values of a subarray of wires. This takes up time, as specified by the {@link Wire}s travel time.
262                  * 
263                  * @param newValues   The new values the wires should take on.
264                  * @param startingBit The first index of the subarray of wires.
265                  * 
266                  * @author Fabian Stemmler
267                  */
268                 public void feedSignals(int startingBit, Bit... newValues)
269                 {
270                         if (!open)
271                                 throw new RuntimeException("Attempted to write to closed WireArrayEnd.");
272                         Simulation.TIMELINE.addEvent((e) -> setValues(startingBit, newValues), travelTime);
273                 }
274
275                 private void setValues(int startingBit, Bit... newValues)
276                 {
277                         int exclLastIndex = startingBit + newValues.length;
278                         if (length < exclLastIndex)
279                                 throw new ArrayIndexOutOfBoundsException(
280                                                 String.format("Attempted to input bits from index %d to %d when there are only %d wires.", startingBit,
281                                                                 exclLastIndex - 1, length));
282                         if (!Arrays.equals(inputValues, startingBit, exclLastIndex, newValues, 0, newValues.length))
283                         {
284                                 System.arraycopy(newValues, 0, inputValues, startingBit, newValues.length);
285                                 Wire.this.recalculate();
286                         }
287                 }
288
289                 /**
290                  * @return The value (of bit 0) the {@link WireEnd} is currently feeding into the associated {@link Wire}.
291                  */
292                 public Bit getInputValue()
293                 {
294                         return getInputValue(0);
295                 }
296
297                 /**
298                  * @return The value which the {@link WireEnd} is currently feeding into the associated {@link Wire} at the indexed {@link Bit}.
299                  */
300                 public Bit getInputValue(int index)
301                 {
302                         return inputValues[index];
303                 }
304
305                 /**
306                  * @return A copy (safe to modify) of the values the {@link WireEnd} is currently feeding into the associated {@link Wire}.
307                  */
308                 public Bit[] getInputValues()
309                 {
310                         return getInputValues(0, length);
311                 }
312
313                 public Bit[] getInputValues(int start, int end)
314                 {
315                         int length = end - start;
316                         Bit[] bits = new Bit[length];
317                         System.arraycopy(inputValues, start, bits, 0, length);
318                         return bits;
319                 }
320
321                 /**
322                  * {@link WireEnd} now feeds Z into the associated {@link Wire}.
323                  */
324                 public void clearSignals()
325                 {
326                         feedSignals(Bit.Z.makeArray(length));
327                 }
328
329                 public Bit[] wireValuesExcludingMe()
330                 {
331                         Bit[] bits = Bit.Z.makeArray(length);
332                         for (WireEnd wai : inputs)
333                         {
334                                 if (wai == this)
335                                         continue;
336                                 Util.combineInto(bits, wai.getInputValues());
337                         }
338                         return bits;
339                 }
340
341                 /**
342                  * Included for convenient use on {@link Wire}s of length 1.
343                  * 
344                  * @return The value of bit 0.
345                  * 
346                  * @author Fabian Stemmler
347                  */
348                 public Bit getValue()
349                 {
350                         return Wire.this.getValue();
351                 }
352
353                 /**
354                  * @param index Index of the requested bit.
355                  * @return The value of the indexed bit.
356                  * 
357                  * @author Fabian Stemmler
358                  */
359                 public Bit getValue(int index)
360                 {
361                         return Wire.this.getValue(index);
362                 }
363
364                 /**
365                  * @param index Index of the requested bit.
366                  * @return The value of the indexed bit.
367                  * 
368                  * @author Fabian Stemmler
369                  */
370                 public Bit[] getValues()
371                 {
372                         return Wire.this.getValues();
373                 }
374
375                 /**
376                  * @param start Start of the wanted segment. (inclusive)
377                  * @param end   End of the wanted segment. (exclusive)
378                  * @return The values of the segment of {@link Bit}s indexed.
379                  * 
380                  * @author Fabian Stemmler
381                  */
382                 public Bit[] getValues(int start, int end)
383                 {
384                         return Wire.this.getValues(start, end);
385                 }
386
387                 /**
388                  * The {@link Wire} is interpreted as an unsigned integer with n bits.
389                  * 
390                  * @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
391                  *         same value), not <code>Bit.X</code> or <code>Bit.Z</code>. <code>false</code> is returned otherwise.
392                  * 
393                  * @author Fabian Stemmler
394                  */
395                 public boolean hasNumericValue()
396                 {
397                         return Wire.this.hasNumericValue();
398                 }
399
400                 /**
401                  * The {@link Wire} is interpreted as an unsigned integer with n bits.
402                  * 
403                  * @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.
404                  * 
405                  * @author Fabian Stemmler
406                  */
407                 public long getUnsignedValue()
408                 {
409                         return Wire.this.getUnsignedValue();
410                 }
411
412                 /**
413                  * The {@link Wire} is interpreted as a signed integer with n bits.
414                  * 
415                  * @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.
416                  * 
417                  * @author Fabian Stemmler
418                  */
419                 public long getSignedValue()
420                 {
421                         return Wire.this.getSignedValue();
422                 }
423
424                 @Override
425                 public String toString()
426                 {
427                         return Arrays.toString(inputValues);
428                         // return String.format("%s \nFeeding: %s", WireArray.this.toString(), Arrays.toString(inputValues));
429                 }
430
431                 public void close()
432                 {
433                         inputs.remove(this);
434                         open = false;
435                 }
436
437                 public int length()
438                 {
439                         return length;
440                 }
441
442                 public boolean addObserver(WireObserver ob)
443                 {
444                         return Wire.this.addObserver(ob);
445                 }
446
447                 public Wire getWire()
448                 {
449                         return Wire.this;
450                 }
451         }
452
453         @Override
454         public String toString()
455         {
456                 return String.format("wire 0x%08x value: %s inputs: %s", hashCode(), Arrays.toString(values), inputs);
457                 // Arrays.toString(values), inputs.stream().map(i -> Arrays.toString(i.inputValues)).reduce((s1, s2) -> s1 + s2)
458         }
459
460         public static WireEnd[] extractEnds(Wire[] w)
461         {
462                 WireEnd[] inputs = new WireEnd[w.length];
463                 for (int i = 0; i < w.length; i++)
464                         inputs[i] = w[i].createEnd();
465                 return inputs;
466         }
467 }