mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-14 07:17:13 -04:00
improved the LUT circuit builder
This commit is contained in:
parent
1bd11674c7
commit
b57e79b99f
@ -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
|
||||
*
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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}));
|
||||
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user