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