improved the LUT circuit builder

This commit is contained in:
hneemann 2019-03-09 13:54:01 +01:00
parent 1bd11674c7
commit b57e79b99f
9 changed files with 199 additions and 21 deletions

View File

@ -8,6 +8,7 @@ package de.neemann.digital.analyse.expression;
import java.util.ArrayList;
/**
* Represents a variable as part of an expression.
*/
public class Variable implements Comparable<Variable>, Expression {
@ -49,6 +50,26 @@ public class Variable implements Comparable<Variable>, Expression {
return v;
}
/**
* Returns true if the given expression is a variable.
*
* @param e the expression
* @return true if the given expression is a variable.
*/
public static boolean isVar(Expression e) {
return e instanceof Variable;
}
/**
* Returns true if the given expression is a variable or a inverted variable.
*
* @param e the expression
* @return true if the given expression is a variable or a inverted variable.
*/
public static boolean isVarOrNotVar(Expression e) {
return isVar(e) || (e instanceof Not && isVar(((Not) e).getExpression()));
}
/**
* Creates a new intsnce
*

View File

@ -37,6 +37,8 @@ import de.neemann.digital.lang.Lang;
import java.util.*;
import static de.neemann.digital.analyse.expression.Variable.isVar;
import static de.neemann.digital.analyse.expression.Variable.isVarOrNotVar;
import static de.neemann.digital.draw.shapes.GenericShape.SIZE;
/**
@ -207,16 +209,13 @@ public class CircuitBuilder implements BuilderInterface<CircuitBuilder> {
private Fragment createFragment(Expression expression) throws BuilderException {
if (useLUT) {
if (expression instanceof Variable)
return createBasicFragment(expression);
if (expression instanceof Not && ((Not) expression).getExpression() instanceof Variable)
if (isVarOrNotVar(expression) || expression instanceof Constant)
return createBasicFragment(expression);
if (expression instanceof Operation) {
boolean allVars = true;
for (Expression ex : ((Operation) expression).getExpressions()) {
if (!(ex instanceof Variable || (ex instanceof Not && ((Not) ex).getExpression() instanceof Variable)))
if (!isVarOrNotVar(ex))
allVars = false;
}
if (allVars)
@ -251,12 +250,32 @@ public class CircuitBuilder implements BuilderInterface<CircuitBuilder> {
}
}
lutNumber++;
return new FragmentExpression(frags, new FragmentVisualElement(LookUpTable.DESCRIPTION, frags.size(), shapeFactory)
.setAttr(Keys.LABEL, "L" + lutNumber)
.setAttr(Keys.INPUT_COUNT, frags.size())
.setAttr(Keys.DATA, data)
.setAttr(Keys.BITS, 1));
if (isXor(data.getData()))
return new FragmentExpression(frags, new FragmentVisualElement(XOr.DESCRIPTION, frags.size(), shapeFactory));
else if (isXNor(data.getData()))
return new FragmentExpression(frags, new FragmentVisualElement(XNOr.DESCRIPTION, frags.size(), shapeFactory));
else {
lutNumber++;
return new FragmentExpression(frags, new FragmentVisualElement(LookUpTable.DESCRIPTION, frags.size(), shapeFactory)
.setAttr(Keys.LABEL, "L" + lutNumber)
.setAttr(Keys.INPUT_COUNT, frags.size())
.setAttr(Keys.DATA, data)
.setAttr(Keys.BITS, 1));
}
}
static boolean isXNor(long[] data) {
for (int i = 0; i < data.length; i++)
if ((Integer.bitCount(i) & 1) == data[i])
return false;
return true;
}
static boolean isXor(long[] data) {
for (int i = 0; i < data.length; i++)
if (!((Integer.bitCount(i) & 1) == data[i]))
return false;
return true;
}
private Fragment createBasicFragment(Expression expression) throws BuilderException {
@ -273,7 +292,7 @@ public class CircuitBuilder implements BuilderInterface<CircuitBuilder> {
throw new BuilderException(Lang.get("err_builder_operationNotSupported", op.getClass().getSimpleName()));
} else if (expression instanceof Not) {
Not n = (Not) expression;
if (n.getExpression() instanceof Variable) {
if (isVar(n.getExpression())) {
FragmentVariable fragmentVariable = new FragmentVariable((Variable) n.getExpression(), true);
fragmentVariables.add(fragmentVariable);
return fragmentVariable;
@ -288,7 +307,7 @@ public class CircuitBuilder implements BuilderInterface<CircuitBuilder> {
return new FragmentExpression(frags, new FragmentVisualElement(XNOr.DESCRIPTION, frags.size(), shapeFactory));
}
return new FragmentExpression(createBasicFragment(n.getExpression()), new FragmentVisualElement(de.neemann.digital.core.basic.Not.DESCRIPTION, shapeFactory));
} else if (expression instanceof Variable) {
} else if (isVar(expression)) {
FragmentVariable fragmentVariable = new FragmentVariable((Variable) expression, false);
fragmentVariables.add(fragmentVariable);
return fragmentVariable;
@ -367,10 +386,11 @@ public class CircuitBuilder implements BuilderInterface<CircuitBuilder> {
fr.setPos(new Vector(0, 0));
Box b = fr.doLayout();
if (fr.traverse(new FindLUTVisitor()).containsLUT())
pos += SIZE * 2;
fr.addToCircuit(new Vector(0, pos), circuit);
pos += b.getHeight() + SIZE * 2;
if (useLUT)
pos += SIZE * 2;
}
/**
@ -682,4 +702,20 @@ public class CircuitBuilder implements BuilderInterface<CircuitBuilder> {
mai = modelAnalyserInfo;
return this;
}
private static final class FindLUTVisitor implements FragmentVisitor {
private boolean hasLUT = false;
@Override
public void visit(Fragment fr) {
if (fr instanceof FragmentVisualElement) {
if (((FragmentVisualElement) fr).getVisualElement().equalsDescription(LookUpTable.DESCRIPTION))
hasLUT = true;
}
}
private boolean containsLUT() {
return hasLUT;
}
}
}

View File

@ -48,4 +48,12 @@ public interface Fragment {
*/
List<Vector> getOutputs();
/**
* Visits all fragments
*
* @param v the visitor
* @param <V> the type of the visitor
* @return the visitor
*/
<V extends FragmentVisitor> V traverse(V v);
}

