First fully working implementation

This commit is contained in:
hneemann 2021-01-06 18:33:03 +01:00
parent 00d8a2f845
commit 9c78909bdc
16 changed files with 220 additions and 75 deletions

View File

@ -150,7 +150,7 @@ public class SubstituteLibrary implements LibraryInterface {
c.getAttributes().set(Keys.IS_GENERIC, false);
generify(attr, c);
return ElementLibrary.createCustomDescription(new File(filename), c, library).isSubstitutedBuiltIn();
return ElementLibrary.createCustomDescription(new File(filename), c, library);
}
private void generify(ElementAttributes attr, Circuit circuit) throws IOException {

View File

@ -295,12 +295,24 @@ public class ElementAttributes implements HGSMap {
return get(k);
}
/**
* Adds a value to the instance specific cache
*
* @param key key
* @param value value
*/
public void putToCache(String key, Object value) {
if (cache == null)
cache = new HashMap<>();
cache.put(key, value);
}
/**
* Requests a value from the cache
*
* @param key the key
* @return the value
*/
public Object getFromCache(String key) {
if (cache == null)
return null;

View File

@ -831,7 +831,13 @@ public final class Keys {
* Used to input statements to generify a circuit.
*/
public static final Key<String> GENERIC =
new Key.LongString("generic").allowGroupEdit();
new Key.LongString("generic").setLineNumbers(true).allowGroupEdit();
/**
* Used to input statements to generify a circuit.
*/
public static final Key<String> GENERICLARGE =
new Key.LongString("generic").setLineNumbers(true).setRows(20).allowGroupEdit();
/**
* Circuit is generic

View File

@ -11,7 +11,6 @@ import de.neemann.digital.draw.graphics.*;
import de.neemann.digital.draw.shapes.Shape;
import de.neemann.digital.draw.shapes.*;
import de.neemann.digital.gui.components.CircuitComponent;
import de.neemann.digital.hdl.hgs.Context;
import de.neemann.gui.Screen;
import javax.swing.*;

View File

@ -226,6 +226,7 @@ public class ElementLibrary implements Iterable<ElementLibrary.ElementContainer>
.add(new LibraryNode(Lang.get("lib_misc"))
.add(TestCaseElement.DESCRIPTION)
.add(GenericInitCode.DESCRIPTION)
.add(GenericCode.DESCRIPTION)
.add(DummyElement.RECTDESCRIPTION)
.add(PowerSupply.DESCRIPTION)
.add(BusSplitter.DESCRIPTION)
@ -619,6 +620,7 @@ public class ElementLibrary implements Iterable<ElementLibrary.ElementContainer>
*
* @param file the file
* @param circuit the circuit
* @param library the library
* @return the type description
* @throws PinException PinException
*/

View File

@ -35,7 +35,6 @@ public final class ElementTypeDescriptionCustom extends ElementTypeDescription {
private final LibraryInterface library;
private String description;
private NetList netList;
private boolean isCustom = true;
private String declarationDefault;
/**
@ -127,21 +126,6 @@ public final class ElementTypeDescriptionCustom extends ElementTypeDescription {
return new ModelCreator(circuit, library, true, new NetList(netList, errorVisualElement), subName, depth, errorVisualElement);
}
public boolean isCustom() {
return isCustom;
}
/**
* Used by element substitution to allow to mark custom circuits which replace a built-in
* component to be not custom.
*
* @return this for chained calls
*/
public ElementTypeDescriptionCustom isSubstitutedBuiltIn() {
isCustom = false;
return this;
}
/**
* @return the generics field default value
* @throws NodeException NodeException

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2020 Helmut Neemann.
* Use of this source code is governed by the GPL v3 license
* that can be found in the LICENSE file.
*/
package de.neemann.digital.draw.library;
import de.neemann.digital.core.Model;
import de.neemann.digital.core.NodeException;
import de.neemann.digital.core.ObservableValues;
import de.neemann.digital.core.element.Element;
import de.neemann.digital.core.element.ElementAttributes;
import de.neemann.digital.core.element.ElementTypeDescription;
import de.neemann.digital.core.element.Keys;
/**
* Allows to a generic init code to a circuit.
*/
public class GenericCode implements Element {
/**
* The GenericInitCodeElement description
*/
public static final ElementTypeDescription DESCRIPTION
= new ElementTypeDescription(GenericCode.class)
.addAttribute(Keys.GENERICLARGE)
.supportsHDL();
/**
* creates a new instance
*
* @param attributes the attributes
*/
public GenericCode(ElementAttributes attributes) {
}
@Override
public void setInputs(ObservableValues inputs) throws NodeException {
}
@Override
public ObservableValues getOutputs() {
return ObservableValues.EMPTY_LIST;
}
@Override
public void registerNodes(Model model) {
}
}

View File

@ -31,11 +31,13 @@ import static de.neemann.digital.draw.shapes.GenericShape.SIZE;
*/
public class ResolveGenerics {
private static final Logger LOGGER = LoggerFactory.getLogger(ResolveGenerics.class);
private static final Context EMPTY_CONTEXT = new Context();
/**
* Key uses to store the args for the generic circuits
*/
public static final String GEN_ARGS_KEY = "genArgs";
private final HashMap<String, Statement> map;
private final HashMap<Context, CircuitHolder> circuitMap;
private final HashMap<Args, CircuitHolder> circuitMap;
private final Circuit circuit;
private final LibraryInterface library;
@ -61,23 +63,57 @@ public class ResolveGenerics {
* @throws ElementNotFoundException ElementNotFoundException
*/
public CircuitHolder resolveCircuit(ElementAttributes attributes) throws NodeException, ElementNotFoundException {
Context context = EMPTY_CONTEXT;
if (attributes != null)
context = (Context) attributes.getFromCache(GEN_ARGS_KEY);
Args args;
if (attributes == null)
args = createArgsFromGenericBlock();
else
args = createArgsFromParentCircuitEmbedding(attributes);
CircuitHolder ch = circuitMap.get(context);
CircuitHolder ch = circuitMap.get(args);
if (ch == null) {
ch = innerResolveCircuit(attributes);
circuitMap.put(context, ch);
ch = innerResolveCircuit(args);
circuitMap.put(args, ch);
}
return ch;
}
public CircuitHolder innerResolveCircuit(ElementAttributes parentAttributes) throws NodeException, ElementNotFoundException {
private Args createArgsFromParentCircuitEmbedding(ElementAttributes attributes) throws NodeException {
Context context = (Context) attributes.getFromCache(GEN_ARGS_KEY);
if (context == null) {
String argsCode = attributes.get(Keys.GENERIC);
try {
Statement s = getStatement(argsCode);
context = new Context();
s.execute(context);
} catch (HGSEvalException | ParserException | IOException e) {
final NodeException ex = new NodeException(Lang.get("err_evaluatingGenericsCode_N_N", null, argsCode), e);
ex.setOrigin(circuit.getOrigin());
throw ex;
}
}
return new Args(context);
}
private Args createArgsFromGenericBlock() throws NodeException {
Context context = new Context();
List<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);
}
private CircuitHolder innerResolveCircuit(Args args) throws NodeException, ElementNotFoundException {
LOGGER.info("create concrete circuit based on " + circuit.getOrigin());
final Circuit c = circuit.createDeepCopy();
ArrayList<VisualElement> newComponents = new ArrayList<>();
final Args args = createArgs(parentAttributes, c, newComponents);
for (VisualElement ve : c.getElements()) {
ElementAttributes elementAttributes = ve.getElementAttributes();
@ -125,40 +161,6 @@ public class ResolveGenerics {
}
}
private Args createArgs(ElementAttributes attributes, Circuit circuit, ArrayList<VisualElement> newComponents) throws NodeException {
Context context;
if (attributes != null) {
context = (Context) attributes.getFromCache(GEN_ARGS_KEY);
if (context == null) {
String argsCode = attributes.get(Keys.GENERIC);
try {
Statement s = getStatement(argsCode);
context = createContext(circuit, newComponents);
s.execute(context);
} catch (HGSEvalException | ParserException | IOException e) {
final NodeException ex = new NodeException(Lang.get("err_evaluatingGenericsCode_N_N", null, argsCode), e);
ex.setOrigin(circuit.getOrigin());
throw ex;
}
}
} else {
context = createContext(circuit, newComponents);
List<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);
}
private Statement getStatement(String code) throws IOException, ParserException {
Statement genS = map.get(code);
if (genS == null) {

View File

@ -0,0 +1,86 @@
/*
* Copyright (c) 2016 Helmut Neemann
* Use of this source code is governed by the GPL v3 license
* that can be found in the LICENSE file.
*/
package de.neemann.digital.draw.shapes;
import de.neemann.digital.core.element.ElementAttributes;
import de.neemann.digital.core.element.Keys;
import de.neemann.digital.core.element.PinDescriptions;
import de.neemann.digital.draw.elements.IOState;
import de.neemann.digital.draw.elements.Pins;
import de.neemann.digital.draw.graphics.Graphic;
import de.neemann.digital.draw.graphics.Orientation;
import de.neemann.digital.draw.graphics.Style;
import de.neemann.digital.draw.graphics.Vector;
import de.neemann.digital.lang.Lang;
import java.util.ArrayList;
/**
* Simple text
*/
public class GenericCodeShape implements Shape {
private static final Style STYLE = Style.NORMAL.deriveFontStyle(Style.NORMAL.getFontSize(), true);
private final ArrayList<String> text;
/**
* Create a new instance
*
* @param attr attributes
* @param inputs the inputs
* @param outputs the outputs
*/
public GenericCodeShape(ElementAttributes attr, PinDescriptions inputs, PinDescriptions outputs) {
String gen = attr.get(Keys.GENERIC);
text = new ArrayList<>();
if (gen.isEmpty())
text.add(Lang.get("elem_GenericCode"));
else {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < gen.length(); i++) {
char c = gen.charAt(i);
switch (c) {
case ' ':
sb.append("\u00A0");
break;
case '_':
sb.append("\\_");
break;
case '^':
sb.append("\\^");
break;
case '\n':
text.add(sb.toString());
sb.setLength(0);
default:
sb.append(c);
}
}
if (sb.length() > 0)
text.add(sb.toString());
}
}
@Override
public Pins getPins() {
return new Pins();
}
@Override
public Interactor applyStateMonitor(IOState ioState) {
return null;
}
@Override
public void drawTo(Graphic graphic, Style highLight) {
Vector pos = new Vector(0, 0);
final int dy = (STYLE.getFontSize() * 20) / 16;
for (String s : text) {
graphic.drawText(pos, s, Orientation.LEFTCENTER, STYLE);
pos = pos.add(0, dy);
}
}
}

View File

@ -20,10 +20,7 @@ import de.neemann.digital.core.wiring.*;
import de.neemann.digital.draw.elements.PinException;
import de.neemann.digital.draw.elements.Tunnel;
import de.neemann.digital.draw.graphics.Style;
import de.neemann.digital.draw.library.ElementLibrary;
import de.neemann.digital.draw.library.ElementTypeDescriptionCustom;
import de.neemann.digital.draw.library.GenericInitCode;
import de.neemann.digital.draw.library.JarComponentManager;
import de.neemann.digital.draw.library.*;
import de.neemann.digital.draw.shapes.custom.CustomShape;
import de.neemann.digital.draw.shapes.custom.CustomShapeDescription;
import de.neemann.digital.draw.shapes.ieee.IEEEAndShape;
@ -163,6 +160,7 @@ public final class ShapeFactory {
map.put(DummyElement.RECTDESCRIPTION.getName(), RectShape::new);
map.put(TestCaseElement.DESCRIPTION.getName(), TestCaseShape::new);
map.put(GenericInitCode.DESCRIPTION.getName(), GenericInitCodeShape::new);
map.put(GenericCode.DESCRIPTION.getName(), GenericCodeShape::new);
map.put(AsyncSeq.DESCRIPTION.getName(), AsyncClockShape::new);
map.put(Diode.DESCRIPTION.getName(), DiodeShape::new);

View File

@ -1427,7 +1427,7 @@ public class CircuitComponent extends JComponent implements ChangedListener, Lib
private ArrayList<Key> getAttributeList(VisualElement ve) throws ElementNotFoundException {
ArrayList<Key> list = library.getElementType(ve.getElementName()).getAttributeList();
if (getCircuit().getAttributes().get(Keys.IS_GENERIC) && !list.contains(Keys.GENERIC)) {
if (getCircuit().getAttributes().get(Keys.IS_GENERIC) && !(list.contains(Keys.GENERIC) || list.contains(Keys.GENERICLARGE))) {
list = new ArrayList<>(list);
list.add(Keys.GENERIC);
}

View File

@ -959,6 +959,10 @@
können.
Soll eine generische Schaltung direkt gestartet werden, muss eine solche Komponente vorhanden sein.
</string>
<string name="elem_GenericCode">Code</string>
<string name="elem_GenericCode_tt">Code der ausgeführt wird, wenn eine generische Schaltung konkretisiert wird.
Kann z.B. benutzt werden, um einer Schaltung Komponenten oder Leitungen hinzuzufügen.
</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

View File

@ -938,6 +938,10 @@
<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_GenericCode">Code</string>
<string name="elem_GenericCode_tt">Code that is executed when a generic circuit is made concrete.
Can be used, for example, to add components or wires to a circuit.
</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

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.GenericCode;
import de.neemann.digital.draw.library.GenericInitCode;
import de.neemann.digital.hdl.vhdl2.entities.VHDLTemplate;
import de.neemann.digital.testing.TestCaseElement;
@ -45,6 +46,7 @@ public class TestHDLExportFlag extends TestCase {
implicitSupported.add(TestCaseElement.DESCRIPTION);
implicitSupported.add(GenericInitCode.DESCRIPTION);
implicitSupported.add(GenericCode.DESCRIPTION);
}
public void testHDLExportFlag() {

View File

@ -31,15 +31,8 @@ import static de.neemann.digital.draw.library.ResolveGenerics.GEN_ARGS_KEY;
* Does not ensure that they work correctly if no tests are present in the circuit!
*/
public class TestExamples extends TestCase {
private int testCasesInFiles;
public void testDebug() throws Exception {
File f = new File("/home/hneemann/Dokumente/Java/digital/src/main/dig/generic/barrelShifter/TestBarrelShifter.dig");
check(f);
}
/**
* Tests the examples which are distributed
*

View File

@ -697,6 +697,11 @@
</elementAttributes>
<pos x="420" y="1080"/>
</visualElement>
<visualElement>
<elementName>GenericCode</elementName>
<elementAttributes/>
<pos x="120" y="1120"/>
</visualElement>
</visualElements>
<wires>
<wire>