mirror of
https://github.com/sethm/symon.git
synced 2025-04-14 21:37:21 +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.KeyEvent;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
import java.util.logging.Level;
|
||||
@ -61,6 +62,9 @@ public class Simulator implements ActionListener, Observer {
|
||||
private JButton stepButton;
|
||||
private JButton resetButton;
|
||||
|
||||
// The most recently read key code
|
||||
private char keyBuffer;
|
||||
|
||||
// TODO: loadMenuItem seriously violates encapsulation!
|
||||
// A far better solution would be to extend JMenu and add callback
|
||||
// methods to enable and disable menus as required.
|
||||
@ -71,10 +75,7 @@ public class Simulator implements ActionListener, Observer {
|
||||
private JFileChooser fileChooser;
|
||||
private Preferences preferences;
|
||||
|
||||
private StringBuffer aciaBuffer;
|
||||
|
||||
public Simulator() throws MemoryRangeException {
|
||||
this.aciaBuffer = new StringBuffer(512);
|
||||
this.acia = new Acia(ACIA_BASE);
|
||||
this.bus = new Bus(BUS_BOTTOM, BUS_TOP);
|
||||
this.cpu = new Cpu();
|
||||
@ -275,7 +276,8 @@ public class Simulator implements ActionListener, Observer {
|
||||
// Update status.
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
updateConsoleAndStatus(cpu);
|
||||
// Now update the state
|
||||
statusPane.updateState(cpu);
|
||||
}
|
||||
});
|
||||
} catch (MemoryAccessException ex) {
|
||||
@ -294,7 +296,8 @@ public class Simulator implements ActionListener, Observer {
|
||||
// immediate update after stepping manually.
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
updateConsoleAndStatus(cpu);
|
||||
// Now update the state
|
||||
statusPane.updateState(cpu);
|
||||
}
|
||||
});
|
||||
} catch (SymonException ex) {
|
||||
@ -321,9 +324,27 @@ public class Simulator implements ActionListener, Observer {
|
||||
|
||||
cpu.step();
|
||||
|
||||
// Read from the ACIA
|
||||
while (acia.hasTxChar()) {
|
||||
aciaBuffer.append((char) acia.txRead());
|
||||
// Read from the ACIA and immediately update the console if there's
|
||||
// output ready.
|
||||
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
|
||||
@ -332,7 +353,8 @@ public class Simulator implements ActionListener, Observer {
|
||||
if (stepsSinceLastUpdate++ > MAX_STEPS_BETWEEN_UPDATES) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
updateConsoleAndStatus(cpu);
|
||||
// Now update the state
|
||||
statusPane.updateState(cpu);
|
||||
}
|
||||
});
|
||||
stepsSinceLastUpdate = 0;
|
||||
@ -361,28 +383,12 @@ public class Simulator implements ActionListener, Observer {
|
||||
// Immediately update the UI.
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
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[]) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
@ -457,8 +463,8 @@ public class Simulator implements ActionListener, Observer {
|
||||
stepButton.setEnabled(true);
|
||||
loadMenuItem.setEnabled(true);
|
||||
runStopButton.setText("Run");
|
||||
// Update state.
|
||||
updateConsoleAndStatus(cpu);
|
||||
// Now update the state
|
||||
statusPane.updateState(cpu);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -32,6 +32,8 @@ public class Acia extends Device {
|
||||
private int commandRegister;
|
||||
private int controlRegister;
|
||||
|
||||
private boolean overrun = false;
|
||||
|
||||
/**
|
||||
* Read/Write buffers
|
||||
*/
|
||||
@ -52,6 +54,8 @@ public class Acia extends Device {
|
||||
case DATA_REG:
|
||||
return rxRead();
|
||||
case STAT_REG:
|
||||
// TODO: Overrun, Parity Error, Framing Error,
|
||||
// DTR, DSR, and Interrupt flags.
|
||||
return ((rxFull ? 0x08 : 0x00) |
|
||||
(txFull ? 0x00 : 0x10));
|
||||
case CMND_REG:
|
||||
|
@ -18,6 +18,9 @@ import javax.swing.border.Border;
|
||||
|
||||
public class Console extends JTerminal implements KeyListener, MouseListener {
|
||||
|
||||
private boolean hasInput = false;
|
||||
private char keyBuffer;
|
||||
|
||||
public Console() {
|
||||
super();
|
||||
addKeyListener(this);
|
||||
@ -33,6 +36,7 @@ public class Console extends JTerminal implements KeyListener, MouseListener {
|
||||
getModel().setCursorColumn(0);
|
||||
getModel().setCursorRow(0);
|
||||
repaint();
|
||||
this.hasInput = false;
|
||||
}
|
||||
|
||||
public void keyTyped(KeyEvent keyEvent) {
|
||||
@ -40,19 +44,23 @@ public class Console extends JTerminal implements KeyListener, MouseListener {
|
||||
}
|
||||
|
||||
public void keyPressed(KeyEvent keyEvent) {
|
||||
int keyCode = keyEvent.getKeyCode();
|
||||
int modifiersMask = keyEvent.getModifiers();
|
||||
int modifiersExMask = keyEvent.getModifiersEx();
|
||||
keyBuffer = keyEvent.getKeyChar();
|
||||
hasInput = true;
|
||||
|
||||
System.out.println("Key Pressed #" + keyEvent.getKeyCode() + " : " +
|
||||
KeyEvent.getKeyText(keyCode) + " MASK : " +
|
||||
modifiersMask + " EXT MASK : " +
|
||||
modifiersExMask
|
||||
);
|
||||
System.out.println("Key Pressed (0x" + Integer.toString((int)keyBuffer, 16) + ") : " + keyBuffer);
|
||||
|
||||
keyEvent.consume();
|
||||
}
|
||||
|
||||
public boolean hasInput() {
|
||||
return hasInput;
|
||||
}
|
||||
|
||||
public char readInputChar() {
|
||||
hasInput = false;
|
||||
return this.keyBuffer;
|
||||
}
|
||||
|
||||
public void keyReleased(KeyEvent keyEvent) {
|
||||
keyEvent.consume();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user