mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-17 08:55:05 -04:00
Refactoring of signal state sharing used by the FSM frame.
This commit is contained in:
parent
8d1b34cc5b
commit
fc41cae32a
@ -7,7 +7,6 @@ package de.neemann.digital.analyse;
|
||||
|
||||
import de.neemann.digital.core.Model;
|
||||
import de.neemann.digital.core.Signal;
|
||||
import de.neemann.digital.gui.Main;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@ -25,7 +24,7 @@ public class ModelAnalyserInfo {
|
||||
private ArrayList<Signal> inputs;
|
||||
private ArrayList<Signal> outputs;
|
||||
private ArrayList<String> pinsWithoutNumber;
|
||||
private Main.CreatedNotification mainCreatedNotification;
|
||||
private String stateSignalName;
|
||||
|
||||
/**
|
||||
* creates a new instance
|
||||
@ -132,22 +131,6 @@ public class ModelAnalyserInfo {
|
||||
return outputBusMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the fsm state info;
|
||||
*
|
||||
* @param info the info instance
|
||||
*/
|
||||
public void setMainCreatedNotification(Main.CreatedNotification info) {
|
||||
mainCreatedNotification = info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the fsm state info
|
||||
*/
|
||||
public Main.CreatedNotification getMainCreatedNotification() {
|
||||
return mainCreatedNotification;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the init value of a sequential state machine
|
||||
*
|
||||
@ -171,4 +154,19 @@ public class ModelAnalyserInfo {
|
||||
initValueMap.put(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the state variable name, maybe null
|
||||
*/
|
||||
public String getStateSignalName() {
|
||||
return stateSignalName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the state variable name
|
||||
*
|
||||
* @param stateSignalName the state variable name
|
||||
*/
|
||||
public void setStateSignalName(String stateSignalName) {
|
||||
this.stateSignalName = stateSignalName;
|
||||
}
|
||||
}
|
||||
|
@ -6,9 +6,6 @@
|
||||
package de.neemann.digital.builder.circuit;
|
||||
|
||||
import de.neemann.digital.analyse.DetermineJKStateMachine;
|
||||
import de.neemann.digital.core.memory.DataField;
|
||||
import de.neemann.digital.core.memory.LookUpTable;
|
||||
import de.neemann.digital.fsm.FSMStateInfo;
|
||||
import de.neemann.digital.analyse.ModelAnalyserInfo;
|
||||
import de.neemann.digital.analyse.expression.*;
|
||||
import de.neemann.digital.analyse.expression.Not;
|
||||
@ -24,6 +21,8 @@ import de.neemann.digital.core.io.Const;
|
||||
import de.neemann.digital.core.io.In;
|
||||
import de.neemann.digital.core.io.Out;
|
||||
import de.neemann.digital.core.io.Probe;
|
||||
import de.neemann.digital.core.memory.DataField;
|
||||
import de.neemann.digital.core.memory.LookUpTable;
|
||||
import de.neemann.digital.core.wiring.Clock;
|
||||
import de.neemann.digital.core.wiring.Splitter;
|
||||
import de.neemann.digital.draw.elements.Circuit;
|
||||
@ -32,7 +31,6 @@ import de.neemann.digital.draw.elements.VisualElement;
|
||||
import de.neemann.digital.draw.elements.Wire;
|
||||
import de.neemann.digital.draw.graphics.Vector;
|
||||
import de.neemann.digital.draw.shapes.ShapeFactory;
|
||||
import de.neemann.digital.gui.Main;
|
||||
import de.neemann.digital.lang.Lang;
|
||||
|
||||
import java.util.*;
|
||||
@ -445,11 +443,9 @@ public class CircuitBuilder implements BuilderInterface<CircuitBuilder> {
|
||||
outSplitterY = addNetConnections(circuit, maxWidth + SIZE * 17, outSplitterY);
|
||||
|
||||
if (mai != null) {
|
||||
Main.CreatedNotification mon = mai.getMainCreatedNotification();
|
||||
if (mon instanceof FSMStateInfo) {
|
||||
FSMStateInfo fsmInfo = (FSMStateInfo) mon;
|
||||
outSplitterY = createStateVar(maxWidth + SIZE * 15, outSplitterY, circuit, fsmInfo.getSignalName());
|
||||
}
|
||||
final String stateVariableName = mai.getStateSignalName();
|
||||
if (stateVariableName != null)
|
||||
outSplitterY = createStateVar(maxWidth + SIZE * 15, outSplitterY, circuit, stateVariableName);
|
||||
}
|
||||
|
||||
circuit.setModified(false);
|
||||
|
74
src/main/java/de/neemann/digital/core/GlobalValues.java
Normal file
74
src/main/java/de/neemann/digital/core/GlobalValues.java
Normal file
@ -0,0 +1,74 @@
|
||||
package de.neemann.digital.core;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Instance used by the model to share signal values.
|
||||
* Used by the FSM dialog to indicate the current state.
|
||||
* Up to now only probe values are shared.
|
||||
*/
|
||||
public final class GlobalValues {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(GlobalValues.class);
|
||||
private static GlobalValues ourInstance = new GlobalValues();
|
||||
|
||||
/**
|
||||
* @return returns the global instance
|
||||
*/
|
||||
public static GlobalValues getInstance() {
|
||||
return ourInstance;
|
||||
}
|
||||
|
||||
private ArrayList<GlobalValueListener> listeners = new ArrayList<>();
|
||||
|
||||
private GlobalValues() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a value
|
||||
*
|
||||
* @param name the name of the value
|
||||
* @param value the value itself
|
||||
* @param model the model the value belongs to
|
||||
*/
|
||||
public void register(String name, ObservableValue value, Model model) {
|
||||
for (GlobalValueListener l : listeners)
|
||||
l.valueCreated(name, value, model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener for global values
|
||||
*
|
||||
* @param listener the listener to add
|
||||
*/
|
||||
public void addListener(GlobalValueListener listener) {
|
||||
listeners.add(listener);
|
||||
LOGGER.debug("global value listener added " + listeners.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a listener for global values
|
||||
*
|
||||
* @param listener the listener to remove
|
||||
*/
|
||||
public void removeListener(GlobalValueListener listener) {
|
||||
listeners.remove(listener);
|
||||
LOGGER.debug("global value listener removed " + listeners.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* A listener for global values
|
||||
*/
|
||||
public interface GlobalValueListener {
|
||||
/**
|
||||
* Called if a value is created
|
||||
*
|
||||
* @param name the name of the value
|
||||
* @param value the value itself
|
||||
* @param model the model the value belongs to
|
||||
*/
|
||||
void valueCreated(String name, ObservableValue value, Model model);
|
||||
}
|
||||
}
|
@ -54,6 +54,7 @@ public class Probe implements Element {
|
||||
@Override
|
||||
public void registerNodes(Model model) {
|
||||
model.addSignal(new Signal(label, value).setFormat(format));
|
||||
GlobalValues.getInstance().register(label, value, model);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,10 +13,10 @@ import de.neemann.digital.analyse.expression.ExpressionException;
|
||||
import de.neemann.digital.draw.graphics.Graphic;
|
||||
import de.neemann.digital.draw.graphics.Vector;
|
||||
import de.neemann.digital.draw.graphics.VectorFloat;
|
||||
import de.neemann.digital.fsm.gui.FSMFrame;
|
||||
import de.neemann.digital.lang.Lang;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ -126,7 +126,7 @@ public class FSM {
|
||||
* @throws IOException IOException
|
||||
*/
|
||||
public void save(OutputStream out) throws IOException {
|
||||
try (Writer w = new OutputStreamWriter(out, "utf-8")) {
|
||||
try (Writer w = new OutputStreamWriter(out, StandardCharsets.UTF_8)) {
|
||||
XStream xStream = getxStream();
|
||||
w.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
|
||||
xStream.marshal(this, new PrettyPrintWriter(w));
|
||||
@ -341,13 +341,13 @@ public class FSM {
|
||||
/**
|
||||
* Creates the truth table which is defined by this finite state machine
|
||||
*
|
||||
* @param creator the creator of the truth table
|
||||
* @param stateSignalName the name of the signal used to represent the state
|
||||
* @return the truth table
|
||||
* @throws ExpressionException ExpressionException
|
||||
* @throws FiniteStateMachineException FiniteStateMachineException
|
||||
*/
|
||||
public TruthTable createTruthTable(FSMFrame creator) throws ExpressionException, FiniteStateMachineException {
|
||||
return new TransitionTableCreator(this, creator).create();
|
||||
public TruthTable createTruthTable(String stateSignalName) throws ExpressionException, FiniteStateMachineException {
|
||||
return new TransitionTableCreator(this, stateSignalName).create();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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.fsm;
|
||||
|
||||
import de.neemann.digital.fsm.gui.FSMFrame;
|
||||
import de.neemann.digital.gui.Main;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* The model state info
|
||||
*/
|
||||
public class FSMStateInfo implements Main.CreatedNotification {
|
||||
private final String signalName;
|
||||
private final FSMFrame fsmFrame;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param file the file of the fsm, maybe null
|
||||
* @param fsmFrame the creator, maybe null
|
||||
*/
|
||||
public FSMStateInfo(File file, FSMFrame fsmFrame) {
|
||||
this.fsmFrame = fsmFrame;
|
||||
if (file != null)
|
||||
this.signalName = file.getName();
|
||||
else
|
||||
this.signalName = "state";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the signal name used for state transfer
|
||||
*/
|
||||
public String getSignalName() {
|
||||
return signalName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void isCreated(Main main) {
|
||||
if (fsmFrame != null)
|
||||
fsmFrame.registerTo(main);
|
||||
}
|
||||
}
|
@ -12,7 +12,6 @@ import de.neemann.digital.analyse.expression.ExpressionException;
|
||||
import de.neemann.digital.analyse.expression.Variable;
|
||||
import de.neemann.digital.analyse.expression.VariableVisitor;
|
||||
import de.neemann.digital.core.Signal;
|
||||
import de.neemann.digital.fsm.gui.FSMFrame;
|
||||
import de.neemann.digital.lang.Lang;
|
||||
|
||||
import java.util.*;
|
||||
@ -47,15 +46,15 @@ public class TransitionTableCreator {
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param fsm the fsm
|
||||
* @param creator the creating frame
|
||||
* @param stateSignalName the name if the signal indicating the actual state
|
||||
*/
|
||||
TransitionTableCreator(FSM fsm, FSMFrame creator) throws FiniteStateMachineException {
|
||||
TransitionTableCreator(FSM fsm, String stateSignalName) throws FiniteStateMachineException {
|
||||
this.states = fsm.getStates();
|
||||
this.transitions = fsm.getTransitions();
|
||||
this.initState = fsm.getInitState();
|
||||
outputValues = new HashMap<>();
|
||||
modelAnalyserInfo = new ModelAnalyserInfo(null);
|
||||
modelAnalyserInfo.setMainCreatedNotification(new FSMStateInfo(fsm.getFile(), creator));
|
||||
modelAnalyserInfo.setStateSignalName(stateSignalName);
|
||||
inputSignals = new ArrayList<>();
|
||||
outputSignals = new ArrayList<>();
|
||||
}
|
||||
|
@ -5,10 +5,7 @@
|
||||
*/
|
||||
package de.neemann.digital.fsm.gui;
|
||||
|
||||
import de.neemann.digital.core.Model;
|
||||
import de.neemann.digital.core.ModelEvent;
|
||||
import de.neemann.digital.core.ObservableValue;
|
||||
import de.neemann.digital.core.Signal;
|
||||
import de.neemann.digital.core.*;
|
||||
import de.neemann.digital.core.element.ElementAttributes;
|
||||
import de.neemann.digital.draw.graphics.*;
|
||||
import de.neemann.digital.draw.library.ElementLibrary;
|
||||
@ -37,7 +34,7 @@ import java.util.prefs.Preferences;
|
||||
/**
|
||||
* The dialog to show the FSM
|
||||
*/
|
||||
public class FSMFrame extends JFrame implements ClosingWindowListener.ConfirmSave, FSM.ModifiedListener, ModelCreationListener, FileHistory.OpenInterface {
|
||||
public class FSMFrame extends JFrame implements ClosingWindowListener.ConfirmSave, FSM.ModifiedListener, FileHistory.OpenInterface {
|
||||
private static final Preferences PREFS = Preferences.userRoot().node("dig").node("fsm");
|
||||
private static final String PREF_FOLDER = "folder";
|
||||
private static final Icon ICON_NEW = IconCreator.create("document-new.png");
|
||||
@ -59,6 +56,7 @@ public class FSMFrame extends JFrame implements ClosingWindowListener.ConfirmSav
|
||||
private File baseFilename;
|
||||
private boolean lastModified;
|
||||
private String probeLabelName;
|
||||
private GlobalValues.GlobalValueListener stateListener = new StateListener();
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
@ -89,11 +87,13 @@ public class FSMFrame extends JFrame implements ClosingWindowListener.ConfirmSav
|
||||
}
|
||||
});
|
||||
|
||||
GlobalValues.getInstance().addListener(stateListener);
|
||||
addWindowListener(new ClosingWindowListener(this, this));
|
||||
addWindowListener(new WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosed(WindowEvent windowEvent) {
|
||||
timer.stop();
|
||||
GlobalValues.getInstance().removeListener(stateListener);
|
||||
}
|
||||
});
|
||||
|
||||
@ -355,7 +355,7 @@ public class FSMFrame extends JFrame implements ClosingWindowListener.ConfirmSav
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent actionEvent) {
|
||||
try {
|
||||
new TableDialog(FSMFrame.this, fsm.createTruthTable(FSMFrame.this), library, filename).setVisible(true);
|
||||
new TableDialog(FSMFrame.this, fsm.createTruthTable(getStateSignalName()), library, filename).setVisible(true);
|
||||
} catch (Exception e) {
|
||||
new ErrorMessage(Lang.get("msg_fsmCantCreateTable")).addCause(e).show(FSMFrame.this);
|
||||
}
|
||||
@ -432,20 +432,11 @@ public class FSMFrame extends JFrame implements ClosingWindowListener.ConfirmSav
|
||||
toolBar.add(viewHelp);
|
||||
}
|
||||
|
||||
|
||||
private class StateListener implements GlobalValues.GlobalValueListener {
|
||||
@Override
|
||||
public void created(Model model) {
|
||||
String name = "state";
|
||||
if (filename != null)
|
||||
name = filename.getName();
|
||||
|
||||
Signal found = null;
|
||||
for (Signal s : model.getSignals()) {
|
||||
if (s.getName().equals(name))
|
||||
found = s;
|
||||
}
|
||||
|
||||
if (found != null) {
|
||||
ObservableValue value = found.getValue();
|
||||
public void valueCreated(String name, ObservableValue value, Model model) {
|
||||
if (name.equals(getStateSignalName())) {
|
||||
value.addObserverToValue(() -> setActiveState(value.getValue()));
|
||||
setActiveState(value.getValue());
|
||||
model.addObserver(event -> {
|
||||
@ -455,29 +446,20 @@ public class FSMFrame extends JFrame implements ClosingWindowListener.ConfirmSav
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getStateSignalName() {
|
||||
if (filename != null)
|
||||
return filename.getName();
|
||||
else
|
||||
return "state";
|
||||
}
|
||||
|
||||
private void setActiveState(long value) {
|
||||
if (fsm.setActiveState((int) value))
|
||||
SwingUtilities.invokeLater(fsmComponent::repaint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a circuit window to this fsm
|
||||
*
|
||||
* @param main the main window
|
||||
* @return this for chained calls
|
||||
*/
|
||||
public FSMFrame registerTo(Main main) {
|
||||
main.addModelCreationListener(this);
|
||||
addWindowListener(new WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosed(WindowEvent windowEvent) {
|
||||
main.removeModelCreationListener(FSMFrame.this);
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the current fsm
|
||||
*/
|
||||
|
@ -145,7 +145,6 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
|
||||
private State runModelMicroState;
|
||||
private JComponent componentOnPane;
|
||||
private LibraryTreeModel treeModel;
|
||||
private ArrayList<ModelCreationListener> modelCreationListener = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
@ -288,8 +287,6 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
|
||||
} else
|
||||
setLocationRelativeTo(null);
|
||||
|
||||
if (builder.createdNotification != null)
|
||||
builder.createdNotification.isCreated(this);
|
||||
}
|
||||
|
||||
private void enableClockShortcut() {
|
||||
@ -1150,7 +1147,6 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
|
||||
new FSMFrame(Main.this, library)
|
||||
.setBaseFileName(filename)
|
||||
.setProbeLabelName(foundName)
|
||||
.registerTo(Main.this)
|
||||
.setVisible(true);
|
||||
}
|
||||
}
|
||||
@ -1158,24 +1154,6 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
|
||||
.createJMenuItem());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a model creation listener
|
||||
*
|
||||
* @param listener the listener to add
|
||||
*/
|
||||
public void addModelCreationListener(ModelCreationListener listener) {
|
||||
modelCreationListener.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a model creation listener
|
||||
*
|
||||
* @param listener the listener to remove
|
||||
*/
|
||||
public void removeModelCreationListener(ModelCreationListener listener) {
|
||||
modelCreationListener.remove(listener);
|
||||
}
|
||||
|
||||
private void orderMeasurements() {
|
||||
try {
|
||||
Model m = new ModelCreator(circuitComponent.getCircuit(), library).createModel(false);
|
||||
@ -1325,9 +1303,6 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
|
||||
|
||||
model.init();
|
||||
|
||||
for (ModelCreationListener mcl : modelCreationListener)
|
||||
mcl.created(model);
|
||||
|
||||
if (updateEvent == ModelEvent.MICROSTEP)
|
||||
doStep.setEnabled(model.needsUpdate());
|
||||
|
||||
@ -1824,7 +1799,6 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
|
||||
private boolean allowAllFileActions = true;
|
||||
private File baseFileName;
|
||||
private boolean keepPrefMainFile;
|
||||
private CreatedNotification createdNotification;
|
||||
|
||||
/**
|
||||
* @param fileToOpen the file to open
|
||||
@ -1892,17 +1866,6 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a open notification
|
||||
*
|
||||
* @param createdNotification createdNotification
|
||||
* @return this for chained calls
|
||||
*/
|
||||
public MainBuilder setCreatedNotification(CreatedNotification createdNotification) {
|
||||
this.createdNotification = createdNotification;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Main instance
|
||||
*
|
||||
@ -1921,18 +1884,6 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification if a main frame is created
|
||||
*/
|
||||
public interface CreatedNotification {
|
||||
/**
|
||||
* Called if main frae is created
|
||||
*
|
||||
* @param main main
|
||||
*/
|
||||
void isCreated(Main main);
|
||||
}
|
||||
|
||||
private class ModelKeyListener extends KeyAdapter {
|
||||
|
||||
@Override
|
||||
|
@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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.gui;
|
||||
|
||||
import de.neemann.digital.core.Model;
|
||||
|
||||
/**
|
||||
* Listener notified every time a model is created
|
||||
*/
|
||||
public interface ModelCreationListener {
|
||||
/**
|
||||
* Called if a model is created
|
||||
*
|
||||
* @param model the model created
|
||||
*/
|
||||
void created(Model model);
|
||||
}
|
@ -518,15 +518,11 @@ public class TableDialog extends JDialog {
|
||||
.create(lastGeneratedExpressions);
|
||||
Circuit circuit = circuitBuilder.createCircuit();
|
||||
|
||||
Main.CreatedNotification mon = null;
|
||||
if (modelAnalyzerInfo != null)
|
||||
mon = modelAnalyzerInfo.getMainCreatedNotification();
|
||||
new Main.MainBuilder()
|
||||
.setParent(TableDialog.this)
|
||||
.setLibrary(library)
|
||||
.setCircuit(circuit)
|
||||
.setBaseFileName(filename)
|
||||
.setCreatedNotification(mon)
|
||||
.openLater();
|
||||
} catch (ExpressionException | FormatterException | RuntimeException e) {
|
||||
new ErrorMessage(Lang.get("msg_errorDuringCalculation")).addCause(e).show(this);
|
||||
|
Loading…
x
Reference in New Issue
Block a user