New UI layout, ROM loading, Font selection

- The UI layout has changed, and will likely change again in the future.

- Symon can now re-load ROM images from the File menu, under "Load ROM..."

- Font size can be changed under the "View" menu
This commit is contained in:
Seth Morabito committed 2012-12-05 23:19:34 -08:00
1 parent a7d9239ef1
commit 38a4458aff
14 files changed
+449 -310

No files matched your search

@@ -6,17 +6,17 @@ public interface Preferences {
public static final int DEFAULT_PROGRAM_LOAD_ADDRESS = 0x0300;
public static final int DEFAULT_ACIA_ADDRESS = 0xc000;
public static final int DEFAULT_BORDER_WIDTH = 10;
public static final boolean DEFAULT_HALT_ON_BREAK = true;
public JDialog getDialog();
public int getProgramStartAddress();
public int getAciaAddress();
public int getBorderWidth();
public boolean getHaltOnBreak();
public void updateUi();
}
+289 -204
View File
@@ -33,9 +33,9 @@ import com.loomcom.symon.exceptions.SymonException;
import com.loomcom.symon.ui.Console;
import com.loomcom.symon.ui.PreferencesDialog;
import com.loomcom.symon.ui.StatusPanel;
import sun.rmi.rmic.iiop.DirectoryLoader;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
@@ -55,7 +55,7 @@ import java.util.logging.Logger;
* with a basic 80x25 character display.
*
*/
public class Simulator implements ActionListener, Observer {
public class Simulator implements Observer {
// Constants used by the simulated system. These define the memory map.
private static final int BUS_BOTTOM = 0x0000;
@@ -75,6 +75,9 @@ public class Simulator implements ActionListener, Observer {
private static final int ROM_BASE = 0xC000;
private static final int ROM_SIZE = 0x4000;
private static final int DEFAULT_FONT_SIZE = 12;
private static final Font DEFAULT_FONT = new Font(Font.MONOSPACED, Font.PLAIN, DEFAULT_FONT_SIZE);
// Since it is very expensive to update the UI with Swing's Event Dispatch Thread, we can't afford
// to refresh the view on every simulated clock cycle. Instead, we will only refresh the view after this
// number of steps when running normally.
@@ -100,25 +103,37 @@ public class Simulator implements ActionListener, Observer {
// requested
private int stepsSinceLastUpdate = 0;
private JFrame mainWindow;
private RunLoop runLoop;
private Console console;
private StatusPanel statusPane;
/**
* The Main Window is the primary control point for the simulator.
* It is in charge of the menu, and sub-windows. It also shows the
* CPU status at all times.
*/
private JFrame mainWindow;
private JButton runStopButton;
private JButton stepButton;
private JButton resetButton;
/**
* The Console Window is connected to the ACIA's TX and RX lines.
*/
private JFrame consoleWindow;
// The most recently read key code
private char keyBuffer;
/**
* The Trace Window shows the most recent 50,000 CPU states.
*/
private JFrame traceWindow;
// TODO: loadProgramItem seriously violates encapsulation!
// A far better solution would be to extend JMenu and add callback
// methods to enable and disable menus as required.
/**
* The Zero Page Window shows the contents of page 0.
*/
private JFrame zeroPageWindow;
// Menu Items
private JMenuItem loadProgramItem;
private JMenuItem loadRomItem;
private SimulatorMenu menuBar;
private RunLoop runLoop;
private Console console;
private StatusPanel statusPane;
private JButton runStopButton;
private JButton stepButton;
private JButton resetButton;
private JFileChooser fileChooser;
private PreferencesDialog preferences;
@@ -154,10 +169,11 @@ public class Simulator implements ActionListener, Observer {
mainWindow.getContentPane().setLayout(new BorderLayout());
// The Menu
mainWindow.setJMenuBar(createMenuBar());
menuBar = new SimulatorMenu();
mainWindow.setJMenuBar(menuBar);
// UI components used for I/O.
this.console = new com.loomcom.symon.ui.Console();
this.console = new com.loomcom.symon.ui.Console(80, 25, DEFAULT_FONT);
this.statusPane = new StatusPanel();
// File Chooser
@@ -166,15 +182,11 @@ public class Simulator implements ActionListener, Observer {
preferences.addObserver(this);
// Panel for Console and Buttons
JPanel controlsContainer = new JPanel();
JPanel consoleContainer = new JPanel();
JPanel buttonContainer = new JPanel();
Dimension buttonPanelSize = new Dimension(console.getWidth(), 36);
buttonContainer.setMinimumSize(buttonPanelSize);
buttonContainer.setMaximumSize(buttonPanelSize);
buttonContainer.setPreferredSize(buttonPanelSize);
controlsContainer.setLayout(new BorderLayout());
consoleContainer.setLayout(new BorderLayout());
consoleContainer.setBorder(new EmptyBorder(10, 10, 10, 0));
buttonContainer.setLayout(new FlowLayout());
runStopButton = new JButton("Run");
@@ -186,8 +198,8 @@ public class Simulator implements ActionListener, Observer {
buttonContainer.add(resetButton);
// Left side - console
controlsContainer.add(console, BorderLayout.PAGE_START);
mainWindow.getContentPane().add(controlsContainer, BorderLayout.LINE_START);
consoleContainer.add(console, BorderLayout.CENTER);
mainWindow.getContentPane().add(consoleContainer, BorderLayout.LINE_START);
// Right side - status pane
mainWindow.getContentPane().add(statusPane, BorderLayout.LINE_END);
@@ -195,9 +207,27 @@ public class Simulator implements ActionListener, Observer {
// Bottom - buttons.
mainWindow.getContentPane().add(buttonContainer, BorderLayout.PAGE_END);
runStopButton.addActionListener(this);
stepButton.addActionListener(this);
resetButton.addActionListener(this);
runStopButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
if (runLoop != null && runLoop.isRunning()) {
handleStop();
} else {
handleStart();
}
}
});
stepButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
handleStep();
}
});
resetButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
handleReset();
}
});
mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
@@ -207,78 +237,6 @@ public class Simulator implements ActionListener, Observer {
mainWindow.setVisible(true);
}
private JMenuBar createMenuBar() {
JMenuBar menuBar = new JMenuBar();
JMenu fileMenu = new JMenu("File");
menuBar.add(fileMenu);
loadProgramItem = new JMenuItem("Load Program");
loadProgramItem.setMnemonic(KeyEvent.VK_L);
loadRomItem = new JMenuItem("Load ROM...");
loadRomItem.setMnemonic(KeyEvent.VK_R);
JMenuItem prefsItem = new JMenuItem("Preferences...");
prefsItem.setMnemonic(KeyEvent.VK_P);
JMenuItem quitItem = new JMenuItem("Quit");
quitItem.setMnemonic(KeyEvent.VK_Q);
loadProgramItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
handleProgramLoad();
}
});
loadRomItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
handleRomLoad();
}
});
prefsItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
showAndUpdatePreferences();
}
});
quitItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
handleQuit();
}
});
fileMenu.add(loadProgramItem);
fileMenu.add(loadRomItem);
fileMenu.add(prefsItem);
fileMenu.add(quitItem);
return menuBar;
}
public void showAndUpdatePreferences() {
preferences.getDialog().setVisible(true);
}
/**
* Receive an ActionEvent from the UI, and act on it.
*/
public void actionPerformed(ActionEvent actionEvent) {
if (actionEvent.getSource() == resetButton) {
coldReset();
} else if (actionEvent.getSource() == stepButton) {
handleStep();
} else if (actionEvent.getSource() == runStopButton) {
if (runLoop != null && runLoop.isRunning()) {
handleStop();
} else {
handleStart();
}
}
}
private void handleStart() {
// Shift focus to the console.
console.requestFocus();
@@ -311,85 +269,10 @@ public class Simulator implements ActionListener, Observer {
// TODO: Update memory window, if frame is visible.
}
// TODO: Alert user of errors.
private void handleRomLoad() {
try {
int retVal = fileChooser.showOpenDialog(mainWindow);
if (retVal == JFileChooser.APPROVE_OPTION) {
File romFile = fileChooser.getSelectedFile();
if (romFile.canRead()) {
long fileSize = romFile.length();
if (fileSize != ROM_SIZE) {
throw new IOException("ROM file must be exactly " + String.valueOf(fileSize) + " bytes.");
} else {
if (rom != null) {
// Unload the existing ROM image.
bus.removeDevice(rom);
}
// Load the new ROM image
rom = Memory.makeROM(ROM_BASE, ROM_SIZE, romFile);
bus.addDevice(rom);
logger.log(Level.INFO, "ROM File `" + romFile.getName() + "' loaded at " +
String.format("0x%04X", ROM_BASE));
}
}
}
} catch (IOException ex) {
logger.log(Level.SEVERE, "Unable to read file: " + ex.getMessage());
ex.printStackTrace();
} catch (MemoryRangeException ex) {
logger.log(Level.SEVERE, "Memory range error loading ROM");
ex.printStackTrace();
}
}
/**
* Display a file chooser prompting the user to load a binary program.
* After the user selects a file, read it in starting at PROGRAM_START_ADDRESS.
/*
* Perform a reset.
*/
private void handleProgramLoad() {
try {
int retVal = fileChooser.showOpenDialog(mainWindow);
if (retVal == JFileChooser.APPROVE_OPTION) {
File f = fileChooser.getSelectedFile();
if (f.canRead()) {
long fileSize = f.length();
if (fileSize > MEMORY_SIZE) {
throw new IOException("Program will not fit in available memory.");
} else {
byte[] program = new byte[(int) fileSize];
int i = 0;
FileInputStream fis = new FileInputStream(f);
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis);
while (dis.available() != 0) {
program[i++] = dis.readByte();
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
console.reset();
}
});
// Now load the program at the starting address.
loadProgram(program, preferences.getProgramStartAddress());
}
}
}
} catch (IOException ex) {
logger.log(Level.SEVERE, "Unable to read file: " + ex.getMessage());
ex.printStackTrace();
} catch (MemoryAccessException ex) {
logger.log(Level.SEVERE, "Memory access error loading program");
ex.printStackTrace();
}
}
private void coldReset() {
private void handleReset() {
if (runLoop != null && runLoop.isRunning()) {
runLoop.requestStop();
runLoop.interrupt();
@@ -412,7 +295,6 @@ public class Simulator implements ActionListener, Observer {
});
} catch (MemoryAccessException ex) {
logger.log(Level.SEVERE, "Exception during simulator reset: " + ex.getMessage());
ex.printStackTrace();
}
}
@@ -429,17 +311,6 @@ public class Simulator implements ActionListener, Observer {
}
}
/**
* Handle a request to quit.
*/
private void handleQuit() {
if (runLoop != null && runLoop.isRunning()) {
runLoop.requestStop();
runLoop.interrupt();
}
System.exit(0);
}
/**
* Perform a single step of the simulated system.
*/
@@ -516,7 +387,7 @@ public class Simulator implements ActionListener, Observer {
Simulator simulator = new Simulator();
simulator.createAndShowUi();
// Reset the simulator.
simulator.coldReset();
simulator.handleReset();
} catch (Exception e) {
e.printStackTrace();
}
@@ -533,8 +404,6 @@ public class Simulator implements ActionListener, Observer {
public void update(Observable observable, Object o) {
// Instance equality should work here, there is only one instance.
if (observable == preferences) {
// TODO: Update ACIA base address if it has changed.
int oldBorderWidth = console.getBorderWidth();
if (oldBorderWidth != preferences.getBorderWidth()) {
// Resize the main window if the border width has changed.
@@ -544,7 +413,6 @@ public class Simulator implements ActionListener, Observer {
}
}
/**
* The main run thread.
*/
@@ -569,16 +437,14 @@ public class Simulator implements ActionListener, Observer {
console.startListening();
// Don't allow step while the simulator is running
stepButton.setEnabled(false);
loadProgramItem.setEnabled(false);
loadRomItem.setEnabled(false);
menuBar.simulatorDidStart();
// Toggle the state of the run button
runStopButton.setText("Stop");
}
});
try {
// TODO: Interrupts - both software and hardware. i.e., jump to address stored in FFFE/FFFF on BRK.
while (isRunning && !cpu.getBreakFlag()) {
while (isRunning && !(preferences.getHaltOnBreak() && cpu.getBreakFlag())) {
step();
}
} catch (SymonException ex) {
@@ -591,16 +457,235 @@ public class Simulator implements ActionListener, Observer {
console.stopListening();
// Allow step while the simulator is stopped
stepButton.setEnabled(true);
loadProgramItem.setEnabled(true);
loadRomItem.setEnabled(true);
menuBar.simulatorDidStop();
runStopButton.setText("Run");
// Now update the state
statusPane.updateState(cpu);
}
});
logger.log(Level.INFO, "Exiting main run loop. BREAK=" + cpu.getBreakBit() + "; RUN_FLAG=" + isRunning);
isRunning = false;
}
}
class LoadProgramAction extends AbstractAction {
public LoadProgramAction() {
super("Load Program...", null);
putValue(SHORT_DESCRIPTION, "Load a program into memory");
putValue(MNEMONIC_KEY, KeyEvent.VK_L);
}
public void actionPerformed(ActionEvent actionEvent) {
// TODO: Error dialogs on failure.
try {
int retVal = fileChooser.showOpenDialog(mainWindow);
if (retVal == JFileChooser.APPROVE_OPTION) {
File f = fileChooser.getSelectedFile();
if (f.canRead()) {
long fileSize = f.length();
if (fileSize > MEMORY_SIZE) {
throw new IOException("Program will not fit in available memory.");
} else {
byte[] program = new byte[(int) fileSize];
int i = 0;
FileInputStream fis = new FileInputStream(f);
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis);
while (dis.available() != 0) {
program[i++] = dis.readByte();
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
console.reset();
}
});
// Now load the program at the starting address.
loadProgram(program, preferences.getProgramStartAddress());
}
}
}
} catch (IOException ex) {
logger.log(Level.SEVERE, "Unable to read program file: " + ex.getMessage());
} catch (MemoryAccessException ex) {
logger.log(Level.SEVERE, "Memory access error loading program: " + ex.getMessage());
}
}
}
class LoadRomAction extends AbstractAction {
public LoadRomAction() {
super("Load ROM...", null);
putValue(SHORT_DESCRIPTION, "Load a ROM image");
putValue(MNEMONIC_KEY, KeyEvent.VK_R);
}
public void actionPerformed(ActionEvent actionEvent) {
// TODO: Error dialogs on failure.
try {
int retVal = fileChooser.showOpenDialog(mainWindow);
if (retVal == JFileChooser.APPROVE_OPTION) {
File romFile = fileChooser.getSelectedFile();
if (romFile.canRead()) {
long fileSize = romFile.length();
if (fileSize != ROM_SIZE) {
throw new IOException("ROM file must be exactly " + String.valueOf(ROM_SIZE) + " bytes.");
} else {
if (rom != null) {
// Unload the existing ROM image.
bus.removeDevice(rom);
}
// Load the new ROM image
rom = Memory.makeROM(ROM_BASE, ROM_SIZE, romFile);
bus.addDevice(rom);
// Now, reset
cpu.reset();
logger.log(Level.INFO, "ROM File `" + romFile.getName() + "' loaded at " +
String.format("0x%04X", ROM_BASE));
}
}
}
} catch (IOException ex) {
logger.log(Level.SEVERE, "Unable to read ROM file: " + ex.getMessage());
} catch (MemoryRangeException ex) {
logger.log(Level.SEVERE, "Memory range error while loading ROM file: " + ex.getMessage());
} catch (MemoryAccessException ex) {
logger.log(Level.SEVERE, "Memory access error while loading ROM file: " + ex.getMessage());
}
}
}
class ShowPrefsAction extends AbstractAction {
public ShowPrefsAction() {
super("Preferences...", null);
putValue(SHORT_DESCRIPTION, "Show Preferences Dialog");
putValue(MNEMONIC_KEY, KeyEvent.VK_P);
}
public void actionPerformed(ActionEvent actionEvent) {
preferences.getDialog().setVisible(true);
}
}
class QuitAction extends AbstractAction {
public QuitAction() {
super("Quit", null);
putValue(SHORT_DESCRIPTION, "Exit the Simulator");
putValue(MNEMONIC_KEY, KeyEvent.VK_Q);
}
public void actionPerformed(ActionEvent actionEvent) {
if (runLoop != null && runLoop.isRunning()) {
runLoop.requestStop();
runLoop.interrupt();
}
System.exit(0);
}
}
class SetFontAction extends AbstractAction {
private int size;
public SetFontAction(int size) {
super(Integer.toString(size) + " pt", null);
this.size = size;
putValue(SHORT_DESCRIPTION, "Set font to " + Integer.toString(size) + "pt.");
}
public void actionPerformed(ActionEvent actionEvent) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
console.setFont(new Font("Monospaced", Font.PLAIN, size));
mainWindow.pack();
}
});
}
}
class SimulatorMenu extends JMenuBar {
// Menu Items
private JMenuItem loadProgramItem;
private JMenuItem loadRomItem;
/**
* Create a new SimulatorMenu instance.
*/
public SimulatorMenu() {
initMenu();
}
/**
* Disable menu items that should not be available during simulator execution.
*/
public void simulatorDidStart() {
loadProgramItem.setEnabled(false);
loadRomItem.setEnabled(false);
}
/**
* Enable menu items that should be available while the simulator is stopped.
*/
public void simulatorDidStop() {
loadProgramItem.setEnabled(true);
loadRomItem.setEnabled(true);
}
private void initMenu() {
/*
* File Menu
*/
JMenu fileMenu = new JMenu("File");
loadProgramItem = new JMenuItem(new LoadProgramAction());
loadRomItem = new JMenuItem(new LoadRomAction());
JMenuItem prefsItem = new JMenuItem(new ShowPrefsAction());
JMenuItem quitItem = new JMenuItem(new QuitAction());
fileMenu.add(loadProgramItem);
fileMenu.add(loadRomItem);
fileMenu.add(prefsItem);
fileMenu.add(quitItem);
add(fileMenu);
/*
* View Menu
*/
JMenu viewMenu = new JMenu("View");
JMenu fontSubMenu = new JMenu("Font Size");
ButtonGroup group = new ButtonGroup();
makeFontSizeMenuItem(10, fontSubMenu, group);
makeFontSizeMenuItem(11, fontSubMenu, group);
makeFontSizeMenuItem(12, fontSubMenu, group);
makeFontSizeMenuItem(13, fontSubMenu, group);
makeFontSizeMenuItem(14, fontSubMenu, group);
makeFontSizeMenuItem(15, fontSubMenu, group);
makeFontSizeMenuItem(16, fontSubMenu, group);
makeFontSizeMenuItem(17, fontSubMenu, group);
makeFontSizeMenuItem(18, fontSubMenu, group);
makeFontSizeMenuItem(19, fontSubMenu, group);
makeFontSizeMenuItem(20, fontSubMenu, group);
viewMenu.add(fontSubMenu);
add(viewMenu);
}
private void makeFontSizeMenuItem(int size, JMenu fontSubMenu, ButtonGroup group) {
Action action = new SetFontAction(size);
JRadioButtonMenuItem item = new JRadioButtonMenuItem(action);
item.setSelected(size == DEFAULT_FONT_SIZE);
fontSubMenu.add(item);
group.add(item);
}
}
}
@@ -170,8 +170,8 @@ public class Acia extends Device {
*/
private long calculateBaudRateDelay() {
if (baudRate > 0) {
// This is a pretty rough approximation based on 8 bits per character,
// and 1/baudRate per bit.
// TODO: This is a pretty rough approximation based on 8 bits per character,
// and 1/baudRate per bit. It could certainly be improved
return (long)((1.0 / baudRate) * 1000000000 * 8);
} else {
return 0;
@@ -1,5 +1,6 @@
package com.loomcom.symon.ui;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
@@ -36,12 +37,8 @@ public class Console extends JTerminal implements KeyListener, MouseListener {
private FifoRingBuffer<Character> typeAheadBuffer;
public Console() {
this(DEFAULT_COLUMNS, DEFAULT_ROWS);
}
public Console(int columns, int rows) {
super(new Vt100TerminalModel(columns, rows));
public Console(int columns, int rows, Font font) {
super(new Vt100TerminalModel(columns, rows), font);
// A small type-ahead buffer, as might be found in any real
// VT100-style serial terminal.
this.typeAheadBuffer = new FifoRingBuffer<Character>(128);
@@ -12,13 +12,13 @@ public class PreferencesDialog extends Observable implements Preferences {
private final JDialog dialog;
private JTextField aciaAddressField;
private JCheckBox haltOnBreakCheckBox;
private JTextField programLoadAddressField;
private JTextField borderWidthField;
private int programLoadAddress = DEFAULT_PROGRAM_LOAD_ADDRESS;
private int aciaAddress = DEFAULT_ACIA_ADDRESS;
private int borderWidth = DEFAULT_BORDER_WIDTH;
private boolean haltOnBreak = DEFAULT_HALT_ON_BREAK;
public PreferencesDialog(Frame parent, boolean modal) {
this.dialog = new JDialog(parent, modal);
@@ -43,15 +43,14 @@ public class PreferencesDialog extends Observable implements Preferences {
GridBagLayout layout = new GridBagLayout();
settingsContainer.setLayout(layout);
final JLabel aciaAddressLabel = new JLabel("ACIA Address");
final JLabel haltOnBreakLabel = new JLabel("Halt on BRK");
final JLabel programLoadAddressLabel = new JLabel("Program Load Address");
final JLabel borderWidthLabel = new JLabel("Console Border Width");
aciaAddressField = new JTextField(8);
haltOnBreakCheckBox = new JCheckBox();
programLoadAddressField = new JTextField(8);
borderWidthField = new JTextField(8);
aciaAddressLabel.setLabelFor(aciaAddressField);
programLoadAddressLabel.setLabelFor(programLoadAddressField);
borderWidthLabel.setLabelFor(borderWidthField);
@@ -61,11 +60,10 @@ public class PreferencesDialog extends Observable implements Preferences {
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.gridx = 0;
constraints.gridy = 0;
settingsContainer.add(aciaAddressLabel, constraints);
settingsContainer.add(haltOnBreakLabel, constraints);
constraints.gridx = 1;
settingsContainer.add(aciaAddressField, constraints);
settingsContainer.add(haltOnBreakCheckBox, constraints);
constraints.gridy = 1;
constraints.gridx = 0;
@@ -94,8 +92,8 @@ public class PreferencesDialog extends Observable implements Preferences {
applyButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
haltOnBreak = haltOnBreakCheckBox.isSelected();
programLoadAddress = hexToInt(programLoadAddressField.getText());
aciaAddress = hexToInt(aciaAddressField.getText());
borderWidth = Integer.parseInt(borderWidthField.getText());
updateUi();
// TODO: Actually check to see if values have changed, don't assume.
@@ -118,10 +116,6 @@ public class PreferencesDialog extends Observable implements Preferences {
return programLoadAddress;
}
public int getAciaAddress() {
return aciaAddress;
}
/**
* @return The width of the console border, in pixels.
*/
@@ -129,8 +123,15 @@ public class PreferencesDialog extends Observable implements Preferences {
return borderWidth;
}
/**
* @return True if 'halt on break' is desired, false otherwise.
*/
public boolean getHaltOnBreak() {
return haltOnBreak;
}
public void updateUi() {
aciaAddressField.setText(intToHex(aciaAddress));
haltOnBreakCheckBox.setSelected(haltOnBreak);
programLoadAddressField.setText(intToHex(programLoadAddress));
borderWidthField.setText(Integer.toString(borderWidth));
}
@@ -26,6 +26,7 @@ public class StatusPanel extends JPanel {
private final ImageIcon negativeOn;
private final ImageIcon negativeOff;
private final JLabel statusFlagsLabel;
private final JLabel carryFlagLabel;
private final JLabel zeroFlagLabel;
private final JLabel irqDisableFlagLabel;
@@ -40,7 +41,6 @@ public class StatusPanel extends JPanel {
private JTextField aField;
private JTextField xField;
private JTextField yField;
// private JTextField stepCountField;
private final JLabel opcodeLabel;
private final JLabel pcLabel;
@@ -48,11 +48,10 @@ public class StatusPanel extends JPanel {
private final JLabel aLabel;
private final JLabel xLabel;
private final JLabel yLabel;
// private final JLabel stepCountLabel;
private static final int EMPTY_BORDER = 5;
private static final Border LABEL_BORDER = BorderFactory.createEmptyBorder(0, 4, 0, 0);
private static final Font LABEL_FONT = new Font("sansserif", Font.PLAIN, 11);
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);
public StatusPanel() {
super();
@@ -63,7 +62,10 @@ public class StatusPanel extends JPanel {
setBorder(BorderFactory.createCompoundBorder(emptyBorder, etchedBorder));
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
GridBagLayout layout = new GridBagLayout();
GridBagConstraints constraints = new GridBagConstraints();
setLayout(layout);
JPanel statusFlagsPanel = new JPanel();
statusFlagsPanel.setAlignmentX(LEFT_ALIGNMENT);
@@ -101,37 +103,72 @@ public class StatusPanel extends JPanel {
statusFlagsPanel.add(carryFlagLabel);
// Create and add register and address labels
opcodeLabel = makeLabel("Instruction");
pcLabel = makeLabel("Program Counter");
spLabel = makeLabel("Stack Pointer");
aLabel = makeLabel("Accumulator");
xLabel = makeLabel("X Register");
yLabel = makeLabel("Y Register");
// stepCountLabel = new JLabel("Steps");
statusFlagsLabel = makeLabel("Flags");
opcodeLabel = makeLabel("IR");
pcLabel = makeLabel("PC");
spLabel = makeLabel("SP");
aLabel = makeLabel("A");
xLabel = makeLabel("X");
yLabel = makeLabel("Y");
opcodeField = makeTextField();
pcField = makeTextField();
spField = makeTextField();
aField = makeTextField();
xField = makeTextField();
yField = makeTextField();
// stepCountField = new JTextField("");
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);
add(statusFlagsPanel);
add(opcodeLabel);
add(opcodeField);
add(pcLabel);
add(pcField);
add(spLabel);
add(spField);
add(aLabel);
add(aField);
add(xLabel);
add(xField);
add(yLabel);
add(yField);
// add(stepCountLabel);
// add(stepCountField);
constraints.anchor = GridBagConstraints.LINE_START;
constraints.gridwidth = 2;
constraints.gridx = 0;
constraints.gridy = 0;
add(statusFlagsLabel, constraints);
constraints.gridy = 1;
add(statusFlagsPanel, constraints);
constraints.insets = new Insets(5, 0, 0, 0);
constraints.gridy = 2;
add(opcodeLabel, constraints);
constraints.insets = new Insets(0, 0, 0, 0);
constraints.gridy = 3;
add(opcodeField, constraints);
constraints.insets = new Insets(5, 0, 0, 0);
constraints.gridy = 4;
add(pcLabel, constraints);
constraints.insets = new Insets(0, 0, 0, 0);
constraints.gridy = 5;
add(pcField, constraints);
constraints.insets = new Insets(5, 0, 0, 0);
constraints.gridwidth = 1;
constraints.gridy = 6;
add(spLabel, constraints);
constraints.gridx = 1;
add(aLabel, constraints);
constraints.insets = new Insets(0, 0, 0, 0);
constraints.gridx = 0;
constraints.gridy = 7;
add(spField, constraints);
constraints.gridx = 1;
add(aField, constraints);
constraints.insets = new Insets(5, 0, 0, 0);
constraints.gridx = 0;
constraints.gridy = 8;
add(yLabel, constraints);
constraints.gridx = 1;
add(xLabel, constraints);
constraints.insets = new Insets(0, 0, 5, 0);
constraints.gridx = 0;
constraints.gridy = 9;
add(xField, constraints);
constraints.gridx = 1;
add(yField, constraints);
}
/**
@@ -158,7 +195,6 @@ public class StatusPanel extends JPanel {
aField.setText(cpu.getAccumulatorStatus());
xField.setText(cpu.getXRegisterStatus());
yField.setText(cpu.getYRegisterStatus());
// stepCountField.setText(Long.toString(cpu.getStepCounter()));
repaint();
}
@@ -228,10 +264,16 @@ public class StatusPanel extends JPanel {
return label;
}
private JTextField makeTextField() {
private static final Dimension LARGE_TEXT_FIELD_SIZE = new Dimension(134, 22);
private static final Dimension SMALL_TEXT_FIELD_SIZE = new Dimension(65, 22);
private JTextField makeTextField(Dimension size) {
JTextField textField = new JTextField("");
textField.setAlignmentX(LEFT_ALIGNMENT);
textField.setEditable(false);
textField.setMinimumSize(size);
textField.setMaximumSize(size);
textField.setPreferredSize(size);
return textField;
}