Renamed core components to have the common prefix Core
[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.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 CoreWire
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         FusedBit[] fusedBits;
34
35         public CoreWire(Timeline timeline, int width, int travelTime)
36         {
37                 this(timeline, width, travelTime, null);
38         }
39
40         public CoreWire(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 (FusedBit 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                                 FusedBit 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 CoreWire} 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 CoreWire} is interpreted as an unsigned integer with n bits.
143          * 
144          * @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.
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 CoreWire} is interpreted as a signed integer with n bits.
172          * 
173          * @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.
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 CoreWire} 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 CoreWire}. 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 CoreWire}. 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 CoreWire} it is tied to. The combination of all inputs determines the
264          * {@link CoreWire}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                         CoreWire.this.attachEnd(this);
277                 }
278
279                 public void update()
280                 {
281                         notifyObservers();
282                 }
283
284                 /**
285                  * Included for convenient use on {@link CoreWire}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 CoreWire.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 CoreWire.this.getValue(index);
305                 }
306
307                 public BitVector getValues()
308                 {
309                         return CoreWire.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 CoreWire.this.getValues(start, end);
322                 }
323
324                 /**
325                  * The {@link CoreWire} 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 CoreWire.this.hasNumericValue();
335                 }
336
337                 /**
338                  * The {@link CoreWire} is interpreted as an unsigned integer with n bits.
339                  * 
340                  * @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.
341                  * 
342                  * @author Fabian Stemmler
343                  */
344                 public long getUnsignedValue()
345                 {
346                         return CoreWire.this.getUnsignedValue();
347                 }
348
349                 /**
350                  * The {@link CoreWire} is interpreted as a signed integer with n bits.
351                  * 
352                  * @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.
353                  * 
354                  * @author Fabian Stemmler
355                  */
356                 public long getSignedValue()
357                 {
358                         return CoreWire.this.getSignedValue();
359                 }
360
361                 @Override
362                 public String toString()
363                 {
364                         return CoreWire.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 CoreWire getWire()
380                 {
381                         return CoreWire.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 CoreWire}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 CoreWire}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 CoreWire}. 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                                 CoreWire.this.recalculateValuesWithoutFusions();
483                         }
484                 }
485
486                 /**
487                  * Sets the values that are being fed into the {@link CoreWire}. 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                         CoreWire.this.recalculateValuesWithoutFusions();
496                 }
497
498                 /**
499                  * @return The value (of bit 0) the {@link ReadEnd} is currently feeding into the associated {@link CoreWire}.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 CoreWire} 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 CoreWire}.
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 CoreWire}.
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                                 CoreWire.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(CoreWire[] 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 CoreWire} to be fused with b
607          * @param b The {@link CoreWire} to be fused with a
608          */
609         public static void fuse(CoreWire a, CoreWire 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 CoreWire} to be (partially) fused with b
619          * @param b     The {@link CoreWire} to be (partially) fused with a
620          * @param fromA The first bit of {@link CoreWire} a to be fused
621          * @param fromB The first bit of {@link CoreWire} b to be fused
622          * @param width The amount of bits to fuse
623          */
624         public static void fuse(CoreWire a, CoreWire b, int fromA, int fromB, int width)
625         {
626                 // iterate in this direction to be fail-fast (rely on the checks in fuse(Wire, Wire, int, int)
627                 for (int i = width - 1; i >= 0; i--)
628                         fuse(a, b, fromA + i, fromB + i);
629         }
630
631         /**
632          * Fuses one bit of two wires together. If this bit changes in one Wire, the other is changed accordingly immediately. Warning: The bits
633          * are permanently fused together.
634          * 
635          * @param a    The {@link CoreWire} to be (partially) fused with b
636          * @param b    The {@link CoreWire} to be (partially) fused with a
637          * @param bitA The bit of {@link CoreWire} a to be fused
638          * @param bitB The bit of {@link CoreWire} b to be fused
639          */
640         public static void fuse(CoreWire a, CoreWire b, int bitA, int bitB)
641         {
642                 if (bitA >= a.width)
643                         throw new IllegalArgumentException("No bit " + bitA + " in " + a + " (width " + a.width + ")");
644                 if (bitB >= b.width)
645                         throw new IllegalArgumentException("No bit " + bitB + " in " + b + " (width " + b.width + ")");
646                 if (a.fusedBits == null)
647                         a.fusedBits = new FusedBit[a.width];
648                 if (b.fusedBits == null)
649                         b.fusedBits = new FusedBit[b.width];
650                 FusedBit oldFusionA = a.fusedBits[bitA];
651                 FusedBit oldFusionB = b.fusedBits[bitB];
652                 if (oldFusionA == null)
653                         if (oldFusionB == null)
654                         {
655                                 FusedBit fusion = new FusedBit();
656                                 fusion.addParticipatingWireBit(a, bitA);
657                                 fusion.addParticipatingWireBit(b, bitB);
658                         } else
659                                 oldFusionB.addParticipatingWireBit(a, bitA);
660                 else if (oldFusionB == null)
661                         oldFusionA.addParticipatingWireBit(b, bitB);
662                 else
663                         oldFusionA.mergeOtherIntoThis(oldFusionB);
664         }
665
666         private static class FusedBit
667         {
668                 private final List<WireBit> participatingWireBits;
669
670                 public FusedBit()
671                 {
672                         this.participatingWireBits = new ArrayList<>();
673                 }
674
675                 public void addParticipatingWireBit(CoreWire w, int bit)
676                 {
677                         addParticipatingWireBit(new WireBit(w, bit));
678                 }
679
680                 private void addParticipatingWireBit(WireBit wb)
681                 {
682                         wb.wire.fusedBits[wb.bit] = this;
683                         participatingWireBits.add(wb);
684                         wb.wire.invalidateCachedValuesForAllFusedWires();
685                 }
686
687                 public void mergeOtherIntoThis(FusedBit other)
688                 {
689                         for (WireBit wb : other.participatingWireBits)
690                                 addParticipatingWireBit(wb);
691                 }
692
693                 public void invalidateCachedValuesForAllParticipatingWires()
694                 {
695                         for (WireBit wb : participatingWireBits)
696                                 wb.wire.invalidateCachedValues();
697                 }
698
699                 public Bit getValue()
700                 {
701                         Bit result = null;
702                         for (WireBit wb : participatingWireBits)
703                                 if (!wb.wire.inputs.isEmpty())
704                                 {
705                                         Bit bit = wb.wire.bitsWithoutFusions[wb.bit];
706                                         result = result == null ? bit : result.join(bit);
707                                 }
708                         return result == null ? U : result;
709                 }
710         }
711
712         private static class WireBit
713         {
714                 public final CoreWire wire;
715                 public final int bit;
716
717                 public WireBit(CoreWire wire, int bit)
718                 {
719                         this.wire = wire;
720                         this.bit = bit;
721                 }
722         }
723 }