diff --git a/src/main/java/de/neemann/digital/analyse/SubstituteLibrary.java b/src/main/java/de/neemann/digital/analyse/SubstituteLibrary.java index ffc8db1ce..516685646 100644 --- a/src/main/java/de/neemann/digital/analyse/SubstituteLibrary.java +++ b/src/main/java/de/neemann/digital/analyse/SubstituteLibrary.java @@ -150,7 +150,7 @@ public class SubstituteLibrary implements LibraryInterface { c.getAttributes().set(Keys.IS_GENERIC, false); generify(attr, c); - return ElementLibrary.createCustomDescription(new File(filename), c, library).isSubstitutedBuiltIn(); + 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/ElementAttributes.java b/src/main/java/de/neemann/digital/core/element/ElementAttributes.java index 6140da0fd..691045a30 100644 --- a/src/main/java/de/neemann/digital/core/element/ElementAttributes.java +++ b/src/main/java/de/neemann/digital/core/element/ElementAttributes.java @@ -295,12 +295,24 @@ public class ElementAttributes implements HGSMap { return get(k); } + /** + * Adds a value to the instance specific cache + * + * @param key key + * @param value value + */ public void putToCache(String key, Object value) { if (cache == null) cache = new HashMap<>(); cache.put(key, value); } + /** + * Requests a value from the cache + * + * @param key the key + * @return the value + */ public Object getFromCache(String key) { if (cache == null) return null; 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 9b84c99d5..c4dbcd5ad 100644 --- a/src/main/java/de/neemann/digital/core/element/Keys.java +++ b/src/main/java/de/neemann/digital/core/element/Keys.java @@ -831,7 +831,13 @@ public final class Keys { * Used to input statements to generify a circuit. */ public static final Key GENERIC = - new Key.LongString("generic").allowGroupEdit(); + new Key.LongString("generic").setLineNumbers(true).allowGroupEdit(); + + /** + * Used to input statements to generify a circuit. + */ + public static final Key GENERICLARGE = + new Key.LongString("generic").setLineNumbers(true).setRows(20).allowGroupEdit(); /** * Circuit is generic diff --git a/src/main/java/de/neemann/digital/draw/elements/VisualElement.java b/src/main/java/de/neemann/digital/draw/elements/VisualElement.java index cc8165ce9..8274ffa83 100644 --- a/src/main/java/de/neemann/digital/draw/elements/VisualElement.java +++ b/src/main/java/de/neemann/digital/draw/elements/VisualElement.java @@ -11,7 +11,6 @@ import de.neemann.digital.draw.graphics.*; import de.neemann.digital.draw.shapes.Shape; import de.neemann.digital.draw.shapes.*; import de.neemann.digital.gui.components.CircuitComponent; -import de.neemann.digital.hdl.hgs.Context; import de.neemann.gui.Screen; import javax.swing.*; 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 1bad69314..2502bce9a 100644 --- a/src/main/java/de/neemann/digital/draw/library/ElementLibrary.java +++ b/src/main/java/de/neemann/digital/draw/library/ElementLibrary.java @@ -226,6 +226,7 @@ public class ElementLibrary implements Iterable .add(new LibraryNode(Lang.get("lib_misc")) .add(TestCaseElement.DESCRIPTION) .add(GenericInitCode.DESCRIPTION) + .add(GenericCode.DESCRIPTION) .add(DummyElement.RECTDESCRIPTION) .add(PowerSupply.DESCRIPTION) .add(BusSplitter.DESCRIPTION) @@ -619,6 +620,7 @@ public class ElementLibrary implements Iterable * * @param file the file * @param circuit the circuit + * @param library the library * @return the type description * @throws PinException PinException */ diff --git a/src/main/java/de/neemann/digital/draw/library/ElementTypeDescriptionCustom.java b/src/main/java/de/neemann/digital/draw/library/ElementTypeDescriptionCustom.java index 35b61b115..a98947286 100644 --- a/src/main/java/de/neemann/digital/draw/library/ElementTypeDescriptionCustom.java +++ b/src/main/java/de/neemann/digital/draw/library/ElementTypeDescriptionCustom.java @@ -35,7 +35,6 @@ public final class ElementTypeDescriptionCustom extends ElementTypeDescription { private final LibraryInterface library; private String description; private NetList netList; - private boolean isCustom = true; private String declarationDefault; /** @@ -127,21 +126,6 @@ public final class ElementTypeDescriptionCustom extends ElementTypeDescription { return new ModelCreator(circuit, library, true, new NetList(netList, errorVisualElement), subName, depth, errorVisualElement); } - public boolean isCustom() { - return isCustom; - } - - /** - * Used by element substitution to allow to mark custom circuits which replace a built-in - * component to be not custom. - * - * @return this for chained calls - */ - public ElementTypeDescriptionCustom isSubstitutedBuiltIn() { - isCustom = false; - return this; - } - /** * @return the generics field default value * @throws NodeException NodeException diff --git a/src/main/java/de/neemann/digital/draw/library/GenericCode.java b/src/main/java/de/neemann/digital/draw/library/GenericCode.java new file mode 100644 index 000000000..fcfaf68e6 --- /dev/null +++ b/src/main/java/de/neemann/digital/draw/library/GenericCode.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020 Helmut Neemann. + * Use of this source code is governed by the GPL v3 license + * that can be found in the LICENSE file. + */ +package de.neemann.digital.draw.library; + +import de.neemann.digital.core.Model; +import de.neemann.digital.core.NodeException; +import de.neemann.digital.core.ObservableValues; +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; + +/** + * Allows to a generic init code to a circuit. + */ +public class GenericCode implements Element { + /** + * The GenericInitCodeElement description + */ + public static final ElementTypeDescription DESCRIPTION + = new ElementTypeDescription(GenericCode.class) + .addAttribute(Keys.GENERICLARGE) + .supportsHDL(); + + /** + * creates a new instance + * + * @param attributes the attributes + */ + public GenericCode(ElementAttributes attributes) { + } + + @Override + public void setInputs(ObservableValues inputs) throws NodeException { + } + + @Override + public ObservableValues getOutputs() { + return ObservableValues.EMPTY_LIST; + } + + @Override + public void registerNodes(Model model) { + } +} diff --git a/src/main/java/de/neemann/digital/draw/library/ResolveGenerics.java b/src/main/java/de/neemann/digital/draw/library/ResolveGenerics.java index efebfa861..9b1e53b09 100644 --- a/src/main/java/de/neemann/digital/draw/library/ResolveGenerics.java +++ b/src/main/java/de/neemann/digital/draw/library/ResolveGenerics.java @@ -31,11 +31,13 @@ import static de.neemann.digital.draw.shapes.GenericShape.SIZE; */ public class ResolveGenerics { private static final Logger LOGGER = LoggerFactory.getLogger(ResolveGenerics.class); - private static final Context EMPTY_CONTEXT = new Context(); + /** + * Key uses to store the args for the generic circuits + */ public static final String GEN_ARGS_KEY = "genArgs"; private final HashMap map; - private final HashMap circuitMap; + private final HashMap circuitMap; private final Circuit circuit; private final LibraryInterface library; @@ -61,23 +63,57 @@ public class ResolveGenerics { * @throws ElementNotFoundException ElementNotFoundException */ public CircuitHolder resolveCircuit(ElementAttributes attributes) throws NodeException, ElementNotFoundException { - Context context = EMPTY_CONTEXT; - if (attributes != null) - context = (Context) attributes.getFromCache(GEN_ARGS_KEY); + Args args; + if (attributes == null) + args = createArgsFromGenericBlock(); + else + args = createArgsFromParentCircuitEmbedding(attributes); - CircuitHolder ch = circuitMap.get(context); + CircuitHolder ch = circuitMap.get(args); if (ch == null) { - ch = innerResolveCircuit(attributes); - circuitMap.put(context, ch); + ch = innerResolveCircuit(args); + circuitMap.put(args, ch); } return ch; } - public CircuitHolder innerResolveCircuit(ElementAttributes parentAttributes) throws NodeException, ElementNotFoundException { + private Args createArgsFromParentCircuitEmbedding(ElementAttributes attributes) throws NodeException { + Context context = (Context) attributes.getFromCache(GEN_ARGS_KEY); + if (context == null) { + String argsCode = attributes.get(Keys.GENERIC); + try { + Statement s = getStatement(argsCode); + context = new Context(); + s.execute(context); + } catch (HGSEvalException | ParserException | IOException e) { + final NodeException ex = new NodeException(Lang.get("err_evaluatingGenericsCode_N_N", null, argsCode), e); + ex.setOrigin(circuit.getOrigin()); + throw ex; + } + } + return new Args(context); + } + + private Args createArgsFromGenericBlock() throws NodeException { + Context context = new Context(); + List g = circuit.getElements(v -> v.equalsDescription(GenericInitCode.DESCRIPTION) && v.getElementAttributes().get(Keys.ENABLED)); + if (g.size() == 0) + throw new NodeException(Lang.get("err_noGenericInitCode")); + if (g.size() > 1) + throw new NodeException(Lang.get("err_multipleGenericInitCodes")); + String argsCode = g.get(0).getElementAttributes().get(Keys.GENERIC); + try { + getStatement(argsCode).execute(context); + } catch (IOException | ParserException | HGSEvalException e) { + throw new NodeException(Lang.get("err_inGenericInitCode"), e); + } + return new Args(context); + } + + private CircuitHolder innerResolveCircuit(Args args) throws NodeException, ElementNotFoundException { LOGGER.info("create concrete circuit based on " + circuit.getOrigin()); final Circuit c = circuit.createDeepCopy(); ArrayList newComponents = new ArrayList<>(); - final Args args = createArgs(parentAttributes, c, newComponents); for (VisualElement ve : c.getElements()) { ElementAttributes elementAttributes = ve.getElementAttributes(); @@ -125,40 +161,6 @@ public class ResolveGenerics { } } - private Args createArgs(ElementAttributes attributes, Circuit circuit, ArrayList newComponents) throws NodeException { - Context context; - if (attributes != null) { - context = (Context) attributes.getFromCache(GEN_ARGS_KEY); - if (context == null) { - String argsCode = attributes.get(Keys.GENERIC); - try { - Statement s = getStatement(argsCode); - context = createContext(circuit, newComponents); - s.execute(context); - } catch (HGSEvalException | ParserException | IOException e) { - final NodeException ex = new NodeException(Lang.get("err_evaluatingGenericsCode_N_N", null, argsCode), e); - ex.setOrigin(circuit.getOrigin()); - throw ex; - } - } - } else { - context = createContext(circuit, newComponents); - List g = circuit.getElements(v -> v.equalsDescription(GenericInitCode.DESCRIPTION) && v.getElementAttributes().get(Keys.ENABLED)); - if (g.size() == 0) - throw new NodeException(Lang.get("err_noGenericInitCode")); - if (g.size() > 1) - throw new NodeException(Lang.get("err_multipleGenericInitCodes")); - String argsCode = g.get(0).getElementAttributes().get(Keys.GENERIC); - try { - getStatement(argsCode).execute(context); - } catch (IOException | ParserException | HGSEvalException e) { - throw new NodeException(Lang.get("err_inGenericInitCode"), e); - } - } - - return new Args(context); - } - private Statement getStatement(String code) throws IOException, ParserException { Statement genS = map.get(code); if (genS == null) { diff --git a/src/main/java/de/neemann/digital/draw/shapes/GenericCodeShape.java b/src/main/java/de/neemann/digital/draw/shapes/GenericCodeShape.java new file mode 100644 index 000000000..e08dbedab --- /dev/null +++ b/src/main/java/de/neemann/digital/draw/shapes/GenericCodeShape.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2016 Helmut Neemann + * Use of this source code is governed by the GPL v3 license + * that can be found in the LICENSE file. + */ +package de.neemann.digital.draw.shapes; + +import de.neemann.digital.core.element.ElementAttributes; +import de.neemann.digital.core.element.Keys; +import de.neemann.digital.core.element.PinDescriptions; +import de.neemann.digital.draw.elements.IOState; +import de.neemann.digital.draw.elements.Pins; +import de.neemann.digital.draw.graphics.Graphic; +import de.neemann.digital.draw.graphics.Orientation; +import de.neemann.digital.draw.graphics.Style; +import de.neemann.digital.draw.graphics.Vector; +import de.neemann.digital.lang.Lang; + +import java.util.ArrayList; + +/** + * Simple text + */ +public class GenericCodeShape implements Shape { + private static final Style STYLE = Style.NORMAL.deriveFontStyle(Style.NORMAL.getFontSize(), true); + + private final ArrayList text; + + /** + * Create a new instance + * + * @param attr attributes + * @param inputs the inputs + * @param outputs the outputs + */ + public GenericCodeShape(ElementAttributes attr, PinDescriptions inputs, PinDescriptions outputs) { + String gen = attr.get(Keys.GENERIC); + text = new ArrayList<>(); + if (gen.isEmpty()) + text.add(Lang.get("elem_GenericCode")); + else { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < gen.length(); i++) { + char c = gen.charAt(i); + switch (c) { + case ' ': + sb.append("\u00A0"); + break; + case '_': + sb.append("\\_"); + break; + case '^': + sb.append("\\^"); + break; + case '\n': + text.add(sb.toString()); + sb.setLength(0); + default: + sb.append(c); + } + } + if (sb.length() > 0) + text.add(sb.toString()); + } + } + + @Override + public Pins getPins() { + return new Pins(); + } + + @Override + public Interactor applyStateMonitor(IOState ioState) { + return null; + } + + @Override + public void drawTo(Graphic graphic, Style highLight) { + Vector pos = new Vector(0, 0); + final int dy = (STYLE.getFontSize() * 20) / 16; + for (String s : text) { + graphic.drawText(pos, s, Orientation.LEFTCENTER, STYLE); + pos = pos.add(0, dy); + } + } +} 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 156fc6b95..7b77cb953 100644 --- a/src/main/java/de/neemann/digital/draw/shapes/ShapeFactory.java +++ b/src/main/java/de/neemann/digital/draw/shapes/ShapeFactory.java @@ -20,10 +20,7 @@ import de.neemann.digital.core.wiring.*; import de.neemann.digital.draw.elements.PinException; import de.neemann.digital.draw.elements.Tunnel; import de.neemann.digital.draw.graphics.Style; -import de.neemann.digital.draw.library.ElementLibrary; -import de.neemann.digital.draw.library.ElementTypeDescriptionCustom; -import de.neemann.digital.draw.library.GenericInitCode; -import de.neemann.digital.draw.library.JarComponentManager; +import de.neemann.digital.draw.library.*; import de.neemann.digital.draw.shapes.custom.CustomShape; import de.neemann.digital.draw.shapes.custom.CustomShapeDescription; import de.neemann.digital.draw.shapes.ieee.IEEEAndShape; @@ -163,6 +160,7 @@ public final class ShapeFactory { map.put(DummyElement.RECTDESCRIPTION.getName(), RectShape::new); map.put(TestCaseElement.DESCRIPTION.getName(), TestCaseShape::new); map.put(GenericInitCode.DESCRIPTION.getName(), GenericInitCodeShape::new); + map.put(GenericCode.DESCRIPTION.getName(), GenericCodeShape::new); map.put(AsyncSeq.DESCRIPTION.getName(), AsyncClockShape::new); map.put(Diode.DESCRIPTION.getName(), DiodeShape::new); diff --git a/src/main/java/de/neemann/digital/gui/components/CircuitComponent.java b/src/main/java/de/neemann/digital/gui/components/CircuitComponent.java index 0f6f4db67..c363fd9b1 100644 --- a/src/main/java/de/neemann/digital/gui/components/CircuitComponent.java +++ b/src/main/java/de/neemann/digital/gui/components/CircuitComponent.java @@ -1427,7 +1427,7 @@ public class CircuitComponent extends JComponent implements ChangedListener, Lib private ArrayList getAttributeList(VisualElement ve) throws ElementNotFoundException { ArrayList list = library.getElementType(ve.getElementName()).getAttributeList(); - if (getCircuit().getAttributes().get(Keys.IS_GENERIC) && !list.contains(Keys.GENERIC)) { + if (getCircuit().getAttributes().get(Keys.IS_GENERIC) && !(list.contains(Keys.GENERIC) || list.contains(Keys.GENERICLARGE))) { list = new ArrayList<>(list); list.add(Keys.GENERIC); } diff --git a/src/main/resources/lang/lang_de.xml b/src/main/resources/lang/lang_de.xml index 5e430b415..1edfe0f09 100644 --- a/src/main/resources/lang/lang_de.xml +++ b/src/main/resources/lang/lang_de.xml @@ -959,6 +959,10 @@ können. Soll eine generische Schaltung direkt gestartet werden, muss eine solche Komponente vorhanden sein. + Code + Code der ausgeführt wird, wenn eine generische Schaltung konkretisiert wird. + Kann z.B. benutzt werden, um einer Schaltung Komponenten oder Leitungen hinzuzufügen. + Asynchrones Timing Erlaubt die Konfiguration des Timings eines asynchronen Automaten wie z.B einer diff --git a/src/main/resources/lang/lang_en.xml b/src/main/resources/lang/lang_en.xml index c1e8d7cdf..7a1767f52 100644 --- a/src/main/resources/lang/lang_en.xml +++ b/src/main/resources/lang/lang_en.xml @@ -938,6 +938,10 @@ Code that is executed to start a generic circuit directly. If a generic circuit is to be started directly, such a component must be present. + Code + Code that is executed when a generic circuit is made concrete. + Can be used, for example, to add components or wires to a circuit. + Asynchronous Timing Allows configuration of the timing of an asynchronous sequential circuit such as a diff --git a/src/test/java/de/neemann/digital/hdl/TestHDLExportFlag.java b/src/test/java/de/neemann/digital/hdl/TestHDLExportFlag.java index 57976ab2c..2e8c82dd9 100644 --- a/src/test/java/de/neemann/digital/hdl/TestHDLExportFlag.java +++ b/src/test/java/de/neemann/digital/hdl/TestHDLExportFlag.java @@ -12,6 +12,7 @@ import de.neemann.digital.core.wiring.Clock; import de.neemann.digital.core.wiring.Splitter; import de.neemann.digital.draw.elements.Tunnel; import de.neemann.digital.draw.library.ElementLibrary; +import de.neemann.digital.draw.library.GenericCode; import de.neemann.digital.draw.library.GenericInitCode; import de.neemann.digital.hdl.vhdl2.entities.VHDLTemplate; import de.neemann.digital.testing.TestCaseElement; @@ -45,6 +46,7 @@ public class TestHDLExportFlag extends TestCase { implicitSupported.add(TestCaseElement.DESCRIPTION); implicitSupported.add(GenericInitCode.DESCRIPTION); + implicitSupported.add(GenericCode.DESCRIPTION); } public void testHDLExportFlag() { diff --git a/src/test/java/de/neemann/digital/integration/TestExamples.java b/src/test/java/de/neemann/digital/integration/TestExamples.java index 33d5a71db..f30b5318e 100644 --- a/src/test/java/de/neemann/digital/integration/TestExamples.java +++ b/src/test/java/de/neemann/digital/integration/TestExamples.java @@ -31,15 +31,8 @@ import static de.neemann.digital.draw.library.ResolveGenerics.GEN_ARGS_KEY; * Does not ensure that they work correctly if no tests are present in the circuit! */ public class TestExamples extends TestCase { - private int testCasesInFiles; - - public void testDebug() throws Exception { - File f = new File("/home/hneemann/Dokumente/Java/digital/src/main/dig/generic/barrelShifter/TestBarrelShifter.dig"); - check(f); - } - /** * Tests the examples which are distributed * diff --git a/src/test/resources/dig/backtrack/AllComponents.dig b/src/test/resources/dig/backtrack/AllComponents.dig index d8d7c50de..e77b4c23c 100644 --- a/src/test/resources/dig/backtrack/AllComponents.dig +++ b/src/test/resources/dig/backtrack/AllComponents.dig @@ -697,6 +697,11 @@ + + GenericCode + + +