Added a clock input to the keyboard component. See #138

This commit is contained in:
hneemann 2018-04-21 11:08:14 +02:00
parent 5627357b12
commit 52c4efb6e2
7 changed files with 185 additions and 67 deletions

View File

@ -3,8 +3,9 @@ Release Notes
HEAD, planned as v0.19 HEAD, planned as v0.19
- Added support for asynchronous sequential circuits such as the Muller-pipeline. - Added support for asynchronous sequential circuits such as the Muller-pipeline.
Take a look at the new asynchronous examples for illustration. Take a look at the new asynchronous examples for illustration.
- Braking changes: - Breaking changes:
- Added an enable input to the terminal component. - Added an enable input to the terminal component.
- Added a clock input to the keyboard component.
- Bug fixes - Bug fixes
- Fixed a bug in the VHDL export concerning an invalid optimization of a - Fixed a bug in the VHDL export concerning an invalid optimization of a
std_logic_vector access. std_logic_vector access.

View File

@ -35,6 +35,8 @@ import de.neemann.digital.gui.components.modification.Modifications;
import de.neemann.digital.gui.components.modification.ModifyAttribute; import de.neemann.digital.gui.components.modification.ModifyAttribute;
import de.neemann.digital.gui.components.modification.ModifyMeasurementOrdering; import de.neemann.digital.gui.components.modification.ModifyMeasurementOrdering;
import de.neemann.digital.gui.components.table.TableDialog; import de.neemann.digital.gui.components.table.TableDialog;
import de.neemann.digital.gui.components.terminal.Keyboard;
import de.neemann.digital.gui.components.terminal.KeyboardDialog;
import de.neemann.digital.gui.components.testing.ValueTableDialog; import de.neemann.digital.gui.components.testing.ValueTableDialog;
import de.neemann.digital.gui.components.tree.LibraryTreeModel; import de.neemann.digital.gui.components.tree.LibraryTreeModel;
import de.neemann.digital.gui.components.tree.SelectTree; import de.neemann.digital.gui.components.tree.SelectTree;
@ -1221,6 +1223,8 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
// all repainting is initiated by user actions! // all repainting is initiated by user actions!
modelCreator.connectToGui(null); modelCreator.connectToGui(null);
handleKeyboardComponent(updateEvent, modelSync);
doStep.setEnabled(false); doStep.setEnabled(false);
runToBreakAction.setEnabled(!realTimeClockRunning && model.isFastRunModel()); runToBreakAction.setEnabled(!realTimeClockRunning && model.isFastRunModel());
@ -1250,6 +1254,37 @@ public final class Main extends JFrame implements ClosingWindowListener.ConfirmS
return false; return false;
} }
private void handleKeyboardComponent(ModelEvent updateEvent, Sync modelSync) {
KeyboardDialog.KeyPressedHandler handler = null;
for (Keyboard k : model.findNode(Keyboard.class)) {
if (handler == null)
if (updateEvent == ModelEvent.MICROSTEP)
handler = keyboard -> {
keyboard.hasChanged();
modelCreator.addNodeElementsTo(model.nodesToUpdate(), circuitComponent.getHighLighted());
model.fireManualChangeEvent();
doStep.setEnabled(model.needsUpdate());
circuitComponent.repaintNeeded();
};
else
handler = keyboard -> {
try {
modelSync.accessNEx(() -> {
keyboard.hasChanged();
model.fireManualChangeEvent();
model.doStep();
});
circuitComponent.repaintNeeded();
} catch (NodeException | RuntimeException e) {
showErrorAndStopModel(Lang.get("msg_errorCalculatingStep"), e);
}
};
windowPosManager.register("keyboard_" + k.getLabel(), new KeyboardDialog(this, k, handler));
}
}
private void showMeasurementGraph(ModelEvent updateEvent) { private void showMeasurementGraph(ModelEvent updateEvent) {
List<String> ordering = circuitComponent.getCircuit().getMeasurementOrdering(); List<String> ordering = circuitComponent.getCircuit().getMeasurementOrdering();
windowPosManager.register("dataSet", GraphDialog.createLiveDialog(this, model, updateEvent == ModelEvent.MICROSTEP, ordering, modelSync)).setVisible(true); windowPosManager.register("dataSet", GraphDialog.createLiveDialog(this, model, updateEvent == ModelEvent.MICROSTEP, ordering, modelSync)).setVisible(true);

View File

@ -14,8 +14,6 @@ import de.neemann.digital.core.element.ElementAttributes;
import de.neemann.digital.core.element.ElementTypeDescription; import de.neemann.digital.core.element.ElementTypeDescription;
import de.neemann.digital.core.element.Keys; import de.neemann.digital.core.element.Keys;
import javax.swing.*;
import static de.neemann.digital.core.element.PinInfo.input; import static de.neemann.digital.core.element.PinInfo.input;
/** /**
@ -27,17 +25,20 @@ public class Keyboard extends Node implements Element {
*/ */
public static final ElementTypeDescription DESCRIPTION public static final ElementTypeDescription DESCRIPTION
= new ElementTypeDescription(Keyboard.class, = new ElementTypeDescription(Keyboard.class,
input("sel")) input("C").setClock(),
input("en"))
.addAttribute(Keys.ROTATE) .addAttribute(Keys.ROTATE)
.addAttribute(Keys.LABEL); .addAttribute(Keys.LABEL)
.addAttribute(Keys.INVERTER_CONFIG);
private final String label; private final String label;
private KeyboardDialog keyboardDialog; private final ObservableValue data;
private ObservableValue data; private final ObservableValue isKeyOut;
private ObservableValue select; private KeyboardInterface keyboardInterface;
private boolean sel; private ObservableValue clock;
private boolean lastSel = false; private ObservableValue enable;
private int keyData; private boolean enableVal;
private boolean lastClock = false;
/** /**
* Creates a new terminal instance * Creates a new terminal instance
@ -48,49 +49,83 @@ public class Keyboard extends Node implements Element {
data = new ObservableValue("D", 16) data = new ObservableValue("D", 16)
.setToHighZ() .setToHighZ()
.setPinDescription(DESCRIPTION); .setPinDescription(DESCRIPTION);
isKeyOut = new ObservableValue("av", 1)
.setPinDescription(DESCRIPTION);
label = attributes.getCleanLabel(); label = attributes.getCleanLabel();
} }
@Override @Override
public void setInputs(ObservableValues inputs) throws NodeException { public void setInputs(ObservableValues inputs) throws NodeException {
select = inputs.get(0).addObserverToValue(this).checkBits(1, this); clock = inputs.get(0).addObserverToValue(this).checkBits(1, this, 0);
enable = inputs.get(1).addObserverToValue(this).checkBits(1, this, 1);
} }
@Override @Override
public ObservableValues getOutputs() { public ObservableValues getOutputs() {
return data.asList(); return new ObservableValues(data, isKeyOut);
} }
@Override @Override
public void readInputs() throws NodeException { public void readInputs() throws NodeException {
sel = select.getBool(); enableVal = enable.getBool();
if (!lastSel && sel) { boolean nowClock = clock.getBool();
KeyboardDialog kbd = getKeyboard();
if (kbd != null) if (keyboardInterface != null && nowClock && !lastClock && enableVal)
keyData = kbd.getChar(); keyboardInterface.removeChar();
else
keyData = 0; lastClock = nowClock;
}
lastSel = sel;
} }
@Override @Override
public void writeOutputs() throws NodeException { public void writeOutputs() throws NodeException {
if (sel) if (keyboardInterface != null) {
data.setValue(keyData); if (enableVal)
else data.setValue(keyboardInterface.getChar());
data.setToHighZ(); else
data.setToHighZ();
isKeyOut.setBool(keyboardInterface.isChar());
} else {
if (enableVal)
data.setValue(0);
else
data.setToHighZ();
isKeyOut.setBool(false);
}
} }
private KeyboardDialog getKeyboard() { /**
if (keyboardDialog == null || !keyboardDialog.isVisible()) { * Sets the keyboard interface
SwingUtilities.invokeLater(() -> { *
if (keyboardDialog == null || !keyboardDialog.isVisible()) { * @param keyboardInterface the keyboard interface
keyboardDialog = new KeyboardDialog(getModel().getWindowPosManager().getMainFrame()); */
getModel().getWindowPosManager().register("keyboard_" + label, keyboardDialog); public void setKeyboardDialog(KeyboardInterface keyboardInterface) {
} this.keyboardInterface = keyboardInterface;
}); }
}
return keyboardDialog; /**
* @return the keyboard label
*/
public String getLabel() {
return label;
}
/**
* The keyboard interface
*/
public interface KeyboardInterface {
/**
* @return a char or 0 if no char available
*/
int getChar();
/**
* @return true if there is a char
*/
boolean isChar();
/**
* removes the first character
*/
void removeChar();
} }
} }

