Merge branch 'genericInit'

This commit is contained in:
hneemann 2020-11-06 12:43:05 +01:00
commit 0184e2c43c
43 changed files with 822 additions and 210 deletions

View File

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

View File

@ -80,33 +80,36 @@
<elementAttributes>
<entry>
<string>generic</string>
<string>if (isPresent(args)) {
if (args.direction=&quot;right&quot;) {
export circuit:=&quot;shift-fixed-right-inc.dig&quot;;
} else {
if (args.direction=&quot;arith&quot;) {
export circuit:=&quot;shift-fixed-arith-right-inc.dig&quot;;
} else {
if (args.direction=&quot;left&quot;) {
export circuit:=&quot;shift-fixed-left-inc.dig&quot;;
} else {
panic(&quot;only \&quot;left\&quot;, \&quot;right\&quot; or \&quot;arith\&quot; is allowed as direction, not \&quot;&quot;+args.direction+&quot;\&quot;!&quot;);
}
}
}
export shiftBits:=bitsNeededFor(args.dataBits-1);
<string>if (args.direction=&quot;right&quot;) {
export circuit:=&quot;shift-fixed-right-inc.dig&quot;;
} else {
// used if circuit is started as the main circuit
export circuit:=&quot;shift-fixed-left-inc.dig&quot;;
export dataBits:=16;
export shiftBits:=int(4);
}</string>
if (args.direction=&quot;arith&quot;) {
export circuit:=&quot;shift-fixed-arith-right-inc.dig&quot;;
} else {
if (args.direction=&quot;left&quot;) {
export circuit:=&quot;shift-fixed-left-inc.dig&quot;;
} else {
panic(&quot;only \&quot;left\&quot;, \&quot;right\&quot; or \&quot;arith\&quot; is allowed as direction, not \&quot;&quot;+args.direction+&quot;\&quot;!&quot;);
}
}
}
shiftBits:=bitsNeededFor(args.dataBits-1);</string>
</entry>
</elementAttributes>
<pos x="420" y="120"/>
</visualElement>
<visualElement>
<elementName>GenericInitCode</elementName>
<elementAttributes>
<entry>
<string>generic</string>
<string>dataBits := 5;
direction := &quot;left&quot;;</string>
</entry>
</elementAttributes>
<pos x="400" y="0"/>
</visualElement>
</visualElements>
<wires>
<wire>

View File

@ -106,6 +106,17 @@ this.outputBits=int(args.dataBits);</string>
</elementAttributes>
<pos x="440" y="160"/>
</visualElement>
<visualElement>
<elementName>GenericInitCode</elementName>
<elementAttributes>
<entry>
<string>generic</string>
<string>dataBits := 8;
shift := 3;</string>
</entry>
</elementAttributes>
<pos x="380" y="20"/>
</visualElement>
</visualElements>
<wires>
<wire>

View File

@ -116,6 +116,17 @@ this.&apos;Output Splitting&apos; = &quot;0-&quot;+(args.dataBits-args.shift-1);
</elementAttributes>
<pos x="440" y="160"/>
</visualElement>
<visualElement>
<elementName>GenericInitCode</elementName>
<elementAttributes>
<entry>
<string>generic</string>
<string>dataBits := 8;
shift := 3;</string>
</entry>
</elementAttributes>
<pos x="400" y="20"/>
</visualElement>
</visualElements>
<wires>
<wire>

View File

@ -116,6 +116,17 @@ this.&apos;Output Splitting&apos; = args.shift+&quot;-&quot;+(args.dataBits-1);<
</elementAttributes>
<pos x="440" y="180"/>
</visualElement>
<visualElement>
<elementName>GenericInitCode</elementName>
<elementAttributes>
<entry>
<string>generic</string>
<string>dataBits := 8;
shift := 3;</string>
</entry>
</elementAttributes>
<pos x="400" y="20"/>
</visualElement>
</visualElements>
<wires>
<wire>

View File

