mirror of
https://github.com/sethm/symon.git
synced 2024-06-14 17:29:38 +00:00
Finally handling key presses in the console! (Took long enough, huh?) Added a dead simple console echo example program in 6502 assembly, as well.
This commit is contained in:
parent
ed36690e9e
commit
365809459c
36
samples/echo.asm
Normal file
36
samples/echo.asm
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
;;
|
||||||
|
;; Read input from the keyboard, and echo to console.
|
||||||
|
;;
|
||||||
|
|
||||||
|
|
||||||
|
.alias iobase $c000
|
||||||
|
.alias iostatus [iobase + 1]
|
||||||
|
.alias iocmd [iobase + 2]
|
||||||
|
.alias ioctrl [iobase + 3]
|
||||||
|
|
||||||
|
.org $0300
|
||||||
|
|
||||||
|
start: cli
|
||||||
|
lda #$09
|
||||||
|
sta iocmd ; Set command status
|
||||||
|
lda #$16
|
||||||
|
sta ioctrl ; 0 stop bits, 8 bit word, 300 baud
|
||||||
|
|
||||||
|
;; Load a character from the keyboard and store it into
|
||||||
|
;; the accumulator
|
||||||
|
|
||||||
|
getkey: lda iostatus ; Read the ACIA status
|
||||||
|
and #$08 ; Is the rx register empty?
|
||||||
|
beq getkey ; Yes, wait for it to fill
|
||||||
|
lda iobase ; Otherwise, read into accumulator
|
||||||
|
|
||||||
|
;; Write the current char in the accumulator to the console
|
||||||
|
|
||||||
|
write: pha ; Save accumulator
|
||||||
|
lda iostatus ; Read the ACIA status
|
||||||
|
and #$10 ; Is the tx register empty?
|
||||||
|
beq write ; No, wait for it to empty
|
||||||
|
pla ; Otherwise, load saved accumulator
|
||||||
|
sta iobase ; and write to output.
|
||||||
|
|
||||||
|
jmp getkey ; Repeat
|
BIN
samples/echo.prg
Normal file
BIN
samples/echo.prg
Normal file
Binary file not shown.
BIN
src/assets/new_led_images.psd
Normal file
BIN
src/assets/new_led_images.psd
Normal file
Binary file not shown.
|
@ -14,6 +14,7 @@ import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
@ -61,6 +62,9 @@ public class Simulator implements ActionListener, Observer {
|
||||||
private JButton stepButton;
|
private JButton stepButton;
|
||||||
private JButton resetButton;
|
private JButton resetButton;
|
||||||
|
|
||||||
|
// The most recently read key code
|
||||||
|
private char keyBuffer;
|
||||||
|
|
||||||
// TODO: loadMenuItem seriously violates encapsulation!
|
// TODO: loadMenuItem seriously violates encapsulation!
|
||||||
// A far better solution would be to extend JMenu and add callback
|
// A far better solution would be to extend JMenu and add callback
|
||||||
// methods to enable and disable menus as required.
|
// methods to enable and disable menus as required.
|
||||||
|
@ -71,10 +75,7 @@ public class Simulator implements ActionListener, Observer {
|
||||||
private JFileChooser fileChooser;
|
private JFileChooser fileChooser;
|
||||||
private Preferences preferences;
|
private Preferences preferences;
|
||||||
|
|
||||||
private StringBuffer aciaBuffer;
|
|
||||||
|
|
||||||
public Simulator() throws MemoryRangeException {
|
public Simulator() throws MemoryRangeException {
|
||||||
this.aciaBuffer = new StringBuffer(512);
|
|
||||||
this.acia = new Acia(ACIA_BASE);
|
this.acia = new Acia(ACIA_BASE);
|
||||||
this.bus = new Bus(BUS_BOTTOM, BUS_TOP);
|
this.bus = new Bus(BUS_BOTTOM, BUS_TOP);
|
||||||
this.cpu = new Cpu();
|
this.cpu = new Cpu();
|
||||||
|
@ -275,7 +276,8 @@ public class Simulator implements ActionListener, Observer {
|
||||||
// Update status.
|
// Update status.
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
updateConsoleAndStatus(cpu);
|
// Now update the state
|
||||||
|
statusPane.updateState(cpu);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (MemoryAccessException ex) {
|
} catch (MemoryAccessException ex) {
|
||||||
|
@ -294,7 +296,8 @@ public class Simulator implements ActionListener, Observer {
|
||||||
// immediate update after stepping manually.
|
// immediate update after stepping manually.
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
updateConsoleAndStatus(cpu);
|
// Now update the state
|
||||||
|
statusPane.updateState(cpu);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (SymonException ex) {
|
} catch (SymonException ex) {
|
||||||
|
@ -321,9 +324,27 @@ public class Simulator implements ActionListener, Observer {
|
||||||
|
|
||||||
cpu.step();
|
cpu.step();
|
||||||
|
|
||||||
// Read from the ACIA
|
// Read from the ACIA and immediately update the console if there's
|
||||||
while (acia.hasTxChar()) {
|
// output ready.
|
||||||
aciaBuffer.append((char) acia.txRead());
|
if (acia.hasTxChar()) {
|
||||||
|
try {
|
||||||
|
SwingUtilities.invokeAndWait(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
console.print(Character.toString((char)acia.txRead()));
|
||||||
|
console.repaint();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a key has been pressed, fill the ACIA.
|
||||||
|
// TODO: Interrupt handling.
|
||||||
|
if (console.hasInput()) {
|
||||||
|
acia.rxWrite((int)console.readInputChar());
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a very expensive update, and we're doing it without
|
// This is a very expensive update, and we're doing it without
|
||||||
|
@ -332,7 +353,8 @@ public class Simulator implements ActionListener, Observer {
|
||||||
if (stepsSinceLastUpdate++ > MAX_STEPS_BETWEEN_UPDATES) {
|
if (stepsSinceLastUpdate++ > MAX_STEPS_BETWEEN_UPDATES) {
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
updateConsoleAndStatus(cpu);
|
// Now update the state
|
||||||
|
statusPane.updateState(cpu);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
stepsSinceLastUpdate = 0;
|
stepsSinceLastUpdate = 0;
|
||||||
|
@ -361,28 +383,12 @@ public class Simulator implements ActionListener, Observer {
|
||||||
// Immediately update the UI.
|
// Immediately update the UI.
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
updateConsoleAndStatus(cpu);
|
// Now update the state
|
||||||
|
statusPane.updateState(cpu);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the UI with the latest state of the simulator.
|
|
||||||
*/
|
|
||||||
private void updateConsoleAndStatus(Cpu cpu) {
|
|
||||||
// If we have accumulated any ACIA output in our temporary
|
|
||||||
// buffer since the last UI update, write it to the console,
|
|
||||||
// then clear the buffer.
|
|
||||||
if (aciaBuffer.length() > 0) {
|
|
||||||
console.print(aciaBuffer.toString());
|
|
||||||
console.repaint();
|
|
||||||
aciaBuffer.delete(0, aciaBuffer.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now update the state
|
|
||||||
statusPane.updateState(cpu);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String args[]) {
|
public static void main(String args[]) {
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
|
@ -457,8 +463,8 @@ public class Simulator implements ActionListener, Observer {
|
||||||
stepButton.setEnabled(true);
|
stepButton.setEnabled(true);
|
||||||
loadMenuItem.setEnabled(true);
|
loadMenuItem.setEnabled(true);
|
||||||
runStopButton.setText("Run");
|
runStopButton.setText("Run");
|
||||||
// Update state.
|
// Now update the state
|
||||||
updateConsoleAndStatus(cpu);
|
statusPane.updateState(cpu);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,8 @@ public class Acia extends Device {
|
||||||
private int commandRegister;
|
private int commandRegister;
|
||||||
private int controlRegister;
|
private int controlRegister;
|
||||||
|
|
||||||
|
private boolean overrun = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read/Write buffers
|
* Read/Write buffers
|
||||||
*/
|
*/
|
||||||
|
@ -52,6 +54,8 @@ public class Acia extends Device {
|
||||||
case DATA_REG:
|
case DATA_REG:
|
||||||
return rxRead();
|
return rxRead();
|
||||||
case STAT_REG:
|
case STAT_REG:
|
||||||
|
// TODO: Overrun, Parity Error, Framing Error,
|
||||||
|
// DTR, DSR, and Interrupt flags.
|
||||||
return ((rxFull ? 0x08 : 0x00) |
|
return ((rxFull ? 0x08 : 0x00) |
|
||||||
(txFull ? 0x00 : 0x10));
|
(txFull ? 0x00 : 0x10));
|
||||||
case CMND_REG:
|
case CMND_REG:
|
||||||
|
|
|
@ -18,6 +18,9 @@ import javax.swing.border.Border;
|
||||||
|
|
||||||
public class Console extends JTerminal implements KeyListener, MouseListener {
|
public class Console extends JTerminal implements KeyListener, MouseListener {
|
||||||
|
|
||||||
|
private boolean hasInput = false;
|
||||||
|
private char keyBuffer;
|
||||||
|
|
||||||
public Console() {
|
public Console() {
|
||||||
super();
|
super();
|
||||||
addKeyListener(this);
|
addKeyListener(this);
|
||||||
|
@ -33,6 +36,7 @@ public class Console extends JTerminal implements KeyListener, MouseListener {
|
||||||
getModel().setCursorColumn(0);
|
getModel().setCursorColumn(0);
|
||||||
getModel().setCursorRow(0);
|
getModel().setCursorRow(0);
|
||||||
repaint();
|
repaint();
|
||||||
|
this.hasInput = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void keyTyped(KeyEvent keyEvent) {
|
public void keyTyped(KeyEvent keyEvent) {
|
||||||
|
@ -40,19 +44,23 @@ public class Console extends JTerminal implements KeyListener, MouseListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void keyPressed(KeyEvent keyEvent) {
|
public void keyPressed(KeyEvent keyEvent) {
|
||||||
int keyCode = keyEvent.getKeyCode();
|
keyBuffer = keyEvent.getKeyChar();
|
||||||
int modifiersMask = keyEvent.getModifiers();
|
hasInput = true;
|
||||||
int modifiersExMask = keyEvent.getModifiersEx();
|
|
||||||
|
|
||||||
System.out.println("Key Pressed #" + keyEvent.getKeyCode() + " : " +
|
System.out.println("Key Pressed (0x" + Integer.toString((int)keyBuffer, 16) + ") : " + keyBuffer);
|
||||||
KeyEvent.getKeyText(keyCode) + " MASK : " +
|
|
||||||
modifiersMask + " EXT MASK : " +
|
|
||||||
modifiersExMask
|
|
||||||
);
|
|
||||||
|
|
||||||
keyEvent.consume();
|
keyEvent.consume();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasInput() {
|
||||||
|
return hasInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
public char readInputChar() {
|
||||||
|
hasInput = false;
|
||||||
|
return this.keyBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
public void keyReleased(KeyEvent keyEvent) {
|
public void keyReleased(KeyEvent keyEvent) {
|
||||||
keyEvent.consume();
|
keyEvent.consume();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user