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:
Seth Morabito 2012-10-11 16:08:04 -07:00
parent ed36690e9e
commit 365809459c
6 changed files with 91 additions and 37 deletions

36
samples/echo.asm Normal file
View 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

Binary file not shown.

Binary file not shown.

View File

@ -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);
}
});

View File

@ -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:

View File

@ -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();
}