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