mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-17 08:55:05 -04:00
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:
parent
03de69ba5d
commit
230bb56e1d
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -60,4 +60,10 @@ public class Not extends Node implements Element {
|
||||
return output.asList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the output
|
||||
*/
|
||||
public ObservableValue getOutput() {
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
@ -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,6 +73,7 @@ public class ToBreakRunner {
|
||||
|
||||
ModelDescription md = new ModelDescription(circuit, library);
|
||||
model = md.createModel(false);
|
||||
if (doInit)
|
||||
model.init(true);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user