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