mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-13 14:56:29 -04:00
improved node ordering
This commit is contained in:
parent
9d628be2ce
commit
f7521228c8
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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" +
|
||||
|
Loading…
x
Reference in New Issue
Block a user