added simple analyser for circuits which creates a truth table

This commit is contained in:
hneemann 2016-04-20 21:13:44 +02:00
parent b68570030c
commit 6e5728ca2a
14 changed files with 691 additions and 319 deletions

View File

@ -7,10 +7,10 @@
<elementAttributes> <elementAttributes>
<entry> <entry>
<string>Label</string> <string>Label</string>
<string>A_0</string> <string>A_1</string>
</entry> </entry>
</elementAttributes> </elementAttributes>
<pos x="160" y="60"/> <pos x="160" y="120"/>
<rotate>0</rotate> <rotate>0</rotate>
</visualElement> </visualElement>
<visualElement> <visualElement>
@ -18,10 +18,10 @@
<elementAttributes> <elementAttributes>
<entry> <entry>
<string>Label</string> <string>Label</string>
<string>A_1</string> <string>A_0</string>
</entry> </entry>
</elementAttributes> </elementAttributes>
<pos x="160" y="120"/> <pos x="160" y="60"/>
<rotate>0</rotate> <rotate>0</rotate>
</visualElement> </visualElement>
<visualElement> <visualElement>

View File

@ -76,10 +76,10 @@
<elementAttributes> <elementAttributes>
<entry> <entry>
<string>Label</string> <string>Label</string>
<string>C_i</string> <string>S_i</string>
</entry> </entry>
</elementAttributes> </elementAttributes>
<pos x="940" y="280"/> <pos x="940" y="440"/>
<rotate>0</rotate> <rotate>0</rotate>
</visualElement> </visualElement>
<visualElement> <visualElement>
@ -87,10 +87,10 @@
<elementAttributes> <elementAttributes>
<entry> <entry>
<string>Label</string> <string>Label</string>
<string>S_i</string> <string>C_i</string>
</entry> </entry>
</elementAttributes> </elementAttributes>
<pos x="940" y="440"/> <pos x="940" y="280"/>
<rotate>0</rotate> <rotate>0</rotate>
</visualElement> </visualElement>
</visualElements> </visualElements>

View File

@ -0,0 +1,17 @@
package de.neemann.digital.analyse;
/**
* Exception thrown if there problems analysing the circuit
*
* @author hneemann
*/
public class AnalyseException extends Exception {
/**
* Creates a new instance
*
* @param message the message
*/
public AnalyseException(String message) {
super(message);
}
}

View File

