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