Timeline now passed via constructor
[Mograsim.git] / era.mi / src / era / mi / logic / wires / Wire.java
1 package era.mi.logic.wires;\r
2 \r
3 import static era.mi.logic.types.Bit.U;\r
4 import static era.mi.logic.types.Bit.Z;\r
5 \r
6 import java.util.ArrayList;\r
7 import java.util.List;\r
8 \r
9 import era.mi.logic.timeline.Timeline;\r
10 import era.mi.logic.types.Bit;\r
11 import era.mi.logic.types.BitVector;\r
12 import era.mi.logic.types.BitVector.BitVectorMutator;\r
13 \r
14 /**\r
15  * Represents an array of wires that can store n bits of information.\r
16  * \r
17  * @author Fabian Stemmler\r
18  *\r
19  */\r
20 public class Wire\r
21 {\r
22         private BitVector values;\r
23         public final int travelTime;\r
24         private List<ReadEnd> attached = new ArrayList<ReadEnd>();\r
25         public final int length;\r
26         private List<ReadWriteEnd> inputs = new ArrayList<ReadWriteEnd>();\r
27         private Timeline timeline;\r
28 \r
29         public Wire(Timeline timeline, int length, int travelTime)\r
30         {\r
31                 if (length < 1)\r
32                         throw new IllegalArgumentException(\r
33                                         String.format("Tried to create an array of wires with length %d, but a length of less than 1 makes no sense.", length));\r
34                 this.timeline = timeline;\r
35                 this.length = length;\r
36                 this.travelTime = travelTime;\r
37                 initValues();\r
38         }\r
39 \r
40         private void initValues()\r
41         {\r
42                 values = U.toVector(length);\r
43         }\r
44 \r
45         private void recalculateSingleInput()\r
46         {\r
47                 setNewValues(inputs.get(0).getInputValues());\r
48         }\r
49 \r
50         private void recalculateMultipleInputs()\r
51         {\r
52                 BitVectorMutator mutator = BitVectorMutator.empty();\r
53                 for (ReadWriteEnd wireArrayEnd : inputs)\r
54                         mutator.join(wireArrayEnd.getInputValues());\r
55                 setNewValues(mutator.get());\r
56         }\r
57 \r
58         private void setNewValues(BitVector newValues)\r
59         {\r
60                 if (values.equals(newValues))\r
61                         return;\r
62                 BitVector oldValues = values;\r
63                 values = newValues;\r
64                 notifyObservers(oldValues);\r
65         }\r
66 \r
67         private void recalculate()\r
68         {\r
69                 switch (inputs.size())\r
70                 {\r
71                 case 0:\r
72                         return;\r
73                 case 1:\r
74                         recalculateSingleInput();\r
75                         break;\r
76                 default:\r
77                         recalculateMultipleInputs();\r
78                 }\r
79         }\r
80 \r
81         /**\r
82          * The {@link Wire} is interpreted as an unsigned integer with n bits.\r
83          * \r
84          * @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
85          *         value), not <code>Bit.X</code> or <code>Bit.Z</code>. <code>false</code> is returned otherwise.\r
86          * \r
87          * @author Fabian Stemmler\r
88          */\r
89         public boolean hasNumericValue()\r
90         {\r
91                 for (Bit b : values)\r
92                 {\r
93                         if (b != Bit.ZERO && b != Bit.ONE)\r
94                                 return false;\r
95                 }\r
96                 return true;\r
97         }\r
98 \r
99         /**\r
100          * The {@link Wire} is interpreted as an unsigned integer with n bits.\r
101          * \r
102          * @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
103          * \r
104          * @author Fabian Stemmler\r
105          */\r
106         public long getUnsignedValue()\r
107         {\r
108                 long val = 0;\r
109                 long mask = 1;\r
110                 for (Bit bit : values)\r
111                 {\r
112                         switch (bit)\r
113                         {\r
114                         default:\r
115                         case Z:\r
116                         case X:\r
117                                 return 0; // TODO: Proper handling for getUnsignedValue(), if not all bits are 1 or 0;\r
118                         case ONE:\r
119                                 val |= mask;\r
120                                 break;\r
121                         case ZERO:\r
122                         }\r
123                         mask = mask << 1;\r
124                 }\r
125                 return val;\r
126         }\r
127 \r
128         /**\r
129          * The {@link Wire} is interpreted as a signed integer with n bits.\r
130          * \r
131          * @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
132          * \r
133          * @author Fabian Stemmler\r
134          */\r
135         public long getSignedValue()\r
136         {\r
137                 long val = getUnsignedValue();\r
138                 long mask = 1 << (length - 1);\r
139                 if ((mask & val) != 0)\r
140                 {\r
141                         int shifts = 64 - length;\r
142                         return (val << shifts) >> shifts;\r
143                 }\r
144                 return val;\r
145         }\r
146 \r
147         public Bit getValue()\r
148         {\r
149                 return getValue(0);\r
150         }\r
151 \r
152         public Bit getValue(int index)\r
153         {\r
154                 return values.getBit(index);\r
155         }\r
156 \r
157         public BitVector getValues(int start, int end)\r
158         {\r
159                 return values.subVector(start, end);\r
160         }\r
161 \r
162         public BitVector getValues()\r
163         {\r
164                 return values;\r
165         }\r
166 \r
167         /**\r
168          * Adds an {@link WireObserver}, who will be notified when the value of the {@link Wire} is updated.\r
169          * \r
170          * @param ob The {@link WireObserver} to be notified of changes.\r
171          * @return true if the given {@link WireObserver} was not already registered, false otherwise\r
172          * \r
173          * @author Fabian Stemmler\r
174          */\r
175         private void attachEnd(ReadEnd end)\r
176         {\r
177                 attached.add(end);\r
178         }\r
179 \r
180         private void detachEnd(ReadEnd end)\r
181         {\r
182                 attached.remove(end);\r
183         }\r
184 \r
185         private void notifyObservers(BitVector oldValues)\r
186         {\r
187                 for (ReadEnd o : attached)\r
188                         o.update(oldValues);\r
189         }\r
190 \r
191         /**\r
192          * Create and register a {@link ReadWriteEnd} object, which is tied to this {@link Wire}. This {@link ReadWriteEnd} can be written to.\r
193          */\r
194         public ReadWriteEnd createReadWriteEnd()\r
195         {\r
196                 return new ReadWriteEnd();\r
197         }\r
198 \r
199         /**\r
200          * Create a {@link ReadEnd} object, which is tied to this {@link Wire}. This {@link ReadEnd} cannot be written to.\r
201          */\r
202         public ReadEnd createReadOnlyEnd()\r
203         {\r
204                 return new ReadEnd();\r
205         }\r
206 \r
207         private void registerInput(ReadWriteEnd toRegister)\r
208         {\r
209                 inputs.add(toRegister);\r
210         }\r
211 \r
212         /**\r
213          * A {@link ReadEnd} feeds a constant signal into the {@link Wire} it is tied to. The combination of all inputs determines the\r
214          * {@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
215          * and 1 turn into X when they are mixed\r
216          * \r
217          * @author Fabian Stemmler\r
218          */\r
219         public class ReadEnd\r
220         {\r
221                 private List<WireObserver> observers = new ArrayList<WireObserver>();\r
222 \r
223                 private ReadEnd()\r
224                 {\r
225                         super();\r
226                         Wire.this.attachEnd(this);\r
227                 }\r
228 \r
229                 public void update(BitVector oldValues)\r
230                 {\r
231                         for (WireObserver ob : observers)\r
232                                 ob.update(this, oldValues);\r
233                 }\r
234 \r
235                 /**\r
236                  * Included for convenient use on {@link Wire}s of length 1.\r
237                  * \r
238                  * @return The value of bit 0.\r
239                  * \r
240                  * @author Fabian Stemmler\r
241                  */\r
242                 public Bit getValue()\r
243                 {\r
244                         return Wire.this.getValue();\r
245                 }\r
246 \r
247                 /**\r
248                  * @param index Index of the requested bit.\r
249                  * @return The value of the indexed bit.\r
250                  * \r
251                  * @author Fabian Stemmler\r
252                  */\r
253                 public Bit getValue(int index)\r
254                 {\r
255                         return Wire.this.getValue(index);\r
256                 }\r
257 \r
258                 /**\r
259                  * @param index Index of the requested bit.\r
260                  * @return The value of the indexed bit.\r
261                  * \r
262                  * @author Fabian Stemmler\r
263                  */\r
264                 public BitVector getValues()\r
265                 {\r
266                         return Wire.this.getValues();\r
267                 }\r
268 \r
269                 /**\r
270                  * @param start Start of the wanted segment. (inclusive)\r
271                  * @param end   End of the wanted segment. (exclusive)\r
272                  * @return The values of the segment of {@link Bit}s indexed.\r
273                  * \r
274                  * @author Fabian Stemmler\r
275                  */\r
276                 public BitVector getValues(int start, int end)\r
277                 {\r
278                         return Wire.this.getValues(start, end);\r
279                 }\r
280 \r
281                 /**\r
282                  * The {@link Wire} is interpreted as an unsigned integer with n bits.\r
283                  * \r
284                  * @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
285                  *         same value), not <code>Bit.X</code> or <code>Bit.Z</code>. <code>false</code> is returned otherwise.\r
286                  * \r
287                  * @author Fabian Stemmler\r
288                  */\r
289                 public boolean hasNumericValue()\r
290                 {\r
291                         return Wire.this.hasNumericValue();\r
292                 }\r
293 \r
294                 /**\r
295                  * The {@link Wire} is interpreted as an unsigned integer with n bits.\r
296                  * \r
297                  * @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
298                  * \r
299                  * @author Fabian Stemmler\r
300                  */\r
301                 public long getUnsignedValue()\r
302                 {\r
303                         return Wire.this.getUnsignedValue();\r
304                 }\r
305 \r
306                 /**\r
307                  * The {@link Wire} is interpreted as a signed integer with n bits.\r
308                  * \r
309                  * @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
310                  * \r
311                  * @author Fabian Stemmler\r
312                  */\r
313                 public long getSignedValue()\r
314                 {\r
315                         return Wire.this.getSignedValue();\r
316                 }\r
317 \r
318                 @Override\r
319                 public String toString()\r
320                 {\r
321                         return Wire.this.toString();\r
322                 }\r
323 \r
324                 public void close()\r
325                 {\r
326                         inputs.remove(this);\r
327                         detachEnd(this);\r
328                         recalculate();\r
329                 }\r
330 \r
331                 public int length()\r
332                 {\r
333                         return length;\r
334                 }\r
335 \r
336                 public boolean addObserver(WireObserver ob)\r
337                 {\r
338                         return observers.add(ob);\r
339                 }\r
340 \r
341                 public Wire getWire()\r
342                 {\r
343                         return Wire.this;\r
344                 }\r
345         }\r
346 \r
347         public class ReadWriteEnd extends ReadEnd\r
348         {\r
349                 private boolean open;\r
350                 private BitVector inputValues;\r
351 \r
352                 private ReadWriteEnd()\r
353                 {\r
354                         super();\r
355                         open = true;\r
356                         initValues();\r
357                         registerInput(this);\r
358                 }\r
359 \r
360                 private void initValues()\r
361                 {\r
362                         inputValues = U.toVector(length);\r
363                 }\r
364 \r
365                 /**\r
366                  * Sets the wires values. This takes up time, as specified by the {@link Wire}s travel time.\r
367                  * \r
368                  * @param newValues The new values the wires should take on.\r
369                  * \r
370                  * @author Fabian Stemmler\r
371                  */\r
372                 public void feedSignals(Bit... newValues)\r
373                 {\r
374                         feedSignals(BitVector.of(newValues));\r
375                 }\r
376 \r
377                 public void feedSignals(BitVector newValues)\r
378                 {\r
379                         if (newValues.length() != length)\r
380                                 throw new IllegalArgumentException(\r
381                                                 String.format("Attempted to input %d bits instead of %d bits.", newValues.length(), length));\r
382                         if (!open)\r
383                                 throw new RuntimeException("Attempted to write to closed WireArrayEnd.");\r
384                         timeline.addEvent(e -> setValues(newValues), travelTime);\r
385                 }\r
386 \r
387                 /**\r
388                  * Sets values of a subarray of wires. This takes up time, as specified by the {@link Wire}s travel time.\r
389                  * \r
390                  * @param bitVector   The new values the wires should take on.\r
391                  * @param startingBit The first index of the subarray of wires.\r
392                  * \r
393                  * @author Fabian Stemmler\r
394                  */\r
395                 public void feedSignals(int startingBit, BitVector bitVector)\r
396                 {\r
397                         if (!open)\r
398                                 throw new RuntimeException("Attempted to write to closed WireArrayEnd.");\r
399                         timeline.addEvent(e -> setValues(startingBit, bitVector), travelTime);\r
400                 }\r
401 \r
402                 private void setValues(int startingBit, BitVector newValues)\r
403                 {\r
404                         // index check covered in equals\r
405                         if (!inputValues.equalsWithOffset(newValues, startingBit))\r
406                         {\r
407                                 Bit[] vals = inputValues.getBits();\r
408                                 System.arraycopy(newValues.getBits(), 0, vals, startingBit, newValues.length());\r
409                                 inputValues = BitVector.of(vals);\r
410                                 Wire.this.recalculate();\r
411                         }\r
412                 }\r
413 \r
414                 private void setValues(BitVector newValues)\r
415                 {\r
416                         if (inputValues.equals(newValues))\r
417                                 return;\r
418                         inputValues = newValues;\r
419                         Wire.this.recalculate();\r
420                 }\r
421 \r
422                 /**\r
423                  * @return The value (of bit 0) the {@link ReadEnd} is currently feeding into the associated {@link Wire}.\r
424                  */\r
425                 public Bit getInputValue()\r
426                 {\r
427                         return getInputValue(0);\r
428                 }\r
429 \r
430                 /**\r
431                  * @return The value which the {@link ReadEnd} is currently feeding into the associated {@link Wire} at the indexed {@link Bit}.\r
432                  */\r
433                 public Bit getInputValue(int index)\r
434                 {\r
435                         return inputValues.getBit(index);\r
436                 }\r
437 \r
438                 /**\r
439                  * @return A copy (safe to modify) of the values the {@link ReadEnd} is currently feeding into the associated {@link Wire}.\r
440                  */\r
441                 public BitVector getInputValues()\r
442                 {\r
443                         return getInputValues(0, length);\r
444                 }\r
445 \r
446                 public BitVector getInputValues(int start, int end)\r
447                 {\r
448                         return inputValues.subVector(start, end);\r
449                 }\r
450 \r
451                 /**\r
452                  * {@link ReadEnd} now feeds Z into the associated {@link Wire}.\r
453                  */\r
454                 public void clearSignals()\r
455                 {\r
456                         feedSignals(Z.toVector(length));\r
457                 }\r
458 \r
459                 public BitVector wireValuesExcludingMe()\r
460                 {\r
461                         BitVectorMutator mutator = BitVectorMutator.empty();\r
462                         for (ReadWriteEnd wireEnd : inputs)\r
463                         {\r
464                                 if (wireEnd == this)\r
465                                         continue;\r
466                                 mutator.join(wireEnd.inputValues);\r
467                         }\r
468                         return mutator.get();\r
469                 }\r
470 \r
471                 @Override\r
472                 public String toString()\r
473                 {\r
474                         return inputValues.toString();\r
475                 }\r
476         }\r
477 \r
478         @Override\r
479         public String toString()\r
480         {\r
481                 return String.format("wire 0x%08x value: %s inputs: %s", hashCode(), values, inputs);\r
482                 // Arrays.toString(values), inputs.stream().map(i -> Arrays.toString(i.inputValues)).reduce((s1, s2) -> s1 + s2)\r
483         }\r
484 \r
485         public static ReadEnd[] extractEnds(Wire[] w)\r
486         {\r
487                 ReadEnd[] inputs = new ReadEnd[w.length];\r
488                 for (int i = 0; i < w.length; i++)\r
489                         inputs[i] = w[i].createReadWriteEnd();\r
490                 return inputs;\r
491         }\r
492 }