diff --git a/.gitattributes b/.gitattributes
index e9448d27e..42748d8e7 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,5 +1,6 @@
*.java text eol=lf
*.xml text eol=lf
*.dig text eol=lf
+*.fsm text eol=lf
*.tem text eol=lf
*.v text eol=lf
diff --git a/distribution/Assembly.xml b/distribution/Assembly.xml
index 0d0928457..dd056a142 100644
--- a/distribution/Assembly.xml
+++ b/distribution/Assembly.xml
@@ -114,6 +114,13 @@
*.dig
+
+ ${basedir}/src/main/fsm
+ /examples/fsm/
+
+ *.fsm
+
+
${basedir}/target/docu
/docu/
diff --git a/src/main/fsm/SevenSegCounter.fsm b/src/main/fsm/SevenSegCounter.fsm
new file mode 100644
index 000000000..93021ad1a
--- /dev/null
+++ b/src/main/fsm/SevenSegCounter.fsm
@@ -0,0 +1,210 @@
+
+
+
+
+
+ 0
+ 0
+ 90
+ S=0111111
+
+
+
+ 1
+ 1
+ 90
+ S=0000110
+
+
+
+ 2
+ 2
+ 90
+ S=1011011
+
+
+
+ 3
+ 3
+ 90
+ S=1001111
+
+
+
+ 4
+ 4
+ 90
+ S=1100110
+
+
+
+ 5
+ 5
+ 90
+ S=1101101
+
+
+
+ 6
+ 6
+ 90
+ S=1111101
+
+
+
+ 7
+ 7
+ 90
+ S=0000111
+
+
+
+ 8
+ 8
+ 90
+ S=1111111
+
+
+
+ 9
+ 9
+ 90
+ S=1101111
+
+
+
+
+
+
+
+ en=1 & clr=0
+
+
+
+
+
+
+ en=1 & clr=0
+
+
+
+
+
+
+ en=1 & clr=0
+
+
+
+
+
+
+ en=1 & clr=0
+
+
+
+
+
+
+ en=1 & clr=0
+
+
+
+
+
+
+ en=1 & clr=0
+
+
+
+
+
+
+ en=1 & clr=0
+
+
+
+
+
+
+ en=1 & clr=0
+
+
+
+
+
+
+ en=1 & clr=0
+
+
+
+
+
+
+ en=1 & clr=0
+ ov=1
+
+
+
+
+
+ clr=1
+
+
+
+
+
+
+ clr=1
+
+
+
+
+
+
+ clr=1
+
+
+
+
+
+
+ clr=1
+
+
+
+
+
+
+ clr=1
+
+
+
+
+
+
+ clr=1
+
+
+
+
+
+
+ clr=1
+
+
+
+
+
+
+ clr=1
+
+
+
+
+
+
+ clr=1
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/de/neemann/digital/fsm/FSM.java b/src/main/java/de/neemann/digital/fsm/FSM.java
index 7ade8c257..21bcc65a9 100644
--- a/src/main/java/de/neemann/digital/fsm/FSM.java
+++ b/src/main/java/de/neemann/digital/fsm/FSM.java
@@ -302,12 +302,13 @@ public class FSM {
*/
public FSM circle() {
double delta = 2 * Math.PI / states.size();
- double rad = 0;
+ double circumference = 0;
for (State s : states)
- if (s.getVisualRadius() > rad)
- rad = s.getVisualRadius();
+ circumference += s.getVisualRadius() * 2;
+
+ circumference += states.size() * State.DEFAULT_RAD * 2;
+ double rad = circumference / Math.PI / 2;
- rad *= 4;
double phi = 0;
for (State s : states) {
s.setPosition(new VectorFloat((float) (Math.sin(phi) * rad), (float) (-Math.cos(phi) * rad)));
diff --git a/src/main/java/de/neemann/digital/fsm/State.java b/src/main/java/de/neemann/digital/fsm/State.java
index 7d614f67e..5713a7009 100644
--- a/src/main/java/de/neemann/digital/fsm/State.java
+++ b/src/main/java/de/neemann/digital/fsm/State.java
@@ -14,9 +14,12 @@ import java.util.TreeMap;
* Represents a state
*/
public class State extends Movable {
- private static final int RASTER = 60;
+ /**
+ * The default state radius
+ */
+ public static final int DEFAULT_RAD = 70;
- private static final int RAD = 70;
+ private static final int RASTER = 60;
private static final float REACH = 2000;
private static final int INIT_RADIUS = 20;
@@ -35,7 +38,7 @@ public class State extends Movable {
public State(String name) {
super();
this.name = name;
- this.radius = RAD;
+ this.radius = DEFAULT_RAD;
}
/**
@@ -151,7 +154,7 @@ public class State extends Movable {
/**
* @return the radius of the state
*/
- float getVisualRadius() {
+ public int getVisualRadius() {
if (isInitialState())
return INIT_RADIUS;
else
@@ -165,6 +168,15 @@ public class State extends Movable {
return radius;
}
+ /**
+ * Sets the radius of the state
+ *
+ * @param radius the radius
+ */
+ public void setRadius(int radius) {
+ this.radius = radius;
+ }
+
/**
* Sets the number of the state
*
diff --git a/src/main/java/de/neemann/digital/fsm/Transition.java b/src/main/java/de/neemann/digital/fsm/Transition.java
index 051fb71ea..1b1e961c9 100644
--- a/src/main/java/de/neemann/digital/fsm/Transition.java
+++ b/src/main/java/de/neemann/digital/fsm/Transition.java
@@ -24,7 +24,7 @@ public class Transition extends Movable {
private final State fromState;
private final State toState;
- private String condition = "";
+ private String condition;
private String values = "";
private transient Expression conditionExpression;
private transient TreeMap valuesMap;
@@ -41,7 +41,7 @@ public class Transition extends Movable {
super();
this.fromState = fromState;
this.toState = toState;
- this.condition = condition;
+ this.condition = condition == null ? "" : condition;
initPos();
}
@@ -168,7 +168,7 @@ public class Transition extends Movable {
this.condition = condition;
wasModified();
conditionExpression = null;
- if (getFsm()!=null)
+ if (getFsm() != null)
getFsm().resetInitInitialization();
}
}
diff --git a/src/main/java/de/neemann/digital/fsm/TransitionTableCreator.java b/src/main/java/de/neemann/digital/fsm/TransitionTableCreator.java
index 6ea608f0a..5bb00ca78 100644
--- a/src/main/java/de/neemann/digital/fsm/TransitionTableCreator.java
+++ b/src/main/java/de/neemann/digital/fsm/TransitionTableCreator.java
@@ -82,7 +82,7 @@ public class TransitionTableCreator {
}
}
- // set all next state variables to "stay is state"
+ // set all next state results to "stay is state"
for (State s : states) {
int c = stateBits * 2;
int row = s.getNumber();
@@ -137,7 +137,7 @@ public class TransitionTableCreator {
int col = stateBits * 2 + inVars.size();
int row = startRow + r;
- checkRow(row, t);
+ checkRow(row, t); // allow only deterministic transitions
// fill in transition
int mask = t.getTargetState().getNumber();
@@ -150,7 +150,7 @@ public class TransitionTableCreator {
// fill in output state, if any
final TreeMap valueMap = t.getValueMap();
if (!valueMap.isEmpty()) {
- col = stateBits * 2 + results.size();
+ col = stateBits * 2 + inVars.size();
for (String name : results) {
Integer val = valueMap.get(name);
if (val != null)
@@ -163,11 +163,9 @@ public class TransitionTableCreator {
}
private void checkRow(int row, Transition t) throws FiniteStateMachineException {
- if (transitionSet != null) {
- if (transitionSet[row])
- throw new FiniteStateMachineException(Lang.get("err_notDeterministic_N", t.toString()));
- transitionSet[row] = true;
- }
+ if (transitionSet[row])
+ throw new FiniteStateMachineException(Lang.get("err_notDeterministic_N", t.toString()));
+ transitionSet[row] = true;
}
private int getStateVarBits() throws FiniteStateMachineException {
diff --git a/src/main/java/de/neemann/digital/fsm/gui/FSMComponent.java b/src/main/java/de/neemann/digital/fsm/gui/FSMComponent.java
index ecdd744a7..e27b453d2 100644
--- a/src/main/java/de/neemann/digital/fsm/gui/FSMComponent.java
+++ b/src/main/java/de/neemann/digital/fsm/gui/FSMComponent.java
@@ -35,6 +35,8 @@ public class FSMComponent extends JComponent {
private static final Key KEY_NUMBER = new Key.KeyInteger("stateNum", 0);
private static final Key KEY_VALUES = new Key<>("stateValues", "");
private static final Key KEY_CONDITION = new Key<>("transCond", "");
+ private static final Key KEY_RADIUS = new Key.KeyInteger("transRad", 70)
+ .setComboBoxValues(50, 70, 90);
private static final String DEL_ACTION = "myDelAction";
private Mouse mouse = Mouse.getMouse();
@@ -198,14 +200,16 @@ public class FSMComponent extends JComponent {
ElementAttributes attr = new ElementAttributes()
.set(KEY_NUMBER, state.getNumber())
.set(KEY_VALUES, state.getValues())
+ .set(KEY_RADIUS, state.getVisualRadius())
.set(Keys.LABEL, state.getName());
SwingUtilities.convertPointToScreen(point, this);
AttributeDialog ad = new AttributeDialog(SwingUtilities.getWindowAncestor(this),
- point, attr, Keys.LABEL, KEY_NUMBER, KEY_VALUES);
+ point, attr, Keys.LABEL, KEY_NUMBER, KEY_VALUES, KEY_RADIUS);
ElementAttributes newAttr = ad.showDialog();
if (newAttr != null) {
state.setNumber(newAttr.get(KEY_NUMBER));
state.setValues(newAttr.get(KEY_VALUES));
+ state.setRadius(newAttr.get(KEY_RADIUS));
state.setName(newAttr.get(Keys.LABEL));
repaint();
}
diff --git a/src/main/java/de/neemann/digital/fsm/gui/FSMFrame.java b/src/main/java/de/neemann/digital/fsm/gui/FSMFrame.java
index f99f20c8d..18f570409 100644
--- a/src/main/java/de/neemann/digital/fsm/gui/FSMFrame.java
+++ b/src/main/java/de/neemann/digital/fsm/gui/FSMFrame.java
@@ -95,19 +95,7 @@ public class FSMFrame extends JFrame implements ClosingWindowListener.ConfirmSav
toolBar.addSeparator();
createViewMenu(bar, toolBar);
toolBar.addSeparator();
-
- JMenu create = new JMenu(Lang.get("menu_fsm_create"));
- bar.add(create);
- create.add(new ToolTipAction(Lang.get("menu_fsm_create_table")) {
- @Override
- public void actionPerformed(ActionEvent actionEvent) {
- try {
- new TableDialog(FSMFrame.this, fsm.createTruthTable(), library, null).setVisible(true);
- } catch (Exception e) {
- new ErrorMessage(Lang.get("msg_fsmCantCreateTable")).addCause(e).show(FSMFrame.this);
- }
- }
- }.createJMenuItem());
+ createCreateMenu(bar, library);
moveControl = new JComboBox<>(new String[]{
@@ -280,6 +268,7 @@ public class FSMFrame extends JFrame implements ClosingWindowListener.ConfirmSav
private void saveFile(File file) {
try {
+ moveControl.setSelectedIndex(0);
fsm.save(file);
setFilename(file);
save.setEnabled(false);
@@ -329,6 +318,36 @@ public class FSMFrame extends JFrame implements ClosingWindowListener.ConfirmSav
view.add(zoomIn.createJMenuItem());
}
+ private void createCreateMenu(JMenuBar bar, ElementLibrary library) {
+ JMenu create = new JMenu(Lang.get("menu_fsm_create"));
+ bar.add(create);
+ create.add(new ToolTipAction(Lang.get("menu_fsm_create_table")) {
+ @Override
+ public void actionPerformed(ActionEvent actionEvent) {
+ try {
+ new TableDialog(FSMFrame.this, fsm.createTruthTable(), library, null).setVisible(true);
+ } catch (Exception e) {
+ new ErrorMessage(Lang.get("msg_fsmCantCreateTable")).addCause(e).show(FSMFrame.this);
+ }
+ }
+ }.createJMenuItem());
+
+ JMenu counter = new JMenu(Lang.get("menu_fsm_create_counter"));
+ create.add(counter);
+ int[] counterValues = new int[]{4, 5, 6, 7, 8, 10, 16};
+ for (int n : counterValues) {
+ counter.add(new ToolTipAction(Lang.get("menu_fsm_create_counter_N", n)) {
+ @Override
+ public void actionPerformed(ActionEvent actionEvent) {
+ if (ClosingWindowListener.checkForSave(FSMFrame.this, FSMFrame.this)) {
+ setFSM(FSMDemos.counter(n).circle().setModified(false));
+ setFilename(null);
+ }
+ }
+ });
+ }
+ }
+
private class ExportAction extends ToolTipAction {
private final String name;
private final String suffix;
diff --git a/src/main/resources/lang/lang_de.xml b/src/main/resources/lang/lang_de.xml
index d7c848416..246a1b120 100644
--- a/src/main/resources/lang/lang_de.xml
+++ b/src/main/resources/lang/lang_de.xml
@@ -1755,11 +1755,26 @@ Daher steht auch das Signal 'D_out' zur Verfügung, um in diesem Fall den Wert z