Added prototype component for main memory
[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                 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}.Returns the least\r
450                  *         significant bit (LSB)\r
451                  */\r
452                 public Bit getInputValue()\r
453                 {\r
454                         return getInputValue(0);\r
455                 }\r
456 \r
457                 /**\r
458                  * @return The value which the {@link ReadEnd} is currently feeding into the associated {@link Wire} at the indexed {@link Bit}.\r
459                  *         Returns the least significant bit (LSB)\r
460                  * \r
461                  */\r
462                 public Bit getInputValue(int index)\r
463                 {\r
464                         return inputValues.getLSBit(index);\r
465                 }\r
466 \r
467                 /**\r
468                  * @return A copy (safe to modify) of the values the {@link ReadEnd} is currently feeding into the associated {@link Wire}.\r
469                  */\r
470                 public BitVector getInputValues()\r
471                 {\r
472                         return inputValues;\r
473                 }\r
474 \r
475                 public BitVector getInputValues(int start, int end)\r
476                 {\r
477                         return inputValues.subVector(start, end);\r
478                 }\r
479 \r
480                 /**\r
481                  * {@link ReadEnd} now feeds Z into the associated {@link Wire}.\r
482                  */\r
483                 public void clearSignals()\r
484                 {\r
485                         feedSignals(Z.toVector(length));\r
486                 }\r
487 \r
488                 public BitVector wireValuesExcludingMe()\r
489                 {\r
490                         BitVectorMutator mutator = BitVectorMutator.empty();\r
491                         for (ReadWriteEnd wireEnd : inputs)\r
492                         {\r
493                                 if (wireEnd == this)\r
494                                         continue;\r
495                                 mutator.join(wireEnd.inputValues);\r
496                         }\r
497                         return mutator.toBitVector();\r
498                 }\r
499 \r
500                 @Override\r
501                 public String toString()\r
502                 {\r
503                         return inputValues.toString();\r
504                 }\r
505 \r
506                 @Override\r
507                 public void close()\r
508                 {\r
509                         super.close();\r
510                         open = false;\r
511                 }\r
512 \r
513                 void setWriting(boolean isWriting)\r
514                 {\r
515                         if (this.isWriting != isWriting)\r
516                         {\r
517                                 this.isWriting = isWriting;\r
518                                 if (isWriting)\r
519                                         inputs.add(this);\r
520                                 else\r
521                                         inputs.remove(this);\r
522                                 Wire.this.recalculate();\r
523                         }\r
524                 }\r
525 \r
526                 boolean isWriting()\r
527                 {\r
528                         return isWriting;\r
529                 }\r
530         }\r
531 \r
532         @Override\r
533         public String toString()\r
534         {\r
535                 String name = this.name == null ? String.format("0x%08x", hashCode()) : this.name;\r
536                 return String.format("wire %s value: %s inputs: %s", name, values, inputs);\r
537         }\r
538 \r
539         public static ReadEnd[] extractEnds(Wire[] w)\r
540         {\r
541                 ReadEnd[] inputs = new ReadEnd[w.length];\r
542                 for (int i = 0; i < w.length; i++)\r
543                         inputs[i] = w[i].createReadWriteEnd();\r
544                 return inputs;\r
545         }\r
546 \r
547         // TODO Fix ReadWriteEnd feeding signals to entire Wire (Z) instead of only selected Bits\r
548         /**\r
549          * Fuses the selected bits of two wires together. If the bits change in one Wire, the other is changed accordingly immediately. Warning:\r
550          * The bits are permanently fused together.\r
551          * \r
552          * @param a      The {@link Wire} to be (partially) fused with b\r
553          * @param b      The {@link Wire} to be (partially) fused with a\r
554          * @param fromA  The first bit of {@link Wire} a to be fused\r
555          * @param fromB  The first bit of {@link Wire} b to be fused\r
556          * @param length The amount of bits to fuse\r
557          */\r
558         public static void fuse(Wire a, Wire b, int fromA, int fromB, int length)\r
559         {\r
560                 ReadWriteEnd rA = a.createReadWriteEnd(), rB = b.createReadWriteEnd();\r
561                 rA.setWriting(false);\r
562                 rB.setWriting(false);\r
563                 rA.setValues(BitVector.of(Bit.Z, a.length));\r
564                 rB.setValues(BitVector.of(Bit.Z, b.length));\r
565                 Fusion aF = new Fusion(rB, fromA, fromB, length), bF = new Fusion(rA, fromB, fromA, length);\r
566                 rA.registerObserver(aF);\r
567                 rB.registerObserver(bF);\r
568                 aF.update(rA);\r
569                 bF.update(rB);\r
570         }\r
571 \r
572         /**\r
573          * \r
574          * Fuses two wires together. If the bits change in one Wire, the other is changed accordingly immediately. Warning: The bits are\r
575          * permanently fused together.\r
576          * \r
577          * @param a The {@link Wire} to be fused with b\r
578          * @param b The {@link Wire} to be fused with a\r
579          */\r
580         public static void fuse(Wire a, Wire b)\r
581         {\r
582                 fuse(a, b, 0, 0, a.length);\r
583         }\r
584 \r
585         private static class Fusion implements LogicObserver\r
586         {\r
587                 private ReadWriteEnd target;\r
588                 int fromSource, fromTarget, length;\r
589 \r
590                 public Fusion(ReadWriteEnd target, int fromSource, int fromTarget, int length)\r
591                 {\r
592                         this.target = target;\r
593                         this.fromSource = fromSource;\r
594                         this.fromTarget = fromTarget;\r
595                         this.length = length;\r
596                 }\r
597 \r
598                 @Override\r
599                 public void update(LogicObservable initiator)\r
600                 {\r
601                         ReadWriteEnd source = (ReadWriteEnd) initiator;\r
602                         if (source.getWire().inputs.size() - (source.isWriting() ? 1 : 0) == 0)\r
603                                 target.setWriting(false);\r
604                         else\r
605                         {\r
606                                 target.setWriting(true);\r
607                                 BitVector targetInput = source.wireValuesExcludingMe().subVector(fromSource, fromSource + length);\r
608                                 target.setValues(fromTarget, targetInput);\r
609                         }\r
610                 }\r
611         }\r
612 }