diff --git a/src/main/java/de/neemann/digital/analyse/SubstituteLibrary.java b/src/main/java/de/neemann/digital/analyse/SubstituteLibrary.java index 8145d1e10..fa12a2fab 100644 --- a/src/main/java/de/neemann/digital/analyse/SubstituteLibrary.java +++ b/src/main/java/de/neemann/digital/analyse/SubstituteLibrary.java @@ -12,7 +12,6 @@ import de.neemann.digital.core.element.Keys; import de.neemann.digital.draw.elements.Circuit; import de.neemann.digital.draw.elements.PinException; import de.neemann.digital.draw.elements.VisualElement; -import de.neemann.digital.draw.library.CustomElement; import de.neemann.digital.draw.library.ElementLibrary; import de.neemann.digital.draw.library.ElementNotFoundException; import de.neemann.digital.draw.library.LibraryInterface; @@ -138,10 +137,7 @@ public class SubstituteLibrary implements LibraryInterface { Circuit circuit = Circuit.loadCircuit(in, library.getShapeFactory()); - typeDescriptionCustom = - new ElementLibrary.ElementTypeDescriptionCustom(new File(filename), - attributes -> new CustomElement(circuit, library), - circuit); + typeDescriptionCustom = ElementLibrary.createCustomDescription(new File(filename), circuit, library); } return typeDescriptionCustom; } @@ -170,9 +166,7 @@ public class SubstituteLibrary implements LibraryInterface { Circuit c = circuit.createDeepCopy(); generify(attr, c); - return new ElementLibrary.ElementTypeDescriptionCustom(new File(filename), - attributes -> new CustomElement(c, library), - c); + return ElementLibrary.createCustomDescription(new File(filename), c, library); } private void generify(ElementAttributes attr, Circuit circuit) throws IOException { diff --git a/src/main/java/de/neemann/digital/core/element/ElementTypeDescription.java b/src/main/java/de/neemann/digital/core/element/ElementTypeDescription.java index f2a8353af..afbf90aaa 100644 --- a/src/main/java/de/neemann/digital/core/element/ElementTypeDescription.java +++ b/src/main/java/de/neemann/digital/core/element/ElementTypeDescription.java @@ -22,7 +22,7 @@ public class ElementTypeDescription { private final String name; private final String langKey; private String shortName; - private final ElementFactory elementFactory; + private ElementFactory elementFactory; private final PinDescriptions inputPins; private final ArrayList attributeList; @@ -72,6 +72,15 @@ public class ElementTypeDescription { attributeList = new ArrayList<>(); } + /** + * Sets the factory to create elements. + * + * @param elementFactory the factory + */ + public void setElementFactory(ElementFactory elementFactory) { + this.elementFactory = elementFactory; + } + /** * Returns a short name which should be used to draw on the shape. * If not set, the elements name is used instead. 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 34b1efb2c..51e7822b9 100644 --- a/src/main/java/de/neemann/digital/draw/library/CustomElement.java +++ b/src/main/java/de/neemann/digital/draw/library/CustomElement.java @@ -13,8 +13,6 @@ import de.neemann.digital.draw.elements.Circuit; import de.neemann.digital.draw.elements.PinException; import de.neemann.digital.draw.elements.VisualElement; import de.neemann.digital.draw.model.ModelCreator; -import de.neemann.digital.draw.model.NetList; -import de.neemann.digital.lang.Lang; /** * This class represents a custom, nested element. @@ -22,20 +20,17 @@ import de.neemann.digital.lang.Lang; * existing circuit. So you can build hierarchical circuits. */ public class CustomElement implements Element { - private static final int MAX_DEPTH = 30; - - private final Circuit circuit; + private final ElementLibrary.ElementTypeDescriptionCustom descriptionCustom; private final ElementLibrary library; - private NetList netList; /** * Creates a new custom element * - * @param circuit the inner circuit - * @param library the library to use. + * @param descriptionCustom the inner circuit + * @param library the library to use. */ - public CustomElement(Circuit circuit, ElementLibrary library) { - this.circuit = circuit; + public CustomElement(ElementLibrary.ElementTypeDescriptionCustom descriptionCustom, ElementLibrary library) { + this.descriptionCustom = descriptionCustom; this.library = library; } @@ -52,13 +47,7 @@ public class CustomElement implements Element { * @throws ElementNotFoundException ElementNotFoundException */ public ModelCreator getModelCreator(String subName, int depth, VisualElement containingVisualElement) throws PinException, NodeException, ElementNotFoundException { - if (netList == null) - netList = new NetList(circuit); - - if (depth > MAX_DEPTH) - throw new NodeException(Lang.get("err_recursiveNestingAt_N0", circuit.getOrigin())); - - return new ModelCreator(circuit, library, true, new NetList(netList, containingVisualElement), subName, depth, containingVisualElement); + return descriptionCustom.getModelCreator(subName, depth, containingVisualElement, library); } @Override @@ -68,7 +57,7 @@ public class CustomElement implements Element { @Override public ObservableValues getOutputs() throws PinException { - return circuit.getOutputNames(); + return descriptionCustom.getCircuit().getOutputNames(); } @Override @@ -80,6 +69,6 @@ public class CustomElement implements Element { * @return the circuit which is represented by this element */ public Circuit getCircuit() { - return circuit; + return descriptionCustom.getCircuit(); } } 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 2bec384f2..cb14f9d70 100644 --- a/src/main/java/de/neemann/digital/draw/library/ElementLibrary.java +++ b/src/main/java/de/neemann/digital/draw/library/ElementLibrary.java @@ -5,6 +5,7 @@ */ package de.neemann.digital.draw.library; +import de.neemann.digital.core.NodeException; import de.neemann.digital.core.arithmetic.*; import de.neemann.digital.core.arithmetic.Comparator; import de.neemann.digital.core.basic.*; @@ -25,6 +26,9 @@ import de.neemann.digital.core.wiring.*; import de.neemann.digital.draw.elements.Circuit; import de.neemann.digital.draw.elements.PinException; import de.neemann.digital.draw.elements.Tunnel; +import de.neemann.digital.draw.elements.VisualElement; +import de.neemann.digital.draw.model.ModelCreator; +import de.neemann.digital.draw.model.NetList; import de.neemann.digital.draw.shapes.ShapeFactory; import de.neemann.digital.gui.Settings; import de.neemann.digital.gui.components.data.DummyElement; @@ -570,10 +574,8 @@ public class ElementLibrary implements Iterable } catch (FileNotFoundException e) { throw new IOException(Lang.get("err_couldNotFindIncludedFile_N0", file)); } - ElementTypeDescriptionCustom description = - new ElementTypeDescriptionCustom(file, - attributes -> new CustomElement(circuit, ElementLibrary.this), - circuit); + + ElementTypeDescriptionCustom description = createCustomDescription(file, circuit, this); description.setShortName(createShortName(file)); String descriptionText = Lang.evalMultilingualContent(circuit.getAttributes().get(Keys.DESCRIPTION)); @@ -600,25 +602,41 @@ public class ElementLibrary implements Iterable return transName; } + /** + * Creates a custom element description. + * + * @param file the file + * @param circuit the circuit + * @param library the used library + * @return the type description + * @throws PinException PinException + */ + public static ElementTypeDescriptionCustom createCustomDescription(File file, Circuit circuit, ElementLibrary library) throws PinException { + ElementTypeDescriptionCustom d = new ElementTypeDescriptionCustom(file, circuit); + d.setElementFactory(attributes -> new CustomElement(d, library)); + return d; + } + /** * The description of a nested element. * This is a complete circuit which is used as a element. */ - public static class ElementTypeDescriptionCustom extends ElementTypeDescription { + public static final class ElementTypeDescriptionCustom extends ElementTypeDescription { + private static final int MAX_DEPTH = 30; private final File file; private final Circuit circuit; private String description; + private NetList netList; /** * Creates a new element * - * @param file the file which is loaded - * @param elementFactory a element factory which is used to create concrete elements if needed - * @param circuit the circuit + * @param file the file which is loaded + * @param circuit the circuit * @throws PinException PinException */ - public ElementTypeDescriptionCustom(File file, ElementFactory elementFactory, Circuit circuit) throws PinException { - super(file.getName(), elementFactory, circuit.getInputNames()); + private ElementTypeDescriptionCustom(File file, Circuit circuit) throws PinException { + super(file.getName(), (ElementFactory) null, circuit.getInputNames()); this.file = file; this.circuit = circuit; setShortName(file.getName()); @@ -668,6 +686,29 @@ public class ElementLibrary implements Iterable return super.getDescription(elementAttributes); } + /** + * Gets a {@link ModelCreator} of this circuit. + * Every time this method is called a new {@link ModelCreator} is created. + * + * @param subName name of the circuit, used to name unique elements + * @param depth recursion depth, used to detect a circuit which contains itself + * @param containingVisualElement the containing visual element + * @param library the library used + * @return the {@link ModelCreator} + * @throws PinException PinException + * @throws NodeException NodeException + * @throws ElementNotFoundException ElementNotFoundException + */ + public ModelCreator getModelCreator(String subName, int depth, VisualElement containingVisualElement, ElementLibrary library) throws PinException, NodeException, ElementNotFoundException { + if (netList == null) + netList = new NetList(circuit); + + if (depth > MAX_DEPTH) + throw new NodeException(Lang.get("err_recursiveNestingAt_N0", circuit.getOrigin())); + + return new ModelCreator(circuit, library, true, new NetList(netList, containingVisualElement), subName, depth, containingVisualElement); + } + } diff --git a/src/main/java/de/neemann/digital/gui/Main.java b/src/main/java/de/neemann/digital/gui/Main.java index 90a798813..ec7d3f6f6 100644 --- a/src/main/java/de/neemann/digital/gui/Main.java +++ b/src/main/java/de/neemann/digital/gui/Main.java @@ -5,9 +5,9 @@ */ package de.neemann.digital.gui; -import de.neemann.digital.analyse.SubstituteLibrary; import de.neemann.digital.analyse.AnalyseException; import de.neemann.digital.analyse.ModelAnalyser; +import de.neemann.digital.analyse.SubstituteLibrary; import de.neemann.digital.analyse.TruthTable; import de.neemann.digital.analyse.expression.format.FormatToExpression; import de.neemann.digital.core.*; @@ -21,7 +21,6 @@ import de.neemann.digital.core.wiring.Clock; import de.neemann.digital.draw.elements.*; import de.neemann.digital.draw.gif.GifExporter; import de.neemann.digital.draw.graphics.*; -import de.neemann.digital.draw.library.CustomElement; import de.neemann.digital.draw.library.ElementLibrary; import de.neemann.digital.draw.library.ElementNotFoundException; import de.neemann.digital.draw.model.AsyncSequentialClock; @@ -51,10 +50,10 @@ import de.neemann.digital.gui.state.StateManager; import de.neemann.digital.hdl.printer.CodePrinter; import de.neemann.digital.hdl.verilog2.VerilogGenerator; import de.neemann.digital.hdl.vhdl2.VHDLGenerator; -import de.neemann.digital.toolchain.Configuration; import de.neemann.digital.lang.Lang; import de.neemann.digital.testing.TestCaseElement; import de.neemann.digital.testing.TestingDataException; +import de.neemann.digital.toolchain.Configuration; import de.neemann.digital.undo.ChangedListener; import de.neemann.digital.undo.Modifications; import de.neemann.gui.*; @@ -370,9 +369,7 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS file = new File(name); try { ElementLibrary.ElementTypeDescriptionCustom description = - new ElementLibrary.ElementTypeDescriptionCustom(file, - attributes -> new CustomElement(circuit, library), - circuit); + ElementLibrary.createCustomDescription(file, circuit, library); description.setShortName(name); description.setDescription(Lang.evalMultilingualContent(circuit.getAttributes().get(Keys.DESCRIPTION))); new ElementHelpDialog(Main.this, description, circuit.getAttributes()).setVisible(true); diff --git a/src/test/java/de/neemann/digital/analyse/ModelAnalyserTest.java b/src/test/java/de/neemann/digital/analyse/ModelAnalyserTest.java index 64b59a480..baf8c9ee6 100644 --- a/src/test/java/de/neemann/digital/analyse/ModelAnalyserTest.java +++ b/src/test/java/de/neemann/digital/analyse/ModelAnalyserTest.java @@ -71,12 +71,24 @@ public class ModelAnalyserTest extends TestCase { check2BitCounter(tt); } + public void testAnalyzerDFFInvIn() throws Exception { + Model model = createModel("dig/analyze/analyzeTestDFFInvIn.dig"); + TruthTable tt = new ModelAnalyser(model).analyse(); + check2BitCounter(tt); + } + public void testAnalyzerJKFF() throws Exception { Model model = createModel("dig/analyze/analyzeTestJKFF.dig"); TruthTable tt = new ModelAnalyser(model).analyse(); check2BitCounter(tt); } + public void testAnalyzerJKFFInvInput() throws Exception { + Model model = createModel("dig/analyze/analyzeTestJKFFInvIn.dig"); + TruthTable tt = new ModelAnalyser(model).analyse(); + check2BitCounter(tt); + } + public void testAnalyzerTFF() throws Exception { Model model = createModel("dig/analyze/analyzeTestTFF.dig"); TruthTable tt = new ModelAnalyser(model).analyse(); @@ -89,6 +101,12 @@ public class ModelAnalyserTest extends TestCase { check2BitCounter(tt); } + public void testAnalyzerTFFEnableInvIn() throws Exception { + Model model = createModel("dig/analyze/analyzeTestTFFEnableInvIn.dig"); + TruthTable tt = new ModelAnalyser(model).analyse(); + check2BitCounter(tt); + } + private void check2BitCounter(TruthTable tt) { assertEquals(4, tt.getRows()); assertEquals(4, tt.getCols()); diff --git a/src/test/resources/dig/analyze/analyzeTestDFFInvIn.dig b/src/test/resources/dig/analyze/analyzeTestDFFInvIn.dig new file mode 100644 index 000000000..ba3a533c8 --- /dev/null +++ b/src/test/resources/dig/analyze/analyzeTestDFFInvIn.dig @@ -0,0 +1,285 @@ + + + 1 + + + + Tunnel + + + Inputs + 1 + + + NetName + Q_1n + + + + + + D_FF + + + Label + Q_1n + + + inverterConfig + + D + + + + Inputs + 1 + + + + + + And + + + + + And + + + + + Tunnel + + + Inputs + 1 + + + NetName + Q_0n + + + + + + D_FF + + + Label + Q_0n + + + Inputs + 1 + + + + + + Tunnel + + + rotation + + + + NetName + Q_0n + + + + + + Not + + + rotation + + + + + + + Tunnel + + + rotation + + + + NetName + Q_1n + + + + + + Not + + + rotation + + + + + + + Clock + + + runRealTime + true + + + rotation + + + + Label + C + + + + + + NOr + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/dig/analyze/analyzeTestJKFFInvIn.dig b/src/test/resources/dig/analyze/analyzeTestJKFFInvIn.dig new file mode 100644 index 000000000..d75198775 --- /dev/null +++ b/src/test/resources/dig/analyze/analyzeTestJKFFInvIn.dig @@ -0,0 +1,107 @@ + + + 1 + + + + JK_FF + + + Label + Q_1n + + + inverterConfig + + J + K + + + + + + + JK_FF + + + Label + Q_0n + + + + + + Clock + + + + + Const + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/dig/analyze/analyzeTestTFFEnableInvIn.dig b/src/test/resources/dig/analyze/analyzeTestTFFEnableInvIn.dig new file mode 100644 index 000000000..d8d3ec3fd --- /dev/null +++ b/src/test/resources/dig/analyze/analyzeTestTFFEnableInvIn.dig @@ -0,0 +1,90 @@ + + + 1 + + + + Clock + + + + + T_FF + + + Label + Q_1n + + + inverterConfig + + T + + + + + + + T_FF + + + Label + Q_0n + + + + + + VDD + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file