Merge remote-tracking branch 'upstream/master'
24
README.md
|
@ -3,14 +3,18 @@ SYMON - A 6502 System Simulator
|
|||
|
||||
**NOTE: THIS SOFTWARE IS UNDER ACTIVE DEVELOPMENT. Feedback is welcome!**
|
||||
|
||||
**Version:** 0.9.9.1
|
||||
**Version:** 1.0.0-SNAPSHOT
|
||||
|
||||
**Last Updated:** 27 July, 2014
|
||||
**Last Updated:** 10 August, 2014
|
||||
|
||||
Copyright (c) 2014 Seth J. Morabito <web@loomcom.com>
|
||||
**Copyright (c) 2014 Seth J. Morabito <web@loomcom.com>**
|
||||
|
||||
Portions Copyright (c) 2014 Maik Merten <maikmerten@googlemail.com>
|
||||
|
||||
Enhanced 6502 BASIC (c) Lee Davison
|
||||
|
||||
6502 Functional Tests (c) Klaus Dormann
|
||||
|
||||
See the file COPYING for license.
|
||||
|
||||
![Symon Simulator in Action] (https://github.com/sethm/symon/raw/master/screenshots/full.jpg)
|
||||
|
@ -39,8 +43,9 @@ for more information about this functional test suite).
|
|||
|
||||
## 3.0 Features
|
||||
|
||||
Symon can simulate multiple 6502 based architectures. At present, two
|
||||
machines are implemented: Symon (the default), and MULTICOMP.
|
||||
Symon can simulate multiple 6502 based architectures. At present, three
|
||||
machines are implemented: Symon (the default), MULTICOMP, and a "Simple"
|
||||
machine useful for debugging.
|
||||
|
||||
### 3.1 Memory Maps
|
||||
|
||||
|
@ -61,6 +66,10 @@ memory.
|
|||
- `$E000`--`$FFFF`: 8KB ROM
|
||||
- `$FFD0`--`$FFD1`: Motorola 6850 ACIA
|
||||
|
||||
### 3.1.3 Simple Memory Map
|
||||
|
||||
- `$0000`--`$FFFF`: 64KB RAM
|
||||
|
||||
### 3.2 Serial Console and CPU Status
|
||||
|
||||
![Serial Console] (https://github.com/sethm/symon/raw/master/screenshots/console.png)
|
||||
|
@ -217,6 +226,11 @@ running.
|
|||
|
||||
## 5.0 Revision History
|
||||
|
||||
- **1.0.0-SNAPSHOT:** 10 August, 2014 - Added "Simple" machine
|
||||
implementation, pure RAM with no IO. Added Klaus Dormann's
|
||||
6502 Functional Tests for further machine verification (these
|
||||
tests must be run in the "Simple" machine).
|
||||
|
||||
- **0.9.9.1:** 27 July, 2014 - Pressing 'Control' while clicking
|
||||
'Reset' now performs a memory clear.
|
||||
|
||||
|
|
2
pom.xml
|
@ -4,7 +4,7 @@
|
|||
<groupId>com.loomcom.symon</groupId>
|
||||
<artifactId>symon</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>0.9.9.1</version>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<name>symon</name>
|
||||
<url>http://www.loomcom.com/symon</url>
|
||||
<properties>
|
||||
|
|
BIN
samples/tests/6502_functional_test.bin
Executable file
13999
samples/tests/6502_functional_test.lst
Executable file
BIN
samples/tests/65C02_extended_opcodes_test.bin
Executable file
11308
samples/tests/65C02_extended_opcodes_test.lst
Executable file
|
@ -26,6 +26,7 @@
|
|||
package com.loomcom.symon;
|
||||
|
||||
import com.loomcom.symon.machines.MulticompMachine;
|
||||
import com.loomcom.symon.machines.SimpleMachine;
|
||||
import com.loomcom.symon.machines.SymonMachine;
|
||||
import java.util.Locale;
|
||||
import javax.swing.JOptionPane;
|
||||
|
@ -51,13 +52,15 @@ public class Main {
|
|||
machineClass = SymonMachine.class;
|
||||
} else if(machine.equals("multicomp")) {
|
||||
machineClass = MulticompMachine.class;
|
||||
} else if (machine.equals("simple")) {
|
||||
machineClass = SimpleMachine.class;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while(true) {
|
||||
if(machineClass == null) {
|
||||
Object[] possibilities = {"Symon", "Multicomp"};
|
||||
while (true) {
|
||||
if (machineClass == null) {
|
||||
Object[] possibilities = {"Symon", "Multicomp", "Simple"};
|
||||
String s = (String)JOptionPane.showInputDialog(
|
||||
null,
|
||||
"Please choose the machine type to be emulated:",
|
||||
|
@ -67,9 +70,11 @@ public class Main {
|
|||
possibilities,
|
||||
"Symon");
|
||||
|
||||
|
||||
if(s != null && s.equals("Multicomp")) {
|
||||
|
||||
if (s != null && s.equals("Multicomp")) {
|
||||
machineClass = MulticompMachine.class;
|
||||
} else if (s != null && s.equals("Simple")) {
|
||||
machineClass = SimpleMachine.class;
|
||||
} else {
|
||||
machineClass = SymonMachine.class;
|
||||
}
|
||||
|
@ -91,13 +96,11 @@ public class Main {
|
|||
|
||||
|
||||
Simulator.MAIN_CMD cmd = simulator.waitForCommand();
|
||||
if(cmd.equals(Simulator.MAIN_CMD.SELECTMACHINE)) {
|
||||
if (cmd.equals(Simulator.MAIN_CMD.SELECTMACHINE)) {
|
||||
machineClass = null;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -110,7 +110,8 @@ public class Simulator {
|
|||
|
||||
private JButton runStopButton;
|
||||
private JButton stepButton;
|
||||
private JButton resetButton;
|
||||
private JButton softResetButton;
|
||||
private JButton hardResetButton;
|
||||
private JComboBox<String> stepCountBox;
|
||||
|
||||
private JFileChooser fileChooser;
|
||||
|
@ -137,13 +138,13 @@ public class Simulator {
|
|||
*/
|
||||
public void createAndShowUi() throws IOException {
|
||||
mainWindow = new JFrame();
|
||||
mainWindow.setTitle("Symon 6502 Simulator");
|
||||
mainWindow.setTitle("6502 Simulator - " + machine.getName());
|
||||
mainWindow.setResizable(false);
|
||||
mainWindow.getContentPane().setLayout(new BorderLayout());
|
||||
|
||||
// UI components used for I/O.
|
||||
this.console = new com.loomcom.symon.ui.Console(80, 25, DEFAULT_FONT);
|
||||
this.statusPane = new StatusPanel();
|
||||
this.statusPane = new StatusPanel(machine);
|
||||
|
||||
console.setBorderWidth(CONSOLE_BORDER_WIDTH);
|
||||
|
||||
|
@ -161,7 +162,8 @@ public class Simulator {
|
|||
|
||||
runStopButton = new JButton("Run");
|
||||
stepButton = new JButton("Step");
|
||||
resetButton = new JButton("Reset");
|
||||
softResetButton = new JButton("Soft Reset");
|
||||
hardResetButton = new JButton("Hard Reset");
|
||||
|
||||
stepCountBox = new JComboBox<String>(STEPS);
|
||||
stepCountBox.addActionListener(new ActionListener() {
|
||||
|
@ -179,7 +181,8 @@ public class Simulator {
|
|||
buttonContainer.add(runStopButton);
|
||||
buttonContainer.add(stepButton);
|
||||
buttonContainer.add(stepCountBox);
|
||||
buttonContainer.add(resetButton);
|
||||
buttonContainer.add(softResetButton);
|
||||
buttonContainer.add(hardResetButton);
|
||||
|
||||
// Left side - console
|
||||
consoleContainer.add(console, BorderLayout.CENTER);
|
||||
|
@ -207,10 +210,17 @@ public class Simulator {
|
|||
}
|
||||
});
|
||||
|
||||
resetButton.addActionListener(new ActionListener() {
|
||||
softResetButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent actionEvent) {
|
||||
// If this was a CTRL-click, do a hard reset.
|
||||
handleReset((actionEvent.getModifiers() & ActionEvent.CTRL_MASK) != 0);
|
||||
handleReset(false);
|
||||
}
|
||||
});
|
||||
|
||||
hardResetButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent actionEvent) {
|
||||
// If this was a CTRL-click, do a hard reset.
|
||||
handleReset(true);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -295,7 +305,7 @@ public class Simulator {
|
|||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
// Now update the state
|
||||
statusPane.updateState(machine.getCpu());
|
||||
statusPane.updateState();
|
||||
memoryWindow.updateState();
|
||||
}
|
||||
});
|
||||
|
@ -317,7 +327,7 @@ public class Simulator {
|
|||
if (traceLog.isVisible()) {
|
||||
traceLog.refresh();
|
||||
}
|
||||
statusPane.updateState(machine.getCpu());
|
||||
statusPane.updateState();
|
||||
memoryWindow.updateState();
|
||||
}
|
||||
});
|
||||
|
@ -337,7 +347,7 @@ public class Simulator {
|
|||
|
||||
// Read from the ACIA and immediately update the console if there's
|
||||
// output ready.
|
||||
if (machine.getAcia().hasTxChar()) {
|
||||
if (machine.getAcia() != null && machine.getAcia().hasTxChar()) {
|
||||
// This is thread-safe
|
||||
console.print(Character.toString((char) machine.getAcia().txRead()));
|
||||
console.repaint();
|
||||
|
@ -346,7 +356,7 @@ public class Simulator {
|
|||
// If a key has been pressed, fill the ACIA.
|
||||
// TODO: Interrupt handling.
|
||||
try {
|
||||
if (console.hasInput()) {
|
||||
if (machine.getAcia() != null && console.hasInput()) {
|
||||
machine.getAcia().rxWrite((int) console.readInputChar());
|
||||
}
|
||||
} catch (FifoUnderrunException ex) {
|
||||
|
@ -364,7 +374,7 @@ public class Simulator {
|
|||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
// Now update the state
|
||||
statusPane.updateState(machine.getCpu());
|
||||
statusPane.updateState();
|
||||
memoryWindow.updateState();
|
||||
}
|
||||
});
|
||||
|
@ -396,7 +406,7 @@ public class Simulator {
|
|||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
// Now update the state
|
||||
statusPane.updateState(machine.getCpu());
|
||||
statusPane.updateState();
|
||||
memoryWindow.updateState();
|
||||
}
|
||||
});
|
||||
|
@ -443,7 +453,7 @@ public class Simulator {
|
|||
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
statusPane.updateState(machine.getCpu());
|
||||
statusPane.updateState();
|
||||
memoryWindow.updateState();
|
||||
runStopButton.setText("Run");
|
||||
stepButton.setEnabled(true);
|
||||
|
@ -487,7 +497,11 @@ public class Simulator {
|
|||
long fileSize = f.length();
|
||||
|
||||
if (fileSize > machine.getMemorySize()) {
|
||||
throw new IOException("Program will not fit in available memory.");
|
||||
throw new IOException("Program of size $" +
|
||||
Integer.toString((int)fileSize, 16) +
|
||||
" will not fit in available memory of size $" +
|
||||
Integer.toString(machine.getMemorySize(), 16) +
|
||||
".");
|
||||
} else {
|
||||
byte[] program = new byte[(int) fileSize];
|
||||
int i = 0;
|
||||
|
@ -572,8 +586,6 @@ public class Simulator {
|
|||
}
|
||||
|
||||
class SelectMachineAction extends AbstractAction {
|
||||
Simulator simulator;
|
||||
|
||||
public SelectMachineAction() {
|
||||
super("Switch emulated machine...", null);
|
||||
putValue(SHORT_DESCRIPTION, "Select the type of the machine to be emulated");
|
||||
|
@ -703,7 +715,9 @@ public class Simulator {
|
|||
*/
|
||||
public void simulatorDidStart() {
|
||||
loadProgramItem.setEnabled(false);
|
||||
loadRomItem.setEnabled(false);
|
||||
if (loadRomItem != null) {
|
||||
loadRomItem.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -711,7 +725,9 @@ public class Simulator {
|
|||
*/
|
||||
public void simulatorDidStop() {
|
||||
loadProgramItem.setEnabled(true);
|
||||
loadRomItem.setEnabled(true);
|
||||
if (loadRomItem != null) {
|
||||
loadRomItem.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void initMenu() {
|
||||
|
@ -722,15 +738,22 @@ public class Simulator {
|
|||
JMenu fileMenu = new JMenu("File");
|
||||
|
||||
loadProgramItem = new JMenuItem(new LoadProgramAction());
|
||||
loadRomItem = new JMenuItem(new LoadRomAction());
|
||||
JMenuItem prefsItem = new JMenuItem(new ShowPrefsAction());
|
||||
JMenuItem selectMachineItem = new JMenuItem(new SelectMachineAction());
|
||||
JMenuItem quitItem = new JMenuItem(new QuitAction());
|
||||
|
||||
fileMenu.add(loadProgramItem);
|
||||
fileMenu.add(loadRomItem);
|
||||
|
||||
// Simple Machine does not implement a ROM, so it makes no sense to
|
||||
// offer a ROM load option.
|
||||
if (machine.getRom() != null) {
|
||||
loadRomItem = new JMenuItem(new LoadRomAction());
|
||||
fileMenu.add(loadRomItem);
|
||||
}
|
||||
|
||||
JMenuItem prefsItem = new JMenuItem(new ShowPrefsAction());
|
||||
fileMenu.add(prefsItem);
|
||||
|
||||
JMenuItem selectMachineItem = new JMenuItem(new SelectMachineAction());
|
||||
fileMenu.add(selectMachineItem);
|
||||
|
||||
JMenuItem quitItem = new JMenuItem(new QuitAction());
|
||||
fileMenu.add(quitItem);
|
||||
|
||||
add(fileMenu);
|
||||
|
|
|
@ -56,5 +56,6 @@ public interface Machine {
|
|||
public int getRomSize();
|
||||
|
||||
public int getMemorySize();
|
||||
|
||||
|
||||
String getName();
|
||||
}
|
||||
|
|
|
@ -154,5 +154,10 @@ public class MulticompMachine implements Machine {
|
|||
public int getMemorySize() {
|
||||
return MEMORY_SIZE;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Multicomp";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
93
src/main/java/com/loomcom/symon/machines/SimpleMachine.java
Normal file
|
@ -0,0 +1,93 @@
|
|||
package com.loomcom.symon.machines;
|
||||
|
||||
import com.loomcom.symon.Bus;
|
||||
import com.loomcom.symon.Cpu;
|
||||
import com.loomcom.symon.devices.Acia;
|
||||
import com.loomcom.symon.devices.Crtc;
|
||||
import com.loomcom.symon.devices.Memory;
|
||||
import com.loomcom.symon.devices.Via;
|
||||
import com.loomcom.symon.exceptions.MemoryRangeException;
|
||||
|
||||
/**
|
||||
* A SimpleMachine is the simplest 6502 implementation possible - it
|
||||
* consists solely of RAM and a CPU. This machine is primarily useful
|
||||
* for running 6502 functional tests or debugging by hand.
|
||||
*/
|
||||
public class SimpleMachine implements Machine {
|
||||
|
||||
private static final int BUS_BOTTOM = 0x0000;
|
||||
private static final int BUS_TOP = 0xffff;
|
||||
|
||||
private final Bus bus;
|
||||
private final Memory ram;
|
||||
private final Cpu cpu;
|
||||
|
||||
public SimpleMachine() throws MemoryRangeException {
|
||||
this.bus = new Bus(BUS_BOTTOM, BUS_TOP);
|
||||
this.ram = new Memory(BUS_BOTTOM, BUS_TOP, false);
|
||||
this.cpu = new Cpu();
|
||||
|
||||
bus.addCpu(cpu);
|
||||
bus.addDevice(ram);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bus getBus() {
|
||||
return bus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cpu getCpu() {
|
||||
return cpu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Memory getRam() {
|
||||
return ram;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Acia getAcia() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Via getVia() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Crtc getCrtc() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Memory getRom() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRom(Memory rom) throws MemoryRangeException {
|
||||
// No-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRomBase() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRomSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMemorySize() {
|
||||
return BUS_TOP + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Simple";
|
||||
}
|
||||
}
|
|
@ -160,8 +160,11 @@ public class SymonMachine implements Machine {
|
|||
public int getMemorySize() {
|
||||
return MEMORY_SIZE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Symon";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -24,11 +24,17 @@
|
|||
package com.loomcom.symon.ui;
|
||||
|
||||
import com.loomcom.symon.Cpu;
|
||||
import com.loomcom.symon.machines.Machine;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.border.EtchedBorder;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* UI component that displays the current state of the simulated CPU.
|
||||
|
@ -73,14 +79,17 @@ public class StatusPanel extends JPanel {
|
|||
private JLabel xLabel;
|
||||
private JLabel yLabel;
|
||||
|
||||
private Machine machine;
|
||||
|
||||
private static final int EMPTY_BORDER = 10;
|
||||
private static final Border LABEL_BORDER = BorderFactory.createEmptyBorder(0, 5, 0, 0);
|
||||
private static final Font LABEL_FONT = new Font(Font.SANS_SERIF, Font.BOLD, 12);
|
||||
private static final Dimension LARGE_TEXT_FIELD_SIZE = new Dimension(134, 22);
|
||||
private static final Dimension SMALL_TEXT_FIELD_SIZE = new Dimension(65, 22);
|
||||
|
||||
public StatusPanel() {
|
||||
public StatusPanel(Machine machine) {
|
||||
super();
|
||||
this.machine = machine;
|
||||
createUi();
|
||||
}
|
||||
|
||||
|
@ -99,20 +108,20 @@ public class StatusPanel extends JPanel {
|
|||
JPanel statusFlagsPanel = new JPanel();
|
||||
statusFlagsPanel.setAlignmentX(LEFT_ALIGNMENT);
|
||||
|
||||
carryOn = new ImageIcon(this.getClass().getResource("images/C_on.png"));
|
||||
carryOff = new ImageIcon(this.getClass().getResource("images/C_off.png"));
|
||||
zeroOn = new ImageIcon(this.getClass().getResource("images/Z_on.png"));
|
||||
zeroOff = new ImageIcon(this.getClass().getResource("images/Z_off.png"));
|
||||
irqOn = new ImageIcon(this.getClass().getResource("images/I_on.png"));
|
||||
irqOff = new ImageIcon(this.getClass().getResource("images/I_off.png"));
|
||||
decimalOn = new ImageIcon(this.getClass().getResource("images/D_on.png"));
|
||||
decimalOff = new ImageIcon(this.getClass().getResource("images/D_off.png"));
|
||||
breakOn = new ImageIcon(this.getClass().getResource("images/B_on.png"));
|
||||
breakOff = new ImageIcon(this.getClass().getResource("images/B_off.png"));
|
||||
overflowOn = new ImageIcon(this.getClass().getResource("images/O_on.png"));
|
||||
overflowOff = new ImageIcon(this.getClass().getResource("images/O_off.png"));
|
||||
negativeOn = new ImageIcon(this.getClass().getResource("images/N_on.png"));
|
||||
negativeOff = new ImageIcon(this.getClass().getResource("images/N_off.png"));
|
||||
carryOn = new ImageIcon(this.getClass().getResource("/C_on.png"));
|
||||
carryOff = new ImageIcon(this.getClass().getResource("/C_off.png"));
|
||||
zeroOn = new ImageIcon(this.getClass().getResource("/Z_on.png"));
|
||||
zeroOff = new ImageIcon(this.getClass().getResource("/Z_off.png"));
|
||||
irqOn = new ImageIcon(this.getClass().getResource("/I_on.png"));
|
||||
irqOff = new ImageIcon(this.getClass().getResource("/I_off.png"));
|
||||
decimalOn = new ImageIcon(this.getClass().getResource("/D_on.png"));
|
||||
decimalOff = new ImageIcon(this.getClass().getResource("/D_off.png"));
|
||||
breakOn = new ImageIcon(this.getClass().getResource("/B_on.png"));
|
||||
breakOff = new ImageIcon(this.getClass().getResource("/B_off.png"));
|
||||
overflowOn = new ImageIcon(this.getClass().getResource("/O_on.png"));
|
||||
overflowOff = new ImageIcon(this.getClass().getResource("/O_off.png"));
|
||||
negativeOn = new ImageIcon(this.getClass().getResource("/N_on.png"));
|
||||
negativeOff = new ImageIcon(this.getClass().getResource("/N_off.png"));
|
||||
|
||||
// Initialize all to off
|
||||
carryFlagLabel = new JLabel(carryOff, JLabel.CENTER);
|
||||
|
@ -157,12 +166,83 @@ public class StatusPanel extends JPanel {
|
|||
pcLabel.setToolTipText("Program Counter");
|
||||
spLabel.setToolTipText("Stack Pointer");
|
||||
|
||||
opcodeField = makeTextField(LARGE_TEXT_FIELD_SIZE);
|
||||
pcField = makeTextField(LARGE_TEXT_FIELD_SIZE);
|
||||
spField = makeTextField(SMALL_TEXT_FIELD_SIZE);
|
||||
aField = makeTextField(SMALL_TEXT_FIELD_SIZE);
|
||||
xField = makeTextField(SMALL_TEXT_FIELD_SIZE);
|
||||
yField = makeTextField(SMALL_TEXT_FIELD_SIZE);
|
||||
opcodeField = makeTextField(LARGE_TEXT_FIELD_SIZE, false);
|
||||
pcField = makeTextField(LARGE_TEXT_FIELD_SIZE, true);
|
||||
spField = makeTextField(SMALL_TEXT_FIELD_SIZE, true);
|
||||
aField = makeTextField(SMALL_TEXT_FIELD_SIZE, true);
|
||||
xField = makeTextField(SMALL_TEXT_FIELD_SIZE, true);
|
||||
yField = makeTextField(SMALL_TEXT_FIELD_SIZE, true);
|
||||
|
||||
// Make fields editable
|
||||
pcField.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
int newVal = getHexVal(pcField) & 0xffff;
|
||||
machine.getCpu().setProgramCounter(newVal);
|
||||
} catch (Exception ex) {
|
||||
// Swallow exception
|
||||
}
|
||||
|
||||
updateState();
|
||||
}
|
||||
});
|
||||
|
||||
spField.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
int newVal = getHexVal(spField) & 0xff;
|
||||
machine.getCpu().setStackPointer(newVal);
|
||||
} catch (Exception ex) {
|
||||
// Swallow exception
|
||||
}
|
||||
|
||||
updateState();
|
||||
}
|
||||
});
|
||||
|
||||
aField.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
int newVal = getHexVal(aField) & 0xff;
|
||||
machine.getCpu().setAccumulator(newVal);
|
||||
} catch (Exception ex) {
|
||||
// Swallow exception
|
||||
}
|
||||
|
||||
updateState();
|
||||
}
|
||||
});
|
||||
|
||||
xField.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
int newVal = getHexVal(xField) & 0xff;
|
||||
machine.getCpu().setXRegister(newVal);
|
||||
} catch (Exception ex) {
|
||||
// Swallow exception
|
||||
}
|
||||
|
||||
updateState();
|
||||
}
|
||||
});
|
||||
|
||||
yField.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
int newVal = getHexVal(yField) & 0xff;
|
||||
machine.getCpu().setYRegister(newVal);
|
||||
} catch (Exception ex) {
|
||||
// Swallow exception
|
||||
}
|
||||
|
||||
updateState();
|
||||
}
|
||||
});
|
||||
|
||||
constraints.anchor = GridBagConstraints.LINE_START;
|
||||
constraints.gridwidth = 2;
|
||||
|
@ -220,14 +300,13 @@ public class StatusPanel extends JPanel {
|
|||
|
||||
/**
|
||||
* Update the display based on the current state of the CPU.
|
||||
*
|
||||
* @param cpu The simulated 6502 CPU.
|
||||
*/
|
||||
public void updateState(Cpu cpu) {
|
||||
public void updateState() {
|
||||
Cpu cpu = machine.getCpu();
|
||||
Cpu.CpuState cpuState = cpu.getCpuState();
|
||||
|
||||
// Update the Processor Status Flag display
|
||||
int status = cpu.getCpuState().getStatusFlag();
|
||||
int status = cpuState.getStatusFlag();
|
||||
|
||||
carryFlagLabel.setIcon(iconForFlag(status, 0));
|
||||
zeroFlagLabel.setIcon(iconForFlag(status, 1));
|
||||
|
@ -313,10 +392,10 @@ public class StatusPanel extends JPanel {
|
|||
return label;
|
||||
}
|
||||
|
||||
private JTextField makeTextField(Dimension size) {
|
||||
private JTextField makeTextField(Dimension size, boolean editable) {
|
||||
JTextField textField = new JTextField("");
|
||||
textField.setAlignmentX(LEFT_ALIGNMENT);
|
||||
textField.setEditable(false);
|
||||
textField.setEditable(editable);
|
||||
textField.setMinimumSize(size);
|
||||
textField.setMaximumSize(size);
|
||||
textField.setPreferredSize(size);
|
||||
|
@ -324,4 +403,8 @@ public class StatusPanel extends JPanel {
|
|||
return textField;
|
||||
}
|
||||
|
||||
private int getHexVal(JTextField source) throws NumberFormatException {
|
||||
String val = source.getText().replaceAll("[^0-9a-fA-F]", "");
|
||||
return Integer.parseInt(val, 16);
|
||||
}
|
||||
}
|
||||
|
|
Before Width: | Height: | Size: 191 B After Width: | Height: | Size: 191 B |
Before Width: | Height: | Size: 191 B After Width: | Height: | Size: 191 B |
Before Width: | Height: | Size: 196 B After Width: | Height: | Size: 196 B |
Before Width: | Height: | Size: 196 B After Width: | Height: | Size: 196 B |
Before Width: | Height: | Size: 192 B After Width: | Height: | Size: 192 B |
Before Width: | Height: | Size: 192 B After Width: | Height: | Size: 192 B |
Before Width: | Height: | Size: 183 B After Width: | Height: | Size: 183 B |
Before Width: | Height: | Size: 183 B After Width: | Height: | Size: 183 B |
Before Width: | Height: | Size: 198 B After Width: | Height: | Size: 198 B |
Before Width: | Height: | Size: 198 B After Width: | Height: | Size: 198 B |
Before Width: | Height: | Size: 192 B After Width: | Height: | Size: 192 B |
Before Width: | Height: | Size: 192 B After Width: | Height: | Size: 192 B |
Before Width: | Height: | Size: 198 B After Width: | Height: | Size: 198 B |
Before Width: | Height: | Size: 198 B After Width: | Height: | Size: 198 B |