diff --git a/src/main/java/de/neemann/digital/draw/model/Net.java b/src/main/java/de/neemann/digital/draw/model/Net.java index 9d45f8214..3047592a6 100644 --- a/src/main/java/de/neemann/digital/draw/model/Net.java +++ b/src/main/java/de/neemann/digital/draw/model/Net.java @@ -277,6 +277,9 @@ public class Net { return visualElement; } + /** + * @return the set of labels attached to this net + */ public HashSet getLabels() { return labelSet; } diff --git a/src/main/java/de/neemann/digital/hdl/model2/HDLCircuit.java b/src/main/java/de/neemann/digital/hdl/model2/HDLCircuit.java index b43820257..b2aea5dff 100644 --- a/src/main/java/de/neemann/digital/hdl/model2/HDLCircuit.java +++ b/src/main/java/de/neemann/digital/hdl/model2/HDLCircuit.java @@ -9,7 +9,6 @@ import de.neemann.digital.core.NodeException; import de.neemann.digital.core.basic.Not; import de.neemann.digital.core.element.ElementAttributes; import de.neemann.digital.core.element.Keys; -import de.neemann.digital.core.element.PinDescription; import de.neemann.digital.core.io.In; import de.neemann.digital.core.io.Out; import de.neemann.digital.core.io.PowerSupply; @@ -23,22 +22,34 @@ import de.neemann.digital.draw.model.InverterConfig; import de.neemann.digital.draw.model.Net; import de.neemann.digital.draw.model.NetList; import de.neemann.digital.gui.components.data.DummyElement; +import de.neemann.digital.hdl.printer.CodePrinter; import de.neemann.digital.testing.TestCaseElement; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; +import java.io.IOException; +import java.util.*; -public class HDLCircuit implements Iterable, HDLContext.BitProvider { +/** + * The representation of a circuit + */ +public class HDLCircuit implements Iterable, HDLContext.BitProvider, Printable { private final String elementName; private final ArrayList outputs; private final ArrayList inputs; + private final ArrayList listOfNets; private NetList netList; private ArrayList nodes; private HashMap nets; - private int netNumber; + /** + * Creates a new instance + * + * @param circuit the circuit + * @param elementName the name of the circuit + * @param c the context to create the circuits + * @throws PinException PinException + * @throws HDLException HDLException + * @throws NodeException NodeException + */ public HDLCircuit(Circuit circuit, String elementName, HDLContext c) throws PinException, HDLException, NodeException { this.elementName = elementName; inputs = new ArrayList<>(); @@ -64,7 +75,7 @@ public class HDLCircuit implements Iterable, HDLContext.BitProvider { v.getElementAttributes().getBits()) .setPinNumber(v.getElementAttributes().get(Keys.PINNUMBER))); else if (isRealElement(v)) - addNode(v, c); + nodes.add(c.createNode(v, this)); } } catch (HDLException e) { throw new HDLException("error parsing " + circuit.getOrigin(), e); @@ -89,6 +100,19 @@ public class HDLCircuit implements Iterable, HDLContext.BitProvider { } nodes.addAll(newNodes); + + listOfNets = new ArrayList<>(); + listOfNets.addAll(nets.values()); + + nets = null; + + for (HDLPort i : inputs) + i.getNet().setIsInput(i.getName()); + + for (HDLPort o : outputs) + if (o.getNet().needsVariable()) + o.getNet().setIsOutput(o.getName(), o.getNet().getInputs().size() == 1); + } private HDLNode createNot(HDLPort p) throws HDLException, NodeException, PinException { @@ -126,7 +150,7 @@ public class HDLCircuit implements Iterable, HDLContext.BitProvider { && !v.equalsDescription(TestCaseElement.TESTCASEDESCRIPTION); } - private HDLNet getNetOfPin(Pin pin) { + HDLNet getNetOfPin(Pin pin) { Net n = netList.getNetOfPos(pin.getPos()); if (n == null) return null; @@ -139,19 +163,7 @@ public class HDLCircuit implements Iterable, HDLContext.BitProvider { if (labels.size() == 1) return labels.iterator().next(); else - return Integer.toString(netNumber++); - } - - private void addNode(VisualElement v, HDLContext c) throws HDLException { - final HDLNode node = c.createNode(v); - for (Pin p : v.getPins()) { - HDLNet net = getNetOfPin(p); - if (p.getDirection().equals(PinDescription.Direction.input)) - node.addInput(new HDLPort(p.getName(), net, HDLPort.Direction.IN, 0)); - else - node.addOutput(new HDLPort(p.getName(), net, HDLPort.Direction.OUT, node.getBits(p.getName()))); - } - nodes.add(node); + return null; } @Override @@ -167,18 +179,32 @@ public class HDLCircuit implements Iterable, HDLContext.BitProvider { return 0; } + /** + * @return the elements name + */ public String getElementName() { return elementName; } + /** + * @return the circuits outputs + */ public ArrayList getOutputs() { return outputs; } + /** + * @return the circuits inputs + */ public ArrayList getInputs() { return inputs; } + /** + * Traverses all the nodes + * + * @param visitor the visitor to use + */ public void traverse(HDLVisitor visitor) { for (HDLNode n : nodes) n.traverse(visitor); @@ -188,4 +214,109 @@ public class HDLCircuit implements Iterable, HDLContext.BitProvider { public String toString() { return "HDLCircuit{elementName='" + elementName + "'}"; } + + /** + * Merges logcal operations if possible + * + * @return this for chained calls + * @throws HDLException HDLException + */ + public HDLCircuit mergeOperations() throws HDLException { + nodes = new OperationMerger(nodes, this).merge(); + return this; + } + + /** + * Name the unnamed nets + * + * @param netNamer the net naming algorithm + * @return this for chained calls + */ + public HDLCircuit nameNets(NetNamer netNamer) { + for (HDLNet n : listOfNets) + if (n.getName() == null) + n.setName(netNamer.createName(n)); + return this; + } + + + @Override + public void print(CodePrinter out) throws IOException { + out.print("circuit ").println(elementName).inc(); + out.print("in"); + printList(out, inputs); + out.print("out"); + printList(out, outputs); + out.print("sig"); + printList(out, listOfNets); + + out.println(); + for (HDLNode n : nodes) { + out.print("node ").println(n.getElementName()).inc(); + n.print(out); + out.dec(); + } + out.println(); + for (HDLPort p : outputs) { + final HDLNet net = p.getNet(); + if (net.needsVariable() || net.isInput()) { + p.print(out); + out.print(" := "); + net.print(out); + out.println(); + } + } + + out.dec().print("end circuit ").println(elementName); + } + + private void printList(CodePrinter out, Collection ports) throws IOException { + boolean first = true; + for (Printable p : ports) { + if (first) { + first = false; + out.print("("); + } else + out.print(", "); + p.print(out); + } + out.println(")"); + } + + private void printList(CodePrinter out, ArrayList nets) throws IOException { + boolean first = true; + for (HDLNet net : nets) { + if (net.needsVariable()) { + if (first) { + first = false; + out.print("("); + } else + out.print(", "); + net.print(out); + } + } + out.println(")"); + } + + /** + * Removed an obsolete net + * + * @param net the net to remove + */ + public void removeNet(HDLNet net) { + listOfNets.remove(net); + } + + /** + * The net naming algorithm + */ + public interface NetNamer { + /** + * Returns a nem for the given net + * + * @param n the net to name + * @return the name to use + */ + String createName(HDLNet n); + } } diff --git a/src/main/java/de/neemann/digital/hdl/model2/HDLContext.java b/src/main/java/de/neemann/digital/hdl/model2/HDLContext.java index e611317ec..771c49427 100644 --- a/src/main/java/de/neemann/digital/hdl/model2/HDLContext.java +++ b/src/main/java/de/neemann/digital/hdl/model2/HDLContext.java @@ -7,26 +7,50 @@ package de.neemann.digital.hdl.model2; import de.neemann.digital.core.NodeException; import de.neemann.digital.core.ObservableValues; -import de.neemann.digital.core.element.Element; +import de.neemann.digital.core.basic.*; import de.neemann.digital.core.element.ElementTypeDescription; +import de.neemann.digital.core.element.Keys; +import de.neemann.digital.core.element.PinDescription; +import de.neemann.digital.core.io.Const; import de.neemann.digital.draw.elements.Circuit; +import de.neemann.digital.draw.elements.Pin; 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.hdl.model2.expression.*; +import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; -public class HDLContext { +/** + * The context of creating nodes and circuits. + * Ensures that every circuit is only processed one time. + */ +public class HDLContext implements Iterable { private ElementLibrary elementLibrary; private HashMap circuitMap; + /** + * Creates a new instance + * + * @param elementLibrary the element library + */ public HDLContext(ElementLibrary elementLibrary) { this.elementLibrary = elementLibrary; circuitMap = new HashMap<>(); } - public HDLNode createNode(VisualElement v) throws HDLException { + /** + * Creates a isolated node + * + * @param v the VisualElement of the node + * @param parent the parrents circuit + * @return the node + * @throws HDLException HDLException + */ + public HDLNode createNode(VisualElement v, HDLCircuit parent) throws HDLException { try { ElementTypeDescription td = elementLibrary.getElementType(v.getElementName()); if (td instanceof ElementLibrary.ElementTypeDescriptionCustom) { @@ -38,26 +62,106 @@ public class HDLContext { circuitMap.put(tdc.getCircuit(), c); } - return new HDLNodeCustom(v.getElementName(), v.getElementAttributes(), c); + return addInputsOutputs( + new HDLNodeCustom(v.getElementName(), v.getElementAttributes(), c), + v, parent); + + } else if (v.equalsDescription(Const.DESCRIPTION)) { + final HDLNodeExpression node = createExpression(v, parent, td); + node.setExpression(new ExprConstant(node.getElementAttributes().get(Keys.VALUE), node.getOutput().getBits())); + return node; + } else if (v.equalsDescription(Not.DESCRIPTION)) { + final HDLNodeExpression node = createExpression(v, parent, td); + node.setExpression(new ExprNot(new ExprVar(node.getInputs().get(0).getNet()))); + return node; + } else if (v.equalsDescription(Or.DESCRIPTION)) { + final HDLNodeExpression node = createExpression(v, parent, td); + node.setExpression(createOperation(node.getInputs(), ExprOperate.Operation.OR)); + return node; + } else if (v.equalsDescription(And.DESCRIPTION)) { + final HDLNodeExpression node = createExpression(v, parent, td); + node.setExpression(createOperation(node.getInputs(), ExprOperate.Operation.AND)); + return node; + } else if (v.equalsDescription(XOr.DESCRIPTION)) { + final HDLNodeExpression node = createExpression(v, parent, td); + node.setExpression(createOperation(node.getInputs(), ExprOperate.Operation.XOR)); + return node; + } else if (v.equalsDescription(NOr.DESCRIPTION)) { + final HDLNodeExpression node = createExpression(v, parent, td); + node.setExpression(new ExprNot(createOperation(node.getInputs(), ExprOperate.Operation.OR))); + return node; + } else if (v.equalsDescription(NAnd.DESCRIPTION)) { + final HDLNodeExpression node = createExpression(v, parent, td); + node.setExpression(new ExprNot(createOperation(node.getInputs(), ExprOperate.Operation.AND))); + return node; + } else if (v.equalsDescription(XNOr.DESCRIPTION)) { + final HDLNodeExpression node = createExpression(v, parent, td); + node.setExpression(new ExprNot(createOperation(node.getInputs(), ExprOperate.Operation.XOR))); + return node; } else - return new HDLNode(v.getElementName(), - v.getElementAttributes(), - new ObserVableValuesBits( - td.createElement(v.getElementAttributes()).getOutputs())); + return addInputsOutputs( + new HDLNode(v.getElementName(), + v.getElementAttributes(), + new ObservableValuesBitsProvider( + td.createElement(v.getElementAttributes()).getOutputs())), + v, parent); + } catch (ElementNotFoundException | PinException | NodeException e) { throw new HDLException("error creating node", e); } } + private Expression createOperation(ArrayList inputs, ExprOperate.Operation op) { + ArrayList list = new ArrayList<>(); + for (HDLPort p : inputs) { + list.add(new ExprVar(p.getNet())); + } + return new ExprOperate(op, list); + } + + private HDLNodeExpression createExpression(VisualElement v, HDLCircuit parent, ElementTypeDescription td) throws HDLException, PinException { + return addInputsOutputs(new HDLNodeExpression(v.getElementName(), + v.getElementAttributes(), + new ObservableValuesBitsProvider( + td.createElement(v.getElementAttributes()).getOutputs())), + v, parent); + } + + private N addInputsOutputs(N node, VisualElement v, HDLCircuit c) throws HDLException { + for (Pin p : v.getPins()) { + HDLNet net = c.getNetOfPin(p); + if (p.getDirection().equals(PinDescription.Direction.input)) + node.addInput(new HDLPort(p.getName(), net, HDLPort.Direction.IN, 0)); + else + node.addOutput(new HDLPort(p.getName(), net, HDLPort.Direction.OUT, node.getBits(p.getName()))); + } + return node; + } + + + @Override + public Iterator iterator() { + return circuitMap.values().iterator(); + } + + /** + * The bit provider interface + */ public interface BitProvider { + /** + * Returns the number of bits of the signal with the given name + * + * @param name the signal name + * @return the number of bits + */ int getBits(String name); } - private class ObserVableValuesBits implements BitProvider { + private static final class ObservableValuesBitsProvider implements BitProvider { private final ObservableValues values; - private ObserVableValuesBits(ObservableValues values) { + private ObservableValuesBitsProvider(ObservableValues values) { this.values = values; } diff --git a/src/main/java/de/neemann/digital/hdl/model2/HDLException.java b/src/main/java/de/neemann/digital/hdl/model2/HDLException.java index cfc4ee84e..0aa89884e 100644 --- a/src/main/java/de/neemann/digital/hdl/model2/HDLException.java +++ b/src/main/java/de/neemann/digital/hdl/model2/HDLException.java @@ -5,11 +5,25 @@ */ package de.neemann.digital.hdl.model2; +/** + * Exception thrown during model building + */ public class HDLException extends Exception { + /** + * Creates a new instance + * + * @param message the message + * @param cause the cause + */ public HDLException(String message, Exception cause) { super(message, cause); } + /** + * Creates a new instance + * + * @param message the message + */ public HDLException(String message) { super(message); } diff --git a/src/main/java/de/neemann/digital/hdl/model2/HDLNet.java b/src/main/java/de/neemann/digital/hdl/model2/HDLNet.java index 25c38c110..72e6e9a46 100644 --- a/src/main/java/de/neemann/digital/hdl/model2/HDLNet.java +++ b/src/main/java/de/neemann/digital/hdl/model2/HDLNet.java @@ -5,18 +5,38 @@ */ package de.neemann.digital.hdl.model2; +import de.neemann.digital.hdl.printer.CodePrinter; + +import java.io.IOException; import java.util.ArrayList; -public class HDLNet { +/** + * Represents a net. + * A net can have only one input and several outputs. + */ +public class HDLNet implements Printable { private String name; private ArrayList inputs; private HDLPort output; + private boolean needsVariable = true; + private boolean isInput; + /** + * Creates a new net + * + * @param name the nets name + */ public HDLNet(String name) { this.name = name; inputs = new ArrayList<>(); } + /** + * Adds a port to this net. + * + * @param hdlPort the port to add + * @throws HDLException HDLException + */ public void addPort(HDLPort hdlPort) throws HDLException { if (hdlPort.getDirection().equals(HDLPort.Direction.OUT)) { if (output != null) @@ -26,12 +46,26 @@ public class HDLNet { inputs.add(hdlPort); } + /** + * @return the inputs which are connected to this net. + */ + public ArrayList getInputs() { + return inputs; + } + + /** + * @return the output which defines the nets value + */ + public HDLPort getOutput() { + return output; + } + @Override public String toString() { return name + " (" + output + " " + inputs + ")"; } - public void fixBits() throws HDLException { + void fixBits() throws HDLException { if (output == null) throw new HDLException("no output connected to net"); final int bits = output.getBits(); @@ -43,7 +77,56 @@ public class HDLNet { } - public void remove(HDLPort p) { + void remove(HDLPort p) { inputs.remove(p); } + + @Override + public void print(CodePrinter out) throws IOException { + out.print(name).print(":").print(output.getBits()); + } + + /** + * @return the name of the net + */ + public String getName() { + return name; + } + + /** + * Sets the name of the net + * + * @param name the name to use + */ + public void setName(String name) { + this.name = name; + } + + void setIsInput(String name) { + this.needsVariable = false; + this.isInput = true; + this.name = name; + } + + /** + * @return true if tins net represents a nodes input + */ + public boolean isInput() { + return isInput; + } + + /** + * @return true if this net needs a temp variable to represent the value + */ + public boolean needsVariable() { + return needsVariable; + } + + void setIsOutput(String name, boolean singleRead) { + if (singleRead) { + this.name = name; + needsVariable = false; + } else + this.name = name + "_temp"; + } } diff --git a/src/main/java/de/neemann/digital/hdl/model2/HDLNode.java b/src/main/java/de/neemann/digital/hdl/model2/HDLNode.java index 7a3a88d1d..c54657156 100644 --- a/src/main/java/de/neemann/digital/hdl/model2/HDLNode.java +++ b/src/main/java/de/neemann/digital/hdl/model2/HDLNode.java @@ -6,9 +6,14 @@ package de.neemann.digital.hdl.model2; import de.neemann.digital.core.element.ElementAttributes; +import de.neemann.digital.hdl.printer.CodePrinter; +import java.io.IOException; import java.util.ArrayList; +/** + * A node which represents a built-in component + */ public class HDLNode { private final String elementName; private final ElementAttributes elementAttributes; @@ -16,6 +21,13 @@ public class HDLNode { private final ArrayList inputs; private final ArrayList outputs; + /** + * Creates e new intance + * + * @param elementName the instances name + * @param elementAttributes the attributes + * @param bitProvider the bit provider which provides the outputs bit width + */ public HDLNode(String elementName, ElementAttributes elementAttributes, HDLContext.BitProvider bitProvider) { this.elementName = elementName; this.elementAttributes = elementAttributes; @@ -24,14 +36,12 @@ public class HDLNode { outputs = new ArrayList<>(); } - public void addInput(HDLPort port) { + void addInput(HDLPort port) { inputs.add(port); - port.setNode(this); } - public void addOutput(HDLPort port) { + void addOutput(HDLPort port) { outputs.add(port); - port.setNode(this); } @Override @@ -39,27 +49,99 @@ public class HDLNode { return elementName + " " + inputs + " " + outputs; } + /** + * @return the elements name + */ public String getElementName() { return elementName; } + /** + * @return the elements attributes + */ public ElementAttributes getElementAttributes() { return elementAttributes; } + /** + * @return the nodes inputs + */ public ArrayList getInputs() { return inputs; } + /** + * @return the nodes single outputs + */ + public HDLPort getOutput() { + return outputs.get(0); + } + + /** + * @return the list of outputs + */ public ArrayList getOutputs() { return outputs; } + /** + * Traverses all the nodes + * + * @param visitor the visitor to use + */ public void traverse(HDLVisitor visitor) { visitor.visit(this); } - public int getBits(String name) { + int getBits(String name) { return bitProvider.getBits(name); } + + /** + * Prints a simple text representation of the node + * + * @param out the CondePrinter to print to + * @throws IOException IOException + */ + public void print(CodePrinter out) throws IOException { + out.print("in"); + printWithLocal(out, inputs); + out.print("out"); + printWithLocal(out, outputs); + } + + private void printWithLocal(CodePrinter out, ArrayList ports) throws IOException { + boolean first = true; + for (HDLPort p : ports) { + if (first) { + first = false; + out.print("("); + } else + out.print(", "); + p.print(out); + if (p.getNet() == null) + out.print(" is not used"); + else { + out.print(" is "); + p.getNet().print(out); + } + } + if (first) + out.println("("); + + out.println(")"); + } + + /** + * Returns true if the node has the given port as an input + * + * @param i the port to search for + * @return true if the given port is a input of this node + */ + public boolean hasInput(HDLPort i) { + for (HDLPort p : inputs) + if (p.getNet() == i.getNet()) + return true; + return false; + } } diff --git a/src/main/java/de/neemann/digital/hdl/model2/HDLNodeCustom.java b/src/main/java/de/neemann/digital/hdl/model2/HDLNodeCustom.java index 6f059e281..5b9df70bf 100644 --- a/src/main/java/de/neemann/digital/hdl/model2/HDLNodeCustom.java +++ b/src/main/java/de/neemann/digital/hdl/model2/HDLNodeCustom.java @@ -7,9 +7,19 @@ package de.neemann.digital.hdl.model2; import de.neemann.digital.core.element.ElementAttributes; +/** + * Represents a node which is build from a circuit. + */ public class HDLNodeCustom extends HDLNode { private final HDLCircuit hdlCircuit; + /** + * Creates a new instance + * + * @param elementName the elements name + * @param elementAttributes the attributes + * @param hdlCircuit the circuit to use to create this node + */ public HDLNodeCustom(String elementName, ElementAttributes elementAttributes, HDLCircuit hdlCircuit) { super(elementName, elementAttributes, hdlCircuit); this.hdlCircuit = hdlCircuit; diff --git a/src/main/java/de/neemann/digital/hdl/model2/HDLNodeExpression.java b/src/main/java/de/neemann/digital/hdl/model2/HDLNodeExpression.java new file mode 100644 index 000000000..6d533c4fb --- /dev/null +++ b/src/main/java/de/neemann/digital/hdl/model2/HDLNodeExpression.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2018 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.hdl.model2; + + +import de.neemann.digital.core.element.ElementAttributes; +import de.neemann.digital.hdl.model2.expression.Expression; +import de.neemann.digital.hdl.printer.CodePrinter; + +import java.io.IOException; + +/** + * A node which represents a simple expression + */ +public class HDLNodeExpression extends HDLNode { + private Expression expression; + + /** + * Creates a new instace + * + * @param elementName the elements name + * @param elementAttributes the attributes + * @param bitProvider the bit provider which provides the outputs bit width + */ + public HDLNodeExpression(String elementName, ElementAttributes elementAttributes, HDLContext.BitProvider bitProvider) { + super(elementName, elementAttributes, bitProvider); + } + + /** + * Sets the expression tu use + * + * @param expression the expression + */ + public void setExpression(Expression expression) { + this.expression = expression; + } + + /** + * @return the expression + */ + public Expression getExpression() { + return expression; + } + + @Override + public void print(CodePrinter out) throws IOException { + getOutput().getNet().print(out); + out.print(" := "); + expression.print(out); + out.println(); + } + +} diff --git a/src/main/java/de/neemann/digital/hdl/model2/HDLPort.java b/src/main/java/de/neemann/digital/hdl/model2/HDLPort.java index 25b7c78d5..baee64187 100644 --- a/src/main/java/de/neemann/digital/hdl/model2/HDLPort.java +++ b/src/main/java/de/neemann/digital/hdl/model2/HDLPort.java @@ -5,19 +5,44 @@ */ package de.neemann.digital.hdl.model2; -public class HDLPort { +import de.neemann.digital.hdl.printer.CodePrinter; +import java.io.IOException; + +/** + * A port + */ +public class HDLPort implements Printable { + + /** + * The ports direction + */ public enum Direction { - IN, OUT + /** + * input + */ + IN, + /** + * output + */ + OUT } private final String name; private final Direction direction; private int bits; private HDLNet net; - private HDLNode node; private String pinNumber; + /** + * Creates a new instance + * + * @param name the name of the port + * @param net the net of this port + * @param direction the ports direction + * @param bits the bit width + * @throws HDLException HDLException + */ public HDLPort(String name, HDLNet net, Direction direction, int bits) throws HDLException { this.name = name; this.net = net; @@ -28,42 +53,70 @@ public class HDLPort { net.addPort(this); } + /** + * Sets the pin number to this port + * + * @param pinNumber the pin number + * @return this for chained calls + */ public HDLPort setPinNumber(String pinNumber) { this.pinNumber = pinNumber; return this; } + /** + * @return the net of this port + */ public HDLNet getNet() { return net; } + /** + * Sets the net of this port + * + * @param net the net + * @throws HDLException HDLException + */ public void setNet(HDLNet net) throws HDLException { this.net = net; net.addPort(this); } + /** + * @return the name of this port + */ public String getName() { return name; } + /** + * @return the bit width of this port + */ public int getBits() { return bits; } + /** + * Sets the bit width of this port + * + * @param bits the number of bits + */ public void setBits(int bits) { this.bits = bits; } + /** + * @return the ports direction + */ public Direction getDirection() { return direction; } - public HDLNode getNode() { - return node; - } - - public void setNode(HDLNode node) { - this.node = node; + /** + * @return the pin number of this port + */ + public String getPinNumber() { + return pinNumber; } @Override @@ -71,4 +124,8 @@ public class HDLPort { return direction + " " + name + "(" + bits + ")"; } + @Override + public void print(CodePrinter out) throws IOException { + out.print(name).print(":").print(bits); + } } diff --git a/src/main/java/de/neemann/digital/hdl/model2/HDLVisitor.java b/src/main/java/de/neemann/digital/hdl/model2/HDLVisitor.java index 7bfa10692..45f3261fa 100644 --- a/src/main/java/de/neemann/digital/hdl/model2/HDLVisitor.java +++ b/src/main/java/de/neemann/digital/hdl/model2/HDLVisitor.java @@ -5,6 +5,14 @@ */ package de.neemann.digital.hdl.model2; +/** + * Visitor to visit the nodes. + */ public interface HDLVisitor { + /** + * Visits a node + * + * @param hdlNode the node to visit + */ void visit(HDLNode hdlNode); } diff --git a/src/main/java/de/neemann/digital/hdl/model2/OperationMerger.java b/src/main/java/de/neemann/digital/hdl/model2/OperationMerger.java new file mode 100644 index 000000000..38b6df5eb --- /dev/null +++ b/src/main/java/de/neemann/digital/hdl/model2/OperationMerger.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2018 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.hdl.model2; + +import de.neemann.digital.hdl.model2.expression.Expression; + +import java.util.ArrayList; + +/** + * Helper to merge expressions + */ +class OperationMerger { + private final ArrayList nodes; + private final HDLCircuit circuit; + + OperationMerger(ArrayList nodes, HDLCircuit circuit) { + this.nodes = nodes; + this.circuit = circuit; + } + + ArrayList merge() throws HDLException { + boolean wasOptimization; + do { + wasOptimization = false; + outer: + for (int i = 0; i < nodes.size(); i++) { + HDLNode n1 = nodes.get(i); + if (n1 instanceof HDLNodeExpression) { + for (HDLPort p : n1.getInputs()) { + HDLNode n2 = searchCreator(p.getNet()); + if (n2 != null && n2 instanceof HDLNodeExpression) { + if (n2.getOutputs().size() == 1 && n2.getOutput().getNet().getInputs().size() == 1) { + nodes.set(i, merge((HDLNodeExpression) n1, (HDLNodeExpression) n2)); + nodes.remove(n2); + wasOptimization = true; + break outer; + } + } + } + } + } + } while (wasOptimization); + + return nodes; + } + + private HDLNodeExpression merge(HDLNodeExpression host, HDLNodeExpression include) throws HDLException { + final Expression expression = host.getExpression(); + expression.replace(include.getOutput().getNet(), include.getExpression()); + + HDLNodeExpression node = new HDLNodeExpression("merged expression", + null, name -> host.getOutput().getBits()); + node.setExpression(expression); + + circuit.removeNet(include.getOutput().getNet()); + + node.addOutput(host.getOutput()); + for (HDLPort i : host.getInputs()) + node.addInput(i); + + for (HDLPort i : include.getInputs()) + if (!node.hasInput(i)) + node.addInput(i); + + return node; + } + + private HDLNode searchCreator(HDLNet net) { + for (HDLNode n : nodes) + for (HDLPort p : n.getOutputs()) + if (p.getNet() == net) + return n; + return null; + } +} diff --git a/src/main/java/de/neemann/digital/hdl/model2/Printable.java b/src/main/java/de/neemann/digital/hdl/model2/Printable.java new file mode 100644 index 000000000..25131348c --- /dev/null +++ b/src/main/java/de/neemann/digital/hdl/model2/Printable.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018 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.hdl.model2; + +import de.neemann.digital.hdl.printer.CodePrinter; + +import java.io.IOException; + +/** + * Something which can print itself to a CodePrinter + */ +public interface Printable { + /** + * Prints itfels to the CodePrinter + * + * @param out the CodePrinter instance + * @throws IOException IOException + */ + void print(CodePrinter out) throws IOException; +} diff --git a/src/main/java/de/neemann/digital/hdl/model2/expression/ExprConstant.java b/src/main/java/de/neemann/digital/hdl/model2/expression/ExprConstant.java new file mode 100644 index 000000000..5cf0cbe55 --- /dev/null +++ b/src/main/java/de/neemann/digital/hdl/model2/expression/ExprConstant.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2018 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.hdl.model2.expression; + +import de.neemann.digital.hdl.model2.HDLNet; +import de.neemann.digital.hdl.printer.CodePrinter; + +import java.io.IOException; + +/** + * Represents a constant + */ +public class ExprConstant implements Expression { + + private long value; + private int bits; + + /** + * Creates a new constant + * @param value the value + * @param bits the number of bits + */ + public ExprConstant(long value, int bits) { + this.value = value; + this.bits = bits; + } + + /** + * @return the value + */ + public long getValue() { + return value; + } + + /** + * @return the number of bits + */ + public int getBits() { + return bits; + } + + @Override + public void print(CodePrinter out) throws IOException { + out.print(value).print(":").print(bits); + } + + @Override + public void replace(HDLNet net, Expression expression) { + } +} diff --git a/src/main/java/de/neemann/digital/hdl/model2/expression/ExprNot.java b/src/main/java/de/neemann/digital/hdl/model2/expression/ExprNot.java new file mode 100644 index 000000000..30688bf38 --- /dev/null +++ b/src/main/java/de/neemann/digital/hdl/model2/expression/ExprNot.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2018 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.hdl.model2.expression; + + +import de.neemann.digital.hdl.model2.HDLNet; +import de.neemann.digital.hdl.printer.CodePrinter; + +import java.io.IOException; + +/** + * Represents a NOT operation + */ +public class ExprNot implements Expression { + + private Expression expr; + + /** + * Creates a new NOT expression + * + * @param expr the enxpression to invert + */ + public ExprNot(Expression expr) { + this.expr = expr; + } + + /** + * @return the expression + */ + public Expression getExpression() { + return expr; + } + + @Override + public void print(CodePrinter out) throws IOException { + out.print("NOT "); + expr.print(out); + } + + @Override + public void replace(HDLNet net, Expression expression) { + if (isVar(expr, net)) + expr = expression; + else + expr.replace(net, expression); + } + + /** + * Help er to check if a expression is a net reference + * + * @param expr the expression to check + * @param net the net + * @return true if the expression is a reference to the given net + */ + public static boolean isVar(Expression expr, HDLNet net) { + return expr instanceof ExprVar && ((ExprVar) expr).getNet() == net; + } +} diff --git a/src/main/java/de/neemann/digital/hdl/model2/expression/ExprOperate.java b/src/main/java/de/neemann/digital/hdl/model2/expression/ExprOperate.java new file mode 100644 index 000000000..64dcba1eb --- /dev/null +++ b/src/main/java/de/neemann/digital/hdl/model2/expression/ExprOperate.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2018 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.hdl.model2.expression; + + +import de.neemann.digital.hdl.model2.HDLNet; +import de.neemann.digital.hdl.printer.CodePrinter; + +import java.io.IOException; +import java.util.ArrayList; + +import static de.neemann.digital.hdl.model2.expression.ExprNot.isVar; + +/** + * Represenst a operation + */ +public class ExprOperate implements Expression { + /** + * the possible operation + */ + public enum Operation { + /** + * And operation + */ + AND, + /** + * Or operation + */ + OR, + /** + * xor operation + */ + XOR + } + + private Operation operation; + private ArrayList operands; + + /** + * Creates a new instance + * + * @param operation the operation + * @param operands the operandes + */ + public ExprOperate(Operation operation, ArrayList operands) { + this.operation = operation; + this.operands = operands; + } + + /** + * @return the operation + */ + public Operation getOperation() { + return operation; + } + + /** + * @return the operands + */ + public ArrayList getOperands() { + return operands; + } + + @Override + public void print(CodePrinter out) throws IOException { + out.print("("); + boolean first = true; + for (Expression op : operands) { + if (first) + first = false; + else + out.print(" ").print(operation.name()).print(" "); + op.print(out); + } + out.print(")"); + } + + @Override + public void replace(HDLNet net, Expression expression) { + for (int i = 0; i < operands.size(); i++) { + final Expression op = operands.get(i); + if (isVar(op, net)) + operands.set(i, expression); + else + op.replace(net, expression); + } + } + +} diff --git a/src/main/java/de/neemann/digital/hdl/model2/expression/ExprVar.java b/src/main/java/de/neemann/digital/hdl/model2/expression/ExprVar.java new file mode 100644 index 000000000..64ae8bcbd --- /dev/null +++ b/src/main/java/de/neemann/digital/hdl/model2/expression/ExprVar.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2018 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.hdl.model2.expression; + +import de.neemann.digital.hdl.model2.HDLNet; +import de.neemann.digital.hdl.printer.CodePrinter; + +import java.io.IOException; + +/** + * A reference to a net + */ +public class ExprVar implements Expression { + private HDLNet net; + + /** + * creates a new net reference + * + * @param net the net + */ + public ExprVar(HDLNet net) { + this.net = net; + } + + /** + * @return the net + */ + public HDLNet getNet() { + return net; + } + + @Override + public void print(CodePrinter out) throws IOException { + net.print(out); + } + + @Override + public void replace(HDLNet net, Expression expression) { + if (net == this.net) + throw new RuntimeException("should not happen!"); + } +} diff --git a/src/main/java/de/neemann/digital/hdl/model2/expression/Expression.java b/src/main/java/de/neemann/digital/hdl/model2/expression/Expression.java new file mode 100644 index 000000000..1513c7b1e --- /dev/null +++ b/src/main/java/de/neemann/digital/hdl/model2/expression/Expression.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018 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.hdl.model2.expression; + +import de.neemann.digital.hdl.model2.HDLNet; +import de.neemann.digital.hdl.model2.Printable; + +/** + * Represents a expression + */ +public interface Expression extends Printable { + + /** + * Replaces a net with and expression + * + * @param net the net to replace + * @param expression the expression to use instead ot the net + */ + void replace(HDLNet net, Expression expression); +} diff --git a/src/main/java/de/neemann/digital/hdl/model2/expression/package-info.java b/src/main/java/de/neemann/digital/hdl/model2/expression/package-info.java new file mode 100644 index 000000000..9f4e384c0 --- /dev/null +++ b/src/main/java/de/neemann/digital/hdl/model2/expression/package-info.java @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2018 Helmut Neemann. + * Use of this source code is governed by the GPL v3 license + * that can be found in the LICENSE file. + */ + +/** + * Classes to describe a model expression + */ +package de.neemann.digital.hdl.model2.expression; diff --git a/src/main/java/de/neemann/digital/hdl/model2/package-info.java b/src/main/java/de/neemann/digital/hdl/model2/package-info.java new file mode 100644 index 000000000..7d5082e02 --- /dev/null +++ b/src/main/java/de/neemann/digital/hdl/model2/package-info.java @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2018 Helmut Neemann. + * Use of this source code is governed by the GPL v3 license + * that can be found in the LICENSE file. + */ + +/** + * The hdl representation of a circuit + */ +package de.neemann.digital.hdl.model2; diff --git a/src/test/java/de/neemann/digital/hdl/model2/HDLCircuitTest.java b/src/test/java/de/neemann/digital/hdl/model2/HDLCircuitTest.java index 77af98fe7..42c547918 100644 --- a/src/test/java/de/neemann/digital/hdl/model2/HDLCircuitTest.java +++ b/src/test/java/de/neemann/digital/hdl/model2/HDLCircuitTest.java @@ -5,6 +5,8 @@ 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.shapes.ShapeFactory; +import de.neemann.digital.hdl.printer.CodePrinter; +import de.neemann.digital.hdl.printer.CodePrinterStr; import de.neemann.digital.integration.Resources; import junit.framework.TestCase; @@ -14,7 +16,7 @@ import java.io.IOException; public class HDLCircuitTest extends TestCase { public void testSimple() throws IOException, PinException, HDLException, NodeException { - File file = new File(Resources.getRoot(), "../../main/dig/processor/VHDLExample.dig"); + File file = new File(Resources.getRoot(), "dig/hdl/model2/comb.dig"); ElementLibrary library = new ElementLibrary(); library.setRootFilePath(file.getParentFile()); ShapeFactory shapeFactory = new ShapeFactory(library); @@ -23,8 +25,25 @@ public class HDLCircuitTest extends TestCase { final HDLContext hdlContext = new HDLContext(library); HDLCircuit hdl = new HDLCircuit(c, "main", hdlContext); - System.out.println(hdl); - hdl.traverse(System.out::println); + CodePrinterStr out = new CodePrinterStr(); + for (HDLCircuit cir : hdlContext) { + cir.mergeOperations(); + cir.print(out); + out.println(); + } + + hdl.mergeOperations().nameNets(new HDLCircuit.NetNamer() { + private int num; + + @Override + public String createName(HDLNet n) { + return "s" + (num++); + } + }); + hdl.print(out); + + System.out.print(out); + System.out.println(); } } \ No newline at end of file diff --git a/src/test/resources/dig/hdl/model2/comb.dig b/src/test/resources/dig/hdl/model2/comb.dig new file mode 100644 index 000000000..80f2527c7 --- /dev/null +++ b/src/test/resources/dig/hdl/model2/comb.dig @@ -0,0 +1,352 @@ + + + 1 + + + + Out + + + Label + X + + + Inputs + 1 + + + + + + And + + + Inputs + 5 + + + + + + Or + + + + + Or + + + + + Or + + + + + In + + + rotation + + + + Label + A + + + + + + Not + + + rotation + + + + + + + In + + + rotation + + + + Label + B + + + + + + In + + + rotation + + + + Label + C + + + + + + Not + + + rotation + + + + + + + NOr + + + + + Out + + + Label + Y + + + + + + Out + + + Label + Z + + + + + + Const + + + + + D_FF + + + + + Const + + + + + Out + + + Label + Aident + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file