analyzer is able to analyse sequential circuits build with JK-FF and T-FF as far as they are connected directly to a single clock.

This commit is contained in:
hneemann 2016-06-10 11:25:13 +02:00
parent 03de69ba5d
commit 230bb56e1d
12 changed files with 254 additions and 3 deletions

View File

@ -14,4 +14,13 @@ public class AnalyseException extends Exception {
public AnalyseException(String message) {
super(message);
}
/**
* Creates a new instance
*
* @param e the cause
*/
public AnalyseException(Exception e) {
super(e);
}
}

View File

@ -3,7 +3,14 @@ package de.neemann.digital.analyse;
import de.neemann.digital.analyse.expression.BitSetter;
import de.neemann.digital.analyse.quinemc.BoolTableIntArray;
import de.neemann.digital.core.*;
import de.neemann.digital.core.basic.And;
import de.neemann.digital.core.basic.Not;
import de.neemann.digital.core.basic.Or;
import de.neemann.digital.core.element.ElementAttributes;
import de.neemann.digital.core.flipflops.FlipflopD;
import de.neemann.digital.core.flipflops.FlipflopJK;
import de.neemann.digital.core.flipflops.FlipflopT;
import de.neemann.digital.core.wiring.Clock;
import de.neemann.digital.lang.Lang;
import java.util.ArrayList;
@ -30,6 +37,14 @@ public class ModelAnalyser {
*/
public ModelAnalyser(Model model) throws AnalyseException {
this.model = model;
try {
replaceJKFF();
replaceTFF();
} catch (NodeException e) {
throw new AnalyseException(e);
}
inputs = checkBinary(model.getInputs());
outputs = checkBinary(model.getOutputs());
@ -40,6 +55,7 @@ public class ModelAnalyser {
int i = 0;
List<FlipflopD> flipflops = model.findNode(FlipflopD.class);
for (FlipflopD ff : flipflops) {
checkClock(ff);
ff.getDInput().removeObserver(ff); // turn off flipflop
String label = ff.getLabel();
if (label.length() == 0)
@ -66,6 +82,18 @@ public class ModelAnalyser {
rows = 1 << inputs.size();
}
private void checkClock(Node node) throws AnalyseException {
if (!getClock().hasObserver(node))
throw new AnalyseException(Lang.get("err_ffNeedsToBeConnectedToClock"));
}
private ObservableValue getClock() throws AnalyseException {
ArrayList<Clock> clocks = model.getClocks();
if (clocks.size() != 1)
throw new AnalyseException(Lang.get("err_aSingleClockNecessary"));
return clocks.get(0).getClockOutput();
}
private ArrayList<Signal> checkBinary(ArrayList<Signal> list) throws AnalyseException {
for (Signal s : list)
if (s.getValue().getBits() != 1)
@ -111,4 +139,63 @@ public class ModelAnalyser {
return tt;
}
private void replaceJKFF() throws NodeException, AnalyseException {
List<FlipflopJK> jkList = model.findNode(FlipflopJK.class);
for (FlipflopJK jk : jkList) {
checkClock(jk);
// remove JK-ff from model
model.removeNode(jk);
jk.getClockVal().removeObserver(jk);
jk.getjVal().removeObserver(jk);
jk.getkVal().removeObserver(jk);
// create d ff
ObservableValue q = jk.getOutputs().get(0);
ObservableValue qn = jk.getOutputs().get(1);
FlipflopD d = new FlipflopD(jk.getLabel(), q, qn);
And a1 = new And(new ElementAttributes());
a1.setInputs(new ObservableValues(jk.getjVal(), qn));
And a2 = new And(new ElementAttributes());
Not nk = new Not(new ElementAttributes());
nk.setInputs(jk.getkVal().asList());
a2.setInputs(new ObservableValues(nk.getOutput(), q));
Or or = new Or(new ElementAttributes());
or.setInputs(new ObservableValues(a1.getOutput(), a2.getOutput()));
d.setInputs(new ObservableValues(or.getOutputs().get(0), jk.getClockVal()));
model.add(a1);
model.add(a2);
model.add(nk);
model.add(or);
model.add(d);
}
}
private void replaceTFF() throws NodeException, AnalyseException {
List<FlipflopT> jkList = model.findNode(FlipflopT.class);
for (FlipflopT tff : jkList) {
checkClock(tff);
// remove T-ff from model
model.removeNode(tff);
tff.getClockVal().removeObserver(tff);
// create d ff
ObservableValue q = tff.getOutputs().get(0);
ObservableValue qn = tff.getOutputs().get(1);
FlipflopD d = new FlipflopD(tff.getLabel(), q, qn);
d.setInputs(new ObservableValues(qn, getClock()));
model.add(d);
}
}
}

View File

@ -461,4 +461,13 @@ public class Model implements Iterable<Node> {
public Iterator<Node> iterator() {
return nodes.iterator();
}
/**
* removes a node from this model
*
* @param node the node to remove
*/
public void removeNode(Node node) {
nodes.remove(node);
}
}

View File

@ -66,4 +66,13 @@ public class Observable {
}
/**
* Returns true if the given observer observes this observable
*
* @param observer the observer
* @return true if the given observer observes this observable
*/
public boolean hasObserver(Observer observer) {
return observers.contains(observer);
}
}

View File

@ -60,4 +60,10 @@ public class Not extends Node implements Element {
return output.asList();
}
/**
* @return the output
*/
public ObservableValue getOutput() {
return output;
}
}

View File

@ -44,10 +44,29 @@ public class FlipflopD extends Node implements Element {
* @param attributes the attributes
*/
public FlipflopD(ElementAttributes attributes) {
this(attributes,
new ObservableValue("Q", attributes.getBits()),
new ObservableValue("\u00ACQ", attributes.getBits()));
}
/**
* Creates a new D-FF with the given outputs!
*
* @param label the label
* @param q output
* @param qn inverted output
*/
public FlipflopD(String label, ObservableValue q, ObservableValue qn) {
this(new ElementAttributes().set(Keys.LABEL, label).setBits(q.getBits()), q, qn);
if (qn.getBits() != q.getBits())
throw new RuntimeException("wrong bit count given!");
}
private FlipflopD(ElementAttributes attributes, ObservableValue q, ObservableValue qn) {
super(true);
bits = attributes.getBits();
this.q = new ObservableValue("Q", bits);
this.qn = new ObservableValue("\u00ACQ", bits);
this.q = q;
this.qn = qn;
isProbe = attributes.get(Keys.VALUE_IS_PROBE);
label = attributes.getCleanLabel();
@ -101,4 +120,11 @@ public class FlipflopD extends Node implements Element {
public String getLabel() {
return label;
}
/**
* @return the clock value
*/
public ObservableValue getClock() {
return clockVal;
}
}

View File

@ -82,6 +82,34 @@ public class FlipflopJK extends Node implements Element {
kVal = inputs.get(2).addObserverToValue(this).checkBits(1, this);
}
/**
* @return the j value
*/
public ObservableValue getjVal() {
return jVal;
}
/**
* @return the k value
*/
public ObservableValue getkVal() {
return kVal;
}
/**
* @return the clock value
*/
public ObservableValue getClockVal() {
return clockVal;
}
/**
* @return the label
*/
public String getLabel() {
return label;
}
@Override
public ObservableValues getOutputs() {
return ovs(q, qn);

View File

@ -80,4 +80,17 @@ public class FlipflopT extends Node implements Element {
model.addSignal(new Signal(label, q));
}
/**
* @return the clock value
*/
public ObservableValue getClockVal() {
return clockVal;
}
/**
* @return the label
*/
public String getLabel() {
return label;
}
}

View File

@ -202,6 +202,8 @@ err_pinMap_NoNameForPin_N=Kein Name f\u00FCr Pin {0}
err_pinMap_input_N_notAllowed=Eingang {0} ist nicht erlaubt!
err_pinMap_output_N_notAllowed=Ausgang {0} ist nicht erlaubt!
err_cannotAnalyse_N=Element {0} kann nicht analysiert werden.
err_ffNeedsToBeConnectedToClock=Flipflops m\u00FCssen direkt mit dem Takt verbunden sein.
err_aSingleClockNecessary=Es darf nur einen Takt geben.
attr_dialogTitle=Eigenschaften
msg_errorEditingValue=Fehler bei der Eingabe eines Wertes

View File

@ -181,6 +181,8 @@ err_pinMap_NoNameForPin_N=No Name for pin {0}
err_pinMap_input_N_notAllowed=Input {0} not allowed!
err_pinMap_output_N_notAllowed=Output {0} not allowed!
err_cannotAnalyse_N=Cannot analyse Node {0}
err_ffNeedsToBeConnectedToClock=Flipflop needs to be connected to the clock.
err_aSingleClockNecessary=A single clock is necessary.
attr_dialogTitle=Attributes

View File

@ -28,4 +28,46 @@ public class ModelAnalyserTest extends TestCase {
"1\t0\t1\t\n" +
"1\t1\t0\t\n", tt.toString());
}
public void testAnalyzerDFF() throws Exception {
Model model = new ToBreakRunner("dig/analyzeTestDFF.dig").getModel();
TruthTable tt = new ModelAnalyser(model).analyse();
check2BitCounter(tt);
}
public void testAnalyzerJKFF() throws Exception {
Model model = new ToBreakRunner("dig/analyzeTestJKFF.dig", false).getModel();
TruthTable tt = new ModelAnalyser(model).analyse();
check2BitCounter(tt);
}
public void testAnalyzerTFF() throws Exception {
Model model = new ToBreakRunner("dig/analyzeTestTFF.dig", false).getModel();
TruthTable tt = new ModelAnalyser(model).analyse();
check2BitCounter(tt);
}
private void check2BitCounter(TruthTable tt) {
assertEquals(4, tt.getRows());
assertEquals(4, tt.getCols());
// first col is XOr:
assertEquals(0, tt.getValue(0, 2));
assertEquals(1, tt.getValue(1, 2));
assertEquals(1, tt.getValue(2, 2));
assertEquals(0, tt.getValue(3, 2));
// second col
assertEquals(1, tt.getValue(0, 3));
assertEquals(0, tt.getValue(1, 3));
assertEquals(1, tt.getValue(2, 3));
assertEquals(0, tt.getValue(3, 3));
assertEquals("Q_1n\tQ_0n\tQ_1n+1\tQ_0n+1\t\n" +
"0\t0\t0\t1\t\n" +
"0\t1\t1\t0\t\n" +
"1\t0\t1\t1\t\n" +
"1\t1\t0\t0\t\n", tt.toString());
}
}

View File

@ -39,6 +39,19 @@ public class ToBreakRunner {
this(new File(Resources.getRoot(), file));
}
/**
* Creates a new instance
*
* @param file the file to load
* @param doInit if true model is initialized
* @throws IOException
* @throws PinException
* @throws NodeException
*/
public ToBreakRunner(String file, boolean doInit) throws IOException, PinException, NodeException {
this(new File(Resources.getRoot(), file), doInit);
}
/**
* Creates a new instance
*
@ -48,6 +61,10 @@ public class ToBreakRunner {
* @throws NodeException
*/
public ToBreakRunner(File filename) throws IOException, PinException, NodeException {
this(filename, true);
}
private ToBreakRunner(File filename, boolean doInit) throws IOException, PinException, NodeException {
ElementLibrary library = new ElementLibrary();
ShapeFactory shapeFactory = new ShapeFactory(library);
circuit = Circuit.loadCircuit(filename, shapeFactory);
@ -56,7 +73,8 @@ public class ToBreakRunner {
ModelDescription md = new ModelDescription(circuit, library);
model = md.createModel(false);
model.init(true);
if (doInit)
model.init(true);
}
/**