diff --git a/distribution/ReleaseNotes.txt b/distribution/ReleaseNotes.txt
index 7e6430ef1..40a0012ad 100644
--- a/distribution/ReleaseNotes.txt
+++ b/distribution/ReleaseNotes.txt
@@ -7,6 +7,8 @@ HEAD, planned as v0.26
provided the translation.
- Fixed a bug in the Demuxer Verilog template that causes problems
when using multiple demuxers in the same circuit.
+- Generic circuits are easier to debug: It is possible now to create
+ a specific, concrete circuit from a generic one.
- Fixed a bug in the value editor, which occurs, if high-z is the
default value of an input.
- Fixed an issue which avoids to restart a running simulation by just
diff --git a/src/main/dig/generic/barrelShifter/barrelShifter.dig b/src/main/dig/generic/barrelShifter/barrelShifter.dig
index 97f749dd5..351b7c010 100644
--- a/src/main/dig/generic/barrelShifter/barrelShifter.dig
+++ b/src/main/dig/generic/barrelShifter/barrelShifter.dig
@@ -80,33 +80,36 @@
generic
- if (isPresent(args)) {
-
- if (args.direction="right") {
- export circuit:="shift-fixed-right-inc.dig";
- } else {
- if (args.direction="arith") {
- export circuit:="shift-fixed-arith-right-inc.dig";
- } else {
- if (args.direction="left") {
- export circuit:="shift-fixed-left-inc.dig";
- } else {
- panic("only \"left\", \"right\" or \"arith\" is allowed as direction, not \""+args.direction+"\"!");
- }
- }
- }
-
- export shiftBits:=bitsNeededFor(args.dataBits-1);
+ if (args.direction="right") {
+ export circuit:="shift-fixed-right-inc.dig";
} else {
- // used if circuit is started as the main circuit
- export circuit:="shift-fixed-left-inc.dig";
- export dataBits:=16;
- export shiftBits:=int(4);
-}
+ if (args.direction="arith") {
+ export circuit:="shift-fixed-arith-right-inc.dig";
+ } else {
+ if (args.direction="left") {
+ export circuit:="shift-fixed-left-inc.dig";
+ } else {
+ panic("only \"left\", \"right\" or \"arith\" is allowed as direction, not \""+args.direction+"\"!");
+ }
+ }
+}
+
+shiftBits:=bitsNeededFor(args.dataBits-1);
+
+ GenericInitCode
+
+
+ generic
+ dataBits := 5;
+direction := "left";
+
+
+
+
diff --git a/src/main/dig/generic/barrelShifter/shift-fixed-arith-right-inc.dig b/src/main/dig/generic/barrelShifter/shift-fixed-arith-right-inc.dig
index 504a1d409..3d39f2baf 100644
--- a/src/main/dig/generic/barrelShifter/shift-fixed-arith-right-inc.dig
+++ b/src/main/dig/generic/barrelShifter/shift-fixed-arith-right-inc.dig
@@ -106,6 +106,17 @@ this.outputBits=int(args.dataBits);
+
+ GenericInitCode
+
+
+ generic
+ dataBits := 8;
+shift := 3;
+
+
+
+
diff --git a/src/main/dig/generic/barrelShifter/shift-fixed-left-inc.dig b/src/main/dig/generic/barrelShifter/shift-fixed-left-inc.dig
index edff6777c..9e06e6548 100644
--- a/src/main/dig/generic/barrelShifter/shift-fixed-left-inc.dig
+++ b/src/main/dig/generic/barrelShifter/shift-fixed-left-inc.dig
@@ -116,6 +116,17 @@ this.'Output Splitting' = "0-"+(args.dataBits-args.shift-1);
+
+ GenericInitCode
+
+
+ generic
+ dataBits := 8;
+shift := 3;
+
+
+
+
diff --git a/src/main/dig/generic/barrelShifter/shift-fixed-right-inc.dig b/src/main/dig/generic/barrelShifter/shift-fixed-right-inc.dig
index ed307c078..0da3c4b0d 100644
--- a/src/main/dig/generic/barrelShifter/shift-fixed-right-inc.dig
+++ b/src/main/dig/generic/barrelShifter/shift-fixed-right-inc.dig
@@ -116,6 +116,17 @@ this.'Output Splitting' = args.shift+"-"+(args.dataBits-1);<
+
+ GenericInitCode
+
+
+ generic
+ dataBits := 8;
+shift := 3;
+
+
+
+
diff --git a/src/main/dig/generic/barrelShifter/shift-inc.dig b/src/main/dig/generic/barrelShifter/shift-inc.dig
index 393b19585..df277e2f4 100644
--- a/src/main/dig/generic/barrelShifter/shift-inc.dig
+++ b/src/main/dig/generic/barrelShifter/shift-inc.dig
@@ -13,14 +13,8 @@
generic
- if (isPresent(args)) {
- export shift := 1<<(args.shiftBits-1);
- setCircuit(args.circuit);
-} else {
- // used if circuit is started as the main circuit
- export dataBits:=16;
- export shift:=8;
-}
+ shift := 1<<(args.shiftBits-1);
+setCircuit(args.circuit);
@@ -92,18 +86,11 @@
generic
- if (isPresent(args)) {
- if (args.shiftBits=2) {
- export shift := 1;
- setCircuit(args.circuit);
- } else {
- export shiftBits := args.shiftBits-1;
- }
+ if (args.shiftBits=2) {
+ export shift := 1;
+ setCircuit(args.circuit);
} else {
- // used if circuit is started as the main circuit
- export dataBits:=16;
- export shiftBits:=3;
- export circuit:="shift-fixed-left-inc.dig";
+ export shiftBits := args.shiftBits-1;
}
@@ -128,6 +115,42 @@ this.'Output Splitting' = (args.shiftBits-1)+"-"+(args.shift
+
+ GenericInitCode
+
+
+ Label
+ 3 bits
+
+
+ generic
+ circuit := "shift-fixed-left-inc.dig";
+dataBits := 8;
+shiftBits := 3;
+
+
+ enabled
+ false
+
+
+
+
+
+ GenericInitCode
+
+
+ Label
+ 2 bits
+
+
+ generic
+ circuit := "shift-fixed-left-inc.dig";
+dataBits := 8;
+shiftBits := 2;
+
+
+
+
diff --git a/src/main/dig/generic/gray/GrayCounter.dig b/src/main/dig/generic/gray/GrayCounter.dig
index 844185588..7d76ae064 100644
--- a/src/main/dig/generic/gray/GrayCounter.dig
+++ b/src/main/dig/generic/gray/GrayCounter.dig
@@ -138,15 +138,23 @@ ist als drei.}}
generic
inBits:=2;
-if (isPresent(args)) {
- if (args.bits>3) {
- setCircuit("GrayNode-inc.dig");
- }
+if (args.bits>3) {
+ setCircuit("GrayNode-inc.dig");
}
+
+ GenericInitCode
+
+
+ generic
+ bits := 3;
+
+
+
+
diff --git a/src/main/dig/generic/gray/GrayFinal-inc.dig b/src/main/dig/generic/gray/GrayFinal-inc.dig
index 8dab7df63..f6fbd98c4 100644
--- a/src/main/dig/generic/gray/GrayFinal-inc.dig
+++ b/src/main/dig/generic/gray/GrayFinal-inc.dig
@@ -162,6 +162,16 @@ den Überlauf korrekt umzusetzen.}}
+
+ GenericInitCode
+
+
+ generic
+ inBits := 2;
+
+
+
+
diff --git a/src/main/dig/generic/gray/GrayNode-inc.dig b/src/main/dig/generic/gray/GrayNode-inc.dig
index 48d7d5513..a10f1dc3d 100644
--- a/src/main/dig/generic/gray/GrayNode-inc.dig
+++ b/src/main/dig/generic/gray/GrayNode-inc.dig
@@ -107,13 +107,9 @@
generic
- if (isPresent(args)) {
- export inBits := args.inBits+1;
- if (args.inBits<args.bits-2) {
- setCircuit("GrayNode-inc.dig");
- }
-} else {
- export inBits:=3;
+ export inBits := args.inBits+1;
+if (args.inBits<args.bits-2) {
+ setCircuit("GrayNode-inc.dig");
}
@@ -187,6 +183,17 @@ noch nicht erreicht ist.}}
+
+ GenericInitCode
+
+
+ generic
+ bits := 4;
+inBits := 2;
+
+
+
+
diff --git a/src/main/dig/lib/RAMs/RAM32Bit.dig b/src/main/dig/lib/RAMs/RAM32Bit.dig
index bca04268a..15d46c520 100644
--- a/src/main/dig/lib/RAMs/RAM32Bit.dig
+++ b/src/main/dig/lib/RAMs/RAM32Bit.dig
@@ -1060,6 +1060,16 @@ this.'Output Splitting'="2-"+(args.addrBits-1)+",0-0,1-
+
+ GenericInitCode
+
+
+ generic
+ addrBits := 8;
+
+
+
+
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 2fb02e471..e3988b348 100644
--- a/src/main/java/de/neemann/digital/draw/library/ElementLibrary.java
+++ b/src/main/java/de/neemann/digital/draw/library/ElementLibrary.java
@@ -220,6 +220,7 @@ public class ElementLibrary implements Iterable
.add(TransGate.DESCRIPTION))
.add(new LibraryNode(Lang.get("lib_misc"))
.add(TestCaseElement.TESTCASEDESCRIPTION)
+ .add(GenericInitCode.DESCRIPTION)
.add(DummyElement.RECTDESCRIPTION)
.add(PowerSupply.DESCRIPTION)
.add(BusSplitter.DESCRIPTION)
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 dc72b4939..82f4daa62 100644
--- a/src/main/java/de/neemann/digital/draw/library/ElementTypeDescriptionCustom.java
+++ b/src/main/java/de/neemann/digital/draw/library/ElementTypeDescriptionCustom.java
@@ -151,11 +151,18 @@ public final class ElementTypeDescriptionCustom extends ElementTypeDescription {
*/
public String getDeclarationDefault() throws NodeException {
if (declarationDefault == null)
- declarationDefault = createDeclarationDefault();
+ declarationDefault = createDeclarationDefault(circuit);
return declarationDefault;
}
- private String createDeclarationDefault() throws NodeException {
+ /**
+ * Creates the default for custom element declarations
+ *
+ * @param circuit the circuit
+ * @return the default code template
+ * @throws NodeException NodeException
+ */
+ public static String createDeclarationDefault(Circuit circuit) throws NodeException {
TreeSet nameSet = new TreeSet<>();
for (VisualElement ve : circuit.getElements()) {
String gen = ve.getElementAttributes().get(Keys.GENERIC).trim();
diff --git a/src/main/java/de/neemann/digital/draw/library/GenericInitCode.java b/src/main/java/de/neemann/digital/draw/library/GenericInitCode.java
new file mode 100644
index 000000000..165069fc2
--- /dev/null
+++ b/src/main/java/de/neemann/digital/draw/library/GenericInitCode.java
@@ -0,0 +1,50 @@
+/*
+ * 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 GenericInitCode implements Element {
+ /**
+ * The GenericInitCodeElement description
+ */
+ public static final ElementTypeDescription DESCRIPTION
+ = new ElementTypeDescription(GenericInitCode.class)
+ .addAttribute(Keys.LABEL)
+ .addAttribute(Keys.ENABLED)
+ .addAttribute(Keys.GENERIC)
+ .supportsHDL();
+
+ /**
+ * creates a new instance
+ *
+ * @param attributes the attributes
+ */
+ public GenericInitCode(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 ebfee72e0..06536b0c6 100644
--- a/src/main/java/de/neemann/digital/draw/library/ResolveGenerics.java
+++ b/src/main/java/de/neemann/digital/draw/library/ResolveGenerics.java
@@ -12,10 +12,13 @@ import de.neemann.digital.draw.elements.Circuit;
import de.neemann.digital.draw.elements.VisualElement;
import de.neemann.digital.hdl.hgs.*;
import de.neemann.digital.hdl.hgs.function.Function;
+import de.neemann.digital.hdl.hgs.function.InnerFunction;
import de.neemann.digital.lang.Lang;
import java.io.IOException;
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
import java.util.Objects;
/**
@@ -24,6 +27,7 @@ import java.util.Objects;
public class ResolveGenerics {
private final HashMap map;
+ private LibraryInterface library;
/**
* Creates a new instance
@@ -43,6 +47,7 @@ public class ResolveGenerics {
* @throws ElementNotFoundException ElementNotFoundException
*/
public CircuitHolder resolveCircuit(VisualElement visualElement, Circuit circuit, LibraryInterface library) throws NodeException, ElementNotFoundException {
+ this.library = library;
final Args args = createArgs(visualElement, circuit);
Circuit c = circuit.createDeepCopy();
@@ -52,18 +57,17 @@ public class ResolveGenerics {
if (!gen.isEmpty()) {
boolean isCustom = library.getElementType(ve.getElementName(), ve.getElementAttributes()).isCustom();
Statement genS = getStatement(gen);
+ Context mod = new Context();
if (isCustom) {
- Context mod = new Context()
- .declareVar("args", args)
+ mod.declareVar("args", args)
.declareFunc("setCircuit", new SetCircuitFunc(ve));
genS.execute(mod);
- ve.setGenericArgs(mod);
} else {
- Context mod = new Context()
- .declareVar("args", args)
+ mod.declareVar("args", args)
.declareVar("this", new SubstituteLibrary.AllowSetAttributes(ve.getElementAttributes()));
genS.execute(mod);
}
+ ve.setGenericArgs(mod);
}
} catch (HGSEvalException | ParserException | IOException e) {
final NodeException ex = new NodeException(Lang.get("err_evaluatingGenericsCode_N_N", ve, gen), e);
@@ -90,8 +94,20 @@ public class ResolveGenerics {
throw ex;
}
}
- } else
+ } else {
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);
}
@@ -145,7 +161,7 @@ public class ResolveGenerics {
/**
* Holds the circuit and the args that created that circuit.
*/
- public static final class CircuitHolder {
+ public final class CircuitHolder {
private final Circuit circuit;
private final Args args;
@@ -167,12 +183,80 @@ public class ResolveGenerics {
public Args getArgs() {
return args;
}
+
+ /**
+ * Converts a circuit that is only suitable for creating a model
+ * to a circuit that can also be edited and saved.
+ *
+ * @return this for chained calls
+ */
+ public CircuitHolder cleanupConcreteCircuit() {
+ for (VisualElement gic : circuit.getElements(v -> v.equalsDescription(GenericInitCode.DESCRIPTION)))
+ circuit.delete(gic);
+ for (VisualElement v : circuit.getElements()) {
+ try {
+ boolean isCustom = library.getElementType(v.getElementName(), v.getElementAttributes()).isCustom();
+ if (isCustom)
+ v.getElementAttributes().set(Keys.GENERIC, createGenericCode(v.getGenericArgs()));
+ else
+ v.getElementAttributes().set(Keys.GENERIC, "");
+ } catch (ElementNotFoundException e) {
+ // can not happen
+ e.printStackTrace();
+ }
+ v.setGenericArgs(null);
+ }
+
+ circuit.getAttributes().set(Keys.IS_GENERIC, false);
+
+ return this;
+ }
+ }
+
+ private static String createGenericCode(Context args) {
+ StringBuilder sb = new StringBuilder();
+ HashSet contentSet = new HashSet<>();
+ addVal(sb, "", args, contentSet);
+ return sb.toString();
+ }
+
+ private static void addVal(StringBuilder sb, String key, Object val, HashSet contentSet) {
+ if (contentSet.contains(key))
+ return;
+
+ if (val instanceof InnerFunction)
+ return;
+
+ if (val instanceof Context) {
+ Context c = (Context) val;
+ for (String k : c.getKeySet()) {
+ Object v = c.hgsMapGet(k);
+ if (!(v instanceof Args))
+ addVal(sb, k, v, contentSet);
+ }
+ for (String k : c.getKeySet()) {
+ Object v = c.hgsMapGet(k);
+ if (v instanceof Args)
+ addVal(sb, k, ((Args) v).args, contentSet);
+ }
+ return;
+ }
+
+ contentSet.add(key);
+ sb.append(key).append(":=");
+ if (val instanceof String)
+ sb.append("\"").append(val).append("\"");
+ else if (val instanceof Integer)
+ sb.append("int(").append(val).append(")");
+ else
+ sb.append(val);
+ sb.append(";\n");
}
private static final class SetCircuitFunc extends Function {
private final VisualElement ve;
- private SetCircuitFunc(VisualElement ve) {
+ private SetCircuitFunc(VisualElement ve) {
super(1);
this.ve = ve;
}
diff --git a/src/main/java/de/neemann/digital/draw/model/ModelCreator.java b/src/main/java/de/neemann/digital/draw/model/ModelCreator.java
index 8970ec978..0a08d6101 100644
--- a/src/main/java/de/neemann/digital/draw/model/ModelCreator.java
+++ b/src/main/java/de/neemann/digital/draw/model/ModelCreator.java
@@ -19,6 +19,7 @@ import de.neemann.digital.draw.graphics.Vector;
import de.neemann.digital.draw.library.CustomElement;
import de.neemann.digital.draw.library.ElementNotFoundException;
import de.neemann.digital.draw.library.LibraryInterface;
+import de.neemann.digital.draw.library.ResolveGenerics;
import de.neemann.digital.draw.shapes.Drawable;
import de.neemann.digital.lang.Lang;
@@ -48,7 +49,24 @@ public class ModelCreator implements Iterable {
* @throws ElementNotFoundException ElementNotFoundException
*/
public ModelCreator(Circuit circuit, LibraryInterface library) throws PinException, NodeException, ElementNotFoundException {
- this(circuit, library, false);
+ this(fixGenerics(circuit, library), library, false);
+ }
+
+ /**
+ * Creates a concrete circuit from a generic on.
+ * Uses the included generic init code.
+ *
+ * @param circuit the generic circuit
+ * @param library the element library
+ * @return the concrete circuit
+ * @throws NodeException NodeException
+ * @throws ElementNotFoundException ElementNotFoundException
+ */
+ public static Circuit fixGenerics(Circuit circuit, LibraryInterface library) throws NodeException, ElementNotFoundException {
+ if (circuit.getAttributes().get(Keys.IS_GENERIC))
+ return new ResolveGenerics().resolveCircuit(null, circuit, library).getCircuit();
+ else
+ return circuit;
}
/**
diff --git a/src/main/java/de/neemann/digital/draw/shapes/GenericInitCodeShape.java b/src/main/java/de/neemann/digital/draw/shapes/GenericInitCodeShape.java
new file mode 100644
index 000000000..194ec64e9
--- /dev/null
+++ b/src/main/java/de/neemann/digital/draw/shapes/GenericInitCodeShape.java
@@ -0,0 +1,71 @@
+/*
+ * 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.*;
+
+import static de.neemann.digital.draw.graphics.Style.DISABLED;
+import static de.neemann.digital.draw.graphics.Style.NORMAL;
+import static de.neemann.digital.draw.shapes.GenericShape.SIZE;
+import static de.neemann.digital.draw.shapes.GenericShape.SIZE2;
+
+/**
+ * The shape to visualize a test case
+ */
+public class GenericInitCodeShape implements Shape {
+
+ private final String label;
+ private final boolean enabled;
+
+ /**
+ * Creates a new instance
+ *
+ * @param attributes the attributes
+ * @param inputs inputs
+ * @param outputs outputs
+ */
+ public GenericInitCodeShape(ElementAttributes attributes, PinDescriptions inputs, PinDescriptions outputs) {
+ label = attributes.getLabel();
+ enabled = attributes.get(Keys.ENABLED);
+ }
+
+ @Override
+ public Pins getPins() {
+ return new Pins();
+ }
+
+ @Override
+ public InteractorInterface applyStateMonitor(IOState ioState) {
+ return null;
+ }
+
+ @Override
+ public void drawTo(Graphic graphic, Style highLight) {
+ if (!graphic.isFlagSet(Graphic.Flag.hideTest)) {
+ Polygon pol = new Polygon(true)
+ .add(SIZE2, SIZE2)
+ .add(SIZE2 + SIZE * 6, SIZE2)
+ .add(SIZE2 + SIZE * 6, SIZE * 2 + SIZE2)
+ .add(SIZE2, SIZE * 2 + SIZE2);
+ Style textStyle = NORMAL;
+ if (enabled) {
+ graphic.drawPolygon(pol, NORMAL);
+ graphic.drawPolygon(pol, Style.THIN);
+ } else {
+ graphic.drawPolygon(pol, DISABLED);
+ textStyle = DISABLED;
+ }
+
+ graphic.drawText(new Vector(SIZE2 + SIZE * 3, SIZE + SIZE2), "generic", Orientation.CENTERCENTER, textStyle);
+ graphic.drawText(new Vector(SIZE2 + SIZE * 3, 0), label, Orientation.CENTERBOTTOM, textStyle);
+ }
+ }
+}
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 9d7559b47..eb7dbddea 100644
--- a/src/main/java/de/neemann/digital/draw/shapes/ShapeFactory.java
+++ b/src/main/java/de/neemann/digital/draw/shapes/ShapeFactory.java
@@ -22,6 +22,7 @@ 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.shapes.custom.CustomShape;
import de.neemann.digital.draw.shapes.custom.CustomShapeDescription;
@@ -158,6 +159,7 @@ public final class ShapeFactory {
map.put(DummyElement.TEXTDESCRIPTION.getName(), TextShape::new);
map.put(DummyElement.RECTDESCRIPTION.getName(), RectShape::new);
map.put(TestCaseElement.TESTCASEDESCRIPTION.getName(), TestCaseShape::new);
+ map.put(GenericInitCode.DESCRIPTION.getName(), GenericInitCodeShape::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/Main.java b/src/main/java/de/neemann/digital/gui/Main.java
index c5ba40874..efc77d073 100644
--- a/src/main/java/de/neemann/digital/gui/Main.java
+++ b/src/main/java/de/neemann/digital/gui/Main.java
@@ -1385,6 +1385,8 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
}
circuitComponent.setModeAndReset(true, model);
+ if (circuitComponent.getCircuit().getAttributes().get(Keys.IS_GENERIC))
+ circuitComponent.setCopy(modelCreator.getCircuit());
modelCreator.connectToGui();
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 84558ee74..8696c704e 100644
--- a/src/main/java/de/neemann/digital/gui/components/CircuitComponent.java
+++ b/src/main/java/de/neemann/digital/gui/components/CircuitComponent.java
@@ -1121,6 +1121,16 @@ public class CircuitComponent extends JComponent implements ChangedListener, Lib
}
}
+ if (elementType == GenericInitCode.DESCRIPTION) {
+ if (element.getElementAttributes().get(Keys.GENERIC).isEmpty()) {
+ try {
+ element.getElementAttributes().set(Keys.GENERIC, ElementTypeDescriptionCustom.createDeclarationDefault(getCircuit()));
+ } catch (NodeException ex) {
+ new ErrorMessage(Lang.get("msg_errParsingGenerics")).addCause(ex).show(CircuitComponent.this);
+ }
+ }
+ }
+
Point p = new Point(e.getX(), e.getY());
SwingUtilities.convertPointToScreen(p, CircuitComponent.this);
AttributeDialog attributeDialog = new AttributeDialog(parent, p, list, element.getElementAttributes())
@@ -1141,6 +1151,36 @@ public class CircuitComponent extends JComponent implements ChangedListener, Lib
}
}.setToolTip(Lang.get("attr_openCircuit_tt")));
}
+ if (elementType == GenericInitCode.DESCRIPTION && getCircuit().getAttributes().get(Keys.IS_GENERIC)) {
+ attributeDialog.addButton(Lang.get("attr_createConcreteCircuitLabel"), new ToolTipAction(Lang.get("attr_createConcreteCircuit")) {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ try {
+ attributeDialog.fireOk();
+ ElementAttributes modified = attributeDialog.getModifiedAttributes();
+ if (modified != null && !isLocked() && !modified.equals(element.getElementAttributes())) {
+ Modification mod = new ModifyAttributes(element, modified);
+ modify(checkNetRename(element, modified, mod));
+ }
+
+ Circuit concreteCircuit = new ResolveGenerics()
+ .resolveCircuit(element, getCircuit(), library)
+ .cleanupConcreteCircuit()
+ .getCircuit();
+
+ new Main.MainBuilder()
+ .setParent(parent)
+ .setCircuit(concreteCircuit)
+ .setLibrary(library)
+ .denyMostFileActions()
+ .keepPrefMainFile()
+ .openLater();
+ } catch (NodeException | ElementNotFoundException | Editor.EditorParseException ex) {
+ new ErrorMessage(Lang.get("attr_createConcreteCircuitErr")).addCause(ex).show(parent);
+ }
+ }
+ }.setToolTip(Lang.get("attr_createConcreteCircuit_tt")));
+ }
attributeDialog.addButton(new ToolTipAction(Lang.get("attr_help")) {
@Override
public void actionPerformed(ActionEvent actionEvent) {
@@ -1401,6 +1441,16 @@ public class CircuitComponent extends JComponent implements ChangedListener, Lib
return isManualScale;
}
+ /**
+ * Sets a copy to use temporarily to draw the circuit.
+ * Used to visualize a created concrete circuit created from a generic one.
+ *
+ * @param circuit the circuit to use.
+ */
+ public void setCopy(Circuit circuit) {
+ shallowCopy = circuit;
+ }
+
private final class PlusMinusAction extends ToolTipAction {
private final int delta;
@@ -2400,7 +2450,12 @@ public class CircuitComponent extends JComponent implements ChangedListener, Lib
}
private VisualElement getInteractiveElementAt(MouseEvent e) {
- List elementList = getCircuit().getElementListAt(getPosVector(e), false);
+ Circuit circuit;
+ if (shallowCopy != null)
+ circuit = shallowCopy;
+ else
+ circuit = getCircuit();
+ List elementList = circuit.getElementListAt(getPosVector(e), false);
for (VisualElement ve : elementList) {
if (ve.isInteractive())
return ve;
diff --git a/src/main/java/de/neemann/digital/hdl/hgs/Context.java b/src/main/java/de/neemann/digital/hdl/hgs/Context.java
index e44cf1b57..a563c0371 100644
--- a/src/main/java/de/neemann/digital/hdl/hgs/Context.java
+++ b/src/main/java/de/neemann/digital/hdl/hgs/Context.java
@@ -281,6 +281,13 @@ public class Context implements HGSMap {
return map.get(key);
}
+ /**
+ * @return the set of all contained values
+ */
+ public HashSet getKeySet() {
+ return new HashSet<>(map.keySet());
+ }
+
private static final class FunctionPrint extends InnerFunction {
private FunctionPrint() {
super(-1);
diff --git a/src/main/java/de/neemann/digital/hdl/hgs/Parser.java b/src/main/java/de/neemann/digital/hdl/hgs/Parser.java
index ee2047e64..2c24b4f84 100644
--- a/src/main/java/de/neemann/digital/hdl/hgs/Parser.java
+++ b/src/main/java/de/neemann/digital/hdl/hgs/Parser.java
@@ -13,6 +13,8 @@ import de.neemann.digital.hdl.hgs.refs.*;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
import static de.neemann.digital.hdl.hgs.Tokenizer.Token.*;
@@ -544,6 +546,8 @@ public class Parser {
Expression exp = parseExpression();
expect(CLOSE);
return exp;
+ case OPENBRACE:
+ return parseStructLiteral();
case FUNC:
FirstClassFunction func = parseFunction();
return c -> new FirstClassFunctionCall(func, c);
@@ -552,6 +556,31 @@ public class Parser {
}
}
+ private Expression parseStructLiteral() throws IOException, ParserException {
+ StructLiteral sl = new StructLiteral();
+ while (true) {
+ Tokenizer.Token t = tok.next();
+ switch (t) {
+ case CLOSEDBRACE:
+ return sl;
+ case IDENT:
+ String key = tok.getIdent();
+ expect(COLON);
+ Expression exp = parseExpression();
+ sl.add(key, exp);
+ if (nextIs(COMMA))
+ tok.consume();
+ else {
+ if (tok.peek() != CLOSEDBRACE)
+ throw newUnexpectedToken(t);
+ }
+ break;
+ default:
+ throw newUnexpectedToken(t);
+ }
+ }
+ }
+
private FirstClassFunction parseFunction() throws IOException, ParserException {
expect(OPEN);
ArrayList args = new ArrayList<>();
@@ -608,4 +637,24 @@ public class Parser {
}
}
+ private static final class StructLiteral implements Expression {
+ private final HashMap map;
+
+ private StructLiteral() {
+ map = new HashMap<>();
+ }
+
+ private void add(String key, Expression exp) {
+ map.put(key, exp);
+ }
+
+ @Override
+ public Object value(Context c) throws HGSEvalException {
+ HashMap vmap = new HashMap<>();
+ for (Map.Entry e : map.entrySet())
+ vmap.put(e.getKey(), e.getValue().value(c));
+ return vmap;
+ }
+
+ }
}
diff --git a/src/main/java/de/neemann/digital/hdl/model2/HDLCircuit.java b/src/main/java/de/neemann/digital/hdl/model2/HDLCircuit.java
index 2a9ce07c0..1d3cc7cc5 100644
--- a/src/main/java/de/neemann/digital/hdl/model2/HDLCircuit.java
+++ b/src/main/java/de/neemann/digital/hdl/model2/HDLCircuit.java
@@ -18,6 +18,7 @@ import de.neemann.digital.core.wiring.Break;
import de.neemann.digital.core.wiring.Clock;
import de.neemann.digital.core.wiring.Splitter;
import de.neemann.digital.draw.elements.*;
+import de.neemann.digital.draw.library.GenericInitCode;
import de.neemann.digital.draw.model.InverterConfig;
import de.neemann.digital.draw.model.Net;
import de.neemann.digital.draw.model.NetList;
@@ -240,7 +241,8 @@ public class HDLCircuit implements Iterable, HDLModel.BitProvider, Prin
&& !v.equalsDescription(DummyElement.TEXTDESCRIPTION)
&& !v.equalsDescription(DummyElement.DATADESCRIPTION)
&& !v.equalsDescription(DummyElement.RECTDESCRIPTION)
- && !v.equalsDescription(TestCaseElement.TESTCASEDESCRIPTION);
+ && !v.equalsDescription(TestCaseElement.TESTCASEDESCRIPTION)
+ && !v.equalsDescription(GenericInitCode.DESCRIPTION);
}
HDLNet getNetOfPin(Pin pin) {
diff --git a/src/main/java/de/neemann/digital/hdl/model2/HDLModel.java b/src/main/java/de/neemann/digital/hdl/model2/HDLModel.java
index 50741d2f7..f87d1d701 100644
--- a/src/main/java/de/neemann/digital/hdl/model2/HDLModel.java
+++ b/src/main/java/de/neemann/digital/hdl/model2/HDLModel.java
@@ -26,6 +26,8 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
+import static de.neemann.digital.draw.model.ModelCreator.fixGenerics;
+
/**
* The context of creating nodes and circuits.
* Ensures that every circuit is only processed one time.
@@ -207,11 +209,13 @@ public class HDLModel implements Iterable {
* @param circuit the circuit
* @param clockIntegrator the clock integrator. Meybe null
* @return this for chained calls
- * @throws PinException PinException
- * @throws HDLException HDLException
- * @throws NodeException NodeException
+ * @throws PinException PinException
+ * @throws HDLException HDLException
+ * @throws NodeException NodeException
+ * @throws ElementNotFoundException ElementNotFoundException
*/
- public HDLModel create(Circuit circuit, HDLClockIntegrator clockIntegrator) throws PinException, HDLException, NodeException {
+ public HDLModel create(Circuit circuit, HDLClockIntegrator clockIntegrator) throws PinException, HDLException, NodeException, ElementNotFoundException {
+ circuit = fixGenerics(circuit, elementLibrary);
main = new HDLCircuit(circuit, "main", this, 0, clockIntegrator);
circuitMap.put(circuit, main);
return this;
diff --git a/src/main/java/de/neemann/digital/hdl/verilog2/VerilogGenerator.java b/src/main/java/de/neemann/digital/hdl/verilog2/VerilogGenerator.java
index c3ad94d33..e61cd3228 100644
--- a/src/main/java/de/neemann/digital/hdl/verilog2/VerilogGenerator.java
+++ b/src/main/java/de/neemann/digital/hdl/verilog2/VerilogGenerator.java
@@ -10,6 +10,7 @@ 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.library.ElementLibrary;
+import de.neemann.digital.draw.library.ElementNotFoundException;
import de.neemann.digital.hdl.hgs.HGSEvalException;
import de.neemann.digital.hdl.model2.HDLCircuit;
import de.neemann.digital.hdl.model2.HDLException;
@@ -98,7 +99,7 @@ public class VerilogGenerator implements Closeable {
}
return this;
- } catch (PinException | NodeException | HDLException | HGSEvalException | NullPointerException e) {
+ } catch (PinException | NodeException | HDLException | HGSEvalException | NullPointerException | ElementNotFoundException e) {
throw new IOException(Lang.get("err_verilogExporting"), e);
}
}
diff --git a/src/main/java/de/neemann/digital/hdl/vhdl2/VHDLGenerator.java b/src/main/java/de/neemann/digital/hdl/vhdl2/VHDLGenerator.java
index 8ff914954..37763fc43 100644
--- a/src/main/java/de/neemann/digital/hdl/vhdl2/VHDLGenerator.java
+++ b/src/main/java/de/neemann/digital/hdl/vhdl2/VHDLGenerator.java
@@ -10,6 +10,7 @@ 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.library.ElementLibrary;
+import de.neemann.digital.draw.library.ElementNotFoundException;
import de.neemann.digital.hdl.hgs.HGSEvalException;
import de.neemann.digital.hdl.model2.HDLCircuit;
import de.neemann.digital.hdl.model2.HDLException;
@@ -85,7 +86,7 @@ public class VHDLGenerator implements Closeable {
}
return this;
- } catch (PinException | NodeException | HDLException | HGSEvalException | NullPointerException e) {
+ } catch (PinException | NodeException | HDLException | HGSEvalException | NullPointerException | ElementNotFoundException e) {
throw new IOException(Lang.get("err_vhdlExporting"), e);
}
}
diff --git a/src/main/resources/lang/lang_de.xml b/src/main/resources/lang/lang_de.xml
index 7667bcaa1..816f61ece 100644
--- a/src/main/resources/lang/lang_de.xml
+++ b/src/main/resources/lang/lang_de.xml
@@ -875,22 +875,32 @@
Steuereingang, invertiert
-
Testfall
Beschreibt einen Testfall. In einem Testfall kann beschrieben werden, wie sich eine
Schaltung verhalten soll. Es kann dann automatisch überprüft werden, ob das Verhalten der Schaltung tatsächlich
- dieser Beschreibung entspricht. Ist das nicht der Fall, wird eine entsprechende Fehlermeldung angezeigt.
+ dieser Beschreibung entspricht. Ist das nicht der Fall, wird eine entsprechende Fehlermeldung angezeigt.
+
+ Generische Initialisierung
+ Code der ausgeführt wird, um eine generische Schaltung direkt starten zu
+ können.
+ Soll eine generische Schaltung direkt gestartet werden, muss eine solche Komponente vorhanden sein.
+
+
Asynchrones Timing
Erlaubt die Konfiguration des Timings eines asynchronen Automaten wie z.B einer
- Muller-Pipeline. Die Schaltung muss im Gatterschrittmodus gestartet werden und muss zunächst einen stabilen Zustand
+ Muller-Pipeline. Die Schaltung muss im Gatterschrittmodus gestartet werden und muss zunächst einen stabilen
+ Zustand
einnehmen. Interaktiv oder mit einem Reset-Element kann dann der Automat gestartet werden.
- Die Taktelemente können in diesem Modus nicht verwendet werden.
+ Die Taktelemente können in diesem Modus nicht verwendet werden.
+
Versorgung
- Hat keine weitere Funktion. Stellt nur sicher, dass VDD und GND angeschlossen sind.
+ Hat keine weitere Funktion. Stellt nur sicher, dass VDD und GND angeschlossen
+ sind.
Kann im Zusammenhang mit den 74xx Bausteinen verwendet werden, um Anschlüsse für die Spannungsversorgung
- zu erzeugen, welche dann auch auf korrekte Beschaltung geprüft werden.
+ zu erzeugen, welche dann auch auf korrekte Beschaltung geprüft werden.
+
Muss mit VDD verbunden werden!
Muss mit GND verbunden werden!
Reset
@@ -1112,27 +1122,37 @@ Sind evtl. die Namen der Variablen nicht eindeutig?
HDL nicht bekannt: {0}
Fehler beim Starten des Kommandos {0}
Es gibt einen unbenannten Ein- oder Ausgang.
- Der Signalname "{0}" ist ungültig oder mehrfach verwendet!
+ Der Signalname "{0}" ist ungültig oder mehrfach verwendet!
+
Fehler bei der Substitution von Elementen für die Analyse.
Fehler bei der Auswertung des generischen Codes der Schaltung. Code:
{1}
in Komponente: {0}
Fehler bei der Analyse des generischen Codes.
+ Kein Initialisierungscode für die generischen Elemente.
+ Mehrere Initialisierungscodes für die generischen Elemente.
+ Fehler bei der Analyse des generischen Initialisierungscodes.
+
Videomodus wurde nicht erkannt ({0})
Es ist kein Dateiname für das automatische Neuladen verfügbar!
Adress-Bits
Anzahl der Adress-Bits, die verwendet werden.
- Daten-Bits
+ Daten-Bits
+
Anzahl der Daten-Bits, die verwendet werden.
Farbe
Die Farbe des Elementes.
Hintergrundfarbe
- Hintergrundfarbe der Schaltung, wenn sie eingebettet wird. Wird für DILs nicht verwendet.
+ Hintergrundfarbe der Schaltung, wenn sie eingebettet wird. Wird für DILs nicht
+ verwendet.
+
Timeout Zyklen
- Wenn nach dieser Anzahl von Takten kein Break eingegangen ist, wird ein Fehler erzeugt
+ Wenn nach dieser Anzahl von Takten kein Break eingegangen ist, wird ein Fehler
+ erzeugt
+
Daten
Die Daten, welche in diesem Element gespeichert sind.
Vorgabe
@@ -1998,6 +2018,12 @@ Stellen Sie sicher, dass der Flash-Vorgang abgeschlossen ist, bevor Sie diesen D
Hilfe
Name in einer generischen Schaltung: {0}
+ Konkrete Schaltung erzeugen
+ Erzeugen
+ Erzeugt aus dieser generischen Schaltung eine konkrete Schaltung
+ unter Anwendung der in diesem Element angegebenen Parameter.
+
+ Fehler bei der Erzeugung der konkreten Schaltung!
Zentrale ROM Inhalte
+ Generic Initialization
+ 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.
+
+
Asynchronous Timing
Allows configuration of the timing of an asynchronous sequential circuit such as a
Muller-pipeline. The circuit must be started in single gate step mode and must be able to reach a stable state
at startup. The sequential circuit can then be started interactively or with a reset gate.
- It is not allowed to use a regular clock component in this mode.
+ It is not allowed to use a regular clock component in this mode.
+
Power
Has no function. Makes sure that VDD and GND are connected.
- Can be used in 74xx circuits to generate the pins for the voltage supply, which are tested for correct wiring.
+ Can be used in 74xx circuits to generate the pins for the voltage supply, which are tested for correct wiring.
+
Must be connected to VDD!
Must be connected to GND!
Reset
@@ -1132,20 +1139,29 @@
Error when substituting components for the analysis.
Error in the evaluation of the generic code of the circuit. Code
{1}
- at Component: {0}
+ at Component: {0}
+
Error while parsing generics code.
+ No initialization code for the generic components.
+ Multiple initialization codes for the generic elements.
+ Error in the analysis of the generic initialization code.
+
There is no file name available for the automatic reload!
Address Bits
Number of address bits used.
- Data Bits
+ Data Bits
+
Number of data bits used.
Color
The Color of the element.
Background color
- Background color of the circuit when it is embedded in another circuit. Is not used for DIL packages.
+ Background color of the circuit when it is embedded in another circuit. Is not
+ used for DIL packages.
+
Timeout cycles
- If this amount of cycles is reached without a break signal, an error is created.
+ If this amount of cycles is reached without a break signal, an error is created.
+
Data
The values stored in this element.
Default
@@ -1845,6 +1861,12 @@
Addr. Bits
Name to use in generic circuits: {0}
+ Create Concrete Circuit
+ Create
+ Creates a concrete circuit from this generic circuit using the
+ parameters specified in this element.
+
+ Error while creating the concrete circuit!
<h1>Digital</h1>A simple simulator for digital circuits.
Written by H. Neemann in 2016-2020.
@@ -1852,9 +1874,11 @@
The icons are taken from the <a href="http://tango.freedesktop.org">Tango Desktop Project</a>.
Visit the project at <a href="https://github.com/hneemann/[[name]]">GitHub</a>.
- At Github you can also <a href="https://github.com/hneemann/[[name]]/releases/latest">download</a> the latest release.
+ At Github you can also <a href="https://github.com/hneemann/[[name]]/releases/latest">download</a>
+ the latest release.
- There you also can file an <a href="https://github.com/hneemann/[[name]]/issues/new?body=version:%20[[version]]&labels=bug">issue</a> or suggest
+ There you also can file an <a href="https://github.com/hneemann/[[name]]/issues/new?body=version:%20[[version]]&labels=bug">issue</a>
+ or suggest
an <a href="https://github.com/hneemann/[[name]]/issues/new?labels=enhancement">enhancement</a>.
{0} nodes
diff --git a/src/test/java/de/neemann/digital/hdl/TestHDLExportFlag.java b/src/test/java/de/neemann/digital/hdl/TestHDLExportFlag.java
index 96f18f7b2..9e93e2bab 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.GenericInitCode;
import de.neemann.digital.hdl.vhdl2.entities.VHDLTemplate;
import de.neemann.digital.testing.TestCaseElement;
import junit.framework.TestCase;
@@ -43,6 +44,7 @@ public class TestHDLExportFlag extends TestCase {
implicitSupported.add(Splitter.DESCRIPTION);
implicitSupported.add(TestCaseElement.TESTCASEDESCRIPTION);
+ implicitSupported.add(GenericInitCode.DESCRIPTION);
}
public void testHDLExportFlag() {
diff --git a/src/test/java/de/neemann/digital/hdl/hgs/ParserTest.java b/src/test/java/de/neemann/digital/hdl/hgs/ParserTest.java
index ed5cfc796..669151e18 100644
--- a/src/test/java/de/neemann/digital/hdl/hgs/ParserTest.java
+++ b/src/test/java/de/neemann/digital/hdl/hgs/ParserTest.java
@@ -175,6 +175,23 @@ public class ParserTest extends TestCase {
assertEquals("false", exec(" a:=true; a=false; print(a); ?>").toString());
}
+ public void testStructLiteral() throws ParserException, IOException, HGSEvalException {
+ Object str = new Parser("{a:1, b:2, c:{d:3+4}}").parseExp().value(new Context());
+ Map m = (Map) str;
+ assertEquals(3, m.size());
+ assertEquals(1L, m.get("a"));
+ assertEquals(2L, m.get("b"));
+ Map c = (Map) m.get("c");
+ assertEquals(1, c.size());
+ assertEquals(7L, c.get("d"));
+
+ str = new Parser("{a:{}}").parseExp().value(new Context());
+ m = (Map) str;
+ assertEquals(1, m.size());
+ Map a = (Map) m.get("a");
+ assertEquals(0, a.size());
+ }
+
public void testTypeChecking() throws IOException, ParserException, HGSEvalException {
assertEquals("5.0", exec(" a:=4.0; a=5.0; print(a); ?>", new Context()).toString());
assertEquals("u", exec(" a:=\"zz\"; a=\"u\"; print(a); ?>", new Context()).toString());
diff --git a/src/test/java/de/neemann/digital/integration/TestExamples.java b/src/test/java/de/neemann/digital/integration/TestExamples.java
index c3cf761c0..2dc450077 100644
--- a/src/test/java/de/neemann/digital/integration/TestExamples.java
+++ b/src/test/java/de/neemann/digital/integration/TestExamples.java
@@ -7,8 +7,15 @@ package de.neemann.digital.integration;
import de.neemann.digital.core.ErrorDetector;
import de.neemann.digital.core.Model;
+import de.neemann.digital.core.NodeException;
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.ElementLibrary;
+import de.neemann.digital.draw.library.ElementNotFoundException;
+import de.neemann.digital.draw.library.GenericInitCode;
+import de.neemann.digital.draw.library.ResolveGenerics;
import de.neemann.digital.draw.model.ModelCreator;
import de.neemann.digital.testing.TestCaseDescription;
import de.neemann.digital.testing.TestCaseElement;
@@ -16,6 +23,7 @@ import de.neemann.digital.testing.TestExecutor;
import junit.framework.TestCase;
import java.io.File;
+import java.util.List;
/**
* Reads all examples and tries to create the model.
@@ -105,5 +113,27 @@ public class TestExamples extends TestCase {
} finally {
br.close();
}
+
+ if (br.getCircuit().getAttributes().get(Keys.IS_GENERIC))
+ checkGeneric(br.getCircuit(), br.getLibrary());
+ }
+
+ private void checkGeneric(Circuit circuit, ElementLibrary library) throws NodeException, ElementNotFoundException, PinException {
+ List initCodeList = circuit.getElements(v -> v.equalsDescription(GenericInitCode.DESCRIPTION) && v.getElementAttributes().get(Keys.ENABLED));
+ assertEquals("init code element count", 1, initCodeList.size());
+
+ VisualElement element = initCodeList.get(0);
+
+ Circuit concreteCircuit = new ResolveGenerics()
+ .resolveCircuit(element, circuit, library)
+ .cleanupConcreteCircuit()
+ .getCircuit();
+
+ for (VisualElement ve : concreteCircuit.getElements()) {
+ assertNull(ve.getGenericArgs());
+ assertFalse(ve.equalsDescription(GenericInitCode.DESCRIPTION));
+ }
+
+ new ModelCreator(concreteCircuit, library).createModel(false).init();
}
}
diff --git a/src/test/resources/dig/backtrack/AllComponents.dig b/src/test/resources/dig/backtrack/AllComponents.dig
index 234b9bb4a..a28026765 100644
--- a/src/test/resources/dig/backtrack/AllComponents.dig
+++ b/src/test/resources/dig/backtrack/AllComponents.dig
@@ -492,7 +492,7 @@
Testcase
-
+
PowerSupply
@@ -658,6 +658,11 @@
+
+ GenericInitCode
+
+
+
diff --git a/src/test/resources/dig/test/generics/count.dig b/src/test/resources/dig/test/generics/count.dig
index bfa7e5efc..969515963 100644
--- a/src/test/resources/dig/test/generics/count.dig
+++ b/src/test/resources/dig/test/generics/count.dig
@@ -168,6 +168,16 @@
+
+ GenericInitCode
+
+
+ generic
+ bits := 4;
+
+
+
+
diff --git a/src/test/resources/dig/test/generics/countSplitter.dig b/src/test/resources/dig/test/generics/countSplitter.dig
index 26a09cf0a..c88346ba3 100644
--- a/src/test/resources/dig/test/generics/countSplitter.dig
+++ b/src/test/resources/dig/test/generics/countSplitter.dig
@@ -88,7 +88,7 @@ this.'Input Splitting'=args.bits+","+args.bits;
generic
- this.Bits=int(args.bits);
+ this.Bits=int(args.bits*2);
@@ -121,6 +121,16 @@ this.'Input Splitting'=args.bits+","+args.bits;
+
+ GenericInitCode
+
+
+ generic
+ bits := 2;
+
+
+
+
diff --git a/src/test/resources/dig/test/generics/nest.dig b/src/test/resources/dig/test/generics/nest.dig
index 826c4271a..6000eefbb 100644
--- a/src/test/resources/dig/test/generics/nest.dig
+++ b/src/test/resources/dig/test/generics/nest.dig
@@ -23,10 +23,7 @@
generic
- bits:=4;
-if (isPresent(args)) {
- bits=args.bits;
-}
+ bits:=args.bits;
@@ -78,6 +75,16 @@ if (isPresent(args)) {
+
+ GenericInitCode
+
+
+ generic
+ bits := 4;
+
+
+
+
diff --git a/src/test/resources/dig/test/vhdl/barrelShifter/barrelShifter.dig b/src/test/resources/dig/test/vhdl/barrelShifter/barrelShifter.dig
index 510601e58..f7b639d3c 100644
--- a/src/test/resources/dig/test/vhdl/barrelShifter/barrelShifter.dig
+++ b/src/test/resources/dig/test/vhdl/barrelShifter/barrelShifter.dig
@@ -80,9 +80,7 @@
generic
- if (isPresent(args)) {
-
- if (args.direction="right") {
+ if (args.direction="right") {
export circuit:="shift-fixed-right-inc.dig";
} else {
if (args.direction="arith") {
@@ -91,22 +89,27 @@
if (args.direction="left") {
export circuit:="shift-fixed-left-inc.dig";
} else {
- panic("only \"left\", \"right\" or \"arith\" is allowed as direction, not \""+args.dir+"\"!");
+ panic("only \"left\", \"right\" or \"arith\" is allowed as direction, not \""+args.direction+"\"!");
}
}
}
- export shiftBits:=bitsNeededFor(args.dataBits-1);
-} else {
- // used if circuit is started as the main circuit
- export circuit:="shift-fixed-left-inc.dig";
- export dataBits:=16;
- export shiftBits:=int(4);
-}
+ export shiftBits:=bitsNeededFor(args.dataBits-1);
+
+ GenericInitCode
+
+
+ generic
+ dataBits := 5;
+direction := "left";
+
+
+
+
diff --git a/src/test/resources/dig/test/vhdl/barrelShifter/shift-fixed-arith-right-inc.dig b/src/test/resources/dig/test/vhdl/barrelShifter/shift-fixed-arith-right-inc.dig
index 504a1d409..3d39f2baf 100644
--- a/src/test/resources/dig/test/vhdl/barrelShifter/shift-fixed-arith-right-inc.dig
+++ b/src/test/resources/dig/test/vhdl/barrelShifter/shift-fixed-arith-right-inc.dig
@@ -106,6 +106,17 @@ this.outputBits=int(args.dataBits);
+
+ GenericInitCode
+
+
+ generic
+ dataBits := 8;
+shift := 3;
+
+
+
+
diff --git a/src/test/resources/dig/test/vhdl/barrelShifter/shift-fixed-left-inc.dig b/src/test/resources/dig/test/vhdl/barrelShifter/shift-fixed-left-inc.dig
index edff6777c..9e06e6548 100644
--- a/src/test/resources/dig/test/vhdl/barrelShifter/shift-fixed-left-inc.dig
+++ b/src/test/resources/dig/test/vhdl/barrelShifter/shift-fixed-left-inc.dig
@@ -116,6 +116,17 @@ this.'Output Splitting' = "0-"+(args.dataBits-args.shift-1);
+
+ GenericInitCode
+
+
+ generic
+ dataBits := 8;
+shift := 3;
+
+
+
+
diff --git a/src/test/resources/dig/test/vhdl/barrelShifter/shift-fixed-right-inc.dig b/src/test/resources/dig/test/vhdl/barrelShifter/shift-fixed-right-inc.dig
index ed307c078..0da3c4b0d 100644
--- a/src/test/resources/dig/test/vhdl/barrelShifter/shift-fixed-right-inc.dig
+++ b/src/test/resources/dig/test/vhdl/barrelShifter/shift-fixed-right-inc.dig
@@ -116,6 +116,17 @@ this.'Output Splitting' = args.shift+"-"+(args.dataBits-1);<
+
+ GenericInitCode
+
+
+ generic
+ dataBits := 8;
+shift := 3;
+
+
+
+
diff --git a/src/test/resources/dig/test/vhdl/barrelShifter/shift-inc.dig b/src/test/resources/dig/test/vhdl/barrelShifter/shift-inc.dig
index 393b19585..a96a8b2b0 100644
--- a/src/test/resources/dig/test/vhdl/barrelShifter/shift-inc.dig
+++ b/src/test/resources/dig/test/vhdl/barrelShifter/shift-inc.dig
@@ -13,14 +13,8 @@
generic
- if (isPresent(args)) {
- export shift := 1<<(args.shiftBits-1);
- setCircuit(args.circuit);
-} else {
- // used if circuit is started as the main circuit
- export dataBits:=16;
- export shift:=8;
-}
+ export shift := 1<<(args.shiftBits-1);
+setCircuit(args.circuit);
@@ -92,18 +86,11 @@
generic
- if (isPresent(args)) {
- if (args.shiftBits=2) {
- export shift := 1;
- setCircuit(args.circuit);
- } else {
- export shiftBits := args.shiftBits-1;
- }
+ if (args.shiftBits=2) {
+ export shift := 1;
+ setCircuit(args.circuit);
} else {
- // used if circuit is started as the main circuit
- export dataBits:=16;
- export shiftBits:=3;
- export circuit:="shift-fixed-left-inc.dig";
+ export shiftBits := args.shiftBits-1;
}
@@ -128,6 +115,18 @@ this.'Output Splitting' = (args.shiftBits-1)+"-"+(args.shift
+
+ GenericInitCode
+
+
+ generic
+ circuit := "shift-fixed-left-inc.dig";
+dataBits := 8;
+shiftBits := 3;
+
+
+
+
diff --git a/src/test/resources/dig/test/vhdl/generics/memLeaf.dig b/src/test/resources/dig/test/vhdl/generics/memLeaf.dig
index 4daca6dfe..a7e7f81f5 100644
--- a/src/test/resources/dig/test/vhdl/generics/memLeaf.dig
+++ b/src/test/resources/dig/test/vhdl/generics/memLeaf.dig
@@ -113,6 +113,16 @@
+
+ GenericInitCode
+
+
+ generic
+ dataBits := 8;
+
+
+
+
diff --git a/src/test/resources/dig/test/vhdl/generics/memLeaf2.dig b/src/test/resources/dig/test/vhdl/generics/memLeaf2.dig
index bd75ad084..746aed613 100644
--- a/src/test/resources/dig/test/vhdl/generics/memLeaf2.dig
+++ b/src/test/resources/dig/test/vhdl/generics/memLeaf2.dig
@@ -134,6 +134,16 @@
+
+ GenericInitCode
+
+
+ generic
+ dataBits := 8;
+
+
+
+
diff --git a/src/test/resources/dig/test/vhdl/generics/memNode.dig b/src/test/resources/dig/test/vhdl/generics/memNode.dig
index 596d0606c..deede69a2 100644
--- a/src/test/resources/dig/test/vhdl/generics/memNode.dig
+++ b/src/test/resources/dig/test/vhdl/generics/memNode.dig
@@ -17,9 +17,7 @@
generic
- if (isPresent(args)) {
- this.Bits=int(args.dataBits);
-}
+ this.Bits=int(args.dataBits);
@@ -37,9 +35,7 @@
generic
- if (isPresent(args)) {
- this.Bits=int(args.addrBits);
-}
+ this.Bits=int(args.addrBits);
@@ -63,9 +59,7 @@
generic
- if (isPresent(args)) {
- this.Bits=int(args.dataBits);
-}
+ this.Bits=int(args.dataBits);
@@ -85,9 +79,7 @@
generic
- if (isPresent(args)) {
- this.Bits=int(args.dataBits);
-}
+ this.Bits=int(args.dataBits);
@@ -122,15 +114,12 @@
generic
- if (isPresent(args)) {
+ if (args.addrBits<2) {
+ panic("at least two address bits are necessary!");
+}
- if (args.addrBits<2) {
- panic("at least two address bits are necessary!");
- }
-
- this.'Input Splitting'=""+args.addrBits;
- this.'Output Splitting'=(args.addrBits-1)+",1";
-}
+this.'Input Splitting'=""+args.addrBits;
+this.'Output Splitting'=(args.addrBits-1)+",1";
@@ -140,13 +129,9 @@
generic
- if (isPresent(args)) {
- export addrBits:=args.addrBits-1;
- if (args.addrBits>2) {
- setCircuit("memNode.dig");
- }
-} else {
- export dataBits:=int(1);
+ export addrBits:=args.addrBits-1;
+if (args.addrBits>2) {
+ setCircuit("memNode.dig");
}
@@ -157,18 +142,25 @@
generic
- if (isPresent(args)) {
- export addrBits:=args.addrBits-1;
- if (args.addrBits>2) {
- setCircuit("memNode.dig");
- }
-} else {
- export dataBits:=int(1);
+ export addrBits:=args.addrBits-1;
+if (args.addrBits>2) {
+ setCircuit("memNode.dig");
}
+
+ GenericInitCode
+
+
+ generic
+ addrBits := 8;
+dataBits := 8;
+
+
+
+
diff --git a/src/test/resources/dig/test/vhdl/generics/memNode2.dig b/src/test/resources/dig/test/vhdl/generics/memNode2.dig
index baada53cc..f505de783 100644
--- a/src/test/resources/dig/test/vhdl/generics/memNode2.dig
+++ b/src/test/resources/dig/test/vhdl/generics/memNode2.dig
@@ -17,9 +17,7 @@
generic
- if (isPresent(args)) {
- this.Bits=int(args.dataBits);
-}
+ this.Bits=int(args.dataBits);
@@ -37,9 +35,7 @@
generic
- if (isPresent(args)) {
- this.Bits=int(args.addrBits);
-}
+ this.Bits=int(args.addrBits);
@@ -63,9 +59,7 @@
generic
- if (isPresent(args)) {
- this.Bits=int(args.dataBits);
-}
+ this.Bits=int(args.dataBits);
@@ -89,9 +83,7 @@
generic
- if (isPresent(args)) {
- this.Bits=int(args.dataBits);
-}
+ this.Bits=int(args.dataBits);
@@ -109,19 +101,16 @@
generic
- if (isPresent(args)) {
+ if (args.addrBits<4) {
+ panic("at least two address bits are necessary!");
+}
- if (args.addrBits<4) {
- panic("at least two address bits are necessary!");
- }
+if ((args.addrBits&1)=1) {
+ panic("number of address bits must be even!");
+}
- if ((args.addrBits&1)=1) {
- panic("number of address bits must be even!");
- }
-
- this.'Input Splitting'=""+args.addrBits;
- this.'Output Splitting'=(args.addrBits-2)+",2";
-}
+this.'Input Splitting'=""+args.addrBits;
+this.'Output Splitting'=(args.addrBits-2)+",2";
@@ -141,13 +130,9 @@
generic
- if (isPresent(args)) {
- export addrBits:=args.addrBits-2;
- if (args.addrBits>4) {
- setCircuit("memNode2.dig");
- }
-} else {
- export dataBits:=int(1);
+ export addrBits:=args.addrBits-2;
+if (args.addrBits>4) {
+ setCircuit("memNode2.dig");
}
@@ -158,13 +143,9 @@
generic
- if (isPresent(args)) {
- export addrBits:=args.addrBits-2;
- if (args.addrBits>4) {
- setCircuit("memNode2.dig");
- }
-} else {
- export dataBits:=int(1);
+ export addrBits:=args.addrBits-2;
+if (args.addrBits>4) {
+ setCircuit("memNode2.dig");
}
@@ -175,13 +156,9 @@
generic
- if (isPresent(args)) {
- export addrBits:=args.addrBits-2;
- if (args.addrBits>4) {
- setCircuit("memNode2.dig");
- }
-} else {
- export dataBits:=int(1);
+ export addrBits:=args.addrBits-2;
+if (args.addrBits>4) {
+ setCircuit("memNode2.dig");
}
@@ -192,18 +169,25 @@
generic
- if (isPresent(args)) {
- export addrBits:=args.addrBits-2;
- if (args.addrBits>4) {
- setCircuit("memNode2.dig");
- }
-} else {
- export dataBits:=int(1);
+ export addrBits:=args.addrBits-2;
+if (args.addrBits>4) {
+ setCircuit("memNode2.dig");
}
+
+ GenericInitCode
+
+
+ generic
+ addrBits := 8;
+dataBits := 8;
+
+
+
+