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