View File

@ -15,7 +15,7 @@ import java.awt.event.KeyEvent;
/** /**
* A simple keyboard implementation * A simple keyboard implementation
*/ */
public class KeyboardDialog extends JDialog { public class KeyboardDialog extends JDialog implements Keyboard.KeyboardInterface {
private final JLabel textLabel; private final JLabel textLabel;
private final Object textLock = new Object(); private final Object textLock = new Object();
private String text; private String text;
@ -23,13 +23,15 @@ public class KeyboardDialog extends JDialog {
/** /**
* Create a new Instance * Create a new Instance
* *
* @param owner the owner frame * @param owner the owner frame
* @param keyboard the keyboard node which has opened this dialog
* @param keyPressedHandler handler called every time a key is typed
*/ */
public KeyboardDialog(Frame owner) { public KeyboardDialog(Frame owner, Keyboard keyboard, KeyPressedHandler keyPressedHandler) {
super(owner, Lang.get("elem_Keyboard"), false); super(owner, Lang.get("elem_Keyboard") + " " + keyboard.getLabel(), false);
setDefaultCloseOperation(DISPOSE_ON_CLOSE); setDefaultCloseOperation(DISPOSE_ON_CLOSE);
textLabel = new JLabel("Enter Text "); textLabel = new JLabel(Lang.get("msg_enterText") + " ");
textLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); textLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
getContentPane().add(textLabel); getContentPane().add(textLabel);
text = ""; text = "";
@ -43,6 +45,7 @@ public class KeyboardDialog extends JDialog {
text += e.getKeyChar(); text += e.getKeyChar();
t = text; t = text;
} }
keyPressedHandler.keyPressed(keyboard);
textLabel.setText(t); textLabel.setText(t);
} }
}); });
@ -50,24 +53,47 @@ public class KeyboardDialog extends JDialog {
pack(); pack();
setLocationRelativeTo(owner); setLocationRelativeTo(owner);
setVisible(true); setVisible(true);
keyboard.setKeyboardDialog(this);
} }
/** @Override
* @return the oldest char
*/
public int getChar() { public int getChar() {
synchronized (textLock) { synchronized (textLock) {
if (text.length() == 0) if (text.length() == 0)
return 0; return 0;
else { else
int c = text.charAt(0); return text.charAt(0);
String t; }
}
@Override
public boolean isChar() {
synchronized (textLock) {
return text.length() > 0;
}
}
@Override
public void removeChar() {
synchronized (textLock) {
if (text.length() > 0) {
text = text.substring(1); text = text.substring(1);
t = text; final String t = text;
SwingUtilities.invokeLater(() -> textLabel.setText(t)); SwingUtilities.invokeLater(() -> textLabel.setText(t));
return c;
} }
} }
} }
/**
* The handler called if a key is typed.
*/
public interface KeyPressedHandler {
/**
* Called if a key is typed
*
* @param keyboard the keyboard used
*/
void keyPressed(Keyboard keyboard);
}
} }

