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