*/\r
public class Wire\r
{\r
+ public final String name;\r
private BitVector values;\r
public final int travelTime;\r
private List<ReadEnd> attached = new ArrayList<>();\r
Timeline timeline;\r
\r
public Wire(Timeline timeline, int length, int travelTime)\r
+ {\r
+ this(timeline, length, travelTime, null);\r
+ }\r
+\r
+ public Wire(Timeline timeline, int length, int travelTime, String name)\r
{\r
if (length < 1)\r
throw new IllegalArgumentException(\r
String.format("Tried to create an array of wires with length %d, but a length of less than 1 makes no sense.", length));\r
+ this.name = name;\r
this.timeline = timeline;\r
this.length = length;\r
this.travelTime = travelTime;\r
values = U.toVector(length);\r
}\r
\r
- private void recalculateSingleInput()\r
- {\r
- setNewValues(inputs.get(0).getInputValues());\r
- }\r
-\r
- private void recalculateMultipleInputs()\r
- {\r
- BitVectorMutator mutator = BitVectorMutator.empty();\r
- for (ReadWriteEnd wireArrayEnd : inputs)\r
- mutator.join(wireArrayEnd.getInputValues());\r
- setNewValues(mutator.get());\r
- }\r
-\r
private void setNewValues(BitVector newValues)\r
{\r
if (values.equals(newValues))\r
\r
void recalculate()\r
{\r
- switch (inputs.size())\r
+ if (inputs.size() == 0)\r
+ setNewValues(BitVector.of(Bit.U, length));\r
+ else\r
{\r
- case 0:\r
- return;\r
- case 1:\r
- recalculateSingleInput();\r
- break;\r
- default:\r
- recalculateMultipleInputs();\r
+ BitVectorMutator mutator = BitVectorMutator.empty();\r
+ for (ReadWriteEnd wireArrayEnd : inputs)\r
+ mutator.join(wireArrayEnd.getInputValues());\r
+ setNewValues(mutator.toBitVector());\r
}\r
}\r
\r
+ /**\r
+ * Forces a Wire to take on specific values. If the new values differ from the old ones, the observers of the Wire will be notified.\r
+ * WARNING! Use this with care! The preferred way of writing the values is ReadWriteEnd.feedSignals(BitVector)\r
+ * \r
+ * @param values The values the <code>Wire</code> will have immediately after this method is called\r
+ */\r
+ public void forceValues(BitVector values)\r
+ {\r
+ setNewValues(values);\r
+ }\r
+\r
/**\r
* The {@link Wire} is interpreted as an unsigned integer with n bits.\r
* \r
\r
public class ReadWriteEnd extends ReadEnd\r
{\r
- private boolean open;\r
+ private boolean open, isWriting;\r
private BitVector inputValues;\r
\r
ReadWriteEnd()\r
{\r
super();\r
open = true;\r
+ isWriting = true;\r
initValues();\r
registerInput(this);\r
}\r
timeline.addEvent(e -> setValues(startingBit, bitVector), travelTime);\r
}\r
\r
- private void setValues(int startingBit, BitVector newValues)\r
+ /**\r
+ * Sets the values that are being fed into the {@link Wire}. The preferred way of setting {@link ReadWriteEnd} values is via\r
+ * feedValues(...) with a delay.\r
+ */\r
+ void setValues(int startingBit, BitVector newValues)\r
{\r
// index check covered in equals\r
if (!inputValues.equalsWithOffset(newValues, startingBit))\r
}\r
}\r
\r
- private void setValues(BitVector newValues)\r
+ /**\r
+ * Sets the values that are being fed into the {@link Wire}. The preferred way of setting {@link ReadWriteEnd} values is via\r
+ * feedValues(...) with a delay.\r
+ */\r
+ void setValues(BitVector newValues)\r
{\r
if (inputValues.equals(newValues))\r
return;\r
continue;\r
mutator.join(wireEnd.inputValues);\r
}\r
- return mutator.get();\r
+ return mutator.toBitVector();\r
}\r
\r
@Override\r
{\r
return inputValues.toString();\r
}\r
+\r
+ @Override\r
+ public void close()\r
+ {\r
+ super.close();\r
+ open = false;\r
+ }\r
+\r
+ void setWriting(boolean isWriting)\r
+ {\r
+ if (this.isWriting != isWriting)\r
+ {\r
+ this.isWriting = isWriting;\r
+ if (isWriting)\r
+ inputs.add(this);\r
+ else\r
+ inputs.remove(this);\r
+ Wire.this.recalculate();\r
+ }\r
+ }\r
+\r
+ boolean isWriting()\r
+ {\r
+ return isWriting;\r
+ }\r
}\r
\r
@Override\r
public String toString()\r
{\r
- return String.format("wire 0x%08x value: %s inputs: %s", hashCode(), values, inputs);\r
+ String name = this.name == null ? String.format("0x%08x", hashCode()) : this.name;\r
+ return String.format("wire %s value: %s inputs: %s", name, values, inputs);\r
}\r
\r
public static ReadEnd[] extractEnds(Wire[] w)\r
inputs[i] = w[i].createReadWriteEnd();\r
return inputs;\r
}\r
+\r
+ // TODO Fix ReadWriteEnd feeding signals to entire Wire (Z) instead of only selected Bits\r
+ /**\r
+ * Fuses the selected bits of two wires together. If the bits change in one Wire, the other is changed accordingly immediately. Warning:\r
+ * The bits are permanently fused together.\r
+ * \r
+ * @param a The {@link Wire} to be (partially) fused with b\r
+ * @param b The {@link Wire} to be (partially) fused with a\r
+ * @param fromA The first bit of {@link Wire} a to be fused\r
+ * @param fromB The first bit of {@link Wire} b to be fused\r
+ * @param length The amount of bits to fuse\r
+ */\r
+ public static void fuse(Wire a, Wire b, int fromA, int fromB, int length)\r
+ {\r
+ ReadWriteEnd rA = a.createReadWriteEnd(), rB = b.createReadWriteEnd();\r
+ rA.setWriting(false);\r
+ rB.setWriting(false);\r
+ rA.setValues(BitVector.of(Bit.Z, a.length));\r
+ rB.setValues(BitVector.of(Bit.Z, b.length));\r
+ Fusion aF = new Fusion(rB, fromA, fromB, length), bF = new Fusion(rA, fromB, fromA, length);\r
+ rA.registerObserver(aF);\r
+ rB.registerObserver(bF);\r
+ aF.update(rA);\r
+ bF.update(rB);\r
+ }\r
+\r
+ /**\r
+ * \r
+ * Fuses two wires together. If the bits change in one Wire, the other is changed accordingly immediately. Warning: The bits are\r
+ * permanently fused together.\r
+ * \r
+ * @param a The {@link Wire} to be fused with b\r
+ * @param b The {@link Wire} to be fused with a\r
+ */\r
+ public static void fuse(Wire a, Wire b)\r
+ {\r
+ fuse(a, b, 0, 0, a.length);\r
+ }\r
+\r
+ private static class Fusion implements LogicObserver\r
+ {\r
+ private ReadWriteEnd target;\r
+ int fromSource, fromTarget, length;\r
+\r
+ public Fusion(ReadWriteEnd target, int fromSource, int fromTarget, int length)\r
+ {\r
+ this.target = target;\r
+ this.fromSource = fromSource;\r
+ this.fromTarget = fromTarget;\r
+ this.length = length;\r
+ }\r
+\r
+ @Override\r
+ public void update(LogicObservable initiator)\r
+ {\r
+ ReadWriteEnd source = (ReadWriteEnd) initiator;\r
+ if (source.getWire().inputs.size() - (source.isWriting() ? 1 : 0) == 0)\r
+ target.setWriting(false);\r
+ else\r
+ {\r
+ target.setWriting(true);\r
+ BitVector targetInput = source.wireValuesExcludingMe().subVector(fromSource, fromSource + length);\r
+ target.setValues(fromTarget, targetInput);\r
+ }\r
+ }\r
+ }\r
}
\ No newline at end of file