View File

@ -224,8 +224,13 @@
Dieses Element puffert die Eingaben, welche dann ausgelesen werden können. Dieses Element puffert die Eingaben, welche dann ausgelesen werden können.
Es wird ein eigenes Fenster für die Eingabe geöffnet. Es wird ein eigenes Fenster für die Eingabe geöffnet.
</string> </string>
<string name="elem_Keyboard_pin_sel">Wenn gesetzt, ist der Ausgang D aktiv und ein Tastendruck wird ausgegeben.</string> <string name="elem_Keyboard_pin_C">Takt. Eine steigende Flanke entfernt das älteste Zeichen aus dem Buffer.</string>
<string name="elem_Keyboard_pin_en">Wenn gesetzt, ist der Ausgang D aktiv und ein Tastendruck wird ausgegeben.
Ist gleichzeitig die freigabe für den Takt.</string>
<string name="elem_Keyboard_pin_D">Die letzte Taste oder 0, wenn keine Taste gedrückt.</string> <string name="elem_Keyboard_pin_D">Die letzte Taste oder 0, wenn keine Taste gedrückt.</string>
<string name="elem_Keyboard_pin_av">Dieser Ausgang zeigt an, dass Zeichen vorhanden sind.
Er kann genutzt werden, um einen Interrupt auszulösen.</string>
<string name="elem_Terminal">Terminal</string> <string name="elem_Terminal">Terminal</string>
<string name="elem_Terminal_tt">Ein Terminal, auf dem ASCII-Zeichen ausgegeben werden können. <string name="elem_Terminal_tt">Ein Terminal, auf dem ASCII-Zeichen ausgegeben werden können.
Öffnet ein eigenes Fenster, um die Ausgabe anzuzeigen.</string> Öffnet ein eigenes Fenster, um die Ausgabe anzuzeigen.</string>
@ -1429,6 +1434,7 @@ Soll dennoch exportiert werden?</string>
nicht der Fall ist, wird die Fehlermeldung der externen Anwendung angezeigt. Wenn es möglich ist, werden zudem nicht der Fall ist, wird die Fehlermeldung der externen Anwendung angezeigt. Wenn es möglich ist, werden zudem
die Eingangs- und Ausgangsdefinitionen an den aktuellen Code angepasst.</string> die Eingangs- und Ausgangsdefinitionen an den aktuellen Code angepasst.</string>
<string name="msg_applicationFileNotFound">Ausführbare Datei "{0}" nicht gefunden!</string> <string name="msg_applicationFileNotFound">Ausführbare Datei "{0}" nicht gefunden!</string>
<string name="msg_enterText">Text eingeben!</string>
<string name="ok">Ok</string> <string name="ok">Ok</string>
<string name="rot_0"></string> <string name="rot_0"></string>

