diff --git a/src/main/java/de/neemann/digital/analyse/SubstituteLibrary.java b/src/main/java/de/neemann/digital/analyse/SubstituteLibrary.java
index 4bc08685d..c83cdcaa6 100644
--- a/src/main/java/de/neemann/digital/analyse/SubstituteLibrary.java
+++ b/src/main/java/de/neemann/digital/analyse/SubstituteLibrary.java
@@ -7,6 +7,7 @@ package de.neemann.digital.analyse;
import de.neemann.digital.core.element.ElementAttributes;
import de.neemann.digital.core.element.ElementTypeDescription;
+import de.neemann.digital.core.element.Key;
import de.neemann.digital.core.element.Keys;
import de.neemann.digital.draw.elements.Circuit;
import de.neemann.digital.draw.elements.PinException;
@@ -15,6 +16,7 @@ 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;
+import de.neemann.digital.hdl.hgs.*;
import de.neemann.digital.lang.Lang;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -40,7 +42,8 @@ public class SubstituteLibrary implements LibraryInterface {
.add(attr -> attr.get(Keys.WITH_ENABLE), new Substitute("T_FF_EN.dig"))
.add(attr -> true, new Substitute("T_FF.dig"))
);
- MAP.put("Counter", new SubstituteGenericBits("Counter.dig"));
+ MAP.put("Counter", new SubstituteGenericHGSParser("Counter.dig"));
+ MAP.put("CounterPreset", new SubstituteGenericHGSParser("CounterPreset.dig"));
}
private final ElementLibrary parent;
@@ -172,7 +175,7 @@ public class SubstituteLibrary implements LibraryInterface {
c);
}
- private void generify(ElementAttributes attr, Circuit circuit) {
+ private void generify(ElementAttributes attr, Circuit circuit) throws IOException {
for (VisualElement v : circuit.getElements()) {
String gen = v.getElementAttributes().get(Keys.GENERIC).trim();
if (!gen.isEmpty())
@@ -180,19 +183,56 @@ public class SubstituteLibrary implements LibraryInterface {
}
}
- abstract void generify(ElementAttributes sourceAttributes, String gen, ElementAttributes nodeAttributes);
+ abstract void generify(ElementAttributes sourceAttributes, String gen, ElementAttributes nodeAttributes) throws IOException;
}
- private static class SubstituteGenericBits extends SubstituteGeneric {
+ private static class SubstituteGenericHGSParser extends SubstituteGeneric {
+ private final HashMap map;
- private SubstituteGenericBits(String filename) {
+ private SubstituteGenericHGSParser(String filename) {
super(filename);
+ map = new HashMap<>();
}
@Override
- void generify(ElementAttributes sourceAttributes, String gen, ElementAttributes nodeAttributes) {
- if (gen.equals("bits"))
- nodeAttributes.setBits(sourceAttributes.getBits());
+ void generify(ElementAttributes sourceAttributes, String gen, ElementAttributes nodeAttributes) throws IOException {
+ try {
+ Statement s = map.get(gen);
+ if (s == null) {
+ LOGGER.info("generic: " + gen);
+ s = new Parser(gen).parse(false);
+ map.put(gen, s);
+ }
+ Context context = new Context()
+ .declareVar("orig", sourceAttributes)
+ .declareVar("this", new AllowSetAttributes(nodeAttributes));
+ s.execute(context);
+ } catch (ParserException | HGSEvalException e) {
+ throw new IOException(e);
+ }
+ }
+
+ }
+
+ private static final class AllowSetAttributes implements HGSMap {
+ private final ElementAttributes attr;
+
+ private AllowSetAttributes(ElementAttributes attr) {
+ this.attr = attr;
+ }
+
+ @Override
+ public void hgsMapPut(String key, Object val) throws HGSEvalException {
+ Key k = Keys.getKeyByName(key);
+ if (k == null) {
+ throw new HGSEvalException("key " + key + " is invalid");
+ } else
+ attr.set(k, val);
+ }
+
+ @Override
+ public Object hgsMapGet(String key) {
+ return attr.hgsMapGet(key);
}
}
}
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 6cae93e16..5659a5779 100644
--- a/src/main/java/de/neemann/digital/core/element/Keys.java
+++ b/src/main/java/de/neemann/digital/core/element/Keys.java
@@ -785,9 +785,9 @@ public final class Keys {
new Key.KeyFile("toolChainConfig", new File("")).setSecondary().setRequiresRestart();
/**
- * Selects the midi channel
+ * Used to input statements to generify a circuit.
*/
public static final Key GENERIC =
- new Key<>("generic", "").allowGroupEdit();
+ new Key.LongString("generic").allowGroupEdit();
}
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 c6b012137..5c62c3599 100644
--- a/src/main/java/de/neemann/digital/hdl/hgs/Parser.java
+++ b/src/main/java/de/neemann/digital/hdl/hgs/Parser.java
@@ -100,14 +100,28 @@ public class Parser {
* @throws ParserException ParserException
*/
public Statement parse() throws IOException, ParserException {
- Statements s = new Statements();
- String text = tok.readText();
- if (nextIs(SUB))
- text = Value.trimRight(text);
+ return parse(true);
+ }
- if (text.length() > 0) {
- String t = text;
- s.add(c -> c.print(t));
+ /**
+ * Parses the given template source
+ *
+ * @param startsWithText true if code starts with text.
+ * @return the Statement to execute
+ * @throws IOException IOException
+ * @throws ParserException ParserException
+ */
+ public Statement parse(boolean startsWithText) throws IOException, ParserException {
+ Statements s = new Statements();
+ if (startsWithText) {
+ String text = tok.readText();
+ if (nextIs(SUB))
+ text = Value.trimRight(text);
+
+ if (text.length() > 0) {
+ String t = text;
+ s.add(c -> c.print(t));
+ }
}
while (!nextIs(EOF)) {
if (nextIs(STATIC)) {
diff --git a/src/main/resources/analyser/Counter.dig b/src/main/resources/analyser/Counter.dig
index 4b6c7ae1a..807ae8b4c 100644
--- a/src/main/resources/analyser/Counter.dig
+++ b/src/main/resources/analyser/Counter.dig
@@ -46,7 +46,7 @@
generic
- bits
+ this.Bits=orig.Bits;
@@ -74,7 +74,7 @@
generic
- bits
+ this.Bits=orig.Bits;
@@ -88,7 +88,7 @@
generic
- bits
+ this.Bits=orig.Bits;
@@ -102,7 +102,7 @@
generic
- bits
+ this.Bits=orig.Bits;
@@ -116,7 +116,7 @@
generic
- bits
+ this.Bits=orig.Bits;
@@ -130,7 +130,7 @@
generic
- bits
+ this.Bits=orig.Bits;
@@ -149,7 +149,7 @@
generic
- bits
+ this.Bits=orig.Bits;
diff --git a/src/main/resources/analyser/CounterPreset.dig b/src/main/resources/analyser/CounterPreset.dig
index 4fc9296bb..f619bc067 100644
--- a/src/main/resources/analyser/CounterPreset.dig
+++ b/src/main/resources/analyser/CounterPreset.dig
@@ -11,17 +11,25 @@
en
-
+
Clock
+
+ runRealTime
+ true
+
Label
C
+
+ Frequency
+ 2
+
-
+
In
@@ -31,7 +39,7 @@
dir
-
+
Out
@@ -44,6 +52,10 @@
Bits
4
+
+ generic
+ this.Bits=orig.Bits;
+
@@ -55,7 +67,7 @@
ovf
-
+
D_FF
@@ -68,6 +80,10 @@
Bits
4
+
+ generic
+ this.Bits=orig.Bits;
+
@@ -78,6 +94,10 @@
Bits
4
+
+ generic
+ this.Bits=orig.Bits;
+
@@ -88,6 +108,10 @@
Bits
4
+
+ generic
+ this.Bits=orig.Bits;
+
@@ -98,13 +122,17 @@
Bits
4
+
+ generic
+ this.Bits=orig.Bits;
+
-
+
Ground
-
+
Const
@@ -113,13 +141,17 @@
Bits
4
+
+ generic
+ this.Bits=orig.Bits;
+
-
+
And
-
+
Multiplexer
@@ -128,8 +160,12 @@
Bits
4
+
+ generic
+ this.Bits=orig.Bits;
+
-
+
Const
@@ -142,8 +178,12 @@
Bits
4
+
+ generic
+ this.Bits=orig.Bits;
+
-
+
In
@@ -160,6 +200,10 @@
Bits
4
+
+ generic
+ this.Bits=orig.Bits;
+
@@ -170,22 +214,35 @@
Bits
4
+
+ generic
+ this.Bits=orig.Bits;
+
-
+
Const
Value
- 9
+ 15
Bits
4
+
+ generic
+ this.Bits=orig.Bits;
+if (orig.maxValue=0) {
+ this.Value=(1<<orig.Bits)-1;
+} else {
+ this.Value=orig.maxValue;
+}
+
-
+
Or
@@ -204,6 +261,10 @@
Bits
4
+
+ generic
+ this.Bits=orig.Bits;
+
@@ -218,6 +279,10 @@
Bits
4
+
+ generic
+ this.Bits=orig.Bits;
+
@@ -231,7 +296,7 @@
-
+
Multiplexer
@@ -240,6 +305,10 @@
Bits
4
+
+ generic
+ this.Bits=orig.Bits;
+
@@ -265,7 +334,43 @@
clr
-
+
+
+
+ Multiplexer
+
+
+ Bits
+ 4
+
+
+ flipSelPos
+ true
+
+
+ generic
+ this.Bits=orig.Bits;
+
+
+
+
+
+ Const
+
+
+ Value
+ 0
+
+
+ Bits
+ 4
+
+
+ generic
+ this.Bits=orig.Bits;
+
+
+
@@ -274,48 +379,44 @@
-
-
+
+
-
-
+
+
-
+
-
-
-
-
-
+
-
-
+
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
@@ -329,20 +430,36 @@
+
+
+
+
+
+
+
+
-
+
-
-
+
+
-
+
+
+
+
+
+
+
+
+
@@ -350,12 +467,20 @@
-
-
+
+
-
-
+
+
+
+
+
+
+
+
+
+
@@ -366,8 +491,8 @@
-
-
+
+
@@ -378,32 +503,24 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
+
+
-
-
+
+
+
+
+
+
@@ -418,12 +535,12 @@
-
-
+
+
-
-
+
+
@@ -438,16 +555,16 @@
-
-
+
+
-
-
+
+
-
-
+
+
@@ -455,19 +572,23 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
@@ -475,7 +596,7 @@
-
+
diff --git a/src/main/resources/lang/lang_de.xml b/src/main/resources/lang/lang_de.xml
index 0a62f33c0..005d9eab2 100644
--- a/src/main/resources/lang/lang_de.xml
+++ b/src/main/resources/lang/lang_de.xml
@@ -1342,7 +1342,7 @@ Sind evtl. die Namen der Variablen nicht eindeutig?
Erlaubt den Start externer Tools, um z.B. einen FPGA zu programmieren o.ä.
Generisch
- String für das Erzeugen generischer Schaltungen.
+ Anweisung um eine generische Schaltung anzupassen.
Leitung eingefügt.
Aus Zwischenablage eingefügt.
diff --git a/src/main/resources/lang/lang_en.xml b/src/main/resources/lang/lang_en.xml
index 23e46c50f..12b4fa5d9 100644
--- a/src/main/resources/lang/lang_en.xml
+++ b/src/main/resources/lang/lang_en.xml
@@ -1330,7 +1330,7 @@
Allows the start of external tools, e.g. to program an FPGA or similar.
Generic
- String used to create generic circuits.
+ Statements used to generify a circuit.
Inserted wire.
Insert from clipboard.
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 8f9b4bd99..bfe6abd61 100644
--- a/src/test/java/de/neemann/digital/hdl/hgs/ParserTest.java
+++ b/src/test/java/de/neemann/digital/hdl/hgs/ParserTest.java
@@ -189,12 +189,18 @@ public class ParserTest extends TestCase {
assertEquals("Hello World!", exec("Hello World!", new Context()).toString());
}
-
public void testParseTemplateTextOnly() throws IOException, ParserException, HGSEvalException {
assertEquals("Hello World!", exec("Hello World!").toString());
assertEquals("Hello < < World!", exec("Hello < < World!").toString());
}
+ public void testParseCommandsOnly() throws IOException, ParserException, HGSEvalException {
+ Statement s = new Parser("a:=2; b:=a*a;").parse(false);
+ Context context = new Context();
+ s.execute(context);
+ assertEquals(4L, context.getVar("b"));
+ }
+
public void testParseTemplateVariable() throws IOException, ParserException, HGSEvalException {
Context c = exec("Hello =a ?> World!", new Context().declareVar("a", "My"));
assertEquals("Hello My World!", c.toString());