fixed Connector and added some useful methods to WireArray and Util
[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 {
20     private Bit[] values;
21     public final int travelTime;
22     private List<WireArrayObserver> observers = new ArrayList<WireArrayObserver>();
23     public final int length;
24     private List<WireArrayInput> inputs = new ArrayList<WireArrayInput>();
25
26     public WireArray(int length, int travelTime)
27     {
28         if (length < 1)
29             throw new IllegalArgumentException("Tried to create an array of wires with length " + length
30                     + ", but a length of less than 1 makes no sense.");
31         this.length = length;
32         this.travelTime = travelTime;
33         initValues();
34     }
35
36     private void initValues()
37     {
38         values = new Bit[length];
39         for (int i = 0; i < length; i++)
40             values[i] = Bit.Z;
41     }
42
43     private void recalculateSingleInput()
44     {
45         WireArrayInput input = inputs.get(0);
46         if (!Arrays.equals(input.getValues(), values))
47         {
48             System.arraycopy(input.getValues(), 0, values, 0, length);
49             notifyObservers();
50         }
51     }
52
53     private void recalculateMultipleInputs()
54     {
55         Iterator<WireArrayInput> it = inputs.iterator();
56         Bit[] newValues = it.next().values.clone();
57
58         while (it.hasNext())
59         {
60             WireArrayInput input = it.next();
61             Bit[] bits = input.getValues();
62             for (int i = 0; i < length; i++)
63             {
64                 if (Bit.Z.equals(bits[i]) || newValues[i].equals(bits[i]))
65                     continue;
66                 else if (Bit.Z.equals(newValues[i]))
67                     newValues[i] = bits[i];
68                 else
69                     newValues[i] = Bit.X;
70             }
71         }
72
73         if (!Arrays.equals(newValues, values))
74         {
75             notifyObservers();
76             values = newValues;
77         }
78     }
79
80     private void recalculate()
81     {
82         switch (inputs.size())
83         {
84         case 0:
85             return;
86         case 1:
87             recalculateSingleInput();
88             break;
89         default:
90             recalculateMultipleInputs();
91         }
92     }
93
94     /**
95      * The WireArray is interpreted as an unsigned integer with n bits.
96      * 
97      * @return <code>true</code> if all bits are either <code>Bit.ONE</code> or
98      *         <code>Bit.ZERO</code> (they do not all have to have the same value),
99      *         not <code>Bit.X</code> or <code>Bit.Z</code>. <code>false</code> is
100      *         returned otherwise.
101      * 
102      * @author Fabian Stemmler
103      */
104     public boolean hasNumericValue()
105     {
106         for (Bit b : values)
107         {
108             if (b != Bit.ZERO && b != Bit.ONE)
109                 return false;
110         }
111         return true;
112     }
113
114     /**
115      * The WireArray is interpreted as an unsigned integer with n bits.
116      * 
117      * @return The unsigned value of the {@link WireArray}'s bits, where value 0
118      *         corresponds with 2^0, value 1 is 2^1 and so on.
119      * 
120      * @author Fabian Stemmler
121      */
122     public long getUnsignedValue()
123     {
124         long val = 0;
125         long mask = 1;
126         for (int i = 0; i < length; i++)
127         {
128             switch (values[i])
129             {
130             default:
131             case Z:
132             case X:
133                 return 0; // TODO: Proper handling for getUnsignedValue(), if not all bits are 1 or 0;
134                           // Random number?
135             case ONE:
136                 val |= mask;
137                 break;
138             case ZERO:
139             }
140             mask = mask << 1;
141         }
142         return val;
143     }
144
145     /**
146      * The WireArray is interpreted as a signed integer with n bits.
147      * 
148      * @return The signed value of the {@link WireArray}'s bits, where value 0
149      *         corresponds with 2^0, value 1 is 2^1 and so on.
150      * 
151      * @author Fabian Stemmler
152      */
153     public long getSignedValue()
154     {
155         long val = getUnsignedValue();
156         long mask = 1 << (length - 1);
157         if ((mask & val) != 0)
158         {
159             int shifts = 64 - length;
160             return (val << shifts) >> shifts;
161         }
162         return val;
163     }
164
165     /**
166      * Included for convenient use on {@link WireArray}s of length 1.
167      * 
168      * @return The value of bit 0.
169      * 
170      * @author Fabian Stemmler
171      */
172     public Bit getValue()
173     {
174         return getValue(0);
175     }
176
177     /**
178      * 
179      * @param index Index of the requested bit.
180      * @return The value of the indexed bit.
181      * 
182      * @author Fabian Stemmler
183      */
184     public Bit getValue(int index)
185     {
186         return values[index];
187     }
188
189     public Bit[] getValues(int start, int end)
190     {
191         int length = end - start;
192         Bit[] bits = new Bit[length];
193         System.arraycopy(values, start, bits, 0, length);
194         return bits;
195     }
196
197     /**
198      * @return An array of length n containing the values of the n bits in the
199      *         {@link WireArray}. Can be safely modified.
200      * 
201      * @author Fabian Stemmler
202      */
203     public Bit[] getValues()
204     {
205         return values.clone();
206     }
207
208     /**
209      * Adds an {@link WireArrayObserver}, who will be notified when the value of the
210      * {@link WireArray} is updated.
211      * 
212      * @param ob The {@link WireArrayObserver} to be notified of changes.
213      * @return true if the given {@link WireArrayObserver} was not already
214      *         registered, false otherwise
215      * 
216      * @author Fabian Stemmler
217      */
218     public boolean addObserver(WireArrayObserver ob)
219     {
220         return observers.add(ob);
221     }
222
223     private void notifyObservers()
224     {
225         for (WireArrayObserver o : observers)
226             o.update(this);
227     }
228
229     /**
230      * Create and register a {@link WireArrayInput} object, which is tied to this
231      * {@link WireArray}.
232      */
233     public WireArrayInput createInput()
234     {
235         return new WireArrayInput(this);
236     }
237
238     private void registerInput(WireArrayInput toRegister)
239     {
240         inputs.add(toRegister);
241     }
242
243     /**
244      * A {@link WireArrayInput} feeds a constant signal into the {@link WireArray}
245      * it is tied to. The combination of all inputs determines the
246      * {@link WireArray}s final value. X dominates all other inputs Z does not
247      * affect the final value, unless there are no other inputs than Z 0 and 1 turn
248      * into X when they are mixed
249      * 
250      * @author Fabian Stemmler
251      */
252     public class WireArrayInput
253     {
254         public final WireArray owner;
255         private Bit[] values;
256
257         private WireArrayInput(WireArray owner)
258         {
259             super();
260             this.owner = owner;
261             initValues();
262             owner.registerInput(this);
263         }
264
265         private void initValues()
266         {
267             values = new Bit[length];
268             for (int i = 0; i < length; i++)
269                 values[i] = Bit.Z;
270         }
271
272         /**
273          * Sets the wires values. This takes up time, as specified by the
274          * {@link WireArray}s travel time.
275          * 
276          * @param newValues The new values the wires should take on.
277          * 
278          * @author Fabian Stemmler
279          */
280         public void feedSignals(Bit... newValues)
281         {
282             if (newValues.length == length)
283             {
284                 feedSignals(0, newValues);
285             } else
286                 throw new IllegalArgumentException(
287                         "Attempted to input " + newValues.length + " bits instead of " + length + " bits.");
288         }
289
290         /**
291          * Sets values of a subarray of wires. This takes up time, as specified by the
292          * {@link WireArray}s travel time.
293          * 
294          * @param newValues   The new values the wires should take on.
295          * @param startingBit The first index of the subarray of wires.
296          * 
297          * @author Fabian Stemmler
298          */
299         public void feedSignals(int startingBit, Bit... newValues)
300         {
301             Simulation.TIMELINE.addEvent((e) -> setValues(startingBit, newValues), travelTime);
302         }
303
304         private void setValues(int startingBit, Bit... newValues)
305         {
306             int exclLastIndex = startingBit + newValues.length;
307             if (length < exclLastIndex)
308                 throw new ArrayIndexOutOfBoundsException("Attempted to input bits from index " + startingBit + " to "
309                         + exclLastIndex + " when there are only " + length + "wires.");
310             if (!Arrays.equals(values, startingBit, exclLastIndex, newValues, 0, newValues.length))
311             {
312                 System.arraycopy(newValues, 0, values, startingBit, newValues.length);
313                 owner.recalculate();
314             }
315         }
316
317         public Bit[] getValues()
318         {
319             return values.clone();
320         }
321         
322         public Bit[] wireValuesExcludingMe() 
323         {
324                 Bit[] bits = Util.arrayOfZ(length);
325                 for (WireArrayInput wai : inputs) 
326                 {
327                         if(wai == this)
328                                 continue;
329                         Util.combineInto(bits, wai.getValues());
330                 }
331                 return bits;
332         }
333
334         public void clearSignals()
335         {
336             Bit[] bits = new Bit[length];
337             for (int i = 0; i < length; i++)
338                 bits[i] = Bit.Z;
339             feedSignals(bits);
340         }
341
342         @Override
343         public String toString()
344         {
345             return Arrays.toString(values);
346         }
347     }
348
349     @Override
350     public String toString()
351     {
352         return String.format("wire 0x%08x value: %s inputs: %s", hashCode(), Arrays.toString(values), inputs);
353     }
354     
355     public static WireArrayInput[] extractInputs(WireArray[] w)
356     {
357         WireArrayInput[] inputs = new WireArrayInput[w.length];
358         for(int i = 0; i < w.length; i++)
359             inputs[i] = w[i].createInput();
360         return inputs;
361     }
362 }