@ -0,0 +1,138 @@
package de.neemann.digital.analyse;
import de.neemann.digital.core.Model;
import de.neemann.digital.core.NodeException;
import de.neemann.digital.lang.Lang;
import java.util.ArrayList;
/**
* Analyses a given model.
* Calculates the truth table which generated by the given model
*
* @author hneemann
*/
public class ModelAnalyser {
private final Model model;
private final ArrayList<Model.Signal> inputs;
private final ArrayList<Model.Signal> outputs;
private final int rows;
private final int cols;
private final boolean[][] data;
/**
* Creates a new instance
*
* @param model the model
* @throws AnalyseException AnalyseException
*/
public ModelAnalyser(Model model) throws AnalyseException {
this.model = model;
inputs = checkBinary(model.getInputs());
if (inputs.size() == 0)
throw new AnalyseException(Lang.get("err_analyseNoInputs"));
outputs = checkBinary(model.getOutputs());
if (outputs.size() == 0)
throw new AnalyseException(Lang.get("err_analyseNoOutputs"));
rows = 1 << inputs.size();
cols = inputs.size() + outputs.size();
data = new boolean[rows][cols];
}
private ArrayList<Model.Signal> checkBinary(ArrayList<Model.Signal> list) throws AnalyseException {
for (Model.Signal s : list)
if (s.getValue().getBits() != 1)
throw new AnalyseException(Lang.get("err_analyseValue_N_IsNotBinary", s.getName()));
return list;
}
/**
* Analyses the circuit
*
* @return this for call chaining
* @throws NodeException NodeException
*/
public ModelAnalyser analyse() throws NodeException {
model.init();
for (int row = 0; row < rows; row++) {
for (int i = 0; i < inputs.size(); i++) {
int pos = inputs.size() - 1 - i;
boolean bool = (row & (1 << pos)) != 0;
inputs.get(i).getValue().setBool(bool);
data[row][i] = bool;
}
model.doStep();
for (int i = 0; i < outputs.size(); i++) {
data[row][inputs.size() + i] = outputs.get(i).getValue().getBool();
}
}
return this;
}
/**
* @return returns the models inputs
*/
public ArrayList<Model.Signal> getInputs() {
return inputs;
}
/**
* @return returns the models outputs
*/
public ArrayList<Model.Signal> getOutputs() {
return outputs;
}
/**
* @return the truth table
*/
public boolean[][] getData() {
return data;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (Model.Signal s : inputs)
sb.append(s.getName()).append("\t");
for (Model.Signal s : outputs)
sb.append(s.getName()).append("\t");
sb.append('\n');
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
if (data[row][col])
sb.append("1\t");
else
sb.append("0\t");
}
sb.append("\n");
}
return sb.toString();
}
/**
* @return the number of rows
*/
public int getRows() {
return rows;
}
/**
* @return the number of columns
*/
public int getCols() {
return cols;
}
/**
* @return returns one value of the truth table
*/
public int getValue(int rowIndex, int columnIndex) {
if (data[rowIndex][columnIndex])
return 1;
else
return 0;
}
}

View File

@ -0,0 +1,60 @@
package de.neemann.digital.analyse;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;
/**
* @author hneemann
*/
public class ModelAnalyzerTableModel implements TableModel {
private final ModelAnalyser analyzer;
public ModelAnalyzerTableModel(ModelAnalyser analyzer) {
this.analyzer = analyzer;
}
@Override
public int getRowCount() {
return analyzer.getRows();
}
@Override
public int getColumnCount() {
return analyzer.getCols();
}
@Override
public String getColumnName(int columnIndex) {
if (columnIndex < analyzer.getInputs().size())
return analyzer.getInputs().get(columnIndex).getName();
else
return analyzer.getOutputs().get(columnIndex - analyzer.getInputs().size()).getName();
}
@Override
public Class<?> getColumnClass(int columnIndex) {
return Integer.class;
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
return analyzer.getValue(rowIndex, columnIndex);
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
}
@Override
public void addTableModelListener(TableModelListener l) {
}
@Override
public void removeTableModelListener(TableModelListener l) {
}
}

View File

@ -0,0 +1,6 @@
/**
* Classes used to analyse the actual circuit
*
* @author hneemann
*/
package de.neemann.digital.analyse;

View File

