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