@ -13,14 +13,8 @@
<elementAttributes>
<entry>
<string>generic</string>
<string>if (isPresent(args)) {
export shift := 1&lt;&lt;(args.shiftBits-1);
setCircuit(args.circuit);
} else {
// used if circuit is started as the main circuit
export dataBits:=16;
export shift:=8;
}</string>
<string>shift := 1&lt;&lt;(args.shiftBits-1);
setCircuit(args.circuit);</string>
</entry>
</elementAttributes>
<pos x="320" y="100"/>
@ -92,18 +86,11 @@
<elementAttributes>
<entry>
<string>generic</string>
<string>if (isPresent(args)) {
if (args.shiftBits=2) {
export shift := 1;
setCircuit(args.circuit);
} else {
export shiftBits := args.shiftBits-1;
}
<string>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:=&quot;shift-fixed-left-inc.dig&quot;;
export shiftBits := args.shiftBits-1;
}</string>
</entry>
</elementAttributes>
@ -128,6 +115,42 @@ this.&apos;Output Splitting&apos; = (args.shiftBits-1)+&quot;-&quot;+(args.shift
</elementAttributes>
<pos x="220" y="140"/>
</visualElement>
<visualElement>
<elementName>GenericInitCode</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>3 bits</string>
</entry>
<entry>
<string>generic</string>
<string>circuit := &quot;shift-fixed-left-inc.dig&quot;;
dataBits := 8;
shiftBits := 3;</string>
</entry>
<entry>
<string>enabled</string>
<boolean>false</boolean>
</entry>
</elementAttributes>
<pos x="360" y="-20"/>
</visualElement>
<visualElement>
<elementName>GenericInitCode</elementName>
<elementAttributes>
<entry>
<string>Label</string>
<string>2 bits</string>
</entry>
<entry>
<string>generic</string>
<string>circuit := &quot;shift-fixed-left-inc.dig&quot;;
dataBits := 8;
shiftBits := 2;</string>
</entry>
</elementAttributes>
<pos x="200" y="-20"/>
</visualElement>
</visualElements>
<wires>
<wire>

View File

@ -138,15 +138,23 @@ ist als drei.}}</string>
<entry>
<string>generic</string>
<string>inBits:=2;
if (isPresent(args)) {
if (args.bits&gt;3) {
setCircuit(&quot;GrayNode-inc.dig&quot;);
}
if (args.bits&gt;3) {
setCircuit(&quot;GrayNode-inc.dig&quot;);
}</string>
</entry>
</elementAttributes>
<pos x="500" y="340"/>
</visualElement>
<visualElement>
<elementName>GenericInitCode</elementName>
<elementAttributes>
<entry>
<string>generic</string>
<string>bits := 3;</string>
</entry>
</elementAttributes>
<pos x="200" y="160"/>
</visualElement>
</visualElements>
<wires>
<wire>

View File

@ -162,6 +162,16 @@ den Überlauf korrekt umzusetzen.}}</string>
</elementAttributes>
<pos x="200" y="40"/>
</visualElement>
<visualElement>
<elementName>GenericInitCode</elementName>
<elementAttributes>
<entry>
<string>generic</string>
<string>inBits := 2;</string>
</entry>
</elementAttributes>
<pos x="620" y="220"/>
</visualElement>
</visualElements>
<wires>
<wire>

View File

@ -107,13 +107,9 @@
<elementAttributes>
<entry>
<string>generic</string>
<string>if (isPresent(args)) {
export inBits := args.inBits+1;
if (args.inBits&lt;args.bits-2) {
setCircuit(&quot;GrayNode-inc.dig&quot;);
}
} else {
export inBits:=3;
<string>export inBits := args.inBits+1;
if (args.inBits&lt;args.bits-2) {
setCircuit(&quot;GrayNode-inc.dig&quot;);
}</string>
</entry>
</elementAttributes>
@ -187,6 +183,17 @@ noch nicht erreicht ist.}}</string>
</elementAttributes>
<pos x="80" y="40"/>
</visualElement>
<visualElement>
<elementName>GenericInitCode</elementName>
<elementAttributes>
<entry>
<string>generic</string>
<string>bits := 4;
inBits := 2;</string>
</entry>
</elementAttributes>
<pos x="480" y="140"/>
</visualElement>
</visualElements>
<wires>
<wire>

View File

@ -1060,6 +1060,16 @@ this.&apos;Output Splitting&apos;=&quot;2-&quot;+(args.addrBits-1)+&quot;,0-0,1-
</elementAttributes>
<pos x="140" y="520"/>
</visualElement>
<visualElement>
<elementName>GenericInitCode</elementName>
<elementAttributes>
<entry>
<string>generic</string>
<string>addrBits := 8;</string>
</entry>
</elementAttributes>
<pos x="880" y="120"/>
</visualElement>
</visualElements>
<wires>
<wire>

View File

@ -220,6 +220,7 @@ public class ElementLibrary implements Iterable<ElementLibrary.ElementContainer>
.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)

View File

@ -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<String> nameSet = new TreeSet<>();
for (VisualElement ve : circuit.getElements()) {
String gen = ve.getElementAttributes().get(Keys.GENERIC).trim();

View File

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

View File

@ -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<String, Statement> 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<VisualElement> 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<String> contentSet = new HashSet<>();
addVal(sb, "", args, contentSet);
return sb.toString();
}
private static void addVal(StringBuilder sb, String key, Object val, HashSet<String> 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;
}

View File

@ -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<ModelEntry> {
* @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;
}
/**

View File

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

View File

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

View File

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

View File

@ -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<Circuit> 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<VisualElement> elementList = getCircuit().getElementListAt(getPosVector(e), false);
Circuit circuit;
if (shallowCopy != null)
circuit = shallowCopy;
else
circuit = getCircuit();
List<VisualElement> elementList = circuit.getElementListAt(getPosVector(e), false);
for (VisualElement ve : elementList) {
if (ve.isInteractive())
return ve;

View File

@ -281,6 +281,13 @@ public class Context implements HGSMap {
return map.get(key);
}
/**
* @return the set of all contained values
*/
public HashSet<String> getKeySet() {
return new HashSet<>(map.keySet());
}
private static final class FunctionPrint extends InnerFunction {
private FunctionPrint() {
super(-1);

View File

@ -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<String> args = new ArrayList<>();
@ -608,4 +637,24 @@ public class Parser {
}
}
private static final class StructLiteral implements Expression {
private final HashMap<String, Expression> 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<String, Object> vmap = new HashMap<>();
for (Map.Entry<String, Expression> e : map.entrySet())
vmap.put(e.getKey(), e.getValue().value(c));
return vmap;
}
}
}