View File

@ -237,4 +237,13 @@ public class FragmentExpression implements Fragment {
fragment.setPos(new Vector(xPos - SIZE, height));
}
}
@Override
public <V extends FragmentVisitor> V traverse(V v) {
v.visit(this);
for (FragmentHolder f : fragments)
f.fragment.traverse(v);
merger.traverse(v);
return v;
}
}

View File

@ -69,4 +69,11 @@ public class FragmentSameInValue implements Fragment {
public List<Vector> getOutputs() {
return Vector.add(fragment.getOutputs(), pos);
}
@Override
public <V extends FragmentVisitor> V traverse(V v) {
v.visit(this);
fragment.traverse(v);
return v;
}
}

View File

@ -79,4 +79,10 @@ public class FragmentVariable implements Fragment {
public Variable getVariable() {
return variable;
}
@Override
public <V extends FragmentVisitor> V traverse(V v) {
v.visit(this);
return v;
}
}

View File

@ -0,0 +1,18 @@
/*
* Copyright (c) 2019 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.builder.circuit;
/**
* Visitor used to visit all fragments
*/
public interface FragmentVisitor {
/**
* Is called with all the fragments
*
* @param fr the fragment to visit
*/
void visit(Fragment fr);
}

View File

@ -141,4 +141,10 @@ public class FragmentVisualElement implements Fragment {
public void setVisualElement(VisualElement visualElement) {
this.visualElement = visualElement;
}
@Override
public <V extends FragmentVisitor> V traverse(V v) {
v.visit(this);
return v;
}
}

