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