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