diff --git a/src/main/java/de/neemann/digital/analyse/expression/Variable.java b/src/main/java/de/neemann/digital/analyse/expression/Variable.java index fbf2df3d1..a1f7ebd37 100644 --- a/src/main/java/de/neemann/digital/analyse/expression/Variable.java +++ b/src/main/java/de/neemann/digital/analyse/expression/Variable.java @@ -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, Expression { @@ -49,6 +50,26 @@ public class Variable implements Comparable, 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 * diff --git a/src/main/java/de/neemann/digital/builder/circuit/CircuitBuilder.java b/src/main/java/de/neemann/digital/builder/circuit/CircuitBuilder.java index 5656ece99..b4c2a852f 100644 --- a/src/main/java/de/neemann/digital/builder/circuit/CircuitBuilder.java +++ b/src/main/java/de/neemann/digital/builder/circuit/CircuitBuilder.java @@ -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 { 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 { } } - 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 { 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 { 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 { 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 { 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; + } + } } diff --git a/src/main/java/de/neemann/digital/builder/circuit/Fragment.java b/src/main/java/de/neemann/digital/builder/circuit/Fragment.java index 7bab72b24..ff4b2dc7f 100644 --- a/src/main/java/de/neemann/digital/builder/circuit/Fragment.java +++ b/src/main/java/de/neemann/digital/builder/circuit/Fragment.java @@ -48,4 +48,12 @@ public interface Fragment { */ List getOutputs(); + /** + * Visits all fragments + * + * @param v the visitor + * @param the type of the visitor + * @return the visitor + */ + V traverse(V v); } diff --git a/src/main/java/de/neemann/digital/builder/circuit/FragmentExpression.java b/src/main/java/de/neemann/digital/builder/circuit/FragmentExpression.java index 1cd92be49..0f476334b 100644 --- a/src/main/java/de/neemann/digital/builder/circuit/FragmentExpression.java +++ b/src/main/java/de/neemann/digital/builder/circuit/FragmentExpression.java @@ -237,4 +237,13 @@ public class FragmentExpression implements Fragment { fragment.setPos(new Vector(xPos - SIZE, height)); } } + + @Override + public V traverse(V v) { + v.visit(this); + for (FragmentHolder f : fragments) + f.fragment.traverse(v); + merger.traverse(v); + return v; + } } diff --git a/src/main/java/de/neemann/digital/builder/circuit/FragmentSameInValue.java b/src/main/java/de/neemann/digital/builder/circuit/FragmentSameInValue.java index 9a4ff63f3..21806a04c 100644 --- a/src/main/java/de/neemann/digital/builder/circuit/FragmentSameInValue.java +++ b/src/main/java/de/neemann/digital/builder/circuit/FragmentSameInValue.java @@ -69,4 +69,11 @@ public class FragmentSameInValue implements Fragment { public List getOutputs() { return Vector.add(fragment.getOutputs(), pos); } + + @Override + public V traverse(V v) { + v.visit(this); + fragment.traverse(v); + return v; + } } diff --git a/src/main/java/de/neemann/digital/builder/circuit/FragmentVariable.java b/src/main/java/de/neemann/digital/builder/circuit/FragmentVariable.java index 417858a70..31d7fbe78 100644 --- a/src/main/java/de/neemann/digital/builder/circuit/FragmentVariable.java +++ b/src/main/java/de/neemann/digital/builder/circuit/FragmentVariable.java @@ -79,4 +79,10 @@ public class FragmentVariable implements Fragment { public Variable getVariable() { return variable; } + + @Override + public V traverse(V v) { + v.visit(this); + return v; + } } diff --git a/src/main/java/de/neemann/digital/builder/circuit/FragmentVisitor.java b/src/main/java/de/neemann/digital/builder/circuit/FragmentVisitor.java new file mode 100644 index 000000000..dd4e8e458 --- /dev/null +++ b/src/main/java/de/neemann/digital/builder/circuit/FragmentVisitor.java @@ -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); +} diff --git a/src/main/java/de/neemann/digital/builder/circuit/FragmentVisualElement.java b/src/main/java/de/neemann/digital/builder/circuit/FragmentVisualElement.java index 056a7c5ab..258012dd2 100644 --- a/src/main/java/de/neemann/digital/builder/circuit/FragmentVisualElement.java +++ b/src/main/java/de/neemann/digital/builder/circuit/FragmentVisualElement.java @@ -141,4 +141,10 @@ public class FragmentVisualElement implements Fragment { public void setVisualElement(VisualElement visualElement) { this.visualElement = visualElement; } + + @Override + public V traverse(V v) { + v.visit(this); + return v; + } } diff --git a/src/test/java/de/neemann/digital/builder/circuit/CircuitBuilderTest.java b/src/test/java/de/neemann/digital/builder/circuit/CircuitBuilderTest.java index 8563aa59f..5b598cec2 100644 --- a/src/test/java/de/neemann/digital/builder/circuit/CircuitBuilderTest.java +++ b/src/test/java/de/neemann/digital/builder/circuit/CircuitBuilderTest.java @@ -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 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})); + + } }