@ -48,6 +48,8 @@ public class Model {
private final ArrayList<Break> breaks; private final ArrayList<Break> breaks;
private final ArrayList<Reset> resets; private final ArrayList<Reset> resets;
private final ArrayList<Signal> signals; private final ArrayList<Signal> signals;
private final ArrayList<Signal> inputs;
private final ArrayList<Signal> outputs;
private final ArrayList<ROM> roms; private final ArrayList<ROM> roms;
private final ArrayList<Node> nodes; private final ArrayList<Node> nodes;
@ -65,6 +67,8 @@ public class Model {
this.breaks = new ArrayList<>(); this.breaks = new ArrayList<>();
this.resets = new ArrayList<>(); this.resets = new ArrayList<>();
this.signals = new ArrayList<>(); this.signals = new ArrayList<>();
this.outputs = new ArrayList<>();
this.inputs = new ArrayList<>();
this.roms = new ArrayList<>(); this.roms = new ArrayList<>();
this.nodes = new ArrayList<>(); this.nodes = new ArrayList<>();
this.nodesToUpdateAct = new ArrayList<>(); this.nodesToUpdateAct = new ArrayList<>();
@ -100,8 +104,7 @@ public class Model {
/** /**
* Needs to be called after all nodes are added. * Needs to be called after all nodes are added.
* If not called it es called automatically. * Calls <code>init(true);</code>
* Calles <code>init(true);</code>
* *
* @throws NodeException NodeException * @throws NodeException NodeException
*/ */
@ -373,10 +376,56 @@ public class Model {
* @param value the signals value * @param value the signals value
*/ */
public void addSignal(String name, ObservableValue value) { public void addSignal(String name, ObservableValue value) {
if (name != null && name.length() > 0 && value != null) if (isSignal(name, value))
signals.add(new Signal(name, value)); signals.add(new Signal(name, value));
} }
private static boolean isSignal(String name, ObservableValue value) {
return name != null && name.length() > 0 && value != null;
}
/**
* registers a input to the model
*
* @param name the signals name
* @param value the signals value
*/
public void addInput(String name, ObservableValue value) {
if (isSignal(name, value)) {
Signal signal = new Signal(name, value);
signals.add(signal);
inputs.add(signal);
}
}
/**
* @return the models inputs
*/
public ArrayList<Signal> getInputs() {
return inputs;
}
/**
* registers a output to the model
*
* @param name the signals name
* @param value the signals value
*/
public void addOutput(String name, ObservableValue value) {
if (isSignal(name, value)) {
Signal signal = new Signal(name, value);
signals.add(signal);
outputs.add(signal);
}
}
/**
* @return the models outputs
*/
public ArrayList<Signal> getOutputs() {
return outputs;
}
/** /**
* @return all registered Signals * @return all registered Signals
*/ */
@ -431,6 +480,9 @@ public class Model {
* @param value the signals value * @param value the signals value
*/ */
public Signal(String name, ObservableValue value) { public Signal(String name, ObservableValue value) {
if (name.length() > 2 && name.charAt(0) == '$' && name.charAt(name.length() - 1) == '$')
this.name = name.substring(1, name.length() - 1);
else
this.name = name; this.name = name;
this.value = value; this.value = value;
} }

View File

@ -59,6 +59,6 @@ public class In implements Element {
@Override @Override
public void registerNodes(Model model) { public void registerNodes(Model model) {
model.addSignal(label, output); model.addInput(label, output);
} }
} }

View File

@ -104,6 +104,6 @@ public class Out implements Element {
@Override @Override
public void registerNodes(Model model) { public void registerNodes(Model model) {
model.addSignal(label, value); model.addOutput(label, value);
} }
} }

View File

@ -1,5 +1,7 @@
package de.neemann.digital.gui; package de.neemann.digital.gui;
import de.neemann.digital.analyse.AnalyseException;
import de.neemann.digital.analyse.ModelAnalyser;
import de.neemann.digital.core.*; import de.neemann.digital.core.*;
import de.neemann.digital.core.element.ElementAttributes; import de.neemann.digital.core.element.ElementAttributes;
import de.neemann.digital.core.element.Key; import de.neemann.digital.core.element.Key;
@ -320,6 +322,8 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, E
run.add(speedTest.createJMenuItem()); run.add(speedTest.createJMenuItem());
doStep.setEnabled(false); doStep.setEnabled(false);
bar.add(createAanalyseMenu());
JToolBar toolBar = new JToolBar(); JToolBar toolBar = new JToolBar();
toolBar.add(newFile.createJButtonNoText()); toolBar.add(newFile.createJButtonNoText());
toolBar.add(open.createJButtonNoText()); toolBar.add(open.createJButtonNoText());
@ -348,6 +352,26 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, E
setLocationRelativeTo(parent); setLocationRelativeTo(parent);
} }
private JMenu createAanalyseMenu() {
JMenu analyse = new JMenu(Lang.get("menu_analyse"));
analyse.add(new ToolTipAction(Lang.get("menu_analyse")) {
@Override
public void actionPerformed(ActionEvent e) {
try {
Model model = new ModelDescription(circuitComponent.getCircuit(), library).createModel();
new TableDialog(Main.this, new ModelAnalyser(model).analyse()).setVisible(true);
elementState.activate();
} catch (PinException | NodeException | AnalyseException e1) {
showErrorAndStopModel(Lang.get("msg_annalyseErr"), e1);
}
}
}
.setToolTip(Lang.get("menu_analyse_tt"))
.createJMenuItem());
return analyse;
}
private void orderMeasurements() { private void orderMeasurements() {
try { try {
Model m = new ModelDescription(circuitComponent.getCircuit(), library).createModel(); Model m = new ModelDescription(circuitComponent.getCircuit(), library).createModel();

View File

@ -0,0 +1,30 @@
package de.neemann.digital.gui.components;
import de.neemann.digital.analyse.ModelAnalyser;
import de.neemann.digital.analyse.ModelAnalyzerTableModel;
import de.neemann.digital.lang.Lang;
import javax.swing.*;
import java.awt.*;
/**
* Dialog to visualise a truth table.
*
* @author hneemann
*/
public class TableDialog extends JDialog {
/**
* Creates a new instance
*
* @param owner the owner of this dialog
* @param analyzer the truth table
*/
public TableDialog(Frame owner, ModelAnalyser analyzer) {
super(owner, Lang.get("win_table"));
JTable table = new JTable(new ModelAnalyzerTableModel(analyzer));
table.setPreferredScrollableViewportSize(table.getPreferredSize());
getContentPane().add(new JScrollPane(table));
pack();
setLocationRelativeTo(owner);
}
}

View File

@ -168,6 +168,9 @@ err_notAllOutputsSameBits=Es haben nicht alle Ausg\u00E4nge die gleiche Bitbreit
err_notAllOutputsSupportHighZ=Wenn mehrere Ausg\u00E4nge verbunden sind, m\u00FCssen alle Ausg\u00E4nge Tri-State Ausg\u00E4nge sein err_notAllOutputsSupportHighZ=Wenn mehrere Ausg\u00E4nge verbunden sind, m\u00FCssen alle Ausg\u00E4nge Tri-State Ausg\u00E4nge sein
err_breakTimeOut=Nach {0} Zyklen ist kein Break aufgetreten err_breakTimeOut=Nach {0} Zyklen ist kein Break aufgetreten
err_labelNotConnectedToNet_N=Ein Tunnel {0} ist nicht verbunden! err_labelNotConnectedToNet_N=Ein Tunnel {0} ist nicht verbunden!
err_analyseNoInputs=Die Schaltung hat keine benannten Eing\u00E4nge
err_analyseNoOutputs=Die Schaltung hat keine benannten Ausg\u00E4nge
err_analyseValue_N_IsNotBinary=Der Wert {0} hat mehr als ein Bit.
attr_dialogTitle=Eigenschaften attr_dialogTitle=Eigenschaften
msg_errorEditingValue=Fehler bei der Eingabe eines Wertes msg_errorEditingValue=Fehler bei der Eingabe eines Wertes
@ -178,10 +181,11 @@ msg_errorWritingFile=Fehler beim Schreiben einer Datei
msg_errorReadingFile=Fehler beim Lesen einer Datei msg_errorReadingFile=Fehler beim Lesen einer Datei
msg_errorCalculatingStep=Fehler beim Berechnen eines Schrittes msg_errorCalculatingStep=Fehler beim Berechnen eines Schrittes
msg_missingShape_N=Es fehlt ein Diagramm f\u00FCr {0} msg_missingShape_N=Es fehlt ein Diagramm f\u00FCr {0}
msg_fastRunError=Ein Fehler beim Schnellen Lauf msg_fastRunError=Ein Fehler beim schnellen Lauf
msg_errorReadingListing_N0=Fehler beim Laden des Listings {0} msg_errorReadingListing_N0=Fehler beim Laden des Listings {0}
msg_clockError=Fehler bei der Berechnung einer Takt\u00E4nderung msg_clockError=Fehler bei der Berechnung einer Takt\u00E4nderung
msg_frequency_N=Die maximale Frequenz ber\u00E4gt {0}Hz. msg_frequency_N=Die maximale Frequenz ber\u00E4gt {0}Hz.
msg_annalyseErr=Fehler bei der Analyse der Schaltung
stat_clocks={0} Halbzyklen stat_clocks={0} Halbzyklen
@ -244,6 +248,8 @@ menu_editRunAttributes=Simulationseinstellungen
menu_editRunAttributes_tt=Einstellungen f\u00FCr den Start der Simulation menu_editRunAttributes_tt=Einstellungen f\u00FCr den Start der Simulation
menu_saveData=Daten speichern menu_saveData=Daten speichern
menu_saveData_tt=Speichert die Daten als CSV Datei menu_saveData_tt=Speichert die Daten als CSV Datei
menu_analyse=Analyse
menu_analyse_tt=Analyse der aktuellen Schaltung
menu_about=\u00DCber Digital menu_about=\u00DCber Digital
@ -255,3 +261,4 @@ win_measures_microstep=Messwerte im Einzelgattermodus
win_measures_fullstep=Messwerte im Vollschrittmodus win_measures_fullstep=Messwerte im Vollschrittmodus
win_listing=Listing win_listing=Listing
win_table=Tabelle

View File

@ -228,6 +228,8 @@ menu_editRunAttributes=Simulation Settings
menu_editRunAttributes_tt=Settings used to start the simulation menu_editRunAttributes_tt=Settings used to start the simulation
menu_saveData=Save Data menu_saveData=Save Data
menu_saveData_tt=Save data as CSV file menu_saveData_tt=Save data as CSV file
menu_analyse=Analyse
menu_analyse_tt=Analyses the actual circuit
win_saveChanges=Save Changes? win_saveChanges=Save Changes?
win_confirmExit=Confirm Exit! win_confirmExit=Confirm Exit!
@ -252,3 +254,8 @@ elem_Text_tt=Shows a text in the circuit
key_Default_tt=Is set if the model is started key_Default_tt=Is set if the model is started
err_labelNotConnectedToNet_N=A tunnel {0} is not connected! err_labelNotConnectedToNet_N=A tunnel {0} is not connected!
key_Width_tt=With of symbol if this circuit is used in an element ins an other circuit. key_Width_tt=With of symbol if this circuit is used in an element ins an other circuit.
err_analyseNoInputs=The circuit has no Inputs
err_analyseNoOutputs=The circuit has no outputs
err_analyseValue_N_IsNotBinary=The value {0} has more the one bit.
msg_annalyseErr=Error analysing the circuit
win_table=Table

View File

@ -0,0 +1,31 @@
package de.neemann.digital.analyse;
import de.neemann.digital.core.Model;
import de.neemann.digital.integration.ToBreakRunner;
import junit.framework.TestCase;
/**
* @author hneemann
*/
public class ModelAnalyserTest extends TestCase {
public void testAnalyzer() throws Exception {
Model model = new ToBreakRunner("dig/analyzeTest.dig").getModel();
ModelAnalyser ma = new ModelAnalyser(model).analyse();
assertEquals(4, ma.getRows());
assertEquals(3, ma.getCols());
// circuit is XOr:
assertEquals(0, ma.getValue(0, 2));
assertEquals(1, ma.getValue(1, 2));
assertEquals(1, ma.getValue(2, 2));
assertEquals(0, ma.getValue(3, 2));
assertEquals("A\tB\tY\t\n" +
"0\t0\t0\t\n" +
"0\t1\t1\t\n" +
"1\t0\t1\t\n" +
"1\t1\t0\t\n", ma.toString());
}
}