View File

@ -223,13 +223,19 @@
<string name="elem_RotEncoder_tt">Rotary knob with rotary encoder. Used to detect rotational movements.</string> <string name="elem_RotEncoder_tt">Rotary knob with rotary encoder. Used to detect rotational movements.</string>
<string name="elem_RotEncoder_pin_A">encoder signal A</string> <string name="elem_RotEncoder_pin_A">encoder signal A</string>
<string name="elem_RotEncoder_pin_B">encoder signal B</string> <string name="elem_RotEncoder_pin_B">encoder signal B</string>
<string name="elem_Keyboard">Keyboard</string> <string name="elem_Keyboard">Keyboard</string>
<string name="elem_Keyboard_tt">A keyboard that can be used to enter text. <string name="elem_Keyboard_tt">A keyboard that can be used to enter text.
This component buffers the inputs, which can then be read out. This component buffers the input, which can then be read out.
A separate window is opened for the text input. A separate window is opened for the text input.
</string> </string>
<string name="elem_Keyboard_pin_sel">If high the output D is active and one keystroke is output.</string> <string name="elem_Keyboard_pin_C">Clock. A rising edge removes the oldest character from the buffer.</string>
<string name="elem_Keyboard_pin_D">The last pressed key, or zero if no key is typed.</string> <string name="elem_Keyboard_pin_en">If high the output D is active and one character is output.
It also enables the clock input.</string>
<string name="elem_Keyboard_pin_D">The last typed character, or zero if no character is available.</string>
<string name="elem_Keyboard_pin_av">This output indicates that characters are available.
It can be used to trigger an interrupt.</string>
<string name="elem_Terminal">Terminal</string> <string name="elem_Terminal">Terminal</string>
<string name="elem_Terminal_tt">You can write ASCII characters to this terminal. <string name="elem_Terminal_tt">You can write ASCII characters to this terminal.
The terminal opens its own window to visualize the output.</string> The terminal opens its own window to visualize the output.</string>
@ -1417,6 +1423,7 @@
If this is not the case, the error message of the external application is displayed. If this is not the case, the error message of the external application is displayed.
If possible, the input and output definitions are also adapted to the current code.</string> If possible, the input and output definitions are also adapted to the current code.</string>
<string name="msg_applicationFileNotFound">Executable file "{0}" not found!</string> <string name="msg_applicationFileNotFound">Executable file "{0}" not found!</string>
<string name="msg_enterText">Enter Text!</string>
<string name="ok">Ok</string> <string name="ok">Ok</string>
<string name="rot_0"></string> <string name="rot_0"></string>

View File

