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