From 42d159f853aa5f8f48145693d38765e10bbf5725 Mon Sep 17 00:00:00 2001 From: hneemann Date: Sun, 25 Nov 2018 12:22:30 +0100 Subject: [PATCH] added a counter creator --- .gitattributes | 1 + distribution/Assembly.xml | 7 + src/main/fsm/SevenSegCounter.fsm | 210 ++++++++++++++++++ src/main/java/de/neemann/digital/fsm/FSM.java | 9 +- .../java/de/neemann/digital/fsm/State.java | 20 +- .../de/neemann/digital/fsm/Transition.java | 6 +- .../digital/fsm/TransitionTableCreator.java | 14 +- .../neemann/digital/fsm/gui/FSMComponent.java | 6 +- .../de/neemann/digital/fsm/gui/FSMFrame.java | 45 ++-- src/main/resources/lang/lang_de.xml | 31 +-- src/main/resources/lang/lang_en.xml | 19 +- .../neemann/digital/fsm/IntegrationTest.java | 31 +++ 12 files changed, 344 insertions(+), 55 deletions(-) create mode 100644 src/main/fsm/SevenSegCounter.fsm create mode 100644 src/test/java/de/neemann/digital/fsm/IntegrationTest.java 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 ]]> + Endlicher Automat + keine Bewegung + Übergänge + Übergänge+Zustände Endlicher Automat Dialog für die Erstellung endlicher Automaten. - Endlicher Automat Erzeugen Zustandsübergangstabelle + Zähler erzeugen + {0} Zustände + Zustandsnummer + Die Nummer welche diesen Zustand representiert. + Ausgänge + Legt Ausgangswerte fest. Wird nichts angegeben, werden alle Werte auf Null gesetzt. + Mit einfachen Zuweisungen wie "A=1, B=0" können Ausgänge gesetzt werden. + + Bedingung + Ein boolscher Ausdruck. + Radius + Radius des Kreises in der Darstellung. Der Automat ist nicht deterministisch: {0} Zustandsnummer {0} ist nicht eindeutig. Es gibt keinen Initialzustand. @@ -1768,18 +1783,6 @@ Daher steht auch das Signal 'D_out' zur Verfügung, um in diesem Fall den Wert z Fehler in Bedingung ''{0}''! Fehler beim Laden der Datei! Fehler beim Speichern der Datei! - Zustandsnummer - Die Nummer welche diesen Zustand representiert. - Ausgänge - Legt Ausgangswerte fest. Wird nichts angegeben, werden alle Werte auf Null gesetzt. - Mit einfachen Zuweisungen wie "A=1, B=0" können Ausgänge gesetzt werden. - - Zustandsübergangstabelle kann nicht erzeugt werden. - Bedingung - Ein boolscher Ausdruck. Neuer Zustand - keine Bewegung - Übergänge - Übergänge+Zustände - + Zustandsübergangstabelle kann nicht erzeugt werden. diff --git a/src/main/resources/lang/lang_en.xml b/src/main/resources/lang/lang_en.xml index 853f39b80..19dd16df0 100644 --- a/src/main/resources/lang/lang_en.xml +++ b/src/main/resources/lang/lang_en.xml @@ -1734,32 +1734,35 @@ Therefore, the signal 'D_out' is also available to check the value in this case. ]]> - + Finite State Machine + no movement + Transitions + Transitions+States Finite State Machine Opens a Dialog to Edit a Finite State Machine. - Finite State Machine Create State Transition Table + Create Counter + {0} States The FSM is not deterministic: {0} State Number {0} used twice. There is no initial state (state number zero). State ''{0}'' not found! Wrong assignment to output (''{0}'')! Error in condition ''{0}''! - Error loading a file! - Error storing a file! State Number The number which represents this state. Outputs Defines the output values. If nothing is specified, all values are set to zero. With simple assignments like "A=1, B=0" outputs can be set. - Can not create state transition table. Condition A boolean expression. + Radius + Radius of the circle in the diagram. + Can not create state transition table. New State - no movement - Transitions - Transitions+States + Error loading a file! + Error storing a file! \ No newline at end of file diff --git a/src/test/java/de/neemann/digital/fsm/IntegrationTest.java b/src/test/java/de/neemann/digital/fsm/IntegrationTest.java new file mode 100644 index 000000000..cb6c98fdb --- /dev/null +++ b/src/test/java/de/neemann/digital/fsm/IntegrationTest.java @@ -0,0 +1,31 @@ +/* + * 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.analyse.expression.ExpressionException; +import de.neemann.digital.integration.FileScanner; +import de.neemann.digital.integration.Resources; +import junit.framework.TestCase; + +import java.io.File; +import java.io.IOException; + +public class IntegrationTest extends TestCase { + + public void testExamples() throws Exception { + File examples = new File(Resources.getRoot().getParentFile().getParentFile(), "/main/fsm"); + assertEquals(7, new FileScanner(this::check).setSuffix("fsm").scan(examples)); + + } + + /* + * For now, only create the truth table. + * Does not test if the truth table is correct! + */ + private void check(File file) throws IOException, ExpressionException, FiniteStateMachineException { + FSM.loadFSM(file).createTruthTable(); + } +}