1 package era.mi.logic.wires;
3 import static era.mi.logic.types.Bit.*;
5 import java.util.ArrayList;
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;
14 * Represents an array of wires that can store n bits of information.
16 * @author Fabian Stemmler
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>();
27 public Wire(int length, int travelTime)
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));
33 this.travelTime = travelTime;
37 private void initValues()
39 values = U.toVector(length);
42 private void recalculateSingleInput()
44 setNewValues(inputs.get(0).getInputValues());
47 private void recalculateMultipleInputs()
49 BitVectorMutator mutator = BitVectorMutator.empty();
50 for (WireEnd wireArrayEnd : inputs)
51 mutator.join(wireArrayEnd.getInputValues());
52 setNewValues(mutator.get());
55 private void setNewValues(BitVector newValues)
57 if (values.equals(newValues))
59 BitVector oldValues = values;
61 notifyObservers(oldValues);
64 private void recalculate()
66 switch (inputs.size())
71 recalculateSingleInput();
74 recalculateMultipleInputs();
79 * The {@link Wire} is interpreted as an unsigned integer with n bits.
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.
84 * @author Fabian Stemmler
86 public boolean hasNumericValue()
90 if (b != Bit.ZERO && b != Bit.ONE)
97 * The {@link Wire} is interpreted as an unsigned integer with n bits.
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.
101 * @author Fabian Stemmler
103 public long getUnsignedValue()
107 for (Bit bit : values)
114 return 0; // TODO: Proper handling for getUnsignedValue(), if not all bits are 1 or 0;
127 * The {@link Wire} is interpreted as a signed integer with n bits.
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.
131 * @author Fabian Stemmler
133 public long getSignedValue()
135 long val = getUnsignedValue();
136 long mask = 1 << (length - 1);
137 if ((mask & val) != 0)
139 int shifts = 64 - length;
140 return (val << shifts) >> shifts;
145 public Bit getValue()
150 public Bit getValue(int index)
152 return values.getBit(index);
155 public BitVector getValues(int start, int end)
157 return values.subVector(start, end);
160 public BitVector getValues()
166 * Adds an {@link WireObserver}, who will be notified when the value of the {@link Wire} is updated.
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
171 * @author Fabian Stemmler
173 public boolean addObserver(WireObserver ob)
175 return observers.add(ob);
178 private void notifyObservers(BitVector oldValues)
180 for (WireObserver o : observers)
181 o.update(this, oldValues);
185 * Create and register a {@link WireEnd} object, which is tied to this {@link Wire}.
187 public WireEnd createEnd()
189 return new WireEnd(false);
193 * Create a {@link WireEnd} object, which is tied to this {@link Wire}. This {@link WireEnd} cannot written to.
195 public WireEnd createReadOnlyEnd()
197 return new WireEnd(true);
200 private void registerInput(WireEnd toRegister)
202 inputs.add(toRegister);
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
210 * @author Fabian Stemmler
214 private boolean open;
215 private BitVector inputValues;
217 private WireEnd(boolean readOnly)
220 open = !readOnly; // TODO: that makes sense, doesn't it?
226 private void initValues()
228 inputValues = U.toVector(length);
232 * Sets the wires values. This takes up time, as specified by the {@link Wire}s travel time.
234 * @param newValues The new values the wires should take on.
236 * @author Fabian Stemmler
238 public void feedSignals(Bit... newValues)
240 feedSignals(BitVector.of(newValues));
243 public void feedSignals(BitVector newValues)
245 if (newValues.length() != length)
246 throw new IllegalArgumentException(
247 String.format("Attempted to input %d bits instead of %d bits.", newValues.length(), length));
249 throw new RuntimeException("Attempted to write to closed WireArrayEnd.");
250 Simulation.TIMELINE.addEvent(e -> setValues(newValues), travelTime);
254 * Sets values of a subarray of wires. This takes up time, as specified by the {@link Wire}s travel time.
256 * @param bitVector The new values the wires should take on.
257 * @param startingBit The first index of the subarray of wires.
259 * @author Fabian Stemmler
261 public void feedSignals(int startingBit, BitVector bitVector)
264 throw new RuntimeException("Attempted to write to closed WireArrayEnd.");
265 Simulation.TIMELINE.addEvent(e -> setValues(startingBit, bitVector), travelTime);
268 private void setValues(int startingBit, BitVector newValues)
270 // index check covered in equals
271 if (!inputValues.equalsWithOffset(newValues, startingBit))
273 Bit[] vals = inputValues.getBits();
274 System.arraycopy(newValues.getBits(), 0, vals, startingBit, newValues.length());
275 inputValues = BitVector.of(vals);
276 Wire.this.recalculate();
280 private void setValues(BitVector newValues)
282 if (inputValues.equals(newValues))
284 inputValues = newValues;
285 Wire.this.recalculate();
289 * @return The value (of bit 0) the {@link WireEnd} is currently feeding into the associated {@link Wire}.
291 public Bit getInputValue()
293 return getInputValue(0);
297 * @return The value which the {@link WireEnd} is currently feeding into the associated {@link Wire} at the indexed {@link Bit}.
299 public Bit getInputValue(int index)
301 return inputValues.getBit(index);
305 * @return A copy (safe to modify) of the values the {@link WireEnd} is currently feeding into the associated {@link Wire}.
307 public BitVector getInputValues()
309 return getInputValues(0, length);
312 public BitVector getInputValues(int start, int end)
314 return inputValues.subVector(start, end);
318 * {@link WireEnd} now feeds Z into the associated {@link Wire}.
320 public void clearSignals()
322 feedSignals(Z.toVector(length));
325 public BitVector wireValuesExcludingMe()
327 BitVectorMutator mutator = BitVectorMutator.empty();
328 for (WireEnd wireEnd : inputs)
332 mutator.join(wireEnd.inputValues);
334 return mutator.get();
338 * Included for convenient use on {@link Wire}s of length 1.
340 * @return The value of bit 0.
342 * @author Fabian Stemmler
344 public Bit getValue()
346 return Wire.this.getValue();
350 * @param index Index of the requested bit.
351 * @return The value of the indexed bit.
353 * @author Fabian Stemmler
355 public Bit getValue(int index)
357 return Wire.this.getValue(index);
361 * @param index Index of the requested bit.
362 * @return The value of the indexed bit.
364 * @author Fabian Stemmler
366 public BitVector getValues()
368 return Wire.this.getValues();
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.
376 * @author Fabian Stemmler
378 public BitVector getValues(int start, int end)
380 return Wire.this.getValues(start, end);
384 * The {@link Wire} is interpreted as an unsigned integer with n bits.
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.
389 * @author Fabian Stemmler
391 public boolean hasNumericValue()
393 return Wire.this.hasNumericValue();
397 * The {@link Wire} is interpreted as an unsigned integer with n bits.
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.
401 * @author Fabian Stemmler
403 public long getUnsignedValue()
405 return Wire.this.getUnsignedValue();
409 * The {@link Wire} is interpreted as a signed integer with n bits.
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.
413 * @author Fabian Stemmler
415 public long getSignedValue()
417 return Wire.this.getSignedValue();
421 public String toString()
423 return inputValues.toString();
424 // return String.format("%s \nFeeding: %s", WireArray.this.toString(), Arrays.toString(inputValues));
438 public boolean addObserver(WireObserver ob)
440 return Wire.this.addObserver(ob);
443 public Wire getWire()
450 public String toString()
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)
456 public static WireEnd[] extractEnds(Wire[] w)
458 WireEnd[] inputs = new WireEnd[w.length];
459 for (int i = 0; i < w.length; i++)
460 inputs[i] = w[i].createEnd();