Wire concept was changed to accommodate multiple inputs. Not all
[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  * @author Fabian Stemmler
14  *
15  */
16 public class WireArray
17 {
18         private Bit[] values;
19         public final int travelTime;
20         private List<WireArrayObserver> observers = new ArrayList<WireArrayObserver>();
21         public final int length;
22         private List<WireArrayInput> inputs = new ArrayList<WireArrayInput>();
23         
24         public WireArray(int length, int travelTime)
25         {
26                 if(length < 1)
27                         throw new IllegalArgumentException("Tried to create an array of wires with length " + length + ", but a length of less than 1 makes no sense.");
28                 this.length = length;
29                 this.travelTime = travelTime;
30                 initValues();
31         }
32         
33         private void initValues()
34         {
35                 values = new Bit[length];
36                 for(int i = 0; i < length; i++)
37                         values[i] = Bit.Z;
38         }
39         
40         private void recalculateSingleInput()
41         {
42                 WireArrayInput input = inputs.get(0);
43                 if(!Arrays.equals(input.getValues(), values))
44                 {
45                         System.arraycopy(input.getValues(), 0, values, 0, length);
46                         notifyObservers();
47                 }
48         }
49         
50         private void recalculateMultipleInputs()
51         {
52                 Iterator<WireArrayInput> it = inputs.iterator();
53                 Bit[] newValues = it.next().values.clone();
54                 
55                 while(it.hasNext())
56                 {
57                         WireArrayInput input = it.next();
58                         Bit[] bits = input.getValues();
59                         for(int i = 0; i < length; i++)
60                         {
61                                 if(Bit.Z.equals(bits[i]) || newValues[i].equals(bits[i]))
62                                         continue;
63                                 else if(Bit.Z.equals(newValues[i]))
64                                         newValues[i] = bits[i];
65                                 else
66                                         newValues[i] = Bit.X;
67                         }
68                 }
69                 
70                 if(!Arrays.equals(newValues, values))
71                 {
72                         notifyObservers();
73                         values = newValues;
74                 }
75         }
76
77         private void recalculate()
78         {
79                 switch(inputs.size())
80                 {
81                 case 0:
82                         return;
83                 case 1:
84                         recalculateSingleInput();
85                         break;
86                 default:
87                         recalculateMultipleInputs();
88                 }
89         }
90         
91         /**
92          * The WireArray is interpreted as an unsigned integer with n bits.
93          * @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 value), not <code>Bit.X</code> or <code>Bit.Z</code>. <code>false</code> is returned otherwise.
94          * 
95          * @author Fabian Stemmler
96          */
97         public boolean hasNumericValue()
98         {
99                 for(Bit b : values)
100                 {
101                         if(b != Bit.ZERO && b != Bit.ONE)
102                                 return false;
103                 }
104                 return true;
105         }
106         
107         /**
108          * The WireArray is interpreted as an unsigned integer with n bits.
109          * @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.
110          * 
111          * @author Fabian Stemmler
112          */
113         public long getUnsignedValue()
114         {
115                 long val = 0;
116                 long mask = 1;
117                 for(int i = 0; i < length; i++)
118                 {
119                         switch(values[i])
120                         {
121                         default:
122                         case Z:
123                         case X:
124                                 return 0; //TODO: Proper handling for getUnsignedValue(), if not all bits are 1 or 0; Random number?
125                         case ONE:
126                                 val |= mask;
127                                 break;
128                         case ZERO:
129                         }
130                         mask = mask << 1;
131                 }
132                 return val;
133         }
134         
135         /**
136          * The WireArray is interpreted as a signed integer with n bits.
137          * @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.
138          * 
139          * @author Fabian Stemmler
140          */
141         public long getSignedValue()
142         {
143                 long val = getUnsignedValue();
144                 long mask = 1 << (length - 1);
145                 if((mask & val) != 0)
146                 {
147                         int shifts = 64 - length;
148                         return (val << shifts) >> shifts;
149                 }
150                 return val;
151         }
152         
153         /**
154          * Included for convenient use on {@link WireArray}s of length 1.
155          * @return The value of bit 0.
156          * 
157          * @author Fabian Stemmler
158          */
159         public Bit getValue()
160         {
161                 return getValue(0);
162         }
163         
164         /**
165          * 
166          * @param index Index of the requested bit.
167          * @return The value of the indexed bit.
168          * 
169          * @author Fabian Stemmler
170          */
171         public Bit getValue(int index)
172         {
173                 return values[index];
174         }
175         
176         public Bit[] getValues(int start, int end)
177         {
178                 int length = end - start;
179                 Bit[] bits = new Bit[length];
180                 System.arraycopy(values, start, bits, 0, length);               
181                 return bits;
182         }
183         
184         
185         /**
186          * @return An array of length n containing the values of the n bits in the {@link WireArray}. Can be safely modified.
187          * 
188          * @author Fabian Stemmler
189          */
190         public Bit[] getValues()
191         {
192                 return values.clone();
193         }
194         
195         /**
196          * Adds an {@link WireArrayObserver}, who will be notified when the value of the {@link WireArray} is updated.
197          * @param ob The {@link WireArrayObserver} to be notified of changes.
198          * @return true if the given {@link WireArrayObserver} was not already registered, false otherwise
199          * 
200          * @author Fabian Stemmler
201          */
202         public boolean addObserver(WireArrayObserver ob)
203         {
204                 return observers.add(ob);
205         }
206         
207         private void notifyObservers()
208         {
209                 for(WireArrayObserver o : observers)
210                         o.update(this);
211         }
212         
213         public WireArrayInput createInput()
214         {
215                 return new WireArrayInput(this);
216         }
217         
218         private void registerInput(WireArrayInput toRegister)
219         {
220                 inputs.add(toRegister);
221         }
222         
223         public class WireArrayInput {
224                 public final WireArray owner;
225                 private Bit[] values;
226                 
227                 private WireArrayInput(WireArray owner) {
228                         super();
229                         this.owner = owner;
230                         initValues();
231                         owner.registerInput(this);
232                 }
233                 
234                 private void initValues()
235                 {
236                         values = new Bit[length];
237                         for(int i = 0; i < length; i++)
238                                 values[i] = Bit.Z;
239                 }
240                 
241                 /**
242                  * Sets the wires values. This takes up time, as specified by the {@link WireArray}s travel time.
243                  * @param newValues The new values the wires should take on.
244                  * 
245                  * @author Fabian Stemmler
246                  */
247                 public void feedSignals(Bit... newValues)
248                 {
249                         if(newValues.length == length)
250                         {
251                                 feedSignals(0, newValues);
252                         }
253                         else
254                                 throw new IllegalArgumentException("Attempted to input " + newValues.length + " bits instead of " + length + " bits.");
255                 }
256                 
257                 /**
258                  * Sets values of a subarray of wires. This takes up time, as specified by the {@link WireArray}s travel time.
259                  * @param newValues The new values the wires should take on.
260                  * @param startingBit The first index of the subarray of wires.
261                  * 
262                  * @author Fabian Stemmler
263                  */
264                 public void feedSignals(int startingBit, Bit... newValues)
265                 {
266                         Simulation.TIMELINE.addEvent((e) -> setValues(startingBit, newValues), travelTime);
267                 }
268                 
269                 private void setValues(int startingBit, Bit... newValues)
270                 {
271                         int exclLastIndex = startingBit + newValues.length;
272                         if(length < exclLastIndex)
273                                 throw new ArrayIndexOutOfBoundsException("Attempted to input bits from index " + startingBit + " to "
274                                         + exclLastIndex + " when there are only " + length + "wires.");
275                         if(!Arrays.equals(values, startingBit, exclLastIndex, newValues, 0, newValues.length))
276                         {
277                                 System.arraycopy(newValues, 0, values, startingBit, newValues.length);
278                                 owner.recalculate();
279                         }
280                 }
281                 
282                 public Bit[] getValues()
283                 {
284                         return values.clone();
285                 }
286                 
287                 public void clearSignals()
288                 {
289                         Bit[] bits = new Bit[length];
290                         for(int i = 0; i < length; i++)
291                                 bits[i] = Bit.Z;
292                         feedSignals(bits);
293                 }
294         }
295 }