improved node ordering

This commit is contained in:
hneemann 2018-03-29 13:46:16 +02:00
parent 9d628be2ce
commit f7521228c8
10 changed files with 171 additions and 129 deletions

View File

@ -157,14 +157,6 @@ public class HDLCircuit implements Iterable<HDLNode>, 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<HDLNode>, 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<HDLNode>, HDLModel.BitProvider, Prin
apply(new RemoveConstantSignals());
apply(new MergeConstants()); // under certain circumstances there are still constants
apply(new NameConstantSignals());
apply(new NodeSorterExpressionBased());
return nameUnnamedSignals();
}

View File

@ -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<HDLPort> inputs;
private final ArrayList<HDLNode> nodes;
/**
* Creates a new instance.
*
* @param inputs the initial inputs
* @param nodes the nodes to sort
*/
NodeSorter(ArrayList<HDLPort> inputs, ArrayList<HDLNode> nodes) {
this.inputs = inputs;
this.nodes = nodes;
}
/**
* Performs the sorting and returns a sorted list.
*
* @return the sorted list
*/
public ArrayList<HDLNode> sort() {
HashSet<HDLNet> nets = new HashSet<>();
for (HDLPort p : inputs)
nets.add(p.getNet());
ArrayList<HDLNode> 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<HDLNode> 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<HDLNet> nets) {
for (HDLPort p : n.getInputs())
if (!p.getNet().isClock() && !nets.contains(p.getNet()))
return false;
return true;
}
private boolean dependsAtLeastAtOne(HDLNode n, HashSet<HDLNet> nets) {
for (HDLPort p : n.getInputs())
if (!p.getNet().isClock() && nets.contains(p.getNet()))
return true;
return false;
}
}

View File

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

View File

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

View File

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

View File

@ -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<HDLNode> nodes = circuit.getNodes();
ArrayList<HDLNode> nodesAvail = new ArrayList<>(nodes);
nodes.clear();
HashSet<HDLNet> 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<HDLNode> 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<HDLNet> nets;
private boolean dependsOnlyOn = true;
private DependsOnlyOn(HashSet<HDLNet> 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<HDLNet> nets;
private boolean dependsAtLeastOnOne = false;
private DependsAtLeastOnOneOf(HashSet<HDLNet> 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<HDLNet> nets) {
for (HDLPort p : n.getInputs())
if (!p.getNet().isClock() && !nets.contains(p.getNet()))
return false;
return true;
}
private boolean dependsAtLeastAtOne(HDLNode n, HashSet<HDLNet> nets) {
for (HDLPort p : n.getInputs())
if (!p.getNet().isClock() && nets.contains(p.getNet()))
return true;
return false;
}
}

View File

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

View File

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

View File

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

View File

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