Made Wire.fuse(Wire, Wire, int, int int) public
[Mograsim.git] / net.mograsim.logic.core / 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.LogicObservable;
10 import net.mograsim.logic.core.LogicObserver;
11 import net.mograsim.logic.core.timeline.Timeline;
12 import net.mograsim.logic.core.types.Bit;
13 import net.mograsim.logic.core.types.BitVector;
14 import net.mograsim.logic.core.types.BitVector.BitVectorMutator;
15
16 /**
17  * Represents an array of wires that can store n bits of information.
18  * 
19  * @author Fabian Stemmler
20  *
21  */
22 public class Wire
23 {
24         public final String name;
25         private BitVector values;
26         public final int travelTime;
27         private List<ReadEnd> attached = new ArrayList<>();
28         public final int length;
29         List<ReadWriteEnd> inputs = new ArrayList<>();
30         Timeline timeline;
31
32         public Wire(Timeline timeline, int length, int travelTime)
33         {
34                 this(timeline, length, travelTime, null);
35         }
36
37         public Wire(Timeline timeline, int length, int travelTime, String name)
38         {
39                 if (length < 1)
40                         throw new IllegalArgumentException(
41                                         String.format("Tried to create an array of wires with length %d, but a length of less than 1 makes no sense.", length));
42                 this.name = name;
43                 this.timeline = timeline;
44                 this.length = length;
45                 this.travelTime = travelTime;
46                 initValues();
47         }
48
49         private void initValues()
50         {
51                 values = U.toVector(length);
52         }
53
54         private void recalculateSingleInput()
55         {
56                 setNewValues(inputs.get(0).getInputValues());
57         }
58
59         private void recalculateMultipleInputs()
60         {
61                 BitVectorMutator mutator = BitVectorMutator.empty();
62                 for (ReadWriteEnd wireArrayEnd : inputs)
63                         mutator.join(wireArrayEnd.getInputValues());
64                 setNewValues(mutator.get());
65         }
66
67         private void setNewValues(BitVector newValues)
68         {
69                 if (values.equals(newValues))
70                         return;
71 //              BitVector oldValues = values;
72                 values = newValues;
73                 notifyObservers();
74         }
75
76         void recalculate()
77         {
78                 switch (inputs.size())
79                 {
80                 case 0:
81                         setNewValues(BitVector.of(Bit.U, length));
82                         break;
83                 case 1:
84                         recalculateSingleInput();
85                         break;
86                 default:
87                         recalculateMultipleInputs();
88                 }
89         }
90
91         /**
92          * The {@link Wire} is interpreted as an unsigned integer with n bits.
93          * 
94          * @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
95          *         value), not <code>Bit.X</code> or <code>Bit.Z</code>. <code>false</code> is returned otherwise.
96          * 
97          * @author Fabian Stemmler
98          */
99         public boolean hasNumericValue()
100         {
101                 for (Bit b : values)
102                 {
103                         if (b != Bit.ZERO && b != Bit.ONE)
104                                 return false;
105                 }
106                 return true;
107         }
108
109         /**
110          * The {@link Wire} is interpreted as an unsigned integer with n bits.
111          * 
112          * @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.
113          * 
114          * @author Fabian Stemmler
115          */
116         public long getUnsignedValue()
117         {
118                 long val = 0;
119                 long mask = 1;
120                 for (Bit bit : values)
121                 {
122                         switch (bit)
123                         {
124                         default:
125                         case Z:
126                         case X:
127                                 return 0; // TODO: Proper handling for getUnsignedValue(), if not all bits are 1 or 0;
128                         case ONE:
129                                 val |= mask;
130                                 break;
131                         case ZERO:
132                         }
133                         mask = mask << 1;
134                 }
135                 return val;
136         }
137
138         /**
139          * The {@link Wire} is interpreted as a signed integer with n bits.
140          * 
141          * @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.
142          * 
143          * @author Fabian Stemmler
144          */
145         public long getSignedValue()
146         {
147                 long val = getUnsignedValue();
148                 long mask = 1 << (length - 1);
149                 if ((mask & val) != 0)
150                 {
151                         int shifts = 64 - length;
152                         return (val << shifts) >> shifts;
153                 }
154                 return val;
155         }
156
157         public Bit getValue()
158         {
159                 return getValue(0);
160         }
161
162         public Bit getValue(int index)
163         {
164                 return values.getBit(index);
165         }
166
167         public BitVector getValues(int start, int end)
168         {
169                 return values.subVector(start, end);
170         }
171
172         public BitVector getValues()
173         {
174                 return values;
175         }
176
177         /**
178          * Adds an {@link LogicObserver}, who will be notified when the value of the {@link Wire} is updated.
179          * 
180          * @param ob The {@link LogicObserver} to be notified of changes.
181          * @return true if the given {@link LogicObserver} was not already registered, false otherwise
182          * 
183          * @author Fabian Stemmler
184          */
185         void attachEnd(ReadEnd end)
186         {
187                 attached.add(end);
188         }
189
190         void detachEnd(ReadEnd end)
191         {
192                 attached.remove(end);
193         }
194
195         private void notifyObservers()
196         {
197                 attached.forEach(r -> r.update());
198         }
199
200         /**
201          * Create and register a {@link ReadWriteEnd} object, which is tied to this {@link Wire}. This {@link ReadWriteEnd} can be written to.
202          */
203         public ReadWriteEnd createReadWriteEnd()
204         {
205                 return new ReadWriteEnd();
206         }
207
208         /**
209          * Create a {@link ReadEnd} object, which is tied to this {@link Wire}. This {@link ReadEnd} cannot be written to.
210          */
211         public ReadEnd createReadOnlyEnd()
212         {
213                 return new ReadEnd();
214         }
215
216         void registerInput(ReadWriteEnd toRegister)
217         {
218                 inputs.add(toRegister);
219         }
220
221         /**
222          * A {@link ReadEnd} feeds a constant signal into the {@link Wire} it is tied to. The combination of all inputs determines the
223          * {@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
224          * and 1 turn into X when they are mixed
225          * 
226          * @author Fabian Stemmler
227          */
228         public class ReadEnd implements LogicObservable
229         {
230                 private List<LogicObserver> observers = new ArrayList<>();
231
232                 ReadEnd()
233                 {
234                         super();
235                         Wire.this.attachEnd(this);
236                 }
237
238                 public void update()
239                 {
240                         notifyObservers();
241                 }
242
243                 /**
244                  * Included for convenient use on {@link Wire}s of length 1.
245                  * 
246                  * @return The value of bit 0.
247                  * 
248                  * @author Fabian Stemmler
249                  */
250                 public Bit getValue()
251                 {
252                         return Wire.this.getValue();
253                 }
254
255                 /**
256                  * @param index Index of the requested bit.
257                  * @return The value of the indexed bit.
258                  * 
259                  * @author Fabian Stemmler
260                  */
261                 public Bit getValue(int index)
262                 {
263                         return Wire.this.getValue(index);
264                 }
265
266                 /**
267                  * @param index Index of the requested bit.
268                  * @return The value of the indexed bit.
269                  * 
270                  * @author Fabian Stemmler
271                  */
272                 public BitVector getValues()
273                 {
274                         return Wire.this.getValues();
275                 }
276
277                 /**
278                  * @param start Start of the wanted segment. (inclusive)
279                  * @param end   End of the wanted segment. (exclusive)
280                  * @return The values of the segment of {@link Bit}s indexed.
281                  * 
282                  * @author Fabian Stemmler
283                  */
284                 public BitVector getValues(int start, int end)
285                 {
286                         return Wire.this.getValues(start, end);
287                 }
288
289                 /**
290                  * The {@link Wire} is interpreted as an unsigned integer with n bits.
291                  * 
292                  * @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
293                  *         same value), not <code>Bit.X</code> or <code>Bit.Z</code>. <code>false</code> is returned otherwise.
294                  * 
295                  * @author Fabian Stemmler
296                  */
297                 public boolean hasNumericValue()
298                 {
299                         return Wire.this.hasNumericValue();
300                 }
301
302                 /**
303                  * The {@link Wire} is interpreted as an unsigned integer with n bits.
304                  * 
305                  * @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.
306                  * 
307                  * @author Fabian Stemmler
308                  */
309                 public long getUnsignedValue()
310                 {
311                         return Wire.this.getUnsignedValue();
312                 }
313
314                 /**
315                  * The {@link Wire} is interpreted as a signed integer with n bits.
316                  * 
317                  * @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.
318                  * 
319                  * @author Fabian Stemmler
320                  */
321                 public long getSignedValue()
322                 {
323                         return Wire.this.getSignedValue();
324                 }
325
326                 @Override
327                 public String toString()
328                 {
329                         return Wire.this.toString();
330                 }
331
332                 public void close()
333                 {
334                         inputs.remove(this);
335                         detachEnd(this);
336                         recalculate();
337                 }
338
339                 public int length()
340                 {
341                         return length;
342                 }
343
344                 public Wire getWire()
345                 {
346                         return Wire.this;
347                 }
348
349                 @Override
350                 public void registerObserver(LogicObserver ob)
351                 {
352                         observers.add(ob);
353                 }
354
355                 @Override
356                 public void deregisterObserver(LogicObserver ob)
357                 {
358                         observers.remove(ob);
359                 }
360
361                 @Override
362                 public void notifyObservers()
363                 {
364                         observers.forEach(ob -> ob.update(this));
365                 }
366         }
367
368         public class ReadWriteEnd extends ReadEnd
369         {
370                 private boolean open, isWriting;
371                 private BitVector inputValues;
372
373                 ReadWriteEnd()
374                 {
375                         super();
376                         open = true;
377                         isWriting = true;
378                         initValues();
379                         registerInput(this);
380                 }
381
382                 private void initValues()
383                 {
384                         inputValues = U.toVector(length);
385                 }
386
387                 /**
388                  * Sets the wires values. This takes up time, as specified by the {@link Wire}s travel time.
389                  * 
390                  * @param newValues The new values the wires should take on.
391                  * 
392                  * @author Fabian Stemmler
393                  */
394                 public void feedSignals(Bit... newValues)
395                 {
396                         feedSignals(BitVector.of(newValues));
397                 }
398
399                 public void feedSignals(BitVector newValues)
400                 {
401                         if (newValues.length() != length)
402                                 throw new IllegalArgumentException(
403                                                 String.format("Attempted to input %d bits instead of %d bits.", newValues.length(), length));
404                         if (!open)
405                                 throw new RuntimeException("Attempted to write to closed WireArrayEnd.");
406                         timeline.addEvent(e -> setValues(newValues), travelTime);
407                 }
408
409                 /**
410                  * Sets values of a subarray of wires. This takes up time, as specified by the {@link Wire}s travel time.
411                  * 
412                  * @param bitVector   The new values the wires should take on.
413                  * @param startingBit The first index of the subarray of wires.
414                  * 
415                  * @author Fabian Stemmler
416                  */
417                 public void feedSignals(int startingBit, BitVector bitVector)
418                 {
419                         if (!open)
420                                 throw new RuntimeException("Attempted to write to closed WireArrayEnd.");
421                         timeline.addEvent(e -> setValues(startingBit, bitVector), travelTime);
422                 }
423
424                 /**
425                  * Sets the values that are being fed into the {@link Wire}. The preferred way of setting {@link ReadWriteEnd} values is via
426                  * feedValues(...) with a delay.
427                  */
428                 void setValues(int startingBit, BitVector newValues)
429                 {
430                         // index check covered in equals
431                         if (!inputValues.equalsWithOffset(newValues, startingBit))
432                         {
433                                 Bit[] vals = inputValues.getBits();
434                                 System.arraycopy(newValues.getBits(), 0, vals, startingBit, newValues.length());
435                                 inputValues = BitVector.of(vals);
436                                 Wire.this.recalculate();
437                         }
438                 }
439
440                 /**
441                  * Sets the values that are being fed into the {@link Wire}. The preferred way of setting {@link ReadWriteEnd} values is via
442                  * feedValues(...) with a delay.
443                  */
444                 void setValues(BitVector newValues)
445                 {
446                         if (inputValues.equals(newValues))
447                                 return;
448                         inputValues = newValues;
449                         Wire.this.recalculate();
450                 }
451
452                 /**
453                  * @return The value (of bit 0) the {@link ReadEnd} is currently feeding into the associated {@link Wire}.
454                  */
455                 public Bit getInputValue()
456                 {
457                         return getInputValue(0);
458                 }
459
460                 /**
461                  * @return The value which the {@link ReadEnd} is currently feeding into the associated {@link Wire} at the indexed {@link Bit}.
462                  */
463                 public Bit getInputValue(int index)
464                 {
465                         return inputValues.getBit(index);
466                 }
467
468                 /**
469                  * @return A copy (safe to modify) of the values the {@link ReadEnd} is currently feeding into the associated {@link Wire}.
470                  */
471                 public BitVector getInputValues()
472                 {
473                         return getInputValues(0, length);
474                 }
475
476                 public BitVector getInputValues(int start, int end)
477                 {
478                         return inputValues.subVector(start, end);
479                 }
480
481                 /**
482                  * {@link ReadEnd} now feeds Z into the associated {@link Wire}.
483                  */
484                 public void clearSignals()
485                 {
486                         feedSignals(Z.toVector(length));
487                 }
488
489                 public BitVector wireValuesExcludingMe()
490                 {
491                         BitVectorMutator mutator = BitVectorMutator.empty();
492                         for (ReadWriteEnd wireEnd : inputs)
493                         {
494                                 if (wireEnd == this)
495                                         continue;
496                                 mutator.join(wireEnd.inputValues);
497                         }
498                         return mutator.get();
499                 }
500
501                 @Override
502                 public String toString()
503                 {
504                         return inputValues.toString();
505                 }
506
507                 @Override
508                 public void close()
509                 {
510                         super.close();
511                         open = false;
512                 }
513
514                 void setWriting(boolean isWriting)
515                 {
516                         if (this.isWriting != isWriting)
517                         {
518                                 this.isWriting = isWriting;
519                                 if (isWriting)
520                                         inputs.add(this);
521                                 else
522                                         inputs.remove(this);
523                                 Wire.this.recalculate();
524                         }
525                 }
526
527                 boolean isWriting()
528                 {
529                         return isWriting;
530                 }
531         }
532
533         @Override
534         public String toString()
535         {
536                 String name = this.name == null ? String.format("0x%08x", hashCode()) : this.name;
537                 return String.format("wire %s value: %s inputs: %s", name, values, inputs);
538         }
539
540         public static ReadEnd[] extractEnds(Wire[] w)
541         {
542                 ReadEnd[] inputs = new ReadEnd[w.length];
543                 for (int i = 0; i < w.length; i++)
544                         inputs[i] = w[i].createReadWriteEnd();
545                 return inputs;
546         }
547
548         // TODO Fix ReadWriteEnd feeding signals to entire Wire (Z) instead of only selected Bits
549         /**
550          * Fuses the selected bits of two wires together. If the bits change in one Wire, the other is changed accordingly immediately. Warning:
551          * The bits are permanently fused together.
552          * 
553          * @param a      The {@link Wire} to be (partially) fused with b
554          * @param b      The {@link Wire} to be (partially) fused with a
555          * @param fromA  The first bit of {@link Wire} a to be fused
556          * @param fromB  The first bit of {@link Wire} b to be fused
557          * @param length The amount of bits to fuse
558          */
559         public static void fuse(Wire a, Wire b, int fromA, int fromB, int length)
560         {
561                 ReadWriteEnd rA = a.createReadWriteEnd(), rB = b.createReadWriteEnd();
562                 rA.setWriting(false);
563                 rB.setWriting(false);
564                 rA.setValues(BitVector.of(Bit.Z, a.length));
565                 rB.setValues(BitVector.of(Bit.Z, b.length));
566                 Fusion aF = new Fusion(rB, fromA, fromB, length), bF = new Fusion(rA, fromB, fromA, length);
567                 rA.registerObserver(aF);
568                 rB.registerObserver(bF);
569                 aF.update(rA);
570                 bF.update(rB);
571         }
572
573         /**
574          * 
575          * Fuses two wires together. If the bits change in one Wire, the other is changed accordingly immediately. Warning: The bits are
576          * permanently fused together.
577          * 
578          * @param a The {@link Wire} to be fused with b
579          * @param b The {@link Wire} to be fused with a
580          */
581         public static void fuse(Wire a, Wire b)
582         {
583                 fuse(a, b, 0, 0, a.length);
584         }
585
586         private static class Fusion implements LogicObserver
587         {
588                 private ReadWriteEnd target;
589                 int fromSource, fromTarget, length;
590
591                 public Fusion(ReadWriteEnd target, int fromSource, int fromTarget, int length)
592                 {
593                         this.target = target;
594                         this.fromSource = fromSource;
595                         this.fromTarget = fromTarget;
596                         this.length = length;
597                 }
598
599                 @Override
600                 public void update(LogicObservable initiator)
601                 {
602                         ReadWriteEnd source = (ReadWriteEnd) initiator;
603                         if (source.getWire().inputs.size() - (source.isWriting() ? 1 : 0) == 0)
604                                 target.setWriting(false);
605                         else
606                         {
607                                 target.setWriting(true);
608                                 BitVector targetInput = source.wireValuesExcludingMe().subVector(fromSource, fromSource + length);
609                                 target.setValues(fromTarget, targetInput);
610                         }
611                 }
612         }
613 }