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