Reformatted everything. Eclipse built-in Linewrapping/Comments 140 chars
[Mograsim.git] / era.mi / src / era / mi / logic / wires / WireArray.java
1 package era.mi.logic.wires;
2
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.Iterator;
6 import java.util.List;
7
8 import era.mi.logic.Bit;
9 import era.mi.logic.Simulation;
10 import era.mi.logic.Util;
11
12 /**
13  * Represents an array of wires that can store n bits of information.
14  * 
15  * @author Fabian Stemmler
16  *
17  */
18 public class WireArray {
19         private Bit[] values;
20         public final int travelTime;
21         private List<WireArrayObserver> observers = new ArrayList<WireArrayObserver>();
22         public final int length;
23         private List<WireArrayInput> inputs = new ArrayList<WireArrayInput>();
24
25         public WireArray(int length, int travelTime) {
26                 if (length < 1)
27                         throw new IllegalArgumentException(
28                                         String.format("Tried to create an array of wires with length %d, but a length of less than 1 makes no sense.", length));
29                 this.length = length;
30                 this.travelTime = travelTime;
31                 initValues();
32         }
33
34         private void initValues() {
35                 values = Bit.Z.makeArray(length);
36         }
37
38         private void recalculateSingleInput() {
39                 WireArrayInput input = inputs.get(0);
40                 if (!Arrays.equals(input.getValues(), values)) {
41                         Bit[] oldValues = values.clone();
42                         System.arraycopy(input.getValues(), 0, values, 0, length);
43                         notifyObservers(oldValues);
44                 }
45         }
46
47         private void recalculateMultipleInputs() {
48                 Iterator<WireArrayInput> it = inputs.iterator();
49                 Bit[] newValues = it.next().inputValues.clone();
50
51                 while (it.hasNext()) {
52                         WireArrayInput input = it.next();
53                         Bit[] bits = input.getValues();
54                         for (int i = 0; i < length; i++) {
55                                 if (Bit.Z.equals(bits[i]) || newValues[i].equals(bits[i]))
56                                         continue;
57                                 else if (Bit.Z.equals(newValues[i]))
58                                         newValues[i] = bits[i];
59                                 else
60                                         newValues[i] = Bit.X;
61                         }
62                 }
63
64                 if (!Arrays.equals(newValues, values)) {
65                         Bit[] oldValues = values;
66                         values = newValues;
67                         notifyObservers(oldValues);
68                 }
69         }
70
71         private void recalculate() {
72                 switch (inputs.size()) {
73                 case 0:
74                         return;
75                 case 1:
76                         recalculateSingleInput();
77                         break;
78                 default:
79                         recalculateMultipleInputs();
80                 }
81         }
82
83         /**
84          * The WireArray is interpreted as an unsigned integer with n bits.
85          * 
86          * @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
87          *         value), not <code>Bit.X</code> or <code>Bit.Z</code>. <code>false</code> is returned otherwise.
88          * 
89          * @author Fabian Stemmler
90          */
91         public boolean hasNumericValue() {
92                 for (Bit b : values) {
93                         if (b != Bit.ZERO && b != Bit.ONE)
94                                 return false;
95                 }
96                 return true;
97         }
98
99         /**
100          * The WireArray is interpreted as an unsigned integer with n bits.
101          * 
102          * @return The unsigned value of the {@link WireArray}'s bits, where value 0 corresponds with 2^0, value 1 is 2^1 and so on.
103          * 
104          * @author Fabian Stemmler
105          */
106         public long getUnsignedValue() {
107                 long val = 0;
108                 long mask = 1;
109                 for (int i = 0; i < length; i++) {
110                         switch (values[i]) {
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 WireArray is interpreted as a signed integer with n bits.
128          * 
129          * @return The signed value of the {@link WireArray}'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                 long val = getUnsignedValue();
135                 long mask = 1 << (length - 1);
136                 if ((mask & val) != 0) {
137                         int shifts = 64 - length;
138                         return (val << shifts) >> shifts;
139                 }
140                 return val;
141         }
142
143         /**
144          * Included for convenient use on {@link WireArray}s of length 1.
145          * 
146          * @return The value of bit 0.
147          * 
148          * @author Fabian Stemmler
149          */
150         public Bit getValue() {
151                 return getValue(0);
152         }
153
154         /**
155          * 
156          * @param index Index of the requested bit.
157          * @return The value of the indexed bit.
158          * 
159          * @author Fabian Stemmler
160          */
161         public Bit getValue(int index) {
162                 return values[index];
163         }
164
165         public Bit[] getValues(int start, int end) {
166                 int length = end - start;
167                 Bit[] bits = new Bit[length];
168                 System.arraycopy(values, start, bits, 0, length);
169                 return bits;
170         }
171
172         /**
173          * @return An array of length n containing the values of the n bits in the {@link WireArray}. Can be safely modified.
174          * 
175          * @author Fabian Stemmler
176          */
177         public Bit[] getValues() {
178                 return values.clone();
179         }
180
181         /**
182          * Adds an {@link WireArrayObserver}, who will be notified when the value of the {@link WireArray} is updated.
183          * 
184          * @param ob The {@link WireArrayObserver} to be notified of changes.
185          * @return true if the given {@link WireArrayObserver} was not already registered, false otherwise
186          * 
187          * @author Fabian Stemmler
188          */
189         public boolean addObserver(WireArrayObserver ob) {
190                 return observers.add(ob);
191         }
192
193         private void notifyObservers(Bit[] oldValues) {
194                 for (WireArrayObserver o : observers)
195                         o.update(this, oldValues);
196         }
197
198         /**
199          * Create and register a {@link WireArrayInput} object, which is tied to this {@link WireArray}.
200          */
201         public WireArrayInput createInput() {
202                 return new WireArrayInput(this);
203         }
204
205         private void registerInput(WireArrayInput toRegister) {
206                 inputs.add(toRegister);
207         }
208
209         /**
210          * A {@link WireArrayInput} feeds a constant signal into the {@link WireArray} it is tied to. The combination of all inputs determines
211          * the {@link WireArray}s final value. X dominates all other inputs Z does not affect the final value, unless there are no other inputs
212          * than Z 0 and 1 turn into X when they are mixed
213          * 
214          * @author Fabian Stemmler
215          */
216         public class WireArrayInput {
217                 public final WireArray owner;
218                 private Bit[] inputValues;
219
220                 private WireArrayInput(WireArray owner) {
221                         super();
222                         this.owner = owner;
223                         initValues();
224                         owner.registerInput(this);
225                 }
226
227                 private void initValues() {
228                         inputValues = Bit.Z.makeArray(length);
229                 }
230
231                 /**
232                  * Sets the wires values. This takes up time, as specified by the {@link WireArray}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                         if (newValues.length == length) {
240                                 feedSignals(0, newValues);
241                         } else
242                                 throw new IllegalArgumentException(
243                                                 String.format("Attempted to input %o bits instead of %o bits.", newValues.length, length));
244                 }
245
246                 /**
247                  * Sets values of a subarray of wires. This takes up time, as specified by the {@link WireArray}s travel time.
248                  * 
249                  * @param newValues   The new values the wires should take on.
250                  * @param startingBit The first index of the subarray of wires.
251                  * 
252                  * @author Fabian Stemmler
253                  */
254                 public void feedSignals(int startingBit, Bit... newValues) {
255                         Simulation.TIMELINE.addEvent((e) -> setValues(startingBit, newValues), travelTime);
256                 }
257
258                 private void setValues(int startingBit, Bit... newValues) {
259                         int exclLastIndex = startingBit + newValues.length;
260                         if (length < exclLastIndex)
261                                 throw new ArrayIndexOutOfBoundsException(
262                                                 String.format("Attempted to input bits from index %o to %o when there are only %o wires.", startingBit,
263                                                                 exclLastIndex - 1, length));
264                         if (!Arrays.equals(inputValues, startingBit, exclLastIndex, newValues, 0, newValues.length)) {
265                                 System.arraycopy(newValues, 0, inputValues, startingBit, newValues.length);
266                                 owner.recalculate();
267                         }
268                 }
269
270                 /**
271                  * Returns a copy (safe to modify) of the values the {@link WireArrayInput} is currently feeding into the associated
272                  * {@link WireArray}.
273                  */
274                 public Bit[] getValues() {
275                         return inputValues.clone();
276                 }
277
278                 /**
279                  * {@link WireArrayInput} now feeds Z into the associated {@link WireArray}.
280                  */
281                 public void clearSignals() {
282                         feedSignals(Bit.Z.makeArray(length));
283                 }
284
285                 public Bit[] wireValuesExcludingMe() {
286                         Bit[] bits = Bit.Z.makeArray(length);
287                         for (WireArrayInput wai : inputs) {
288                                 if (wai == this)
289                                         continue;
290                                 Util.combineInto(bits, wai.getValues());
291                         }
292                         return bits;
293                 }
294
295                 @Override
296                 public String toString() {
297                         return Arrays.toString(inputValues);
298                 }
299         }
300
301         @Override
302         public String toString() {
303                 return String.format("wire 0x%08x value: %s inputs: %s", hashCode(), Arrays.toString(values), inputs);
304         }
305
306         public static WireArrayInput[] extractInputs(WireArray[] w) {
307                 WireArrayInput[] inputs = new WireArrayInput[w.length];
308                 for (int i = 0; i < w.length; i++)
309                         inputs[i] = w[i].createInput();
310                 return inputs;
311         }
312 }