mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-19 01:44:44 -04:00
optimized model analyser.
The model is used to determine the variables on which an output depends. Squashed commit of the following: commit 45efbc50efbf21d242511359c1ba992ccefa7d3f Author: hneemann <helmut.neemann@arcor.de> Date: Sat Jan 13 18:46:21 2018 +0100 improved test case commit 208dde9d94c358b76a540d813ac658c6cf34be32 Author: hneemann <helmut.neemann@arcor.de> Date: Fri Jan 12 21:39:28 2018 +0100 added some more backtracking tests commit 646e50f4e61c879ae7ea51d33c966486a0634691 Author: hneemann <helmut.neemann@arcor.de> Date: Fri Jan 12 19:28:23 2018 +0100 minor changes, more tests are missing commit 71ce4825051e20252284234029c8be012d510a1c Author: hneemann <helmut.neemann@arcor.de> Date: Fri Jan 12 19:05:23 2018 +0100 first attempt to optimize the model analysis using backtracking
This commit is contained in:
parent
a158f6ffe3
commit
0c1714c38c
@ -0,0 +1,76 @@
|
||||
package de.neemann.digital.analyse;
|
||||
|
||||
import de.neemann.digital.analyse.expression.Variable;
|
||||
import de.neemann.digital.analyse.quinemc.BoolTable;
|
||||
import de.neemann.digital.analyse.quinemc.BoolTableByteArray;
|
||||
import de.neemann.digital.analyse.quinemc.ThreeStateValue;
|
||||
import de.neemann.digital.core.Bits;
|
||||
import de.neemann.digital.core.Signal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Creates a bool table which represents an expression which does not depend on all variables.
|
||||
*/
|
||||
public class BoolTableExpanded implements BoolTable {
|
||||
private final BoolTableByteArray e;
|
||||
private final ArrayList<Variable> vars;
|
||||
private final int[] bitsToRemove;
|
||||
private final int bitRemoveCount;
|
||||
private final int size;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param e the values
|
||||
* @param inputs the variables the expression relay depends on
|
||||
* @param originalInputs all variables
|
||||
*/
|
||||
public BoolTableExpanded(BoolTableByteArray e, ArrayList<Signal> inputs, ArrayList<Signal> originalInputs) {
|
||||
this.e = e;
|
||||
bitRemoveCount = originalInputs.size() - inputs.size();
|
||||
bitsToRemove = new int[bitRemoveCount];
|
||||
size = 1 << originalInputs.size();
|
||||
|
||||
int bit = 0;
|
||||
int c = 0;
|
||||
for (int i = originalInputs.size() - 1; i >= 0; i--) {
|
||||
Signal s = originalInputs.get(i);
|
||||
if (!inputs.contains(s)) {
|
||||
bitsToRemove[c] = bit;
|
||||
c++;
|
||||
}
|
||||
bit++;
|
||||
}
|
||||
|
||||
vars = new ArrayList<>();
|
||||
for (Signal s : inputs)
|
||||
vars.add(new Variable(s.getName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThreeStateValue get(int i) {
|
||||
for (int b = bitRemoveCount - 1; b >= 0; b--)
|
||||
i = Bits.removeBitFromValue(i, bitsToRemove[b]);
|
||||
return e.get(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the bool table
|
||||
*/
|
||||
public BoolTableByteArray getBoolTable() {
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the variables
|
||||
*/
|
||||
public ArrayList<Variable> getVars() {
|
||||
return vars;
|
||||
}
|
||||
}
|
@ -48,6 +48,21 @@ public class DependencyAnalyser {
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of model steps needed to analyse the model.
|
||||
*
|
||||
* @param modelAnalyser the model analyser
|
||||
* @return the number of required steps
|
||||
*/
|
||||
public long getRequiredSteps(ModelAnalyser modelAnalyser) {
|
||||
long num = 0;
|
||||
for (Signal o : modelAnalyser.getOutputs()) {
|
||||
int n = getInputs(o).size();
|
||||
num += (1L << n);
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
private void backtracking(ObservableValue value, Set<ObservableValue> effected) throws PinException, BacktrackException {
|
||||
if (!effected.contains(value)) {
|
||||
effected.add(value);
|
||||
|
@ -33,7 +33,6 @@ public class ModelAnalyser {
|
||||
private final Model model;
|
||||
private final ArrayList<Signal> inputs;
|
||||
private final ArrayList<Signal> outputs;
|
||||
private final int rows;
|
||||
private int uniqueIndex = 0;
|
||||
|
||||
/**
|
||||
@ -95,12 +94,8 @@ public class ModelAnalyser {
|
||||
|
||||
if (inputs.size() == 0)
|
||||
throw new AnalyseException(Lang.get("err_analyseNoInputs"));
|
||||
if (inputs.size() > MAX_INPUTS_ALLOWED)
|
||||
throw new AnalyseException(Lang.get("err_toManyInputs_max_N0_is_N1", MAX_INPUTS_ALLOWED, inputs.size()));
|
||||
if (outputs.size() == 0)
|
||||
throw new AnalyseException(Lang.get("err_analyseNoOutputs"));
|
||||
rows = 1 << inputs.size();
|
||||
LOGGER.debug("table has " + rows + " rows");
|
||||
}
|
||||
|
||||
private String createUniqueName(FlipflopD ff) {
|
||||
@ -125,6 +120,63 @@ public class ModelAnalyser {
|
||||
throw new AnalyseException(Lang.get("err_varName_N_UsedTwice", signals.get(i).getName()));
|
||||
}
|
||||
|
||||
private ArrayList<Signal> checkBinaryOutputs(ArrayList<Signal> list) throws AnalyseException {
|
||||
ArrayList<Signal> outputs = new ArrayList<>();
|
||||
for (Signal s : list) {
|
||||
final int bits = s.getValue().getBits();
|
||||
if (bits == 1)
|
||||
outputs.add(s);
|
||||
else {
|
||||
try {
|
||||
Splitter sp = Splitter.createOneToN(bits);
|
||||
sp.setInputs(s.getValue().asList());
|
||||
int i = 0;
|
||||
for (ObservableValue out : sp.getOutputs()) {
|
||||
outputs.add(new Signal(s.getName() + i, out));
|
||||
i++;
|
||||
}
|
||||
s.getValue().fireHasChanged();
|
||||
} catch (NodeException e) {
|
||||
throw new AnalyseException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return outputs;
|
||||
}
|
||||
|
||||
private ArrayList<Signal> checkBinaryInputs(ArrayList<Signal> list) throws AnalyseException {
|
||||
ArrayList<Signal> inputs = new ArrayList<>();
|
||||
for (Signal s : list) {
|
||||
final int bits = s.getValue().getBits();
|
||||
if (bits == 1)
|
||||
inputs.add(s);
|
||||
else {
|
||||
try {
|
||||
Splitter sp = Splitter.createNToOne(bits);
|
||||
final ObservableValue out = sp.getOutputs().get(0);
|
||||
out.addObserver(new NodeWithoutDelay(s.getValue()) {
|
||||
@Override
|
||||
public void hasChanged() {
|
||||
s.getValue().setValue(out.getValue());
|
||||
}
|
||||
});
|
||||
out.fireHasChanged();
|
||||
|
||||
ObservableValues.Builder builder = new ObservableValues.Builder();
|
||||
for (int i = 0; i < bits; i++) {
|
||||
ObservableValue o = new ObservableValue(s.getName() + i, 1);
|
||||
builder.add(o);
|
||||
inputs.add(new Signal(s.getName() + i, o));
|
||||
}
|
||||
sp.setInputs(builder.build());
|
||||
} catch (NodeException e) {
|
||||
throw new AnalyseException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return inputs;
|
||||
}
|
||||
|
||||
private void checkClock(Node node) throws AnalyseException {
|
||||
if (!getClock().hasObserver(node))
|
||||
throw new AnalyseException(Lang.get("err_ffNeedsToBeConnectedToClock"));
|
||||
@ -192,115 +244,6 @@ public class ModelAnalyser {
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
private ArrayList<Signal> checkBinaryOutputs(ArrayList<Signal> list) throws AnalyseException {
|
||||
ArrayList<Signal> outputs = new ArrayList<>();
|
||||
for (Signal s : list) {
|
||||
final int bits = s.getValue().getBits();
|
||||
if (bits == 1)
|
||||
outputs.add(s);
|
||||
else {
|
||||
try {
|
||||
Splitter sp = Splitter.createOneToN(bits);
|
||||
sp.setInputs(s.getValue().asList());
|
||||
int i = 0;
|
||||
for (ObservableValue out : sp.getOutputs()) {
|
||||
outputs.add(new Signal(s.getName() + i, out));
|
||||
i++;
|
||||
}
|
||||
s.getValue().fireHasChanged();
|
||||
} catch (NodeException e) {
|
||||
throw new AnalyseException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return outputs;
|
||||
}
|
||||
|
||||
private ArrayList<Signal> checkBinaryInputs(ArrayList<Signal> list) throws AnalyseException {
|
||||
ArrayList<Signal> inputs = new ArrayList<>();
|
||||
for (Signal s : list) {
|
||||
final int bits = s.getValue().getBits();
|
||||
if (bits == 1)
|
||||
inputs.add(s);
|
||||
else {
|
||||
try {
|
||||
Splitter sp = Splitter.createNToOne(bits);
|
||||
final ObservableValue out = sp.getOutputs().get(0);
|
||||
out.addObserver(new NodeWithoutDelay(s.getValue()) {
|
||||
@Override
|
||||
public void hasChanged() {
|
||||
s.getValue().setValue(out.getValue());
|
||||
}
|
||||
});
|
||||
out.fireHasChanged();
|
||||
|
||||
ObservableValues.Builder builder = new ObservableValues.Builder();
|
||||
for (int i = 0; i < bits; i++) {
|
||||
ObservableValue o = new ObservableValue(s.getName() + i, 1);
|
||||
builder.add(o);
|
||||
inputs.add(new Signal(s.getName() + i, o));
|
||||
}
|
||||
sp.setInputs(builder.build());
|
||||
} catch (NodeException e) {
|
||||
throw new AnalyseException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return inputs;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Analyses the circuit
|
||||
*
|
||||
* @return the generated truth table
|
||||
* @throws NodeException NodeException
|
||||
* @throws PinException PinException
|
||||
* @throws BacktrackException BacktrackException
|
||||
*/
|
||||
public TruthTable analyse() throws NodeException, PinException, BacktrackException {
|
||||
LOGGER.debug("start to analyse the model...");
|
||||
long time = System.currentTimeMillis();
|
||||
BitSetter bitsetter = new BitSetter(inputs.size()) {
|
||||
@Override
|
||||
public void setBit(int row, int bit, boolean value) {
|
||||
inputs.get(bit).getValue().setBool(value);
|
||||
}
|
||||
};
|
||||
|
||||
TruthTable tt = new TruthTable().setPinsWithoutNumber(model.getPinsWithoutNumber());
|
||||
for (Signal s : inputs)
|
||||
tt.addVariable(s.getName());
|
||||
|
||||
for (Signal s : inputs)
|
||||
tt.addPinNumber(s);
|
||||
for (Signal s : outputs)
|
||||
tt.addPinNumber(s);
|
||||
|
||||
if (model.getClocks().size() == 1)
|
||||
tt.setClockPin(model.getClocks().get(0).getClockPin());
|
||||
|
||||
ArrayList<BoolTableByteArray> data = new ArrayList<>();
|
||||
for (Signal s : outputs) {
|
||||
BoolTableByteArray e = new BoolTableByteArray(rows);
|
||||
data.add(e);
|
||||
tt.addResult(s.getName(), e);
|
||||
}
|
||||
|
||||
model.init();
|
||||
for (int row = 0; row < rows; row++) {
|
||||
bitsetter.fill(row);
|
||||
model.doStep();
|
||||
for (int i = 0; i < outputs.size(); i++) {
|
||||
data.get(i).set(row, outputs.get(i).getValue().getBool());
|
||||
}
|
||||
}
|
||||
time = System.currentTimeMillis() - time;
|
||||
LOGGER.debug("model analysis: " + time / 1000.0 + " sec");
|
||||
return tt;
|
||||
}
|
||||
|
||||
private void replaceJKFF() throws NodeException, AnalyseException {
|
||||
List<FlipflopJK> jkList = model.findNode(FlipflopJK.class);
|
||||
|
||||
@ -374,4 +317,114 @@ public class ModelAnalyser {
|
||||
public ArrayList<Signal> getOutputs() {
|
||||
return outputs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyses the circuit
|
||||
*
|
||||
* @return the generated truth table
|
||||
* @throws NodeException NodeException
|
||||
* @throws PinException PinException
|
||||
* @throws BacktrackException BacktrackException
|
||||
* @throws AnalyseException AnalyseException
|
||||
*/
|
||||
public TruthTable analyse() throws NodeException, PinException, BacktrackException, AnalyseException {
|
||||
LOGGER.debug("start to analyse the model...");
|
||||
|
||||
TruthTable tt = new TruthTable().setPinsWithoutNumber(model.getPinsWithoutNumber());
|
||||
for (Signal s : inputs)
|
||||
tt.addVariable(s.getName());
|
||||
|
||||
for (Signal s : inputs)
|
||||
tt.addPinNumber(s);
|
||||
for (Signal s : outputs)
|
||||
tt.addPinNumber(s);
|
||||
|
||||
if (model.getClocks().size() == 1)
|
||||
tt.setClockPin(model.getClocks().get(0).getClockPin());
|
||||
|
||||
DependencyAnalyser da = new DependencyAnalyser(this);
|
||||
long steps = da.getRequiredSteps(this);
|
||||
|
||||
long tableRows = 1L << inputs.size();
|
||||
LOGGER.debug("analyse speedup: " + tableRows + " rows vs " + steps + " steps, speedup " + ((double) tableRows) / steps);
|
||||
|
||||
long time = System.currentTimeMillis();
|
||||
|
||||
|
||||
if (tableRows <= steps || tableRows <= 128)
|
||||
simpleFiller(tt);
|
||||
else
|
||||
dependantFiller(tt, da);
|
||||
|
||||
time = System.currentTimeMillis() - time;
|
||||
LOGGER.debug("model analysis: " + time / 1000.0 + " sec");
|
||||
|
||||
return tt;
|
||||
}
|
||||
|
||||
private void simpleFiller(TruthTable tt) throws NodeException, AnalyseException {
|
||||
if (inputs.size() > MAX_INPUTS_ALLOWED)
|
||||
throw new AnalyseException(Lang.get("err_toManyInputs_max_N0_is_N1", MAX_INPUTS_ALLOWED, inputs.size()));
|
||||
|
||||
|
||||
BitSetter bitsetter = new BitSetter(inputs.size()) {
|
||||
@Override
|
||||
public void setBit(int row, int bit, boolean value) {
|
||||
inputs.get(bit).getValue().setBool(value);
|
||||
}
|
||||
};
|
||||
|
||||
int rows = 1 << inputs.size();
|
||||
ArrayList<BoolTableByteArray> data = new ArrayList<>();
|
||||
for (Signal s : outputs) {
|
||||
BoolTableByteArray e = new BoolTableByteArray(rows);
|
||||
data.add(e);
|
||||
tt.addResult(s.getName(), e);
|
||||
}
|
||||
|
||||
model.init();
|
||||
for (int row = 0; row < rows; row++) {
|
||||
bitsetter.fill(row);
|
||||
model.doStep();
|
||||
for (int i = 0; i < outputs.size(); i++) {
|
||||
data.get(i).set(row, outputs.get(i).getValue().getBool());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void dependantFiller(TruthTable tt, DependencyAnalyser da) throws NodeException, AnalyseException {
|
||||
model.init();
|
||||
for (Signal out : outputs) {
|
||||
|
||||
ArrayList<Signal> ins = reorder(da.getInputs(out), inputs);
|
||||
if (ins.size() > MAX_INPUTS_ALLOWED)
|
||||
throw new AnalyseException(Lang.get("err_toManyInputs_max_N0_is_N1", MAX_INPUTS_ALLOWED, ins.size()));
|
||||
|
||||
int rows = 1 << ins.size();
|
||||
BoolTableByteArray e = new BoolTableByteArray(rows);
|
||||
BitSetter bitsetter = new BitSetter(ins.size()) {
|
||||
@Override
|
||||
public void setBit(int row, int bit, boolean value) {
|
||||
ins.get(bit).getValue().setBool(value);
|
||||
}
|
||||
};
|
||||
|
||||
for (int row = 0; row < rows; row++) {
|
||||
bitsetter.fill(row);
|
||||
model.doStep();
|
||||
e.set(row, out.getValue().getBool());
|
||||
}
|
||||
|
||||
tt.addResult(out.getName(), new BoolTableExpanded(e, ins, inputs));
|
||||
}
|
||||
}
|
||||
|
||||
private ArrayList<Signal> reorder(ArrayList<Signal> ins, ArrayList<Signal> originalOrder) {
|
||||
ArrayList<Signal> newList = new ArrayList<>();
|
||||
for (Signal i : originalOrder)
|
||||
if (ins.contains(i))
|
||||
newList.add(i);
|
||||
return newList;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -403,6 +403,19 @@ public class TruthTable {
|
||||
return results.get(result).getValues();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the result with the given name
|
||||
*
|
||||
* @param resultName the result name
|
||||
* @return the table representing the result or null if not found
|
||||
*/
|
||||
public BoolTable getResult(String resultName) {
|
||||
for (Result r : results)
|
||||
if (r.getName().equals(resultName))
|
||||
return r.getValues();
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the results name
|
||||
*
|
||||
|
@ -1,5 +1,6 @@
|
||||
package de.neemann.digital.analyse.quinemc;
|
||||
|
||||
import de.neemann.digital.analyse.BoolTableExpanded;
|
||||
import de.neemann.digital.analyse.expression.Variable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -29,12 +30,30 @@ public class TableReducer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if there are reduce variables
|
||||
* Returns true if it is possible to reduce variables
|
||||
*
|
||||
* @return true is reduction was possible
|
||||
*/
|
||||
public boolean canReduce() {
|
||||
if (table instanceof BoolTableExpanded) {
|
||||
BoolTableExpanded t = (BoolTableExpanded) table;
|
||||
vars = t.getVars();
|
||||
table = t.getBoolTable();
|
||||
canReduceOnlyCheckTable();
|
||||
return true;
|
||||
} else
|
||||
return canReduceOnlyCheckTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if it is possible to reduce variables
|
||||
* Only used for tests!!!
|
||||
*
|
||||
* @return true is reduction was possible
|
||||
*/
|
||||
public boolean canReduceOnlyCheckTable() {
|
||||
boolean isReduced = false;
|
||||
|
||||
Iterator<Variable> it = vars.iterator();
|
||||
int var = 0;
|
||||
while (it.hasNext()) {
|
||||
|
@ -104,6 +104,22 @@ public final class Bits {
|
||||
return outBits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a bit from a value.
|
||||
* This means it shifts the higher bits down. Behaves like removing an item from a list.
|
||||
*
|
||||
* @param value the value
|
||||
* @param bit the bit to remove
|
||||
* @return the new value
|
||||
*/
|
||||
public static int removeBitFromValue(int value, int bit) {
|
||||
if (bit > 0) {
|
||||
return ((value & (~((1 << (bit + 1)) - 1))) >>> 1) | (value & ((1 << bit) - 1));
|
||||
} else {
|
||||
return value >>> 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a string to a long.
|
||||
* Supports decimal, octal, hex, binary and ascii
|
||||
|
@ -0,0 +1,110 @@
|
||||
package de.neemann.digital.analyse;
|
||||
|
||||
import de.neemann.digital.analyse.expression.Variable;
|
||||
import de.neemann.digital.analyse.quinemc.BoolTable;
|
||||
import de.neemann.digital.analyse.quinemc.BoolTableByteArray;
|
||||
import de.neemann.digital.analyse.quinemc.TableReducer;
|
||||
import de.neemann.digital.analyse.quinemc.ThreeStateValue;
|
||||
import de.neemann.digital.core.Signal;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class BoolTableExpandedTest extends TestCase {
|
||||
|
||||
public void testRegression() {
|
||||
checkTable(new Signals("a", "b").list());
|
||||
checkTable(new Signals("a", "c").list());
|
||||
checkTable(new Signals("a", "d").list());
|
||||
checkTable(new Signals("b", "c").list());
|
||||
checkTable(new Signals("b", "d").list());
|
||||
checkTable(new Signals("c", "d").list());
|
||||
}
|
||||
|
||||
private void checkTable(ArrayList<Signal> in1) {
|
||||
ArrayList<Signal> in2 = new Signals("a", "b", "c", "d").list();
|
||||
List<Variable> vars = new Vars("a", "b", "c", "d").list();
|
||||
|
||||
check(new BoolTableByteArray(new byte[]{1, 1, 0, 1}), in1, in2, vars);
|
||||
check(new BoolTableByteArray(new byte[]{0, 1, 1, 0}), in1, in2, vars);
|
||||
check(new BoolTableByteArray(new byte[]{1, 0, 0, 1}), in1, in2, vars);
|
||||
check(new BoolTableByteArray(new byte[]{0, 0, 0, 1}), in1, in2, vars);
|
||||
check(new BoolTableByteArray(new byte[]{0, 1, 1, 1}), in1, in2, vars);
|
||||
}
|
||||
|
||||
private void check(BoolTableByteArray e, ArrayList<Signal> in1, ArrayList<Signal> in2, List<Variable> vars) {
|
||||
BoolTableExpanded bt = new BoolTableExpanded(e, in1, in2);
|
||||
|
||||
TableReducer tr = new TableReducer(vars, bt);
|
||||
|
||||
assertTrue(tr.canReduceOnlyCheckTable());
|
||||
|
||||
List<Variable> v = tr.getVars();
|
||||
assertEquals(in1.size(), v.size());
|
||||
for (int i = 0; i < v.size(); i++)
|
||||
assertEquals(in1.get(i).getName(), v.get(i).getIdentifier());
|
||||
|
||||
BoolTable t1 = tr.getTable();
|
||||
assertEquals(e.size(), t1.size());
|
||||
for (int r = 0; r < e.size(); r++)
|
||||
assertEquals(e.get(r), t1.get(r));
|
||||
}
|
||||
|
||||
public void testCombined() {
|
||||
ArrayList<Signal> in1 = new Signals("b", "c").list();
|
||||
ArrayList<Signal> in2 = new Signals("a", "b", "c", "d").list();
|
||||
List<Variable> vars = new Vars("a", "b", "c", "d").list();
|
||||
|
||||
BoolTableExpanded bt = new BoolTableExpanded(new BoolTableByteArray(new byte[]{1, 1, 0, 0}), in1, in2);
|
||||
TableReducer tr = new TableReducer(vars, bt);
|
||||
assertTrue(tr.canReduce());
|
||||
List<Variable> v = tr.getVars();
|
||||
assertEquals(1, v.size());
|
||||
assertEquals("b", v.get(0).getIdentifier());
|
||||
BoolTable t1 = tr.getTable();
|
||||
assertEquals(ThreeStateValue.one, t1.get(0));
|
||||
assertEquals(ThreeStateValue.zero, t1.get(1));
|
||||
}
|
||||
|
||||
private static class ListBuilder<A, B> {
|
||||
private final ArrayList<A> list;
|
||||
private Factory<A, B> factory;
|
||||
|
||||
ListBuilder(Factory<A, B> factory) {
|
||||
this.factory = factory;
|
||||
list = new ArrayList<>();
|
||||
}
|
||||
|
||||
ListBuilder(Factory<A, B> factory, B[] bs) {
|
||||
this(factory);
|
||||
for (B b : bs)
|
||||
add(b);
|
||||
}
|
||||
|
||||
public ListBuilder<A, B> add(B b) {
|
||||
list.add(factory.make(b));
|
||||
return this;
|
||||
}
|
||||
|
||||
public ArrayList<A> list() {
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
public class Signals extends ListBuilder<Signal, String> {
|
||||
Signals(String... s) {
|
||||
super((a) -> new Signal(a, null), s);
|
||||
}
|
||||
}
|
||||
|
||||
public class Vars extends ListBuilder<Variable, String> {
|
||||
Vars(String... s) {
|
||||
super(Variable::new, s);
|
||||
}
|
||||
}
|
||||
|
||||
private interface Factory<A, B> {
|
||||
A make(B b);
|
||||
}
|
||||
}
|
@ -1,10 +1,15 @@
|
||||
package de.neemann.digital.analyse;
|
||||
|
||||
import de.neemann.digital.analyse.expression.Variable;
|
||||
import de.neemann.digital.analyse.quinemc.BoolTable;
|
||||
import de.neemann.digital.analyse.quinemc.BoolTableByteArray;
|
||||
import de.neemann.digital.analyse.quinemc.ThreeStateValue;
|
||||
import de.neemann.digital.core.Model;
|
||||
import de.neemann.digital.integration.ToBreakRunner;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static de.neemann.digital.analyse.quinemc.ThreeStateValue.one;
|
||||
import static de.neemann.digital.analyse.quinemc.ThreeStateValue.zero;
|
||||
|
||||
@ -103,21 +108,8 @@ public class ModelAnalyserTest extends TestCase {
|
||||
public void testAnalyzerMultiBit() throws Exception {
|
||||
Model model = new ToBreakRunner("dig/analyze/multiBitCounter.dig", false).getModel();
|
||||
TruthTable tt = new ModelAnalyser(model).analyse();
|
||||
assertEquals("Q0n+1", tt.getResultName(1));
|
||||
final BoolTable r0 = tt.getResult(1);
|
||||
assertEquals(4, r0.size());
|
||||
assertEquals(one, r0.get(0));
|
||||
assertEquals(zero, r0.get(1));
|
||||
assertEquals(one, r0.get(2));
|
||||
assertEquals(zero, r0.get(3));
|
||||
|
||||
assertEquals("Q1n+1", tt.getResultName(0));
|
||||
final BoolTable r1 = tt.getResult(0);
|
||||
assertEquals(4, r1.size());
|
||||
assertEquals(zero, r1.get(0));
|
||||
assertEquals(one, r1.get(1));
|
||||
assertEquals(one, r1.get(2));
|
||||
assertEquals(zero, r1.get(3));
|
||||
checkTable(tt.getResult("Q0n+1"), one, zero, one, zero);
|
||||
checkTable(tt.getResult("Q1n+1"), zero, one, one, zero);
|
||||
|
||||
assertEquals("Y0", tt.getResultName(2));
|
||||
assertEquals("Y1", tt.getResultName(3));
|
||||
@ -144,21 +136,50 @@ public class ModelAnalyserTest extends TestCase {
|
||||
}
|
||||
|
||||
private void checkIdent(TruthTable tt) {
|
||||
assertEquals("B0", tt.getResultName(0));
|
||||
final BoolTable r0 = tt.getResult(0);
|
||||
assertEquals(4, r0.size());
|
||||
assertEquals(zero, r0.get(0));
|
||||
assertEquals(zero, r0.get(1));
|
||||
assertEquals(one, r0.get(2));
|
||||
assertEquals(one, r0.get(3));
|
||||
checkTable(tt.getResult("B0"), zero, zero, one, one);
|
||||
checkTable(tt.getResult("B1"), zero, one, zero, one);
|
||||
}
|
||||
|
||||
assertEquals("B1", tt.getResultName(1));
|
||||
final BoolTable r1 = tt.getResult(1);
|
||||
assertEquals(4, r1.size());
|
||||
assertEquals(zero, r1.get(0));
|
||||
assertEquals(one, r1.get(1));
|
||||
assertEquals(zero, r1.get(2));
|
||||
assertEquals(one, r1.get(3));
|
||||
private void checkTable(BoolTable table, ThreeStateValue... expected) {
|
||||
assertNotNull("result not found", table);
|
||||
assertEquals("wrong table size", expected.length, table.size());
|
||||
for (int i = 0; i < expected.length; i++)
|
||||
assertEquals("wrong value " + i, expected[i], table.get(i));
|
||||
}
|
||||
|
||||
|
||||
public void testAnalyzerBacktrack() throws Exception {
|
||||
Model model = new ToBreakRunner("dig/analyze/analyzeBacktrack.dig", false).getModel();
|
||||
TruthTable tt = new ModelAnalyser(model).analyse();
|
||||
|
||||
final BoolTable Y1 = tt.getResult("1Y");
|
||||
checkRemaining(Y1, "1A", "1B");
|
||||
checkTable(getInner(Y1), zero, one, one, zero);
|
||||
|
||||
final BoolTable Y2 = tt.getResult("2Y");
|
||||
checkRemaining(Y2, "2A", "2B");
|
||||
checkTable(getInner(Y2), one, zero, zero, one);
|
||||
|
||||
final BoolTable Y3 = tt.getResult("3Y");
|
||||
checkRemaining(Y3, "3A", "3B");
|
||||
checkTable(getInner(Y3), zero, one, one, one);
|
||||
|
||||
final BoolTable Y4 = tt.getResult("4Y");
|
||||
checkRemaining(Y4, "4A", "4B", "4C");
|
||||
checkTable(getInner(Y4), zero, zero, zero, zero, zero, zero, zero, one);
|
||||
}
|
||||
|
||||
private BoolTableByteArray getInner(BoolTable table) {
|
||||
assertTrue(table instanceof BoolTableExpanded);
|
||||
return ((BoolTableExpanded) table).getBoolTable();
|
||||
}
|
||||
|
||||
private void checkRemaining(BoolTable table, String... vars) {
|
||||
assertTrue(table instanceof BoolTableExpanded);
|
||||
ArrayList<Variable> v = ((BoolTableExpanded) table).getVars();
|
||||
assertEquals(vars.length, v.size());
|
||||
for (int i = 0; i < vars.length; i++)
|
||||
assertEquals(vars[i], v.get(i).getIdentifier());
|
||||
}
|
||||
|
||||
}
|
@ -109,4 +109,21 @@ public class BitsTest extends TestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public void testRemoveBitFromValue() {
|
||||
assertEquals(0b111, Bits.removeBitFromValue(0b1110, 0));
|
||||
assertEquals(0b111, Bits.removeBitFromValue(0b1111, 0));
|
||||
assertEquals(0b101, Bits.removeBitFromValue(0b1010, 0));
|
||||
assertEquals(0b101, Bits.removeBitFromValue(0b1011, 0));
|
||||
assertEquals(0b111, Bits.removeBitFromValue(0b1101, 1));
|
||||
assertEquals(0b111, Bits.removeBitFromValue(0b1111, 1));
|
||||
assertEquals(0b101, Bits.removeBitFromValue(0b1001, 1));
|
||||
assertEquals(0b101, Bits.removeBitFromValue(0b1011, 1));
|
||||
assertEquals(0b110, Bits.removeBitFromValue(0b1100, 1));
|
||||
assertEquals(0b110, Bits.removeBitFromValue(0b1110, 1));
|
||||
assertEquals(0b111, Bits.removeBitFromValue(0b1111, 2));
|
||||
assertEquals(0b000, Bits.removeBitFromValue(0b0100, 2));
|
||||
assertEquals(0b010, Bits.removeBitFromValue(0b0110, 2));
|
||||
assertEquals(0b100, Bits.removeBitFromValue(0b1100, 2));
|
||||
}
|
||||
|
||||
}
|
217
src/test/resources/dig/analyze/analyzeBacktrack.dig
Normal file
217
src/test/resources/dig/analyze/analyzeBacktrack.dig
Normal file
@ -0,0 +1,217 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<circuit>
|
||||
<version>1</version>
|
||||
<attributes/>
|
||||
<visualElements>
|
||||
<visualElement>
|
||||
<elementName>XOr</elementName>
|
||||
<elementAttributes/>
|
||||
<pos x="440" y="100"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>In</elementName>
|
||||
<elementAttributes>
|
||||
<entry>
|
||||
<string>Label</string>
|
||||
<string>1A</string>
|
||||
</entry>
|
||||
</elementAttributes>
|
||||
<pos x="420" y="100"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>In</elementName>
|
||||
<elementAttributes>
|
||||
<entry>
|
||||
<string>Label</string>
|
||||
<string>1B</string>
|
||||
</entry>
|
||||
</elementAttributes>
|
||||
<pos x="420" y="140"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>Out</elementName>
|
||||
<elementAttributes>
|
||||
<entry>
|
||||
<string>Label</string>
|
||||
<string>1Y</string>
|
||||
</entry>
|
||||
</elementAttributes>
|
||||
<pos x="540" y="120"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>In</elementName>
|
||||
<elementAttributes>
|
||||
<entry>
|
||||
<string>Label</string>
|
||||
<string>2A</string>
|
||||
</entry>
|
||||
</elementAttributes>
|
||||
<pos x="420" y="180"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>In</elementName>
|
||||
<elementAttributes>
|
||||
<entry>
|
||||
<string>Label</string>
|
||||
<string>2B</string>
|
||||
</entry>
|
||||
</elementAttributes>
|
||||
<pos x="420" y="220"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>Out</elementName>
|
||||
<elementAttributes>
|
||||
<entry>
|
||||
<string>Label</string>
|
||||
<string>2Y</string>
|
||||
</entry>
|
||||
</elementAttributes>
|
||||
<pos x="540" y="200"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>XNOr</elementName>
|
||||
<elementAttributes/>
|
||||
<pos x="440" y="180"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>In</elementName>
|
||||
<elementAttributes>
|
||||
<entry>
|
||||
<string>Label</string>
|
||||
<string>3A</string>
|
||||
</entry>
|
||||
</elementAttributes>
|
||||
<pos x="420" y="260"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>In</elementName>
|
||||
<elementAttributes>
|
||||
<entry>
|
||||
<string>Label</string>
|
||||
<string>3B</string>
|
||||
</entry>
|
||||
</elementAttributes>
|
||||
<pos x="420" y="300"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>Out</elementName>
|
||||
<elementAttributes>
|
||||
<entry>
|
||||
<string>Label</string>
|
||||
<string>3Y</string>
|
||||
</entry>
|
||||
</elementAttributes>
|
||||
<pos x="540" y="280"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>Or</elementName>
|
||||
<elementAttributes/>
|
||||
<pos x="440" y="260"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>In</elementName>
|
||||
<elementAttributes>
|
||||
<entry>
|
||||
<string>Label</string>
|
||||
<string>4A</string>
|
||||
</entry>
|
||||
</elementAttributes>
|
||||
<pos x="420" y="340"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>In</elementName>
|
||||
<elementAttributes>
|
||||
<entry>
|
||||
<string>Label</string>
|
||||
<string>4B</string>
|
||||
</entry>
|
||||
</elementAttributes>
|
||||
<pos x="340" y="360"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>Out</elementName>
|
||||
<elementAttributes>
|
||||
<entry>
|
||||
<string>Label</string>
|
||||
<string>4Y</string>
|
||||
</entry>
|
||||
</elementAttributes>
|
||||
<pos x="540" y="360"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>And</elementName>
|
||||
<elementAttributes>
|
||||
<entry>
|
||||
<string>Inputs</string>
|
||||
<int>3</int>
|
||||
</entry>
|
||||
</elementAttributes>
|
||||
<pos x="440" y="340"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>In</elementName>
|
||||
<elementAttributes>
|
||||
<entry>
|
||||
<string>Label</string>
|
||||
<string>4C</string>
|
||||
</entry>
|
||||
</elementAttributes>
|
||||
<pos x="420" y="380"/>
|
||||
</visualElement>
|
||||
</visualElements>
|
||||
<wires>
|
||||
<wire>
|
||||
<p1 x="420" y="100"/>
|
||||
<p2 x="440" y="100"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="420" y="180"/>
|
||||
<p2 x="440" y="180"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="420" y="260"/>
|
||||
<p2 x="440" y="260"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="420" y="340"/>
|
||||
<p2 x="440" y="340"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="500" y="120"/>
|
||||
<p2 x="540" y="120"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="520" y="200"/>
|
||||
<p2 x="540" y="200"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="500" y="280"/>
|
||||
<p2 x="540" y="280"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="500" y="360"/>
|
||||
<p2 x="540" y="360"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="340" y="360"/>
|
||||
<p2 x="440" y="360"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="420" y="140"/>
|
||||
<p2 x="440" y="140"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="420" y="220"/>
|
||||
<p2 x="440" y="220"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="420" y="300"/>
|
||||
<p2 x="440" y="300"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="420" y="380"/>
|
||||
<p2 x="440" y="380"/>
|
||||
</wire>
|
||||
</wires>
|
||||
<measurementOrdering/>
|
||||
</circuit>
|
Loading…
x
Reference in New Issue
Block a user