View File

@ -36,6 +36,7 @@ import static de.neemann.digital.analyse.expression.Operation.and;
import static de.neemann.digital.analyse.expression.Operation.or;
/**
*
*/
public class CircuitBuilderTest extends TestCase {
@ -87,29 +88,36 @@ public class CircuitBuilderTest extends TestCase {
public void testBuilderSequentialLUT() throws Exception {
Variable y0 = new Variable("Y_0");
Variable y1 = new Variable("Y_1");
Variable y2 = new Variable("Y_2");
// counter
Expression y0s = not(y0);
Expression y1s = or(and(not(y0), y1), and(y0, not(y1)));
Expression y2s = or(and(y0, y1, not(y2)), and(not(y0), y2), and(not(y1), y2));
ElementLibrary library = new ElementLibrary();
Circuit circuit = new CircuitBuilder(new ShapeFactory(library))
.setUseLUTs(true)
.addSequential("Y_0", y0s)
.addSequential("Y_1", y1s)
.addSequential("Y_2", y2s)
.createCircuit();
final ArrayList<VisualElement> el = circuit.getElements();
assertEquals(13, el.size());
assertEquals(19, el.size());
assertEquals(1, el.stream().filter(visualElement -> visualElement.equalsDescription(LookUpTable.DESCRIPTION)).count());
ModelCreator m = new ModelCreator(circuit, library);
TestExecuter te = new TestExecuter(m.createModel(false)).setUp(m);
te.check(0, 0);
te.checkC(1, 0);
te.checkC(0, 1);
te.checkC(1, 1);
te.checkC(0, 0);
te.check(0, 0, 0);
te.checkC(1, 0, 0);
te.checkC(0, 1, 0);
te.checkC(1, 1, 0);
te.checkC(0, 0, 1);
te.checkC(1, 0, 1);
te.checkC(0, 1, 1);
te.checkC(1, 1, 1);
te.checkC(0, 0, 0);
}
public void testBuilderSequentialJK_JequalsK() throws Exception {
@ -224,4 +232,63 @@ public class CircuitBuilderTest extends TestCase {
assertEquals(4, e.getElementAttributes().getBits());
assertEquals(pins, e.getElementAttributes().get(Keys.PINNUMBER));
}
public void testIsXor() {
assertFalse(CircuitBuilder.isXor(new long[]{0, 0, 0, 0}));
assertFalse(CircuitBuilder.isXor(new long[]{0, 0, 0, 1}));
assertFalse(CircuitBuilder.isXor(new long[]{0, 0, 1, 0}));
assertFalse(CircuitBuilder.isXor(new long[]{0, 0, 1, 1}));
assertFalse(CircuitBuilder.isXor(new long[]{0, 1, 0, 0}));
assertFalse(CircuitBuilder.isXor(new long[]{0, 1, 0, 1}));
assertTrue(CircuitBuilder.isXor(new long[]{0, 1, 1, 0}));
assertFalse(CircuitBuilder.isXor(new long[]{0, 1, 1, 1}));
assertFalse(CircuitBuilder.isXor(new long[]{1, 0, 0, 0}));
assertFalse(CircuitBuilder.isXor(new long[]{1, 0, 0, 1}));
assertFalse(CircuitBuilder.isXor(new long[]{1, 0, 1, 0}));
assertFalse(CircuitBuilder.isXor(new long[]{1, 0, 1, 1}));
assertFalse(CircuitBuilder.isXor(new long[]{1, 1, 0, 0}));
assertFalse(CircuitBuilder.isXor(new long[]{1, 1, 0, 1}));
assertFalse(CircuitBuilder.isXor(new long[]{1, 1, 1, 0}));
assertFalse(CircuitBuilder.isXor(new long[]{1, 1, 1, 1}));
assertTrue(CircuitBuilder.isXor(new long[]{0, 1, 1, 0, 1, 0, 0, 1}));
assertFalse(CircuitBuilder.isXor(new long[]{1, 1, 1, 0, 1, 0, 0, 1}));
assertFalse(CircuitBuilder.isXor(new long[]{0, 0, 1, 0, 1, 0, 0, 1}));
assertFalse(CircuitBuilder.isXor(new long[]{0, 1, 0, 0, 1, 0, 0, 1}));
assertFalse(CircuitBuilder.isXor(new long[]{0, 1, 1, 1, 1, 0, 0, 1}));
assertFalse(CircuitBuilder.isXor(new long[]{0, 1, 1, 0, 0, 0, 0, 1}));
assertFalse(CircuitBuilder.isXor(new long[]{0, 1, 1, 0, 1, 1, 0, 1}));
assertFalse(CircuitBuilder.isXor(new long[]{0, 1, 1, 0, 1, 0, 1, 1}));
assertFalse(CircuitBuilder.isXor(new long[]{0, 1, 1, 0, 1, 0, 0, 0}));
}
public void testIsXNor() {
assertFalse(CircuitBuilder.isXNor(new long[]{0, 0, 0, 0}));
assertFalse(CircuitBuilder.isXNor(new long[]{0, 0, 0, 1}));
assertFalse(CircuitBuilder.isXNor(new long[]{0, 0, 1, 0}));
assertFalse(CircuitBuilder.isXNor(new long[]{0, 0, 1, 1}));
assertFalse(CircuitBuilder.isXNor(new long[]{0, 1, 0, 0}));
assertFalse(CircuitBuilder.isXNor(new long[]{0, 1, 0, 1}));
assertFalse(CircuitBuilder.isXNor(new long[]{0, 1, 1, 0}));
assertFalse(CircuitBuilder.isXNor(new long[]{0, 1, 1, 1}));
assertFalse(CircuitBuilder.isXNor(new long[]{1, 0, 0, 0}));
assertTrue(CircuitBuilder.isXNor(new long[]{1, 0, 0, 1}));
assertFalse(CircuitBuilder.isXNor(new long[]{1, 0, 1, 0}));
assertFalse(CircuitBuilder.isXNor(new long[]{1, 0, 1, 1}));
assertFalse(CircuitBuilder.isXNor(new long[]{1, 1, 0, 0}));
assertFalse(CircuitBuilder.isXNor(new long[]{1, 1, 0, 1}));
assertFalse(CircuitBuilder.isXNor(new long[]{1, 1, 1, 0}));
assertFalse(CircuitBuilder.isXNor(new long[]{1, 1, 1, 1}));
assertTrue(CircuitBuilder.isXNor(new long[]{1, 0, 0, 1, 0, 1, 1, 0}));
assertFalse(CircuitBuilder.isXNor(new long[]{0, 0, 0, 1, 0, 1, 1, 0}));
assertFalse(CircuitBuilder.isXNor(new long[]{1, 1, 0, 1, 0, 1, 1, 0}));
assertFalse(CircuitBuilder.isXNor(new long[]{1, 0, 1, 1, 0, 1, 1, 0}));
assertFalse(CircuitBuilder.isXNor(new long[]{1, 0, 0, 0, 0, 1, 1, 0}));
assertFalse(CircuitBuilder.isXNor(new long[]{1, 0, 0, 1, 1, 1, 1, 0}));
assertFalse(CircuitBuilder.isXNor(new long[]{1, 0, 0, 1, 0, 0, 1, 0}));
assertFalse(CircuitBuilder.isXNor(new long[]{1, 0, 0, 1, 0, 1, 0, 0}));
assertFalse(CircuitBuilder.isXNor(new long[]{1, 0, 0, 1, 0, 1, 1, 1}));
}
}