View File

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

View File

@ -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<HDLCircuit> {
* @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;

View File

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

View File

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

View File

@ -875,22 +875,32 @@
<string name="elem_TransGate_pin_~S">Steuereingang, invertiert</string>
<!-- Sonstige -->
<string name="elem_Testcase">Testfall</string>
<string name="elem_Testcase_tt">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.</string>
dieser Beschreibung entspricht. Ist das nicht der Fall, wird eine entsprechende Fehlermeldung angezeigt.
</string>
<string name="elem_GenericInitCode">Generische Initialisierung</string>
<string name="elem_GenericInitCode_tt">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.
</string>
<string name="elem_AsyncSeq">Asynchrones Timing</string>
<string name="elem_AsyncSeq_tt">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.</string>
Die Taktelemente können in diesem Modus nicht verwendet werden.
</string>
<string name="elem_PowerSupply">Versorgung</string>
<string name="elem_PowerSupply_tt">Hat keine weitere Funktion. Stellt nur sicher, dass VDD und GND angeschlossen sind.
<string name="elem_PowerSupply_tt">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.</string>
zu erzeugen, welche dann auch auf korrekte Beschaltung geprüft werden.
</string>
<string name="elem_PowerSupply_pin_VDD">Muss mit VDD verbunden werden!</string>
<string name="elem_PowerSupply_pin_GND">Muss mit GND verbunden werden!</string>
<string name="elem_Reset">Reset</string>
@ -1112,27 +1122,37 @@ Sind evtl. die Namen der Variablen nicht eindeutig?</string>
<string name="err_hdlNotKnown_N">HDL nicht bekannt: {0}</string>
<string name="msg_errorStartCommand_N">Fehler beim Starten des Kommandos {0}</string>
<string name="err_thereIsAUnnamedIO">Es gibt einen unbenannten Ein- oder Ausgang.</string>
<string name="err_NameOfIOIsInvalidOrNotUnique_N">Der Signalname "{0}" ist ungültig oder mehrfach verwendet!</string>
<string name="err_NameOfIOIsInvalidOrNotUnique_N">Der Signalname "{0}" ist ungültig oder mehrfach verwendet!
</string>
<string name="err_substitutingError">Fehler bei der Substitution von Elementen für die Analyse.</string>
<string name="err_evaluatingGenericsCode_N_N">Fehler bei der Auswertung des generischen Codes der Schaltung. Code:
{1}
in Komponente: {0}
</string>
<string name="msg_errParsingGenerics">Fehler bei der Analyse des generischen Codes.</string>
<string name="err_noGenericInitCode">Kein Initialisierungscode für die generischen Elemente.</string>
<string name="err_multipleGenericInitCodes">Mehrere Initialisierungscodes für die generischen Elemente.</string>
<string name="err_inGenericInitCode">Fehler bei der Analyse des generischen Initialisierungscodes.</string>
<string name="err_vgaModeNotDetected_N">Videomodus wurde nicht erkannt ({0})</string>
<string name="err_ROM_noFileGivenToLoad">Es ist kein Dateiname für das automatische Neuladen verfügbar!</string>
<string name="key_AddrBits">Adress-Bits</string><!-- ROM, RAMDualPort, RAMSinglePort, RAMSinglePortSel, EEPROM -->
<string name="key_AddrBits_tt">Anzahl der Adress-Bits, die verwendet werden.</string>
<string name="key_Bits">Daten-Bits</string><!-- And, NAnd, Or, NOr, XOr, XNOr, Not, LookUpTable, Delay, Out, In, Ground, VDD, Const, PullUp, PullDown, Driver, DriverInvSel, Multiplexer, Demultiplexer, D_FF, D_FF_AS, Register, ROM, RAMDualPort, RAMSinglePort, RAMSinglePortSel, EEPROM, GraphicCard, Counter, Add, Sub, Mul, BarrelShifter, Comparator, Neg, BitCount, Switch, Relay, PFET, NFET, FGPFET, FGNFET, TransGate -->
<string name="key_Bits">Daten-Bits
</string> <!-- And, NAnd, Or, NOr, XOr, XNOr, Not, LookUpTable, Delay, Out, In, Ground, VDD, Const, PullUp, PullDown, Driver, DriverInvSel, Multiplexer, Demultiplexer, D_FF, D_FF_AS, Register, ROM, RAMDualPort, RAMSinglePort, RAMSinglePortSel, EEPROM, GraphicCard, Counter, Add, Sub, Mul, BarrelShifter, Comparator, Neg, BitCount, Switch, Relay, PFET, NFET, FGPFET, FGNFET, TransGate -->
<string name="key_Bits_tt">Anzahl der Daten-Bits, die verwendet werden.</string>
<string name="key_Color">Farbe</string><!-- LED, LightBulb, Seven-Seg, Seven-Seg-Hex, LedMatrix -->
<string name="key_Color_tt">Die Farbe des Elementes.</string>
<string name="key_backgroundColor">Hintergrundfarbe</string>
<string name="key_backgroundColor_tt">Hintergrundfarbe der Schaltung, wenn sie eingebettet wird. Wird für DILs nicht verwendet.</string>
<string name="key_backgroundColor_tt">Hintergrundfarbe der Schaltung, wenn sie eingebettet wird. Wird für DILs nicht
verwendet.
</string>
<string name="key_Cycles">Timeout Zyklen</string><!-- Break -->
<string name="key_Cycles_tt">Wenn nach dieser Anzahl von Takten kein Break eingegangen ist, wird ein Fehler erzeugt</string>
<string name="key_Cycles_tt">Wenn nach dieser Anzahl von Takten kein Break eingegangen ist, wird ein Fehler
erzeugt
</string>
<string name="key_Data">Daten</string><!-- LookUpTable, ROM, EEPROM -->
<string name="key_Data_tt">Die Daten, welche in diesem Element gespeichert sind.</string>
<string name="key_Default">Vorgabe</string><!-- Demultiplexer, RS_FF, JK_FF, D_FF, T_FF, JK_FF_AS, D_FF_AS -->
@ -1998,6 +2018,12 @@ Stellen Sie sicher, dass der Flash-Vorgang abgeschlossen ist, bevor Sie diesen D
<string name="btn_help">Hilfe</string>
<string name="msg_keyAsGenericAttribute">Name in einer generischen Schaltung: {0}</string>
<string name="attr_createConcreteCircuitLabel">Konkrete Schaltung erzeugen</string>
<string name="attr_createConcreteCircuit">Erzeugen</string>
<string name="attr_createConcreteCircuit_tt">Erzeugt aus dieser generischen Schaltung eine konkrete Schaltung
unter Anwendung der in diesem Element angegebenen Parameter.
</string>
<string name="attr_createConcreteCircuitErr">Fehler bei der Erzeugung der konkreten Schaltung!</string>
<string name="win_romDialogHelpTitle">Zentrale ROM Inhalte</string>
<string name="msg_romDialogHelp"><![CDATA[

View File

@ -887,14 +887,21 @@
behavior of the circuit actually corresponds to this description. If this is not the case, an
error message is shown.
</string>
<string name="elem_GenericInitCode">Generic Initialization</string>
<string name="elem_GenericInitCode_tt">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.
</string>
<string name="elem_AsyncSeq">Asynchronous Timing</string>
<string name="elem_AsyncSeq_tt">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.</string>
It is not allowed to use a regular clock component in this mode.
</string>
<string name="elem_PowerSupply">Power</string>
<string name="elem_PowerSupply_tt">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.</string>
Can be used in 74xx circuits to generate the pins for the voltage supply, which are tested for correct wiring.
</string>
<string name="elem_PowerSupply_pin_VDD">Must be connected to VDD!</string>
<string name="elem_PowerSupply_pin_GND">Must be connected to GND!</string>
<string name="elem_Reset">Reset</string>
@ -1132,20 +1139,29 @@
<string name="err_substitutingError">Error when substituting components for the analysis.</string>
<string name="err_evaluatingGenericsCode_N_N">Error in the evaluation of the generic code of the circuit. Code
{1}
at Component: {0}</string>
at Component: {0}
</string>
<string name="msg_errParsingGenerics">Error while parsing generics code.</string>
<string name="err_noGenericInitCode">No initialization code for the generic components.</string>
<string name="err_multipleGenericInitCodes">Multiple initialization codes for the generic elements.</string>
<string name="err_inGenericInitCode">Error in the analysis of the generic initialization code.</string>
<string name="err_ROM_noFileGivenToLoad">There is no file name available for the automatic reload!</string>
<string name="key_AddrBits">Address Bits</string><!-- ROM, RAMDualPort, RAMSinglePort, RAMSinglePortSel, EEPROM -->
<string name="key_AddrBits_tt">Number of address bits used.</string>
<string name="key_Bits">Data Bits</string><!-- And, NAnd, Or, NOr, XOr, XNOr, Not, LookUpTable, Delay, Out, In, Ground, VDD, Const, PullUp, PullDown, Driver, DriverInvSel, Multiplexer, Demultiplexer, D_FF, D_FF_AS, Register, ROM, RAMDualPort, RAMSinglePort, RAMSinglePortSel, EEPROM, GraphicCard, Counter, Add, Sub, Mul, BarrelShifter, Comparator, Neg, BitCount, Switch, Relay, PFET, NFET, FGPFET, FGNFET, TransGate -->
<string name="key_Bits">Data Bits
</string> <!-- And, NAnd, Or, NOr, XOr, XNOr, Not, LookUpTable, Delay, Out, In, Ground, VDD, Const, PullUp, PullDown, Driver, DriverInvSel, Multiplexer, Demultiplexer, D_FF, D_FF_AS, Register, ROM, RAMDualPort, RAMSinglePort, RAMSinglePortSel, EEPROM, GraphicCard, Counter, Add, Sub, Mul, BarrelShifter, Comparator, Neg, BitCount, Switch, Relay, PFET, NFET, FGPFET, FGNFET, TransGate -->
<string name="key_Bits_tt">Number of data bits used.</string>
<string name="key_Color">Color</string><!-- LED, LightBulb, Seven-Seg, Seven-Seg-Hex, LedMatrix -->
<string name="key_Color_tt">The Color of the element.</string>
<string name="key_backgroundColor">Background color</string>
<string name="key_backgroundColor_tt">Background color of the circuit when it is embedded in another circuit. Is not used for DIL packages.</string>
<string name="key_backgroundColor_tt">Background color of the circuit when it is embedded in another circuit. Is not
used for DIL packages.
</string>
<string name="key_Cycles">Timeout cycles</string><!-- Break -->
<string name="key_Cycles_tt">If this amount of cycles is reached without a break signal, an error is created.</string>
<string name="key_Cycles_tt">If this amount of cycles is reached without a break signal, an error is created.
</string>
<string name="key_Data">Data</string><!-- LookUpTable, ROM, EEPROM -->
<string name="key_Data_tt">The values stored in this element.</string>
<string name="key_Default">Default</string><!-- Demultiplexer, RS_FF, JK_FF, D_FF, T_FF, JK_FF_AS, D_FF_AS -->
@ -1845,6 +1861,12 @@
<string name="stat_addrBits">Addr. Bits</string>
<string name="msg_keyAsGenericAttribute">Name to use in generic circuits: {0}</string>
<string name="attr_createConcreteCircuitLabel">Create Concrete Circuit</string>
<string name="attr_createConcreteCircuit">Create</string>
<string name="attr_createConcreteCircuit_tt">Creates a concrete circuit from this generic circuit using the
parameters specified in this element.
</string>
<string name="attr_createConcreteCircuitErr">Error while creating the concrete circuit!</string>
<string name="message">&lt;h1&gt;Digital&lt;/h1&gt;A simple simulator for digital circuits.
Written by H. Neemann in 2016-2020.
@ -1852,9 +1874,11 @@
The icons are taken from the &lt;a href=&quot;http://tango.freedesktop.org&quot;&gt;Tango Desktop Project&lt;/a&gt;.
Visit the project at &lt;a href=&quot;https://github.com/hneemann/[[name]]&quot;&gt;GitHub&lt;/a&gt;.
At Github you can also &lt;a href=&quot;https://github.com/hneemann/[[name]]/releases/latest&quot;&gt;download&lt;/a&gt; the latest release.
At Github you can also &lt;a href=&quot;https://github.com/hneemann/[[name]]/releases/latest&quot;&gt;download&lt;/a&gt;
the latest release.
There you also can file an &lt;a href=&quot;https://github.com/hneemann/[[name]]/issues/new?body=version:%20[[version]]&amp;labels=bug&quot;&gt;issue&lt;/a&gt; or suggest
There you also can file an &lt;a href=&quot;https://github.com/hneemann/[[name]]/issues/new?body=version:%20[[version]]&amp;labels=bug&quot;&gt;issue&lt;/a&gt;
or suggest
an &lt;a href=&quot;https://github.com/hneemann/[[name]]/issues/new?labels=enhancement&quot;&gt;enhancement&lt;/a&gt;.
</string>
<string name="msg_N_nodes">{0} nodes</string>

View File

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

View File

@ -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<String, Object> m = (Map<String, Object>) str;
assertEquals(3, m.size());
assertEquals(1L, m.get("a"));
assertEquals(2L, m.get("b"));
Map<String, Object> c = (Map<String, Object>) m.get("c");
assertEquals(1, c.size());
assertEquals(7L, c.get("d"));
str = new Parser("{a:{}}").parseExp().value(new Context());
m = (Map<String, Object>) str;
assertEquals(1, m.size());
Map<String, Object> a = (Map<String, Object>) 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());

View File

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

View File

@ -492,7 +492,7 @@
<visualElement>
<elementName>Testcase</elementName>
<elementAttributes/>
<pos x="100" y="480"/>
<pos x="100" y="500"/>
</visualElement>
<visualElement>
<elementName>PowerSupply</elementName>
@ -658,6 +658,11 @@
<elementAttributes/>
<pos x="420" y="1020"/>
</visualElement>
<visualElement>
<elementName>GenericInitCode</elementName>
<elementAttributes/>
<pos x="100" y="440"/>
</visualElement>
</visualElements>
<wires>
<wire>

View File

@ -168,6 +168,16 @@
</elementAttributes>
<pos x="340" y="280"/>
</visualElement>
<visualElement>
<elementName>GenericInitCode</elementName>
<elementAttributes>
<entry>
<string>generic</string>
<string>bits := 4;</string>
</entry>
</elementAttributes>
<pos x="460" y="20"/>
</visualElement>
</visualElements>
<wires>
<wire>

View File

@ -88,7 +88,7 @@ this.&apos;Input Splitting&apos;=args.bits+&quot;,&quot;+args.bits;</string>
</entry>
<entry>
<string>generic</string>
<string>this.Bits=int(args.bits);</string>
<string>this.Bits=int(args.bits*2);</string>
</entry>
</elementAttributes>
<pos x="620" y="120"/>
@ -121,6 +121,16 @@ this.&apos;Input Splitting&apos;=args.bits+&quot;,&quot;+args.bits;</string>
</elementAttributes>
<pos x="380" y="140"/>
</visualElement>
<visualElement>
<elementName>GenericInitCode</elementName>
<elementAttributes>
<entry>
<string>generic</string>
<string>bits := 2;</string>
</entry>
</elementAttributes>
<pos x="500" y="40"/>
</visualElement>
</visualElements>
<wires>
<wire>

View File

@ -23,10 +23,7 @@
<elementAttributes>
<entry>
<string>generic</string>
<string>bits:=4;
if (isPresent(args)) {
bits=args.bits;
}</string>
<string>bits:=args.bits;</string>
</entry>
</elementAttributes>
<pos x="380" y="160"/>
@ -78,6 +75,16 @@ if (isPresent(args)) {
<elementAttributes/>
<pos x="360" y="220"/>
</visualElement>
<visualElement>
<elementName>GenericInitCode</elementName>
<elementAttributes>
<entry>
<string>generic</string>
<string>bits := 4;</string>
</entry>
</elementAttributes>
<pos x="360" y="60"/>
</visualElement>
</visualElements>
<wires>
<wire>

View File

@ -80,9 +80,7 @@
<elementAttributes>
<entry>
<string>generic</string>
<string>if (isPresent(args)) {
if (args.direction=&quot;right&quot;) {
<string>if (args.direction=&quot;right&quot;) {
export circuit:=&quot;shift-fixed-right-inc.dig&quot;;
} else {
if (args.direction=&quot;arith&quot;) {
@ -91,22 +89,27 @@
if (args.direction=&quot;left&quot;) {
export circuit:=&quot;shift-fixed-left-inc.dig&quot;;
} else {
panic(&quot;only \&quot;left\&quot;, \&quot;right\&quot; or \&quot;arith\&quot; is allowed as direction, not \&quot;&quot;+args.dir+&quot;\&quot;!&quot;);
panic(&quot;only \&quot;left\&quot;, \&quot;right\&quot; or \&quot;arith\&quot; is allowed as direction, not \&quot;&quot;+args.direction+&quot;\&quot;!&quot;);
}
}
}
export shiftBits:=bitsNeededFor(args.dataBits-1);
} else {
// used if circuit is started as the main circuit
export circuit:=&quot;shift-fixed-left-inc.dig&quot;;
export dataBits:=16;
export shiftBits:=int(4);
}</string>
export shiftBits:=bitsNeededFor(args.dataBits-1);</string>
</entry>
</elementAttributes>
<pos x="420" y="120"/>
</visualElement>
<visualElement>
<elementName>GenericInitCode</elementName>
<elementAttributes>
<entry>
<string>generic</string>
<string>dataBits := 5;
direction := &quot;left&quot;;</string>
</entry>
</elementAttributes>
<pos x="400" y="0"/>
</visualElement>
</visualElements>
<wires>
<wire>

View File

@ -106,6 +106,17 @@ this.outputBits=int(args.dataBits);</string>
</elementAttributes>
<pos x="440" y="160"/>
</visualElement>
<visualElement>
<elementName>GenericInitCode</elementName>
<elementAttributes>
<entry>
<string>generic</string>
<string>dataBits := 8;
shift := 3;</string>
</entry>
</elementAttributes>
<pos x="380" y="20"/>
</visualElement>
</visualElements>
<wires>
<wire>

View File

@ -116,6 +116,17 @@ this.&apos;Output Splitting&apos; = &quot;0-&quot;+(args.dataBits-args.shift-1);
</elementAttributes>
<pos x="440" y="160"/>
</visualElement>
<visualElement>
<elementName>GenericInitCode</elementName>
<elementAttributes>
<entry>
<string>generic</string>
<string>dataBits := 8;
shift := 3;</string>
</entry>
</elementAttributes>
<pos x="400" y="20"/>
</visualElement>
</visualElements>
<wires>
<wire>

View File

@ -116,6 +116,17 @@ this.&apos;Output Splitting&apos; = args.shift+&quot;-&quot;+(args.dataBits-1);<
</elementAttributes>
<pos x="440" y="180"/>
</visualElement>
<visualElement>
<elementName>GenericInitCode</elementName>
<elementAttributes>
<entry>
<string>generic</string>
<string>dataBits := 8;
shift := 3;</string>
</entry>
</elementAttributes>
<pos x="400" y="20"/>
</visualElement>
</visualElements>
<wires>
<wire>

View File

@ -13,14 +13,8 @@
<elementAttributes>
<entry>
<string>generic</string>
<string>if (isPresent(args)) {
export shift := 1&lt;&lt;(args.shiftBits-1);
setCircuit(args.circuit);
} else {
// used if circuit is started as the main circuit
export dataBits:=16;
export shift:=8;
}</string>
<string>export shift := 1&lt;&lt;(args.shiftBits-1);
setCircuit(args.circuit);</string>
</entry>
</elementAttributes>
<pos x="320" y="100"/>
@ -92,18 +86,11 @@
<elementAttributes>
<entry>
<string>generic</string>
<string>if (isPresent(args)) {
if (args.shiftBits=2) {
export shift := 1;
setCircuit(args.circuit);
} else {
export shiftBits := args.shiftBits-1;
}
<string>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:=&quot;shift-fixed-left-inc.dig&quot;;
export shiftBits := args.shiftBits-1;
}</string>
</entry>
</elementAttributes>
@ -128,6 +115,18 @@ this.&apos;Output Splitting&apos; = (args.shiftBits-1)+&quot;-&quot;+(args.shift
</elementAttributes>
<pos x="220" y="140"/>
</visualElement>
<visualElement>
<elementName>GenericInitCode</elementName>
<elementAttributes>
<entry>
<string>generic</string>
<string>circuit := &quot;shift-fixed-left-inc.dig&quot;;
dataBits := 8;
shiftBits := 3;</string>
</entry>
</elementAttributes>
<pos x="300" y="-20"/>
</visualElement>
</visualElements>
<wires>
<wire>

View File

@ -113,6 +113,16 @@
</elementAttributes>
<pos x="460" y="180"/>
</visualElement>
<visualElement>
<elementName>GenericInitCode</elementName>
<elementAttributes>
<entry>
<string>generic</string>
<string>dataBits := 8;</string>
</entry>
</elementAttributes>
<pos x="440" y="60"/>
</visualElement>
</visualElements>
<wires>
<wire>

View File

@ -134,6 +134,16 @@
</elementAttributes>
<pos x="440" y="180"/>
</visualElement>
<visualElement>
<elementName>GenericInitCode</elementName>
<elementAttributes>
<entry>
<string>generic</string>
<string>dataBits := 8;</string>
</entry>
</elementAttributes>
<pos x="380" y="380"/>
</visualElement>
</visualElements>
<wires>
<wire>

View File

@ -17,9 +17,7 @@
</entry>
<entry>
<string>generic</string>
<string>if (isPresent(args)) {
this.Bits=int(args.dataBits);
}</string>
<string>this.Bits=int(args.dataBits);</string>
</entry>
</elementAttributes>
<pos x="240" y="140"/>
@ -37,9 +35,7 @@
</entry>
<entry>
<string>generic</string>
<string>if (isPresent(args)) {
this.Bits=int(args.addrBits);
}</string>
<string>this.Bits=int(args.addrBits);</string>
</entry>
</elementAttributes>
<pos x="240" y="300"/>
@ -63,9 +59,7 @@
</entry>
<entry>
<string>generic</string>
<string>if (isPresent(args)) {
this.Bits=int(args.dataBits);
}</string>
<string>this.Bits=int(args.dataBits);</string>
</entry>
</elementAttributes>
<pos x="680" y="200"/>
@ -85,9 +79,7 @@
<elementAttributes>
<entry>
<string>generic</string>
<string>if (isPresent(args)) {
this.Bits=int(args.dataBits);
}</string>
<string>this.Bits=int(args.dataBits);</string>
</entry>
</elementAttributes>
<pos x="620" y="180"/>
@ -122,15 +114,12 @@
</entry>
<entry>
<string>generic</string>
<string>if (isPresent(args)) {
<string>if (args.addrBits&lt;2) {
panic(&quot;at least two address bits are necessary!&quot;);
}
if (args.addrBits&lt;2) {
panic(&quot;at least two address bits are necessary!&quot;);
}
this.&apos;Input Splitting&apos;=&quot;&quot;+args.addrBits;
this.&apos;Output Splitting&apos;=(args.addrBits-1)+&quot;,1&quot;;
}</string>
this.&apos;Input Splitting&apos;=&quot;&quot;+args.addrBits;
this.&apos;Output Splitting&apos;=(args.addrBits-1)+&quot;,1&quot;;</string>
</entry>
</elementAttributes>
<pos x="280" y="300"/>
@ -140,13 +129,9 @@
<elementAttributes>
<entry>
<string>generic</string>
<string>if (isPresent(args)) {
export addrBits:=args.addrBits-1;
if (args.addrBits&gt;2) {
setCircuit(&quot;memNode.dig&quot;);
}
} else {
export dataBits:=int(1);
<string>export addrBits:=args.addrBits-1;
if (args.addrBits&gt;2) {
setCircuit(&quot;memNode.dig&quot;);
}</string>
</entry>
</elementAttributes>
@ -157,18 +142,25 @@
<elementAttributes>
<entry>
<string>generic</string>
<string>if (isPresent(args)) {
export addrBits:=args.addrBits-1;
if (args.addrBits&gt;2) {
setCircuit(&quot;memNode.dig&quot;);
}
} else {
export dataBits:=int(1);
<string>export addrBits:=args.addrBits-1;
if (args.addrBits&gt;2) {
setCircuit(&quot;memNode.dig&quot;);
}</string>
</entry>
</elementAttributes>
<pos x="520" y="280"/>
</visualElement>
<visualElement>
<elementName>GenericInitCode</elementName>
<elementAttributes>
<entry>
<string>generic</string>
<string>addrBits := 8;
dataBits := 8;</string>
</entry>
</elementAttributes>
<pos x="200" y="340"/>
</visualElement>
</visualElements>
<wires>
<wire>

View File

@ -17,9 +17,7 @@
</entry>
<entry>
<string>generic</string>
<string>if (isPresent(args)) {
this.Bits=int(args.dataBits);
}</string>
<string>this.Bits=int(args.dataBits);</string>
</entry>
</elementAttributes>
<pos x="240" y="140"/>
@ -37,9 +35,7 @@
</entry>
<entry>
<string>generic</string>
<string>if (isPresent(args)) {
this.Bits=int(args.addrBits);
}</string>
<string>this.Bits=int(args.addrBits);</string>
</entry>
</elementAttributes>
<pos x="240" y="320"/>
@ -63,9 +59,7 @@
</entry>
<entry>
<string>generic</string>
<string>if (isPresent(args)) {
this.Bits=int(args.dataBits);
}</string>
<string>this.Bits=int(args.dataBits);</string>
</entry>
</elementAttributes>
<pos x="740" y="220"/>
@ -89,9 +83,7 @@
</entry>
<entry>
<string>generic</string>
<string>if (isPresent(args)) {
this.Bits=int(args.dataBits);
}</string>
<string>this.Bits=int(args.dataBits);</string>
</entry>
</elementAttributes>
<pos x="680" y="180"/>
@ -109,19 +101,16 @@
</entry>
<entry>
<string>generic</string>
<string>if (isPresent(args)) {
<string>if (args.addrBits&lt;4) {
panic(&quot;at least two address bits are necessary!&quot;);
}
if (args.addrBits&lt;4) {
panic(&quot;at least two address bits are necessary!&quot;);
}
if ((args.addrBits&amp;1)=1) {
panic(&quot;number of address bits must be even!&quot;);
}
if ((args.addrBits&amp;1)=1) {
panic(&quot;number of address bits must be even!&quot;);
}
this.&apos;Input Splitting&apos;=&quot;&quot;+args.addrBits;
this.&apos;Output Splitting&apos;=(args.addrBits-2)+&quot;,2&quot;;
}</string>
this.&apos;Input Splitting&apos;=&quot;&quot;+args.addrBits;
this.&apos;Output Splitting&apos;=(args.addrBits-2)+&quot;,2&quot;;</string>
</entry>
</elementAttributes>
<pos x="280" y="320"/>
@ -141,13 +130,9 @@
<elementAttributes>
<entry>
<string>generic</string>
<string>if (isPresent(args)) {
export addrBits:=args.addrBits-2;
if (args.addrBits&gt;4) {
setCircuit(&quot;memNode2.dig&quot;);
}
} else {
export dataBits:=int(1);
<string>export addrBits:=args.addrBits-2;
if (args.addrBits&gt;4) {
setCircuit(&quot;memNode2.dig&quot;);
}</string>
</entry>
</elementAttributes>
@ -158,13 +143,9 @@
<elementAttributes>
<entry>
<string>generic</string>
<string>if (isPresent(args)) {
export addrBits:=args.addrBits-2;
if (args.addrBits&gt;4) {
setCircuit(&quot;memNode2.dig&quot;);
}
} else {
export dataBits:=int(1);
<string>export addrBits:=args.addrBits-2;
if (args.addrBits&gt;4) {
setCircuit(&quot;memNode2.dig&quot;);
}</string>
</entry>
</elementAttributes>
@ -175,13 +156,9 @@
<elementAttributes>
<entry>
<string>generic</string>
<string>if (isPresent(args)) {
export addrBits:=args.addrBits-2;
if (args.addrBits&gt;4) {
setCircuit(&quot;memNode2.dig&quot;);
}
} else {
export dataBits:=int(1);
<string>export addrBits:=args.addrBits-2;
if (args.addrBits&gt;4) {
setCircuit(&quot;memNode2.dig&quot;);
}</string>
</entry>
</elementAttributes>
@ -192,18 +169,25 @@
<elementAttributes>
<entry>
<string>generic</string>
<string>if (isPresent(args)) {
export addrBits:=args.addrBits-2;
if (args.addrBits&gt;4) {
setCircuit(&quot;memNode2.dig&quot;);
}
} else {
export dataBits:=int(1);
<string>export addrBits:=args.addrBits-2;
if (args.addrBits&gt;4) {
setCircuit(&quot;memNode2.dig&quot;);
}</string>
</entry>
</elementAttributes>
<pos x="540" y="560"/>
</visualElement>
<visualElement>
<elementName>GenericInitCode</elementName>
<elementAttributes>
<entry>
<string>generic</string>
<string>addrBits := 8;
dataBits := 8;</string>
</entry>
</elementAttributes>
<pos x="220" y="420"/>
</visualElement>
</visualElements>
<wires>
<wire>