+
+ /**
+ *
+ * Fuses two wires together. If the bits change in one Wire, the other is changed accordingly immediately. Warning: The bits are
+ * permanently fused together.
+ *
+ * @param a The {@link Wire} to be fused with b
+ * @param b The {@link Wire} to be fused with a
+ */
+ public static void fuse(Wire a, Wire b)
+ {
+ fuse(a, b, 0, 0, a.width);
+ }
+
+ /**
+ * Fuses the selected bits of two wires together. If the bits change in one Wire, the other is changed accordingly immediately. Warning:
+ * The bits are permanently fused together.
+ *
+ * @param a The {@link Wire} to be (partially) fused with b
+ * @param b The {@link Wire} to be (partially) fused with a
+ * @param fromA The first bit of {@link Wire} a to be fused
+ * @param fromB The first bit of {@link Wire} b to be fused
+ * @param width The amount of bits to fuse
+ */
+ public static void fuse(Wire a, Wire b, int fromA, int fromB, int width)
+ {
+ // iterate in this direction to be fail-fast (rely on the checks in fuse(Wire, Wire, int, int)
+ for (int i = width - 1; i >= 0; i--)
+ fuse(a, b, fromA + i, fromB + i);
+ }
+
+ /**
+ * Fuses one bit of two wires together. If this bit changes in one Wire, the other is changed accordingly immediately. Warning: The bits
+ * are permanently fused together.
+ *
+ * @param a The {@link Wire} to be (partially) fused with b
+ * @param b The {@link Wire} to be (partially) fused with a
+ * @param bitA The bit of {@link Wire} a to be fused
+ * @param bitB The bit of {@link Wire} b to be fused
+ */
+ public static void fuse(Wire a, Wire b, int bitA, int bitB)
+ {
+ if (bitA >= a.width)
+ throw new IllegalArgumentException("No bit " + bitA + " in " + a + " (width " + a.width + ")");
+ if (bitB >= b.width)
+ throw new IllegalArgumentException("No bit " + bitB + " in " + b + " (width " + b.width + ")");
+ if (a.fusedBits == null)
+ a.fusedBits = new FusedBit[a.width];
+ if (b.fusedBits == null)
+ b.fusedBits = new FusedBit[b.width];
+ FusedBit oldFusionA = a.fusedBits[bitA];
+ FusedBit oldFusionB = b.fusedBits[bitB];
+ if (oldFusionA == null)
+ if (oldFusionB == null)
+ {
+ FusedBit fusion = new FusedBit();
+ fusion.addParticipatingWireBit(a, bitA);
+ fusion.addParticipatingWireBit(b, bitB);
+ } else
+ oldFusionB.addParticipatingWireBit(a, bitA);
+ else if (oldFusionB == null)
+ oldFusionA.addParticipatingWireBit(b, bitB);
+ else
+ oldFusionA.mergeOtherIntoThis(oldFusionB);
+ }
+
+ private static class FusedBit
+ {
+ private final List<WireBit> participatingWireBits;
+
+ public FusedBit()
+ {
+ this.participatingWireBits = new ArrayList<>();
+ }
+
+ public void addParticipatingWireBit(Wire w, int bit)
+ {
+ addParticipatingWireBit(new WireBit(w, bit));
+ }
+
+ private void addParticipatingWireBit(WireBit wb)
+ {
+ wb.wire.fusedBits[wb.bit] = this;
+ participatingWireBits.add(wb);
+ wb.wire.invalidateCachedValuesForAllFusedWires();
+ }
+
+ public void mergeOtherIntoThis(FusedBit other)
+ {
+ for (WireBit wb : other.participatingWireBits)
+ addParticipatingWireBit(wb);
+ }
+
+ public void invalidateCachedValuesForAllParticipatingWires()
+ {
+ for (WireBit wb : participatingWireBits)
+ wb.wire.invalidateCachedValues();
+ }
+
+ public Bit getValue()
+ {
+ Bit result = null;
+ for (WireBit wb : participatingWireBits)
+ if (!wb.wire.inputs.isEmpty())
+ {
+ Bit bit = wb.wire.bitsWithoutFusions[wb.bit];
+ result = result == null ? bit : result.join(bit);
+ }
+ return result == null ? U : result;
+ }
+ }
+
+ private static class WireBit
+ {
+ public final Wire wire;
+ public final int bit;
+
+ public WireBit(Wire wire, int bit)
+ {
+ this.wire = wire;
+ this.bit = bit;
+ }
+ }