From f7521228c806d61a703ee325e41354d175e7923b Mon Sep 17 00:00:00 2001 From: hneemann Date: Thu, 29 Mar 2018 13:46:16 +0200 Subject: [PATCH] improved node ordering --- .../digital/hdl/model2/HDLCircuit.java | 10 +- .../digital/hdl/model2/NodeSorter.java | 99 ------------- .../hdl/model2/expression/ExprUsingNet.java | 18 +++ .../hdl/model2/expression/ExprVar.java | 6 +- .../hdl/model2/expression/ExprVarRange.java | 6 +- .../NodeSorterExpressionBased.java | 136 ++++++++++++++++++ .../digital/hdl/model2/HDLModelTest.java | 17 +-- .../neemann/digital/hdl/vhdl2/ClockTest.java | 2 +- .../digital/hdl/vhdl2/DescriptionTest.java | 4 +- .../digital/hdl/vhdl2/VHDLGeneratorTest.java | 2 +- 10 files changed, 171 insertions(+), 129 deletions(-) delete mode 100644 src/main/java/de/neemann/digital/hdl/model2/NodeSorter.java create mode 100644 src/main/java/de/neemann/digital/hdl/model2/expression/ExprUsingNet.java create mode 100644 src/main/java/de/neemann/digital/hdl/model2/optimizations/NodeSorterExpressionBased.java 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 84be598ae..1346ce097 100644 --- a/src/main/java/de/neemann/digital/hdl/model2/HDLCircuit.java +++ b/src/main/java/de/neemann/digital/hdl/model2/HDLCircuit.java @@ -157,14 +157,6 @@ public class HDLCircuit implements Iterable, HDLModel.BitProvider, Prin if (o.getNet().needsVariable()) o.getNet().setIsOutput(o.getName(), o.getNet().getInputs().size() == 1); - sortNodes(); - } - - /** - * Sorts the nodes - */ - public void sortNodes() { - nodes = new NodeSorter(inputs, nodes).sort(); } private void handleSplitter(HDLNode node) throws BitsException, HDLException { @@ -320,7 +312,6 @@ public class HDLCircuit implements Iterable, HDLModel.BitProvider, Prin for (HDLNet n : listOfNets) if (n.getName() == null) n.setName(netNaming.createName(n)); - sortNodes(); return this; } @@ -525,6 +516,7 @@ public class HDLCircuit implements Iterable, HDLModel.BitProvider, Prin apply(new RemoveConstantSignals()); apply(new MergeConstants()); // under certain circumstances there are still constants apply(new NameConstantSignals()); + apply(new NodeSorterExpressionBased()); return nameUnnamedSignals(); } diff --git a/src/main/java/de/neemann/digital/hdl/model2/NodeSorter.java b/src/main/java/de/neemann/digital/hdl/model2/NodeSorter.java deleted file mode 100644 index b31f56cd9..000000000 --- a/src/main/java/de/neemann/digital/hdl/model2/NodeSorter.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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 java.util.ArrayList; -import java.util.HashSet; - -/** - * Used to sort the nodes in a more "human typical" order. - * Sorts the nodes from the input side to the output side. - */ -public class NodeSorter { - private final ArrayList inputs; - private final ArrayList nodes; - - /** - * Creates a new instance. - * - * @param inputs the initial inputs - * @param nodes the nodes to sort - */ - NodeSorter(ArrayList inputs, ArrayList nodes) { - this.inputs = inputs; - this.nodes = nodes; - } - - /** - * Performs the sorting and returns a sorted list. - * - * @return the sorted list - */ - public ArrayList sort() { - HashSet nets = new HashSet<>(); - for (HDLPort p : inputs) - nets.add(p.getNet()); - - ArrayList newOrder = new ArrayList<>(); - - // all nodes without an input at top! - for (HDLNode n : nodes) - if (n.getInputs().isEmpty()) { - newOrder.add(n); - for (HDLPort p : n.getOutputs()) - if (p.getNet() != null) - nets.add(p.getNet()); - } - nodes.removeAll(newOrder); - - // than a layer sorting - while (!nodes.isEmpty()) { - ArrayList layer = new ArrayList<>(); - for (HDLNode n : nodes) { - if (dependsOnlyOn(n, nets)) - layer.add(n); - } - - if (layer.isEmpty()) { - // circular dependency detected - for (HDLNode n : nodes) - if (dependsAtLeastAtOne(n, nets)) - layer.add(n); - } - - if (layer.isEmpty()) - break; - - newOrder.addAll(layer); - nodes.removeAll(layer); - for (HDLNode n : layer) - for (HDLPort p : n.getOutputs()) - if (p.getNet() != null) - nets.add(p.getNet()); - - } - - // if there are circular dependencies, keep old order - if (!nodes.isEmpty()) - newOrder.addAll(nodes); - - return newOrder; - } - - private boolean dependsOnlyOn(HDLNode n, HashSet nets) { - for (HDLPort p : n.getInputs()) - if (!p.getNet().isClock() && !nets.contains(p.getNet())) - return false; - return true; - } - - private boolean dependsAtLeastAtOne(HDLNode n, HashSet nets) { - for (HDLPort p : n.getInputs()) - if (!p.getNet().isClock() && nets.contains(p.getNet())) - return true; - return false; - } -} diff --git a/src/main/java/de/neemann/digital/hdl/model2/expression/ExprUsingNet.java b/src/main/java/de/neemann/digital/hdl/model2/expression/ExprUsingNet.java new file mode 100644 index 000000000..526b32ab7 --- /dev/null +++ b/src/main/java/de/neemann/digital/hdl/model2/expression/ExprUsingNet.java @@ -0,0 +1,18 @@ +/* + * 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; + +/** + * Implemented by all expressions using a net + */ +public interface ExprUsingNet { + /** + * @return the used net + */ + HDLNet getNet(); +} 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 index 302c88b80..896083f13 100644 --- a/src/main/java/de/neemann/digital/hdl/model2/expression/ExprVar.java +++ b/src/main/java/de/neemann/digital/hdl/model2/expression/ExprVar.java @@ -13,7 +13,7 @@ import java.io.IOException; /** * A reference to a net */ -public class ExprVar implements Expression { +public class ExprVar implements Expression, ExprUsingNet { private HDLNet net; /** @@ -27,9 +27,7 @@ public class ExprVar implements Expression { this.net = net; } - /** - * @return the net - */ + @Override public HDLNet getNet() { return net; } diff --git a/src/main/java/de/neemann/digital/hdl/model2/expression/ExprVarRange.java b/src/main/java/de/neemann/digital/hdl/model2/expression/ExprVarRange.java index 698ef1f20..84a16bd7b 100644 --- a/src/main/java/de/neemann/digital/hdl/model2/expression/ExprVarRange.java +++ b/src/main/java/de/neemann/digital/hdl/model2/expression/ExprVarRange.java @@ -13,7 +13,7 @@ import java.io.IOException; /** * A reference to a net slice */ -public class ExprVarRange implements Expression { +public class ExprVarRange implements Expression, ExprUsingNet { private HDLNet net; private final int msb; private final int lsb; @@ -31,9 +31,7 @@ public class ExprVarRange implements Expression { this.lsb = lsb; } - /** - * @return the net - */ + @Override public HDLNet getNet() { return net; } diff --git a/src/main/java/de/neemann/digital/hdl/model2/optimizations/NodeSorterExpressionBased.java b/src/main/java/de/neemann/digital/hdl/model2/optimizations/NodeSorterExpressionBased.java new file mode 100644 index 000000000..1bcec8d89 --- /dev/null +++ b/src/main/java/de/neemann/digital/hdl/model2/optimizations/NodeSorterExpressionBased.java @@ -0,0 +1,136 @@ +/* + * 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.optimizations; + +import de.neemann.digital.hdl.model2.HDLCircuit; +import de.neemann.digital.hdl.model2.HDLNet; +import de.neemann.digital.hdl.model2.HDLNode; +import de.neemann.digital.hdl.model2.HDLPort; +import de.neemann.digital.hdl.model2.expression.ExprUsingNet; +import de.neemann.digital.hdl.model2.expression.Expression; +import de.neemann.digital.hdl.model2.expression.Visitor; + +import java.util.ArrayList; +import java.util.HashSet; + +/** + * Used to sort the nodes in a more "human typical" order. + * Sorts the nodes from the input side to the output side. + */ +public class NodeSorterExpressionBased implements Optimization { + + @Override + public void optimize(HDLCircuit circuit) { + ArrayList nodes = circuit.getNodes(); + ArrayList nodesAvail = new ArrayList<>(nodes); + nodes.clear(); + + HashSet nets = new HashSet<>(); + for (HDLPort p : circuit.getInputs()) + nets.add(p.getNet()); + + + // all nodes without an input at top! + for (HDLNode n : nodesAvail) + if (n.getInputs().isEmpty()) { + nodes.add(n); + for (HDLPort p : n.getOutputs()) + if (p.getNet() != null) + nets.add(p.getNet()); + } + nodesAvail.removeAll(nodes); + + // then a layer sorting + while (!nodesAvail.isEmpty()) { + ArrayList layer = new ArrayList<>(); + for (HDLNode n : nodesAvail) { + if (n.traverseExpressions(new DependsOnlyOn(nets)).ok()) + layer.add(n); + } + + if (layer.isEmpty()) { + // circular dependency detected + for (HDLNode n : nodesAvail) + if (n.traverseExpressions(new DependsAtLeastOnOneOf(nets)).ok()) + layer.add(n); + } + + if (layer.isEmpty()) + break; + + nodes.addAll(layer); + nodesAvail.removeAll(layer); + for (HDLNode n : layer) + for (HDLPort p : n.getOutputs()) + if (p.getNet() != null) + nets.add(p.getNet()); + + } + + // if there are unsolvable circular dependencies, keep old order + if (!nodesAvail.isEmpty()) + nodes.addAll(nodesAvail); + } + + private static final class DependsOnlyOn implements Visitor { + private final HashSet nets; + private boolean dependsOnlyOn = true; + + private DependsOnlyOn(HashSet nets) { + this.nets = nets; + } + + @Override + public void visit(Expression expression) { + if (expression instanceof ExprUsingNet) { + final HDLNet net = ((ExprUsingNet) expression).getNet(); + if (!net.isClock() && !nets.contains(net)) + dependsOnlyOn = false; + } + } + + public boolean ok() { + return dependsOnlyOn; + } + } + + private static final class DependsAtLeastOnOneOf implements Visitor { + private final HashSet nets; + private boolean dependsAtLeastOnOne = false; + + private DependsAtLeastOnOneOf(HashSet nets) { + this.nets = nets; + } + + @Override + public void visit(Expression expression) { + if (expression instanceof ExprUsingNet) { + final HDLNet net = ((ExprUsingNet) expression).getNet(); + if (!net.isClock() && nets.contains(net)) + dependsAtLeastOnOne = true; + } + } + + public boolean ok() { + return dependsAtLeastOnOne; + } + } + + private boolean dependsOnlyOn(HDLNode n, HashSet nets) { + for (HDLPort p : n.getInputs()) + if (!p.getNet().isClock() && !nets.contains(p.getNet())) + return false; + return true; + } + + private boolean dependsAtLeastAtOne(HDLNode n, HashSet nets) { + for (HDLPort p : n.getInputs()) + if (!p.getNet().isClock() && nets.contains(p.getNet())) + return true; + return false; + } + +} diff --git a/src/test/java/de/neemann/digital/hdl/model2/HDLModelTest.java b/src/test/java/de/neemann/digital/hdl/model2/HDLModelTest.java index 753157625..9025825ae 100644 --- a/src/test/java/de/neemann/digital/hdl/model2/HDLModelTest.java +++ b/src/test/java/de/neemann/digital/hdl/model2/HDLModelTest.java @@ -10,10 +10,7 @@ import de.neemann.digital.draw.elements.PinException; import de.neemann.digital.draw.library.ElementNotFoundException; import de.neemann.digital.hdl.model2.clock.ClockIntegratorGeneric; import de.neemann.digital.hdl.model2.clock.HDLClockIntegrator; -import de.neemann.digital.hdl.model2.optimizations.MergeConstants; -import de.neemann.digital.hdl.model2.optimizations.MergeAssignements; -import de.neemann.digital.hdl.model2.optimizations.NameConstantSignals; -import de.neemann.digital.hdl.model2.optimizations.ReplaceOneToMany; +import de.neemann.digital.hdl.model2.optimizations.*; import de.neemann.digital.hdl.printer.CodePrinterStr; import de.neemann.digital.integration.ToBreakRunner; import junit.framework.TestCase; @@ -30,6 +27,7 @@ public class HDLModelTest extends TestCase { public void testSimple() throws IOException, PinException, HDLException, NodeException, ElementNotFoundException { HDLCircuit hdl = getCircuit("dig/hdl/model2/comb.dig", null) .apply(new MergeAssignements()) + .apply(new NodeSorterExpressionBased()) .nameUnnamedSignals(); CodePrinterStr cp = new CodePrinterStr(); @@ -43,14 +41,14 @@ public class HDLModelTest extends TestCase { " in()\n" + " out(out:1 defines (s1->1))\n" + " s1->1 := 1:1\n" + - " node Not\n" + - " in(in:1 reads (A->3))\n" + - " out(out:1 defines (Z_temp->2))\n" + - " Z_temp->2 := NOT A\n" + " node merged expression\n" + " in(In_1:1 reads (B->2), in:1 reads (C->2))\n" + " out(out:1 defines (Y_temp->2))\n" + " Y_temp->2 := (B OR NOT C)\n" + + " node Not\n" + + " in(in:1 reads (A->3))\n" + + " out(out:1 defines (Z_temp->2))\n" + + " Z_temp->2 := NOT A\n" + " node merged expression\n" + " in(In_5:1 reads (Y_temp->2), In_1:1 reads (A->3), In_2:1 reads (C->2), In_1:1 reads (Z_temp->2), In_1:1 reads (B->2))\n" + " out(out:1 defines (s0->1))\n" + @@ -220,6 +218,7 @@ public class HDLModelTest extends TestCase { .apply(new MergeAssignements()) .apply(new MergeConstants()) .apply(new NameConstantSignals()) + .apply(new NodeSorterExpressionBased()) .nameUnnamedSignals(); CodePrinterStr cp = new CodePrinterStr(); @@ -294,6 +293,7 @@ public class HDLModelTest extends TestCase { HDLCircuit hdl = getCircuit("dig/hdl/model2/splitter3.dig", null) .apply(new ReplaceOneToMany()) .apply(new MergeAssignements()) + .apply(new NodeSorterExpressionBased()) .nameUnnamedSignals(); CodePrinterStr cp = new CodePrinterStr(); @@ -324,6 +324,7 @@ public class HDLModelTest extends TestCase { HDLCircuit hdl = getCircuit("dig/hdl/model2/splitter4.dig", null) .apply(new ReplaceOneToMany()) .apply(new MergeAssignements()) + .apply(new NodeSorterExpressionBased()) .nameUnnamedSignals(); CodePrinterStr cp = new CodePrinterStr(); diff --git a/src/test/java/de/neemann/digital/hdl/vhdl2/ClockTest.java b/src/test/java/de/neemann/digital/hdl/vhdl2/ClockTest.java index 1639752df..9fd90b6b6 100644 --- a/src/test/java/de/neemann/digital/hdl/vhdl2/ClockTest.java +++ b/src/test/java/de/neemann/digital/hdl/vhdl2/ClockTest.java @@ -291,7 +291,7 @@ public class ClockTest extends TestCase { new HDLModel(br.getLibrary()), ci); - c.apply(new MergeAssignements()).nameUnnamedSignals(); + c.applyDefaultOptimizations(); CodePrinter out = new CodePrinterStr(); new VHDLCreator(out).printHDLCircuit(c); diff --git a/src/test/java/de/neemann/digital/hdl/vhdl2/DescriptionTest.java b/src/test/java/de/neemann/digital/hdl/vhdl2/DescriptionTest.java index 1751867c0..bbb994f36 100644 --- a/src/test/java/de/neemann/digital/hdl/vhdl2/DescriptionTest.java +++ b/src/test/java/de/neemann/digital/hdl/vhdl2/DescriptionTest.java @@ -29,9 +29,7 @@ public class DescriptionTest extends TestCase { "main" , new HDLModel(br.getLibrary()), null) - .apply(new MergeConstants()) - .apply(new MergeAssignements()) - .nameUnnamedSignals(); + .applyDefaultOptimizations(); CodePrinterStr out = new CodePrinterStr(); new VHDLCreator(out).printHDLCircuit(circuit); diff --git a/src/test/java/de/neemann/digital/hdl/vhdl2/VHDLGeneratorTest.java b/src/test/java/de/neemann/digital/hdl/vhdl2/VHDLGeneratorTest.java index 751085dab..1d09044c8 100644 --- a/src/test/java/de/neemann/digital/hdl/vhdl2/VHDLGeneratorTest.java +++ b/src/test/java/de/neemann/digital/hdl/vhdl2/VHDLGeneratorTest.java @@ -70,8 +70,8 @@ public class VHDLGeneratorTest extends TestCase { " signal s0: std_logic;\n" + " signal Z_temp: std_logic;\n" + "begin\n" + - " Z_temp <= NOT A;\n" + " Y_temp <= (B OR NOT C);\n" + + " Z_temp <= NOT A;\n"+ " s0 <= ((A OR C) AND (Z_temp OR C) AND '1' AND NOT (B OR C) AND Y_temp);\n" + " gate0: entity work.DIG_D_FF\n" + " port map (\n" +