allows simple generic circuits

This commit is contained in:
hneemann 2019-06-28 17:45:19 +02:00
parent 3bc8884b5c
commit 29f0b88bbe
8 changed files with 293 additions and 112 deletions

View File

@ -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<String, Statement> 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);
}
}
}

View File

@ -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<String> GENERIC =
new Key<>("generic", "").allowGroupEdit();
new Key.LongString("generic").allowGroupEdit();
}

View File

@ -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)) {

View File

@ -46,7 +46,7 @@
</entry>
<entry>
<string>generic</string>
<string>bits</string>
<string>this.Bits=orig.Bits;</string>
</entry>
</elementAttributes>
<pos x="540" y="160"/>
@ -74,7 +74,7 @@
</entry>
<entry>
<string>generic</string>
<string>bits</string>
<string>this.Bits=orig.Bits;</string>
</entry>
</elementAttributes>
<pos x="440" y="160"/>
@ -88,7 +88,7 @@
</entry>
<entry>
<string>generic</string>
<string>bits</string>
<string>this.Bits=orig.Bits;</string>
</entry>
</elementAttributes>
<pos x="360" y="140"/>
@ -102,7 +102,7 @@
</entry>
<entry>
<string>generic</string>
<string>bits</string>
<string>this.Bits=orig.Bits;</string>
</entry>
</elementAttributes>
<pos x="340" y="200"/>
@ -116,7 +116,7 @@
</entry>
<entry>
<string>generic</string>
<string>bits</string>
<string>this.Bits=orig.Bits;</string>
</entry>
</elementAttributes>
<pos x="300" y="120"/>
@ -130,7 +130,7 @@
</entry>
<entry>
<string>generic</string>
<string>bits</string>
<string>this.Bits=orig.Bits;</string>
</entry>
</elementAttributes>
<pos x="220" y="160"/>
@ -149,7 +149,7 @@
</entry>
<entry>
<string>generic</string>
<string>bits</string>
<string>this.Bits=orig.Bits;</string>
</entry>
</elementAttributes>
<pos x="200" y="180"/>

View File

@ -11,17 +11,25 @@
<string>en</string>
</entry>
</elementAttributes>
<pos x="40" y="540"/>
<pos x="-60" y="560"/>
</visualElement>
<visualElement>
<elementName>Clock</elementName>
<elementAttributes>
<entry>
<string>runRealTime</string>
<boolean>true</boolean>
</entry>
<entry>
<string>Label</string>
<string>C</string>
</entry>
<entry>
<string>Frequency</string>
<int>2</int>
</entry>
</elementAttributes>
<pos x="40" y="460"/>
<pos x="-60" y="460"/>
</visualElement>
<visualElement>
<elementName>In</elementName>
@ -31,7 +39,7 @@
<string>dir</string>
</entry>
</elementAttributes>
<pos x="40" y="240"/>
<pos x="-60" y="260"/>
</visualElement>
<visualElement>
<elementName>Out</elementName>
@ -44,6 +52,10 @@
<string>Bits</string>
<int>4</int>
</entry>
<entry>
<string>generic</string>
<string>this.Bits=orig.Bits;</string>
</entry>
</elementAttributes>
<pos x="660" y="180"/>
</visualElement>
@ -55,7 +67,7 @@
<string>ovf</string>
</entry>
</elementAttributes>
<pos x="660" y="520"/>
<pos x="660" y="540"/>
</visualElement>
<visualElement>
<elementName>D_FF</elementName>
@ -68,6 +80,10 @@
<string>Bits</string>
<int>4</int>
</entry>
<entry>
<string>generic</string>
<string>this.Bits=orig.Bits;</string>
</entry>
</elementAttributes>
<pos x="560" y="180"/>
</visualElement>
@ -78,6 +94,10 @@
<string>Bits</string>
<int>4</int>
</entry>
<entry>
<string>generic</string>
<string>this.Bits=orig.Bits;</string>
</entry>
</elementAttributes>
<pos x="400" y="140"/>
</visualElement>
@ -88,6 +108,10 @@
<string>Bits</string>
<int>4</int>
</entry>
<entry>
<string>generic</string>
<string>this.Bits=orig.Bits;</string>
</entry>
</elementAttributes>
<pos x="320" y="120"/>
</visualElement>
@ -98,13 +122,17 @@
<string>Bits</string>
<int>4</int>
</entry>
<entry>
<string>generic</string>
<string>this.Bits=orig.Bits;</string>
</entry>
</elementAttributes>
<pos x="140" y="160"/>
<pos x="40" y="160"/>
</visualElement>
<visualElement>
<elementName>Ground</elementName>
<elementAttributes/>
<pos x="120" y="220"/>
<pos x="20" y="220"/>
</visualElement>
<visualElement>
<elementName>Const</elementName>
@ -113,13 +141,17 @@
<string>Bits</string>
<int>4</int>
</entry>
<entry>
<string>generic</string>
<string>this.Bits=orig.Bits;</string>
</entry>
</elementAttributes>
<pos x="40" y="160"/>
<pos x="-60" y="160"/>
</visualElement>
<visualElement>
<elementName>And</elementName>
<elementAttributes/>
<pos x="360" y="500"/>
<pos x="360" y="520"/>
</visualElement>
<visualElement>
<elementName>Multiplexer</elementName>
@ -128,8 +160,12 @@
<string>Bits</string>
<int>4</int>
</entry>
<entry>
<string>generic</string>
<string>this.Bits=orig.Bits;</string>
</entry>
</elementAttributes>
<pos x="60" y="160"/>
<pos x="-40" y="160"/>
</visualElement>
<visualElement>
<elementName>Const</elementName>
@ -142,8 +178,12 @@
<string>Bits</string>
<int>4</int>
</entry>
<entry>
<string>generic</string>
<string>this.Bits=orig.Bits;</string>
</entry>
</elementAttributes>
<pos x="40" y="200"/>
<pos x="-60" y="200"/>
</visualElement>
<visualElement>
<elementName>In</elementName>
@ -160,6 +200,10 @@
<string>Bits</string>
<int>4</int>
</entry>
<entry>
<string>generic</string>
<string>this.Bits=orig.Bits;</string>
</entry>
</elementAttributes>
<pos x="460" y="240"/>
</visualElement>
@ -170,22 +214,35 @@
<string>Bits</string>
<int>4</int>
</entry>
<entry>
<string>generic</string>
<string>this.Bits=orig.Bits;</string>
</entry>
</elementAttributes>
<pos x="240" y="480"/>
<pos x="240" y="500"/>
</visualElement>
<visualElement>
<elementName>Const</elementName>
<elementAttributes>
<entry>
<string>Value</string>
<long>9</long>
<long>15</long>
</entry>
<entry>
<string>Bits</string>
<int>4</int>
</entry>
<entry>
<string>generic</string>
<string>this.Bits=orig.Bits;
if (orig.maxValue=0) {
this.Value=(1&lt;&lt;orig.Bits)-1;
} else {
this.Value=orig.maxValue;
}</string>
</entry>
</elementAttributes>
<pos x="40" y="500"/>
<pos x="-60" y="500"/>
</visualElement>
<visualElement>
<elementName>Or</elementName>
@ -204,6 +261,10 @@
<string>Bits</string>
<int>4</int>
</entry>
<entry>
<string>generic</string>
<string>this.Bits=orig.Bits;</string>
</entry>
</elementAttributes>
<pos x="280" y="200"/>
</visualElement>
@ -218,6 +279,10 @@
<string>Bits</string>
<int>4</int>
</entry>
<entry>
<string>generic</string>
<string>this.Bits=orig.Bits;</string>
</entry>
</elementAttributes>
<pos x="260" y="200"/>
</visualElement>
@ -231,7 +296,7 @@
</inverterConfig>
</entry>
</elementAttributes>
<pos x="120" y="300"/>
<pos x="20" y="300"/>
</visualElement>
<visualElement>
<elementName>Multiplexer</elementName>
@ -240,6 +305,10 @@
<string>Bits</string>
<int>4</int>
</entry>
<entry>
<string>generic</string>
<string>this.Bits=orig.Bits;</string>
</entry>
</elementAttributes>
<pos x="480" y="160"/>
</visualElement>
@ -265,7 +334,43 @@
<string>clr</string>
</entry>
</elementAttributes>
<pos x="40" y="420"/>
<pos x="-60" y="420"/>
</visualElement>
<visualElement>
<elementName>Multiplexer</elementName>
<elementAttributes>
<entry>
<string>Bits</string>
<int>4</int>
</entry>
<entry>
<string>flipSelPos</string>
<boolean>true</boolean>
</entry>
<entry>
<string>generic</string>
<string>this.Bits=orig.Bits;</string>
</entry>
</elementAttributes>
<pos x="160" y="500"/>
</visualElement>
<visualElement>
<elementName>Const</elementName>
<elementAttributes>
<entry>
<string>Value</string>
<long>0</long>
</entry>
<entry>
<string>Bits</string>
<int>4</int>
</entry>
<entry>
<string>generic</string>
<string>this.Bits=orig.Bits;</string>
</entry>
</elementAttributes>
<pos x="140" y="540"/>
</visualElement>
</visualElements>
<wires>
@ -274,48 +379,44 @@
<p2 x="480" y="160"/>
</wire>
<wire>
<p1 x="120" y="160"/>
<p2 x="140" y="160"/>
<p1 x="20" y="160"/>
<p2 x="40" y="160"/>
</wire>
<wire>
<p1 x="40" y="160"/>
<p2 x="60" y="160"/>
<p1 x="-60" y="160"/>
<p2 x="-40" y="160"/>
</wire>
<wire>
<p1 x="200" y="160"/>
<p1 x="100" y="160"/>
<p2 x="320" y="160"/>
</wire>
<wire>
<p1 x="220" y="480"/>
<p2 x="240" y="480"/>
</wire>
<wire>
<p1 x="180" y="320"/>
<p1 x="80" y="320"/>
<p2 x="300" y="320"/>
</wire>
<wire>
<p1 x="40" y="420"/>
<p2 x="80" y="420"/>
<p1 x="-60" y="420"/>
<p2 x="-20" y="420"/>
</wire>
<wire>
<p1 x="80" y="420"/>
<p1 x="-20" y="420"/>
<p2 x="400" y="420"/>
</wire>
<wire>
<p1 x="420" y="520"/>
<p2 x="440" y="520"/>
<p1 x="-60" y="260"/>
<p2 x="-20" y="260"/>
</wire>
<wire>
<p1 x="440" y="520"/>
<p2 x="660" y="520"/>
<p1 x="-20" y="260"/>
<p2 x="180" y="260"/>
</wire>
<wire>
<p1 x="120" y="200"/>
<p2 x="140" y="200"/>
<p1 x="20" y="200"/>
<p2 x="40" y="200"/>
</wire>
<wire>
<p1 x="40" y="200"/>
<p2 x="60" y="200"/>
<p1 x="-60" y="200"/>
<p2 x="-40" y="200"/>
</wire>
<wire>
<p1 x="260" y="200"/>
@ -329,20 +430,36 @@
<p1 x="460" y="200"/>
<p2 x="480" y="200"/>
</wire>
<wire>
<p1 x="300" y="520"/>
<p2 x="360" y="520"/>
</wire>
<wire>
<p1 x="200" y="520"/>
<p2 x="240" y="520"/>
</wire>
<wire>
<p1 x="360" y="140"/>
<p2 x="400" y="140"/>
</wire>
<wire>
<p1 x="40" y="460"/>
<p1 x="-60" y="460"/>
<p2 x="540" y="460"/>
</wire>
<wire>
<p1 x="80" y="300"/>
<p2 x="120" y="300"/>
<p1 x="-20" y="300"/>
<p2 x="20" y="300"/>
</wire>
<wire>
<p1 x="120" y="80"/>
<p1 x="-60" y="560"/>
<p2 x="340" y="560"/>
</wire>
<wire>
<p1 x="340" y="560"/>
<p2 x="360" y="560"/>
</wire>
<wire>
<p1 x="20" y="80"/>
<p2 x="220" y="80"/>
</wire>
<wire>
@ -350,12 +467,20 @@
<p2 x="640" y="80"/>
</wire>
<wire>
<p1 x="40" y="240"/>
<p2 x="80" y="240"/>
<p1 x="100" y="240"/>
<p2 x="280" y="240"/>
</wire>
<wire>
<p1 x="200" y="240"/>
<p2 x="280" y="240"/>
<p1 x="-60" y="500"/>
<p2 x="100" y="500"/>
</wire>
<wire>
<p1 x="220" y="500"/>
<p2 x="240" y="500"/>
</wire>
<wire>
<p1 x="100" y="500"/>
<p2 x="160" y="500"/>
</wire>
<wire>
<p1 x="620" y="180"/>
@ -366,8 +491,8 @@
<p2 x="400" y="180"/>
</wire>
<wire>
<p1 x="100" y="180"/>
<p2 x="140" y="180"/>
<p1 x="0" y="180"/>
<p2 x="40" y="180"/>
</wire>
<wire>
<p1 x="520" y="180"/>
@ -378,32 +503,24 @@
<p2 x="660" y="180"/>
</wire>
<wire>
<p1 x="300" y="500"/>
<p2 x="360" y="500"/>
</wire>
<wire>
<p1 x="40" y="500"/>
<p2 x="200" y="500"/>
</wire>
<wire>
<p1 x="200" y="500"/>
<p2 x="240" y="500"/>
</wire>
<wire>
<p1 x="80" y="340"/>
<p2 x="100" y="340"/>
<p1 x="-20" y="340"/>
<p2 x="0" y="340"/>
</wire>
<wire>
<p1 x="220" y="120"/>
<p2 x="320" y="120"/>
</wire>
<wire>
<p1 x="40" y="540"/>
<p2 x="340" y="540"/>
<p1 x="140" y="540"/>
<p2 x="160" y="540"/>
</wire>
<wire>
<p1 x="340" y="540"/>
<p2 x="360" y="540"/>
<p1 x="420" y="540"/>
<p2 x="440" y="540"/>
</wire>
<wire>
<p1 x="440" y="540"/>
<p2 x="660" y="540"/>
</wire>
<wire>
<p1 x="320" y="220"/>
@ -418,12 +535,12 @@
<p2 x="420" y="340"/>
</wire>
<wire>
<p1 x="360" y="180"/>
<p2 x="360" y="220"/>
<p1 x="100" y="240"/>
<p2 x="100" y="500"/>
</wire>
<wire>
<p1 x="200" y="240"/>
<p2 x="200" y="500"/>
<p1 x="360" y="180"/>
<p2 x="360" y="220"/>
</wire>
<wire>
<p1 x="300" y="240"/>
@ -438,16 +555,16 @@
<p2 x="400" y="420"/>
</wire>
<wire>
<p1 x="80" y="200"/>
<p2 x="80" y="240"/>
<p1 x="-20" y="200"/>
<p2 x="-20" y="260"/>
</wire>
<wire>
<p1 x="80" y="340"/>
<p2 x="80" y="420"/>
<p1 x="-20" y="340"/>
<p2 x="-20" y="420"/>
</wire>
<wire>
<p1 x="80" y="240"/>
<p2 x="80" y="300"/>
<p1 x="-20" y="260"/>
<p2 x="-20" y="300"/>
</wire>
<wire>
<p1 x="500" y="200"/>
@ -455,19 +572,23 @@
</wire>
<wire>
<p1 x="340" y="160"/>
<p2 x="340" y="540"/>
<p2 x="340" y="560"/>
</wire>
<wire>
<p1 x="20" y="80"/>
<p2 x="20" y="160"/>
</wire>
<wire>
<p1 x="20" y="200"/>
<p2 x="20" y="220"/>
</wire>
<wire>
<p1 x="180" y="260"/>
<p2 x="180" y="500"/>
</wire>
<wire>
<p1 x="440" y="400"/>
<p2 x="440" y="520"/>
</wire>
<wire>
<p1 x="120" y="80"/>
<p2 x="120" y="160"/>
</wire>
<wire>
<p1 x="120" y="200"/>
<p2 x="120" y="220"/>
<p2 x="440" y="540"/>
</wire>
<wire>
<p1 x="220" y="80"/>
@ -475,7 +596,7 @@
</wire>
<wire>
<p1 x="220" y="120"/>
<p2 x="220" y="480"/>
<p2 x="220" y="500"/>
</wire>
<wire>
<p1 x="540" y="200"/>

View File

@ -1342,7 +1342,7 @@ Sind evtl. die Namen der Variablen nicht eindeutig?</string>
Erlaubt den Start externer Tools, um z.B. einen FPGA zu programmieren o.ä.</string>
<string name="key_generic">Generisch</string>
<string name="key_generic_tt">String für das Erzeugen generischer Schaltungen.</string>
<string name="key_generic_tt">Anweisung um eine generische Schaltung anzupassen.</string>
<string name="mod_insertWire">Leitung eingefügt.</string>
<string name="mod_insertCopied">Aus Zwischenablage eingefügt.</string>

View File

@ -1330,7 +1330,7 @@
Allows the start of external tools, e.g. to program an FPGA or similar.</string>
<string name="key_generic">Generic</string>
<string name="key_generic_tt">String used to create generic circuits.</string>
<string name="key_generic_tt">Statements used to generify a circuit.</string>
<string name="mod_insertWire">Inserted wire.</string>
<string name="mod_insertCopied">Insert from clipboard.</string>

View File

@ -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());