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