Merge remote-tracking branch 'origin/development' 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.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                 public BitVector getValues()
269                 {
270                         return Wire.this.getValues();
271                 }
272
273                 /**
274                  * @param start Start of the wanted segment. (inclusive)
275                  * @param end   End of the wanted segment. (exclusive)
276                  * @return The values of the segment of {@link Bit}s indexed.
277                  * 
278                  * @author Fabian Stemmler
279                  */
280                 public BitVector getValues(int start, int end)
281                 {
282                         return Wire.this.getValues(start, end);
283                 }
284
285                 /**
286                  * The {@link Wire} is interpreted as an unsigned integer with n bits.
287                  * 
288                  * @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
289                  *         same value), not <code>Bit.X</code> or <code>Bit.Z</code>. <code>false</code> is returned otherwise.
290                  * 
291                  * @author Fabian Stemmler
292                  */
293                 public boolean hasNumericValue()
294                 {
295                         return Wire.this.hasNumericValue();
296                 }
297
298                 /**
299                  * The {@link Wire} is interpreted as an unsigned integer with n bits.
300                  * 
301                  * @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.
302                  * 
303                  * @author Fabian Stemmler
304                  */
305                 public long getUnsignedValue()
306                 {
307                         return Wire.this.getUnsignedValue();
308                 }
309
310                 /**
311                  * The {@link Wire} is interpreted as a signed integer with n bits.
312                  * 
313                  * @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.
314                  * 
315                  * @author Fabian Stemmler
316                  */
317                 public long getSignedValue()
318                 {
319                         return Wire.this.getSignedValue();
320                 }
321
322                 @Override
323                 public String toString()
324                 {
325                         return Wire.this.toString();
326                 }
327
328                 public void close()
329                 {
330                         inputs.remove(this);
331                         detachEnd(this);
332                         recalculate();
333                 }
334
335                 public int length()
336                 {
337                         return length;
338                 }
339
340                 public Wire getWire()
341                 {
342                         return Wire.this;
343                 }
344
345                 @Override
346                 public void registerObserver(LogicObserver ob)
347                 {
348                         observers.add(ob);
349                 }
350
351                 @Override
352                 public void deregisterObserver(LogicObserver ob)
353                 {
354                         observers.remove(ob);
355                 }
356
357                 @Override
358                 public void notifyObservers()
359                 {
360                         observers.forEach(ob -> ob.update(this));
361                 }
362         }
363
364         public class ReadWriteEnd extends ReadEnd
365         {
366                 private boolean open, isWriting;
367                 private BitVector inputValues;
368
369                 ReadWriteEnd()
370                 {
371                         super();
372                         open = true;
373                         isWriting = true;
374                         initValues();
375                         registerInput(this);
376                 }
377
378                 private void initValues()
379                 {
380                         inputValues = U.toVector(length);
381                 }
382
383                 /**
384                  * Sets the wires values. This takes up time, as specified by the {@link Wire}s travel time.
385                  * 
386                  * @param newValues The new values the wires should take on.
387                  * 
388                  * @author Fabian Stemmler
389                  */
390                 public void feedSignals(Bit... newValues)
391                 {
392                         feedSignals(BitVector.of(newValues));
393                 }
394
395                 public void feedSignals(BitVector newValues)
396                 {
397                         if (newValues.length() != length)
398                                 throw new IllegalArgumentException(
399                                                 String.format("Attempted to input %d bits instead of %d bits.", newValues.length(), length));
400                         if (!open)
401                                 throw new RuntimeException("Attempted to write to closed WireArrayEnd.");
402                         timeline.addEvent(e -> setValues(newValues), travelTime);
403                 }
404
405                 /**
406                  * Sets values of a subarray of wires. This takes up time, as specified by the {@link Wire}s travel time.
407                  * 
408                  * @param bitVector   The new values the wires should take on.
409                  * @param startingBit The first index of the subarray of wires.
410                  * 
411                  * @author Fabian Stemmler
412                  */
413                 public void feedSignals(int startingBit, BitVector bitVector)
414                 {
415                         if (!open)
416                                 throw new RuntimeException("Attempted to write to closed WireArrayEnd.");
417                         timeline.addEvent(e -> setValues(startingBit, bitVector), travelTime);
418                 }
419
420                 /**
421                  * Sets the values that are being fed into the {@link Wire}. The preferred way of setting {@link ReadWriteEnd} values is via
422                  * feedValues(...) with a delay.
423                  */
424                 void setValues(int startingBit, BitVector newValues)
425                 {
426                         // index check covered in equals
427                         if (!inputValues.equalsWithOffset(newValues, startingBit))
428                         {
429                                 Bit[] vals = inputValues.getBits();
430                                 System.arraycopy(newValues.getBits(), 0, vals, startingBit, newValues.length());
431                                 inputValues = BitVector.of(vals);
432                                 Wire.this.recalculate();
433                         }
434                 }
435
436                 /**
437                  * Sets the values that are being fed into the {@link Wire}. The preferred way of setting {@link ReadWriteEnd} values is via
438                  * feedValues(...) with a delay.
439                  */
440                 void setValues(BitVector newValues)
441                 {
442                         if (inputValues.equals(newValues))
443                                 return;
444                         inputValues = newValues;
445                         Wire.this.recalculate();
446                 }
447
448                 /**
449                  * @return The value (of bit 0) the {@link ReadEnd} is currently feeding into the associated {@link Wire}.Returns the least
450                  *         significant bit (LSB)
451                  */
452                 public Bit getInputValue()
453                 {
454                         return getInputValue(0);
455                 }
456
457                 /**
458                  * @return The value which the {@link ReadEnd} is currently feeding into the associated {@link Wire} at the indexed {@link Bit}.
459                  *         Returns the least significant bit (LSB)
460                  * 
461                  */
462                 public Bit getInputValue(int index)
463                 {
464                         return inputValues.getLSBit(index);
465                 }
466
467                 /**
468                  * @return A copy (safe to modify) of the values the {@link ReadEnd} is currently feeding into the associated {@link Wire}.
469                  */
470                 public BitVector getInputValues()
471                 {
472                         return inputValues;
473                 }
474
475                 public BitVector getInputValues(int start, int end)
476                 {
477                         return inputValues.subVector(start, end);
478                 }
479
480                 /**
481                  * {@link ReadEnd} now feeds Z into the associated {@link Wire}.
482                  */
483                 public void clearSignals()
484                 {
485                         feedSignals(Z.toVector(length));
486                 }
487
488                 public BitVector wireValuesExcludingMe()
489                 {
490                         BitVectorMutator mutator = BitVectorMutator.empty();
491                         for (ReadWriteEnd wireEnd : inputs)
492                         {
493                                 if (wireEnd == this)
494                                         continue;
495                                 mutator.join(wireEnd.inputValues);
496                         }
497                         return mutator.toBitVector();
498                 }
499
500                 @Override
501                 public String toString()
502                 {
503                         return inputValues.toString();
504                 }
505
506                 @Override
507                 public void close()
508                 {
509                         super.close();
510                         open = false;
511                 }
512
513                 void setWriting(boolean isWriting)
514                 {
515                         if (this.isWriting != isWriting)
516                         {
517                                 this.isWriting = isWriting;
518                                 if (isWriting)
519                                         inputs.add(this);
520                                 else
521                                         inputs.remove(this);
522                                 Wire.this.recalculate();
523                         }
524                 }
525
526                 boolean isWriting()
527                 {
528                         return isWriting;
529                 }
530         }
531
532         @Override
533         public String toString()
534         {
535                 String name = this.name == null ? String.format("0x%08x", hashCode()) : this.name;
536                 return String.format("wire %s value: %s inputs: %s", name, values, inputs);
537         }
538
539         public static ReadEnd[] extractEnds(Wire[] w)
540         {
541                 ReadEnd[] inputs = new ReadEnd[w.length];
542                 for (int i = 0; i < w.length; i++)
543                         inputs[i] = w[i].createReadWriteEnd();
544                 return inputs;
545         }
546
547         // TODO Fix ReadWriteEnd feeding signals to entire Wire (Z) instead of only selected Bits
548         /**
549          * Fuses the selected bits of two wires together. If the bits change in one Wire, the other is changed accordingly immediately. Warning:
550          * The bits are permanently fused together.
551          * 
552          * @param a      The {@link Wire} to be (partially) fused with b
553          * @param b      The {@link Wire} to be (partially) fused with a
554          * @param fromA  The first bit of {@link Wire} a to be fused
555          * @param fromB  The first bit of {@link Wire} b to be fused
556          * @param length The amount of bits to fuse
557          */
558         public static void fuse(Wire a, Wire b, int fromA, int fromB, int length)
559         {
560                 ReadWriteEnd rA = a.createReadWriteEnd(), rB = b.createReadWriteEnd();
561                 rA.setWriting(false);
562                 rB.setWriting(false);
563                 rA.setValues(BitVector.of(Bit.Z, a.length));
564                 rB.setValues(BitVector.of(Bit.Z, b.length));
565                 Fusion aF = new Fusion(rB, fromA, fromB, length), bF = new Fusion(rA, fromB, fromA, length);
566                 rA.registerObserver(aF);
567                 rB.registerObserver(bF);
568                 aF.update(rA);
569                 bF.update(rB);
570         }
571
572         /**
573          * 
574          * Fuses two wires together. If the bits change in one Wire, the other is changed accordingly immediately. Warning: The bits are
575          * permanently fused together.
576          * 
577          * @param a The {@link Wire} to be fused with b
578          * @param b The {@link Wire} to be fused with a
579          */
580         public static void fuse(Wire a, Wire b)
581         {
582                 fuse(a, b, 0, 0, a.length);
583         }
584
585         private static class Fusion implements LogicObserver
586         {
587                 private ReadWriteEnd target;
588                 int fromSource, fromTarget, length;
589
590                 public Fusion(ReadWriteEnd target, int fromSource, int fromTarget, int length)
591                 {
592                         this.target = target;
593                         this.fromSource = fromSource;
594                         this.fromTarget = fromTarget;
595                         this.length = length;
596                 }
597
598                 @Override
599                 public void update(LogicObservable initiator)
600                 {
601                         ReadWriteEnd source = (ReadWriteEnd) initiator;
602                         if (source.getWire().inputs.size() - (source.isWriting() ? 1 : 0) == 0)
603                                 target.setWriting(false);
604                         else
605                         {
606                                 target.setWriting(true);
607                                 BitVector targetInput = source.wireValuesExcludingMe().subVector(fromSource, fromSource + length);
608                                 target.setValues(fromTarget, targetInput);
609                         }
610                 }
611         }
612 }