From d76e70049805b48cdc5f38ed10db079fff19f414 Mon Sep 17 00:00:00 2001 From: hneemann Date: Mon, 18 Apr 2016 13:47:52 +0200 Subject: [PATCH] added a tunnel to connect nets --- .../de/neemann/digital/core/element/Keys.java | 5 ++ .../neemann/digital/draw/elements/Tunnel.java | 59 +++++++++++++ .../digital/draw/library/CustomElement.java | 6 +- .../digital/draw/library/ElementLibrary.java | 2 + .../digital/draw/model/ModelDescription.java | 2 +- .../de/neemann/digital/draw/model/Net.java | 36 +++++++- .../neemann/digital/draw/model/NetList.java | 44 ++++++++-- .../digital/draw/shapes/ShapeFactory.java | 2 + .../digital/draw/shapes/TunnelShape.java | 56 ++++++++++++ .../java/de/neemann/digital/gui/Main.java | 2 + src/main/resources/lang/lang_de.properties | 3 + src/main/resources/lang/lang_en.properties | 3 + .../digital/draw/model/NetListTest.java | 85 ++++++++++++++++--- 13 files changed, 283 insertions(+), 22 deletions(-) create mode 100644 src/main/java/de/neemann/digital/draw/elements/Tunnel.java create mode 100644 src/main/java/de/neemann/digital/draw/shapes/TunnelShape.java diff --git a/src/main/java/de/neemann/digital/core/element/Keys.java b/src/main/java/de/neemann/digital/core/element/Keys.java index 734e06296..6be059ec7 100644 --- a/src/main/java/de/neemann/digital/core/element/Keys.java +++ b/src/main/java/de/neemann/digital/core/element/Keys.java @@ -186,4 +186,9 @@ public final class Keys { public static final Key DESCRIPTION = new Key<>("Description", ""); + /** + * A net name + */ + public static final Key NETNAME + = new Key<>("NetName", ""); } diff --git a/src/main/java/de/neemann/digital/draw/elements/Tunnel.java b/src/main/java/de/neemann/digital/draw/elements/Tunnel.java new file mode 100644 index 000000000..ce9d5d4e7 --- /dev/null +++ b/src/main/java/de/neemann/digital/draw/elements/Tunnel.java @@ -0,0 +1,59 @@ +package de.neemann.digital.draw.elements; + +import de.neemann.digital.core.Model; +import de.neemann.digital.core.NodeException; +import de.neemann.digital.core.ObservableValue; +import de.neemann.digital.core.element.Element; +import de.neemann.digital.core.element.ElementAttributes; +import de.neemann.digital.core.element.ElementTypeDescription; +import de.neemann.digital.core.element.Keys; + +import static de.neemann.digital.core.element.PinInfo.input; + +/** + * Allows a tunneling of wires to make the schematic more readable then drawing + * long wires. + * + * @author hneemann + */ +public class Tunnel implements Element { + + /** + * The TunnelElement description + */ + public static final ElementTypeDescription DESCRIPTION + = new ElementTypeDescription(Tunnel.class, input("in")) + .addAttribute(Keys.ROTATE) + .addAttribute(Keys.NETNAME); + + private final String label; + + /** + * Creates a new instance + * + * @param attributes the attributes + */ + public Tunnel(ElementAttributes attributes) { + this.label = attributes.getLabel(); + } + + /** + * @return the label + */ + public String getLabel() { + return label; + } + + @Override + public void setInputs(ObservableValue... inputs) throws NodeException { + } + + @Override + public ObservableValue[] getOutputs() { + return new ObservableValue[0]; + } + + @Override + public void registerNodes(Model model) { + } +} diff --git a/src/main/java/de/neemann/digital/draw/library/CustomElement.java b/src/main/java/de/neemann/digital/draw/library/CustomElement.java index 43e2e32e6..78d365b5c 100644 --- a/src/main/java/de/neemann/digital/draw/library/CustomElement.java +++ b/src/main/java/de/neemann/digital/draw/library/CustomElement.java @@ -18,10 +18,10 @@ import de.neemann.digital.draw.model.NetList; */ public class CustomElement implements Element { - private final NetList netList; private final Circuit circuit; private final ElementLibrary library; private final String name; + private NetList netList; /** * Creates a new custom element @@ -34,7 +34,6 @@ public class CustomElement implements Element { this.circuit = circuit; this.library = library; this.name = name; - netList = new NetList(circuit.getWires()); } /** @@ -46,6 +45,9 @@ public class CustomElement implements Element { * @throws NodeException NodeException */ public ModelDescription getModelDescription() throws PinException, NodeException { + if (netList == null) + netList = new NetList(circuit); + return new ModelDescription(circuit, library, true, name, new NetList(netList)); } diff --git a/src/main/java/de/neemann/digital/draw/library/ElementLibrary.java b/src/main/java/de/neemann/digital/draw/library/ElementLibrary.java index e2950560f..92ae2cd25 100644 --- a/src/main/java/de/neemann/digital/draw/library/ElementLibrary.java +++ b/src/main/java/de/neemann/digital/draw/library/ElementLibrary.java @@ -10,6 +10,7 @@ import de.neemann.digital.core.flipflops.FlipflopT; import de.neemann.digital.core.io.*; import de.neemann.digital.core.memory.*; import de.neemann.digital.core.wiring.*; +import de.neemann.digital.draw.elements.Tunnel; import de.neemann.digital.gui.components.data.DummyElement; import de.neemann.digital.gui.components.terminal.Terminal; import de.neemann.digital.lang.Lang; @@ -63,6 +64,7 @@ public class ElementLibrary implements Iterable add(Splitter.DESCRIPTION, menu); add(Clock.DESCRIPTION, menu); add(Delay.DESCRIPTION, menu); + add(Tunnel.DESCRIPTION, menu); add(Driver.DESCRIPTION, menu); add(Reset.DESCRIPTION, menu); add(Break.DESCRIPTION, menu); diff --git a/src/main/java/de/neemann/digital/draw/model/ModelDescription.java b/src/main/java/de/neemann/digital/draw/model/ModelDescription.java index 1c7ca10d8..2134d4389 100644 --- a/src/main/java/de/neemann/digital/draw/model/ModelDescription.java +++ b/src/main/java/de/neemann/digital/draw/model/ModelDescription.java @@ -54,7 +54,7 @@ public class ModelDescription implements Iterable { * @throws NodeException NodeException */ public ModelDescription(Circuit circuit, ElementLibrary library, boolean readAsCustom) throws PinException, NodeException { - this(circuit, library, readAsCustom, "unknown", new NetList(circuit.getWires())); + this(circuit, library, readAsCustom, "unknown", new NetList(circuit)); } /** diff --git a/src/main/java/de/neemann/digital/draw/model/Net.java b/src/main/java/de/neemann/digital/draw/model/Net.java index 6642eff6a..2a79adb58 100644 --- a/src/main/java/de/neemann/digital/draw/model/Net.java +++ b/src/main/java/de/neemann/digital/draw/model/Net.java @@ -25,6 +25,7 @@ public class Net { private final HashSet points; private final ArrayList pins; private final ArrayList wires; + private final HashSet labelSet; /** * Creates a copy of the given net @@ -35,6 +36,7 @@ public class Net { points = toCopy.points; // no deep copy of points necessary wires = null; // wires not needed pins = new ArrayList<>(toCopy.pins); // Pins are changed so create a deep copy + labelSet = new HashSet<>(toCopy.labelSet); //ToDo copy necessary? } /** @@ -49,6 +51,7 @@ public class Net { pins = new ArrayList<>(); wires = new ArrayList<>(); wires.add(w); + labelSet = new HashSet<>(); } /** @@ -86,9 +89,10 @@ public class Net { * * @param changedNet the net to add */ - public void addAllPointsFrom(Net changedNet) { + void addAllPointsFrom(Net changedNet) { points.addAll(changedNet.points); wires.addAll(changedNet.wires); + labelSet.addAll(changedNet.labelSet); } /** @@ -187,4 +191,34 @@ public class Net { if (!pins.remove(p)) throw new PinException(Lang.get("err_pinNotPresent"), this); } + + /** + * Adds a label this this net + * + * @param label the label to add + */ + public void addLabel(String label) { + labelSet.add(label); + } + + /** + * Returns true if the given net has at least one same net label. + * + * @param net the other net + * @return true if same net + */ + public boolean matchesLabel(Net net) { + for (String l : labelSet) { + if (net.labelSet.contains(l)) + return true; + } + return false; + } + + @Override + public String toString() { + return "Net{" + + "labelSet=" + labelSet + + '}'; + } } diff --git a/src/main/java/de/neemann/digital/draw/model/NetList.java b/src/main/java/de/neemann/digital/draw/model/NetList.java index c3ef3e3c3..ae91f5206 100644 --- a/src/main/java/de/neemann/digital/draw/model/NetList.java +++ b/src/main/java/de/neemann/digital/draw/model/NetList.java @@ -1,12 +1,12 @@ package de.neemann.digital.draw.model; -import de.neemann.digital.draw.elements.Pin; -import de.neemann.digital.draw.elements.Wire; +import de.neemann.digital.core.element.Keys; +import de.neemann.digital.draw.elements.*; import de.neemann.digital.draw.graphics.Vector; +import de.neemann.digital.lang.Lang; import java.util.ArrayList; import java.util.Iterator; -import java.util.List; /** * Holds all the nets in a circuit @@ -18,14 +18,42 @@ public class NetList implements Iterable { private final ArrayList netList; /** - * Creates a net list from the given wires + * Creates a net list from the given circuit * - * @param wires the wires + * @param circuit the circuit + * @throws PinException PinException */ - public NetList(List wires) { + public NetList(Circuit circuit) throws PinException { netList = new ArrayList<>(); - for (Wire w : wires) + for (Wire w : circuit.getWires()) add(w); + + for (VisualElement ve : circuit.getElements()) + if (ve.getElementName().equals(Tunnel.DESCRIPTION.getName())) { + Vector pos = ve.getPos(); + Net found = null; + for (Net n : netList) + if (n.contains(pos)) + found = n; + + String label = ve.getElementAttributes().get(Keys.NETNAME).trim(); + if (found == null) + throw new PinException(Lang.get("err_labelNotConnectedToNet_N", label), ve); + + found.addLabel(label); + } + + mergeLabels(); + } + + private void mergeLabels() { + for (int i = 0; i < netList.size() - 1; i++) + for (int j = i + 1; j < netList.size(); j++) + if (netList.get(i).matchesLabel(netList.get(j))) { + netList.get(i).addAllPointsFrom(netList.get(j)); + netList.remove(j); + j--; + } } /** @@ -49,7 +77,7 @@ public class NetList implements Iterable { } /** - * Adds a pin to tis net list + * Adds a pin to this net list * * @param pin the pin to add */ diff --git a/src/main/java/de/neemann/digital/draw/shapes/ShapeFactory.java b/src/main/java/de/neemann/digital/draw/shapes/ShapeFactory.java index fa10dc617..7d00854e2 100644 --- a/src/main/java/de/neemann/digital/draw/shapes/ShapeFactory.java +++ b/src/main/java/de/neemann/digital/draw/shapes/ShapeFactory.java @@ -10,6 +10,7 @@ import de.neemann.digital.core.io.*; import de.neemann.digital.core.memory.RAMDualPort; import de.neemann.digital.core.memory.RAMSinglePort; import de.neemann.digital.core.wiring.*; +import de.neemann.digital.draw.elements.Tunnel; import de.neemann.digital.draw.library.ElementLibrary; import de.neemann.digital.gui.LibrarySelector; import de.neemann.digital.gui.components.data.DummyElement; @@ -67,6 +68,7 @@ public final class ShapeFactory { map.put(Splitter.DESCRIPTION.getName(), SplitterShape::new); map.put(Driver.DESCRIPTION.getName(), DriverShape::new); + map.put(Tunnel.DESCRIPTION.getName(), TunnelShape::new); map.put(DummyElement.TEXTDESCRIPTION.getName(), TextShape::new); } diff --git a/src/main/java/de/neemann/digital/draw/shapes/TunnelShape.java b/src/main/java/de/neemann/digital/draw/shapes/TunnelShape.java new file mode 100644 index 000000000..4ed9b1312 --- /dev/null +++ b/src/main/java/de/neemann/digital/draw/shapes/TunnelShape.java @@ -0,0 +1,56 @@ +package de.neemann.digital.draw.shapes; + +import de.neemann.digital.core.Observer; +import de.neemann.digital.core.element.ElementAttributes; +import de.neemann.digital.core.element.Keys; +import de.neemann.digital.core.element.PinDescription; +import de.neemann.digital.draw.elements.IOState; +import de.neemann.digital.draw.elements.Pin; +import de.neemann.digital.draw.elements.Pins; +import de.neemann.digital.draw.graphics.*; + +import static de.neemann.digital.draw.shapes.GenericShape.SIZE; +import static de.neemann.digital.draw.shapes.GenericShape.SIZE2; + +/** + * The Tunnel shape + * + * @author hneemann + */ +public class TunnelShape implements Shape { + + private final PinDescription input; + private final String label; + + /** + * Creates a new instance + * + * @param attr the attributes + * @param inputs the inputs + * @param outputs the outputs + */ + public TunnelShape(ElementAttributes attr, PinDescription[] inputs, PinDescription[] outputs) { + input = inputs[0]; + label = attr.get(Keys.NETNAME); + } + + @Override + public Pins getPins() { + return new Pins().add(new Pin(new Vector(0, 0), input)); + } + + @Override + public InteractorInterface applyStateMonitor(IOState ioState, Observer guiObserver) { + return null; + } + + @Override + public void drawTo(Graphic gr, boolean highLight) { + gr.drawPolygon(new Polygon(true) + .add(0, 0) + .add(SIZE, SIZE2) + .add(SIZE, -SIZE2), Style.NORMAL); + Vector pos = new Vector(SIZE + SIZE2, 0); + gr.drawText(pos, pos.add(1, 0), label, Orientation.LEFTCENTER, Style.SHAPE_PIN); + } +} diff --git a/src/main/java/de/neemann/digital/gui/Main.java b/src/main/java/de/neemann/digital/gui/Main.java index 8124b380f..1f1e14d19 100644 --- a/src/main/java/de/neemann/digital/gui/Main.java +++ b/src/main/java/de/neemann/digital/gui/Main.java @@ -492,6 +492,8 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, E circuitComponent.addHighLighted(e.getVisualElement()); if (e.getNet() != null) circuitComponent.addHighLighted(e.getNet().getWires()); + else if (e.getVisualElement() != null) + circuitComponent.addHighLighted(e.getVisualElement()); } else if (cause instanceof BurnException) { BurnException e = (BurnException) cause; circuitComponent.addHighLightedWires(new ObservableValue[]{e.getValue()}); diff --git a/src/main/resources/lang/lang_de.properties b/src/main/resources/lang/lang_de.properties index 9becd9c71..b0e24a21e 100644 --- a/src/main/resources/lang/lang_de.properties +++ b/src/main/resources/lang/lang_de.properties @@ -46,6 +46,8 @@ key_maxStepCount=Maximale Messpunktezahl key_microStep=Zeige Einzelgatterschritte key_isHighZ=Eingang kann hochohmig sein key_Description=Beschreibung +key_NetName=Netzname +key_NetName_tt=Alle Netze mit identischem Namen werden verbunden. elem_And=Und elem_NAnd=Nicht Und @@ -164,6 +166,7 @@ err_readOfHighZ=Lesen einer hochohmigen Leitung err_notAllOutputsSameBits=Es haben nicht alle Ausg\u00E4nge die gleiche Bitbreite err_notAllOutputsSupportHighZ=Wenn mehrere Ausg\u00E4nge verbunden sind, m\u00FCssen alle Ausg\u00E4nge Tri-State Ausg\u00E4nge sein err_breakTimeOut=Nach {0} Zyklen ist kein Break aufgetreten +err_labelNotConnectedToNet_N=Ein Tunnel {0} ist nicht verbunden! attr_dialogTitle=Eigenschaften msg_errorEditingValue=Fehler bei der Eingabe eines Wertes diff --git a/src/main/resources/lang/lang_en.properties b/src/main/resources/lang/lang_en.properties index 841301c8c..323fabc8b 100644 --- a/src/main/resources/lang/lang_en.properties +++ b/src/main/resources/lang/lang_en.properties @@ -41,6 +41,8 @@ key_microStep=Show single gate steps key_isHighZ=Is three-state input key_runRealTime=Start real time clock key_Description=Description +key_NetName=Netname +key_NetName_tt=All nets with identical name are connected together. elem_And=And elem_NAnd=NAnd @@ -248,3 +250,4 @@ elem_Decoder_tt=One selectable output line is high, all other outputs are low. elem_Decode_pin_sel=This input selects the enabled output elem_Text_tt=Shows a text in the circuit key_Default_tt=Is set if the model is started +err_labelNotConnectedToNet_N=A tunnel {0} is not connected! diff --git a/src/test/java/de/neemann/digital/draw/model/NetListTest.java b/src/test/java/de/neemann/digital/draw/model/NetListTest.java index f666707bb..2b1f5b892 100644 --- a/src/test/java/de/neemann/digital/draw/model/NetListTest.java +++ b/src/test/java/de/neemann/digital/draw/model/NetListTest.java @@ -1,26 +1,91 @@ package de.neemann.digital.draw.model; +import de.neemann.digital.core.element.Keys; +import de.neemann.digital.draw.elements.Circuit; +import de.neemann.digital.draw.elements.VisualElement; import de.neemann.digital.draw.elements.Wire; import de.neemann.digital.draw.graphics.Vector; import junit.framework.TestCase; -import java.util.ArrayList; - /** * @author hneemann */ public class NetListTest extends TestCase { public void testSimple() throws Exception { - ArrayList w = new ArrayList<>(); + Circuit c = new Circuit(); - w.add(new Wire(new Vector(1, 1), new Vector(1, 2))); - w.add(new Wire(new Vector(2, 1), new Vector(2, 2))); - w.add(new Wire(new Vector(1, 2), new Vector(2, 2))); - w.add(new Wire(new Vector(1, 1), new Vector(2, 1))); + c.add(new Wire(new Vector(1, 1), new Vector(1, 2))); + c.add(new Wire(new Vector(2, 1), new Vector(2, 2))); + c.add(new Wire(new Vector(1, 2), new Vector(2, 2))); + c.add(new Wire(new Vector(1, 1), new Vector(2, 1))); - NetList ns = new NetList(w); + NetList ns = new NetList(c); assertEquals(1, ns.size()); - } -} \ No newline at end of file + + private void addTunnel(Circuit c, Vector pos, String name) { + VisualElement ve = new VisualElement("Tunnel") + .setPos(pos); + ve.getElementAttributes().set(Keys.NETNAME, name); + c.add(ve); + } + + public void testTunnel() throws Exception { + Circuit c = new Circuit(); + + c.add(new Wire(new Vector(1, 1), new Vector(2, 1))); + addTunnel(c, new Vector(2, 1), "A"); + + c.add(new Wire(new Vector(3, 1), new Vector(4, 1))); + addTunnel(c, new Vector(3, 1), "A"); + + NetList ns = new NetList(c); + assertEquals(1, ns.size()); + } + + + public void testTunnel2() throws Exception { + Circuit c = new Circuit(); + + c.add(new Wire(new Vector(1, 1), new Vector(2, 1))); + addTunnel(c, new Vector(2, 1), "A"); + + c.add(new Wire(new Vector(3, 1), new Vector(4, 1))); + addTunnel(c, new Vector(3, 1), "A"); + + c.add(new Wire(new Vector(1, 4), new Vector(2, 4))); + addTunnel(c, new Vector(2, 4), "B"); + + c.add(new Wire(new Vector(3, 4), new Vector(4, 4))); + addTunnel(c, new Vector(3, 4), "B"); + + + NetList ns = new NetList(c); + assertEquals(2, ns.size()); + } + + public void testTunnel3() throws Exception { + Circuit c = new Circuit(); + + c.add(new Wire(new Vector(1, 1), new Vector(2, 1))); + addTunnel(c, new Vector(2, 1), "A"); + + c.add(new Wire(new Vector(3, 1), new Vector(4, 1))); + addTunnel(c, new Vector(3, 1), "A"); + addTunnel(c, new Vector(4, 1), "C"); + + c.add(new Wire(new Vector(1, 4), new Vector(2, 4))); + addTunnel(c, new Vector(2, 4), "B"); + addTunnel(c, new Vector(1, 4), "C"); + + c.add(new Wire(new Vector(3, 4), new Vector(4, 4))); + addTunnel(c, new Vector(3, 4), "B"); + + + NetList ns = new NetList(c); + assertEquals(1, ns.size()); + } + +} +