@ -170,7 +170,7 @@
<visualElement> <visualElement>
<elementName>Terminal</elementName> <elementName>Terminal</elementName>
<elementAttributes/> <elementAttributes/>
<pos x="420" y="900"/> <pos x="420" y="920"/>
</visualElement> </visualElement>
<visualElement> <visualElement>
<elementName>VDD</elementName> <elementName>VDD</elementName>
@ -575,6 +575,10 @@
<p1 x="780" y="640"/> <p1 x="780" y="640"/>
<p2 x="800" y="640"/> <p2 x="800" y="640"/>
</wire> </wire>
<wire>
<p1 x="400" y="960"/>
<p2 x="420" y="960"/>
</wire>
<wire> <wire>
<p1 x="240" y="260"/> <p1 x="240" y="260"/>
<p2 x="260" y="260"/> <p2 x="260" y="260"/>
@ -619,10 +623,6 @@
<p1 x="460" y="580"/> <p1 x="460" y="580"/>
<p2 x="480" y="580"/> <p2 x="480" y="580"/>
</wire> </wire>
<wire>
<p1 x="380" y="900"/>
<p2 x="420" y="900"/>
</wire>
<wire> <wire>
<p1 x="780" y="200"/> <p1 x="780" y="200"/>
<p2 x="800" y="200"/> <p2 x="800" y="200"/>
@ -776,7 +776,7 @@
<p2 x="1160" y="660"/> <p2 x="1160" y="660"/>
</wire> </wire>
<wire> <wire>
<p1 x="400" y="920"/> <p1 x="380" y="920"/>
<p2 x="420" y="920"/> <p2 x="420" y="920"/>
</wire> </wire>
<wire> <wire>
@ -923,6 +923,10 @@
<p1 x="580" y="680"/> <p1 x="580" y="680"/>
<p2 x="640" y="680"/> <p2 x="640" y="680"/>
</wire> </wire>
<wire>
<p1 x="400" y="940"/>
<p2 x="420" y="940"/>
</wire>
<wire> <wire>
<p1 x="780" y="620"/> <p1 x="780" y="620"/>
<p2 x="800" y="620"/> <p2 x="800" y="620"/>
@ -959,10 +963,6 @@
<p1 x="660" y="300"/> <p1 x="660" y="300"/>
<p2 x="680" y="300"/> <p2 x="680" y="300"/>
</wire> </wire>
<wire>
<p1 x="400" y="940"/>
<p2 x="420" y="940"/>
</wire>
<wire> <wire>
<p1 x="580" y="560"/> <p1 x="580" y="560"/>
<p2 x="620" y="560"/> <p2 x="620" y="560"/>
@ -995,6 +995,10 @@
<p1 x="760" y="880"/> <p1 x="760" y="880"/>
<p2 x="880" y="880"/> <p2 x="880" y="880"/>
</wire> </wire>
<wire>
<p1 x="400" y="880"/>
<p2 x="420" y="880"/>
</wire>
<wire> <wire>
<p1 x="600" y="500"/> <p1 x="600" y="500"/>
<p2 x="620" y="500"/> <p2 x="620" y="500"/>
@ -1276,8 +1280,8 @@
<p2 x="400" y="580"/> <p2 x="400" y="580"/>
</wire> </wire>
<wire> <wire>
<p1 x="400" y="920"/> <p1 x="400" y="940"/>
<p2 x="400" y="940"/> <p2 x="400" y="960"/>
</wire> </wire>
<wire> <wire>
<p1 x="400" y="580"/> <p1 x="400" y="580"/>
@ -1305,12 +1309,16 @@
</wire> </wire>
<wire> <wire>
<p1 x="400" y="860"/> <p1 x="400" y="860"/>
<p2 x="400" y="920"/> <p2 x="400" y="880"/>
</wire> </wire>
<wire> <wire>
<p1 x="400" y="360"/> <p1 x="400" y="360"/>
<p2 x="400" y="400"/> <p2 x="400" y="400"/>
</wire> </wire>
<wire>
<p1 x="400" y="880"/>
<p2 x="400" y="940"/>
</wire>
<wire> <wire>
<p1 x="600" y="100"/> <p1 x="600" y="100"/>
<p2 x="600" y="220"/> <p2 x="600" y="220"/>
@ -1653,7 +1661,7 @@
</wire> </wire>
<wire> <wire>
<p1 x="380" y="820"/> <p1 x="380" y="820"/>
<p2 x="380" y="900"/> <p2 x="380" y="920"/>
</wire> </wire>
</wires> </wires>
<measurementOrdering/> <measurementOrdering/>