mirror of
https://github.com/sethm/symon.git
synced 2025-04-12 23:37:07 +00:00
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:
parent
a7d9239ef1
commit
38a4458aff
51
README.md
51
README.md
@ -47,20 +47,33 @@ Maven will build Symon, run unit tests, and produce a jar file in the
|
||||
Symon is meant to be invoked directly from the jar file. To run with
|
||||
Java 1.5 or greater, just type:
|
||||
|
||||
$ java -jar symon-0.6-jar-with-dependencies.jar
|
||||
$ java -jar symon-0.6-snapshot.jar
|
||||
|
||||
When Symon is running, you should be presented with a simple graphical
|
||||
interface.
|
||||
|
||||
### 3.2 ROM images
|
||||
|
||||
### 3.2 Loading A Program
|
||||
The simulator requires a 16KB ROM image loaded at address $C000 to $FFFF to
|
||||
work properly. Without a ROM in memory, the simulator will not be able to
|
||||
reset, since the reset vector for the 6502 is located in this address space.
|
||||
|
||||
Programs in the form of raw binary object files can be loaded directly
|
||||
into memory with the "Load" button.
|
||||
By default, any 16KB file named 'rom.bin' that exists in the same directory
|
||||
where Symon is launched will be loaded as a ROM image. ROM images can also
|
||||
be swapped out at run-time with the "Load ROM Image..." in the File menu.
|
||||
|
||||
Right now, all programs are loaded starting at addres $0300. After
|
||||
loading, the simulated CPU's reset vector is loaded with the values
|
||||
$00, $03, and the CPU is reset.
|
||||
The "samples" directory contains a ROM image named 'ehbasic.rom', containing
|
||||
Lee Davison's Enhanced 6502 BASIC. This serves as a good starting point for
|
||||
exploration.
|
||||
|
||||
### 3.3 Loading A Program
|
||||
|
||||
In addition to ROM images, programs in the form of raw binary object files can
|
||||
be loaded directly into memory from "Load Program..." in the File menu.
|
||||
|
||||
Programs are loaded starting at addres $0300. After loading the program, the
|
||||
simulated CPU's reset vector is loaded with the values $00, $03, and the CPU is
|
||||
reset.
|
||||
|
||||
There are two very simple sample program in the "samples" directory,
|
||||
for testing.
|
||||
@ -69,33 +82,23 @@ for testing.
|
||||
|
||||
- 'hello.prg' will continuously print "Hello, 6502 World!" to the console.
|
||||
|
||||
The sample directory also contains a ROM image of Lee Davison's
|
||||
Ehanced 6502 BASIC. For instructions on loading the rom, please see
|
||||
the README file in that directory.
|
||||
|
||||
### 3.3 ROM files
|
||||
|
||||
Any 12KB file named 'rom.bin' that exists in the same directory where
|
||||
Symon is launched will be loaded at address $d000. If the file is
|
||||
larger than 12KB, loading will fail. This functionality will be
|
||||
improved in a future release!
|
||||
|
||||
### 3.4 Running
|
||||
|
||||
After loading a program or ROM image, clicking "Run" will start the simulator
|
||||
running at address $0300.
|
||||
|
||||
running.
|
||||
|
||||
## 4.0 To Do
|
||||
|
||||
- Feedback (in the form of dialogs, status bar, etc).
|
||||
|
||||
- Better ROM image handling
|
||||
|
||||
- Better debugging tools from the UI, including memory inspection,
|
||||
disassembly, breakpoints, and execution tracing.
|
||||
|
||||
- Better ROM loading (and re-loading)
|
||||
|
||||
- More accurate timing.
|
||||
|
||||
- Interrupt handling!
|
||||
- Smarter interrupt handling.
|
||||
|
||||
- UI needs a ton more polish.
|
||||
|
||||
@ -109,8 +112,6 @@ running at address $0300.
|
||||
|
||||
- Implement CMOS 65C02 instructions and NMOS / CMOS mode flag.
|
||||
|
||||
- Allow a flag to disable breaking to monitor on BRK.
|
||||
|
||||
- Allow displaying ACIA status and dumping ACIA buffers, for
|
||||
debugging.
|
||||
|
||||
|
2
pom.xml
2
pom.xml
@ -44,7 +44,7 @@
|
||||
<dependency>
|
||||
<groupId>com.grahamedgecombe.jterminal</groupId>
|
||||
<artifactId>jterminal</artifactId>
|
||||
<version>1.0.2.1-loomcom</version>
|
||||
<version>1.0.2.2-loomcom</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
;;
|
||||
|
||||
|
||||
.alias iobase $8000
|
||||
.alias iobase $8800
|
||||
.alias iostatus [iobase + 1]
|
||||
.alias iocmd [iobase + 2]
|
||||
.alias ioctrl [iobase + 3]
|
||||
@ -11,7 +11,7 @@
|
||||
.org $0300
|
||||
|
||||
start: cli
|
||||
lda #$09
|
||||
lda #$0b
|
||||
sta iocmd ; Set command status
|
||||
lda #$1a
|
||||
sta ioctrl ; 0 stop bits, 8 bit word, 2400 baud
|
||||
|
BIN
samples/echo.prg
BIN
samples/echo.prg
Binary file not shown.
Binary file not shown.
@ -37,10 +37,12 @@ RES_vec
|
||||
|
||||
; Initialize the ACIA
|
||||
ACIA_init
|
||||
LDA #$09
|
||||
STA ACIAcommand
|
||||
LDA #$1A ; Set output for 8-N-1 2400
|
||||
STA ACIAcontrol
|
||||
LDA #$00
|
||||
STA ACIAstatus ; Soft reset
|
||||
LDA #$0B
|
||||
STA ACIAcommand ; Parity disabled, IRQ disabled
|
||||
LDA #$1E
|
||||
STA ACIAcontrol ; Set output for 8-N-1 9600
|
||||
|
||||
; set up vectors and interrupt code, copy them to page 2
|
||||
|
||||
@ -77,25 +79,33 @@ LAB_nokey
|
||||
LAB_dowarm
|
||||
JMP LAB_WARM ; do EhBASIC warm start
|
||||
|
||||
; byte out to simulated ACIA
|
||||
; byte out to ACIA
|
||||
ACIAout
|
||||
PHA ; save accumulator
|
||||
ACIAout_w
|
||||
@loop
|
||||
LDA ACIAstatus ; Read 6551 status
|
||||
AND #$10 ; Is tx buffer full?
|
||||
BEQ ACIAout_w ; if not, loop back
|
||||
BEQ @loop ; if not, loop back
|
||||
PLA ; Otherwise, restore accumulator
|
||||
STA ACIAdata ; write byte to 6551
|
||||
RTS
|
||||
|
||||
; byte in from simulated ACIA
|
||||
|
||||
;
|
||||
; byte in from ACIA. This subroutine will also force
|
||||
; all lowercase letters to be uppercase.
|
||||
;
|
||||
ACIAin
|
||||
LDA ACIAstatus ; Read 6551 status
|
||||
AND #$08 ;
|
||||
BEQ LAB_nobyw ; If rx buffer empty, no byte
|
||||
|
||||
LDA ACIAdata ; Read byte from 6551
|
||||
CMP #'a' ; Is it < 'a'?
|
||||
BCC @done ; Yes, we're done
|
||||
CMP #'{' ; Is it >= '{'?
|
||||
BCS @done ; Yes, we're done
|
||||
AND #$5f ; Otherwise, mask to uppercase
|
||||
@done
|
||||
SEC ; Flag byte received
|
||||
RTS
|
||||
|
||||
@ -137,16 +147,19 @@ NMI_CODE
|
||||
|
||||
END_CODE
|
||||
|
||||
; sign on string
|
||||
|
||||
LAB_mess
|
||||
.byte $0D,$0A,"6502 EhBASIC [C]old/[W]arm ?",$00
|
||||
; sign on string
|
||||
.byte $0D,$0A,"Symon 6502 SBC (c) 2012, Seth Morabito"
|
||||
.byte $0D,$0A,"[C]old/[W]arm ?",$00
|
||||
|
||||
|
||||
; system vectors
|
||||
|
||||
.segment "VECTORS"
|
||||
.org $FFFA
|
||||
|
||||
.word 0 ; NMI vector
|
||||
.word NMI_vec ; NMI vector
|
||||
.word RES_vec ; RESET vector
|
||||
.word 0 ; IRQ vector
|
||||
.word IRQ_vec ; IRQ vector
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
;;
|
||||
|
||||
|
||||
.alias iobase $8000
|
||||
.alias iobase $8800
|
||||
.alias iostatus [iobase + 1]
|
||||
.alias iocmd [iobase + 2]
|
||||
.alias ioctrl [iobase + 3]
|
||||
@ -11,7 +11,7 @@
|
||||
.org $0300
|
||||
|
||||
start: cli
|
||||
lda #$09
|
||||
lda #$0b
|
||||
sta iocmd ; Set command status
|
||||
lda #$1a
|
||||
sta ioctrl ; 0 stop bits, 8 bit word, 2400 baud
|
||||
|
Binary file not shown.
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user