Address IntelliJ warnings

This commit addresses a large number of IntelliJ warnings
that have been left hanging around for far too long.
This commit is contained in:
Seth Morabito committed 2025-02-13 16:05:42 -08:00
1 parent ecd4bbbd9a
commit c317544e7b
28 files changed
+148 -334

No files matched your search

@@ -9,8 +9,8 @@ import java.util.TreeSet;
public class Breakpoints extends AbstractTableModel { public class Breakpoints extends AbstractTableModel {
private TreeSet<Integer> breakpoints; private final TreeSet<Integer> breakpoints;
private Simulator simulator; private final Simulator simulator;
public Breakpoints(Simulator simulator) { public Breakpoints(Simulator simulator) {
this.breakpoints = new TreeSet<>(); this.breakpoints = new TreeSet<>();
@@ -26,11 +26,6 @@ public class Breakpoints extends AbstractTableModel {
fireTableDataChanged(); fireTableDataChanged();
} }
public void removeBreakpoint(int address) {
this.breakpoints.remove(address);
fireTableDataChanged();
}
public void removeBreakpointAtIndex(int index) { public void removeBreakpointAtIndex(int index) {
if (index < 0) { if (index < 0) {
return; return;
+10 -17
View File
@@ -42,19 +42,19 @@ import java.util.TreeSet;
public class Bus { public class Bus {
// The default address at which to load programs // The default address at which to load programs
public static int DEFAULT_LOAD_ADDRESS = 0x0200; public static final int DEFAULT_LOAD_ADDRESS = 0x0200;
// By default, our bus starts at 0, and goes up to 64K // By default, our bus starts at 0, and goes up to 64K
private int startAddress = 0x0000; private final int startAddress;
private int endAddress = 0xffff; private final int endAddress;
// The CPU // The CPU
private Cpu cpu; private Cpu cpu;
// Ordered sets of IO devices, associated with their priority // Ordered sets of IO devices, associated with their priority
private Map<Integer, SortedSet<Device>> deviceMap; private final Map<Integer, SortedSet<Device>> deviceMap;
// an array for quick lookup of adresses, brute-force style // an array for quick lookup of addresses, brute-force style
private Device[] deviceAddressArray; private Device[] deviceAddressArray;
@@ -94,8 +94,8 @@ public class Bus {
* Add a device to the bus. * Add a device to the bus.
* *
* @param device Device to add * @param device Device to add
* @param priority Bus prioirity. * @param priority Bus priority.
* @throws MemoryRangeException * @throws MemoryRangeException Invalid device address range.
*/ */
public void addDevice(Device device, int priority) throws MemoryRangeException { public void addDevice(Device device, int priority) throws MemoryRangeException {
@@ -109,12 +109,7 @@ public class Bus {
throw new MemoryRangeException("end address of device " + device.getName() + " does not fall within the address range of the bus"); throw new MemoryRangeException("end address of device " + device.getName() + " does not fall within the address range of the bus");
} }
SortedSet<Device> deviceSet = deviceMap.get(priority); SortedSet<Device> deviceSet = deviceMap.computeIfAbsent(priority, k -> new TreeSet<>());
if (deviceSet == null) {
deviceSet = new TreeSet<>();
deviceMap.put(priority, deviceSet);
}
device.setBus(this); device.setBus(this);
deviceSet.add(device); deviceSet.add(device);
@@ -125,7 +120,7 @@ public class Bus {
* Add a device to the bus. Throws a MemoryRangeException if the device overlaps with any others. * Add a device to the bus. Throws a MemoryRangeException if the device overlaps with any others.
* *
* @param device Device to add * @param device Device to add
* @throws MemoryRangeException * @throws MemoryRangeException Invalid device memory range.
*/ */
public void addDevice(Device device) throws MemoryRangeException { public void addDevice(Device device) throws MemoryRangeException {
addDevice(device, 0); addDevice(device, 0);
@@ -224,9 +219,7 @@ public class Bus {
for (int priority : priorities) { for (int priority : priorities) {
SortedSet<Device> deviceSet = deviceMap.get(priority); SortedSet<Device> deviceSet = deviceMap.get(priority);
for (Device device : deviceSet) { devices.addAll(deviceSet);
devices.add(device);
}
} }
return devices; return devices;
+4 -2
View File
@@ -158,6 +158,8 @@ public class Cpu implements InstructionTable {
* Performs an individual instruction cycle. * Performs an individual instruction cycle.
*/ */
public void step() throws MemoryAccessException { public void step() throws MemoryAccessException {
int hi, lo; // Address calculation
opBeginTime = System.nanoTime(); opBeginTime = System.nanoTime();
// Store the address from which the IR was read, for debugging // Store the address from which the IR was read, for debugging
@@ -317,8 +319,8 @@ public class Cpu implements InstructionTable {
break; break;
case 0x40: // RTI - Return from Interrupt - Implied case 0x40: // RTI - Return from Interrupt - Implied
setProcessorStatus(stackPop()); setProcessorStatus(stackPop());
int lo = stackPop(); lo = stackPop();
int hi = stackPop(); hi = stackPop();
setProgramCounter(Utils.address(lo, hi)); setProgramCounter(Utils.address(lo, hi));
break; break;
case 0x48: // PHA - Push Accumulator - Implied case 0x48: // PHA - Push Accumulator - Implied
@@ -28,23 +28,17 @@ public interface InstructionTable {
/** /**
* Enumeration of valid CPU behaviors. These determine what behavior and instruction * Enumeration of valid CPU behaviors. These determine what behavior and instruction
* set will be simulated, depending on desired version of 6502. * set will be simulated, depending on desired version of 6502.
*
* TODO: As of version 0.6, this is still not used! All CPUs are "idealized" NMOS 6502 only.
*/ */
enum CpuBehavior { enum CpuBehavior {
/** /**
* The earliest NMOS 6502 includes a bug that causes the ROR instruction * The earliest NMOS 6502 includes a bug that causes the ROR instruction
* to behave like an ASL that does not affect the carry bit. This version * to behave like an ASL that does not affect the carry bit. This version
* is very rare in the wild. * is very rare in the wild.
*
* NB: Does NOT implement "unimplemented" NMOS instructions.
*/ */
NMOS_WITH_ROR_BUG, NMOS_WITH_ROR_BUG,
/** /**
* All NMOS 6502's have a bug with the indirect JMP instruction. If the * All NMOS 6502's have a bug with the indirect JMP instruction. If the
*
* NB: Does NOT implement "unimplemented" NMOS instructions.
*/ */
NMOS_6502, NMOS_6502,
+11 -13
View File
@@ -25,11 +25,10 @@
package com.loomcom.symon; package com.loomcom.symon;
import com.loomcom.symon.machines.MulticompMachine; import com.loomcom.symon.machines.*;
import com.loomcom.symon.machines.SimpleMachine;
import com.loomcom.symon.machines.SymonMachine;
import com.loomcom.symon.machines.BenEaterMachine;
import org.apache.commons.cli.*; import org.apache.commons.cli.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Locale; import java.util.Locale;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
@@ -37,6 +36,7 @@ import javax.swing.SwingUtilities;
import javax.swing.UIManager; import javax.swing.UIManager;
public class Main { public class Main {
private final static Logger logger = LoggerFactory.getLogger(Main.class.getName());
/** /**
* Main entry point to the simulator. Creates a simulator and shows the main * Main entry point to the simulator. Creates a simulator and shows the main
@@ -46,7 +46,7 @@ public class Main {
*/ */
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
Class machineClass = SymonMachine.class; Class<?> machineClass = null;
Options options = new Options(); Options options = new Options();
@@ -79,7 +79,7 @@ public class Main {
machineClass = BenEaterMachine.class; machineClass = BenEaterMachine.class;
break; break;
default: default:
System.err.println("Could not start Symon. Unknown machine type " + machine); logger.error("Could not start Symon. Unknown machine type {}", machine);
return; return;
} }
} }
@@ -97,7 +97,7 @@ public class Main {
cpuBehavior = InstructionTable.CpuBehavior.CMOS_65816; cpuBehavior = InstructionTable.CpuBehavior.CMOS_65816;
break; break;
default: default:
System.err.println("Could not start Symon. Unknown cpu type " + cpu); logger.error("Could not start Symon. Unknown cpu type {}", cpu);
return; return;
} }
} }
@@ -140,16 +140,14 @@ public class Main {
final Simulator simulator = new Simulator(machineClass, cpuBehavior, romFile, haltOnBreak); final Simulator simulator = new Simulator(machineClass, cpuBehavior, romFile, haltOnBreak);
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(() -> {
@Override
public void run() {
try { try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
// Create the main UI window // Create the main UI window
simulator.createAndShowUi(); simulator.createAndShowUi();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); logger.error("Error during Symon UI initialization: {}", e.getMessage());
} System.exit(-1);
} }
}); });
@@ -163,7 +161,7 @@ public class Main {
} }
} }
} catch (ParseException ex) { } catch (ParseException ex) {
System.err.println("Could not start Symon. Reason: " + ex.getMessage()); logger.error("Could not start Symon. Reason: {}", ex.getMessage());
} }
} }
} }
@@ -27,7 +27,7 @@ import com.loomcom.symon.exceptions.*;
/** /**
* MemoryRange is a simple container class representing a literal * MemoryRange is a simple container class representing a literal
* range of memory, with a staraddress, and an end address. It has * range of memory, with a start address, and an end address. It has
* guards against creating impossible memory ranges, and implements * guards against creating impossible memory ranges, and implements
* some useful methods for checking address inclusion and range * some useful methods for checking address inclusion and range
* overlaps. * overlaps.
+34 -77
View File
@@ -31,14 +31,11 @@ import com.loomcom.symon.ui.Console;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import javax.management.monitor.CounterMonitor;
import javax.swing.*; import javax.swing.*;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
import java.awt.*; import java.awt.*;
import java.awt.event.*; import java.awt.event.*;
import java.io.*; import java.io.*;
import java.util.SortedSet;
import java.util.TreeSet;
/** /**
* Symon Simulator Interface and Control. * Symon Simulator Interface and Control.
@@ -72,7 +69,7 @@ public class Simulator {
private static final int MAX_STEPS_BETWEEN_UPDATES = 20000; private static final int MAX_STEPS_BETWEEN_UPDATES = 20000;
// The simulated machine // The simulated machine
private Machine machine; private final Machine machine;
// Number of CPU steps between CRT repaints. // Number of CPU steps between CRT repaints.
// TODO: Dynamically refresh the value at runtime based on performance figures to reach ~ 30fps. // TODO: Dynamically refresh the value at runtime based on performance figures to reach ~ 30fps.
@@ -120,13 +117,13 @@ public class Simulator {
private JFileChooser fileChooser; private JFileChooser fileChooser;
private PreferencesDialog preferences; private PreferencesDialog preferences;
private Breakpoints breakpoints; private final Breakpoints breakpoints;
private final Object commandMonitorObject = new Object(); private final Object commandMonitorObject = new Object();
private MainCommand command = MainCommand.NONE; private MainCommand command = MainCommand.NONE;
private boolean haltOnBreak; private final boolean haltOnBreak;
public enum MainCommand { public enum MainCommand {
NONE, NONE,
@@ -138,11 +135,11 @@ public class Simulator {
*/ */
private static final String[] STEPS = {"1", "5", "10", "20", "50", "100"}; private static final String[] STEPS = {"1", "5", "10", "20", "50", "100"};
public Simulator(Class machineClass) throws Exception { public Simulator(Class<?> machineClass) throws Exception {
this(machineClass, InstructionTable.CpuBehavior.NMOS_6502, null, false); this(machineClass, InstructionTable.CpuBehavior.NMOS_6502, null, false);
} }
public Simulator(Class machineClass, InstructionTable.CpuBehavior cpuType, public Simulator(Class<?> machineClass, InstructionTable.CpuBehavior cpuType,
String romFile, boolean haltOnBreak) throws Exception { String romFile, boolean haltOnBreak) throws Exception {
this.haltOnBreak = haltOnBreak; this.haltOnBreak = haltOnBreak;
this.breakpoints = new Breakpoints(this); this.breakpoints = new Breakpoints(this);
@@ -165,7 +162,7 @@ public class Simulator {
/** /**
* Display the main simulator UI. * Display the main simulator UI.
*/ */
public void createAndShowUi() throws IOException { public void createAndShowUi() {
mainWindow = new JFrame(); mainWindow = new JFrame();
mainWindow.setTitle("6502 Simulator - " + machine.getName()); mainWindow.setTitle("6502 Simulator - " + machine.getName());
mainWindow.setResizable(false); mainWindow.setResizable(false);
@@ -195,14 +192,16 @@ public class Simulator {
JButton hardResetButton = new JButton("Hard Reset"); JButton hardResetButton = new JButton("Hard Reset");
stepCountBox = new JComboBox<>(STEPS); stepCountBox = new JComboBox<>(STEPS);
stepCountBox.addActionListener(new ActionListener() { stepCountBox.addActionListener(actionEvent -> {
@Override JComboBox<?> cb = (JComboBox<?>) actionEvent.getSource();
public void actionPerformed(ActionEvent actionEvent) { String cbStepsPerClick = (String) cb.getSelectedItem();
stepsPerClick = 1; // Default in case of error
if (cbStepsPerClick != null) {
try { try {
JComboBox cb = (JComboBox) actionEvent.getSource(); stepsPerClick = Integer.parseInt(cbStepsPerClick);
stepsPerClick = Integer.parseInt((String) cb.getSelectedItem());
} catch (NumberFormatException ex) { } catch (NumberFormatException ex) {
stepsPerClick = 1;
stepCountBox.setSelectedIndex(0); stepCountBox.setSelectedIndex(0);
} }
} }
@@ -224,38 +223,24 @@ public class Simulator {
// Bottom - buttons. // Bottom - buttons.
mainWindow.getContentPane().add(buttonContainer, BorderLayout.PAGE_END); mainWindow.getContentPane().add(buttonContainer, BorderLayout.PAGE_END);
runStopButton.addActionListener(new ActionListener() { runStopButton.addActionListener(actionEvent -> {
@Override
public void actionPerformed(ActionEvent actionEvent) {
if (runLoop != null && runLoop.isRunning()) { if (runLoop != null && runLoop.isRunning()) {
Simulator.this.handleStop(); Simulator.this.handleStop();
} else { } else {
Simulator.this.handleStart(); Simulator.this.handleStart();
} }
}
}); });
stepButton.addActionListener(new ActionListener() { stepButton.addActionListener(actionEvent -> Simulator.this.handleStep(stepsPerClick));
@Override
public void actionPerformed(ActionEvent actionEvent) {
Simulator.this.handleStep(stepsPerClick);
}
});
softResetButton.addActionListener(new ActionListener() { softResetButton.addActionListener(actionEvent -> {
@Override
public void actionPerformed(ActionEvent actionEvent) {
// If this was a CTRL-click, do a hard reset. // If this was a CTRL-click, do a hard reset.
Simulator.this.handleReset(false); Simulator.this.handleReset(false);
}
}); });
hardResetButton.addActionListener(new ActionListener() { hardResetButton.addActionListener(actionEvent -> {
@Override
public void actionPerformed(ActionEvent actionEvent) {
// If this was a CTRL-click, do a hard reset. // If this was a CTRL-click, do a hard reset.
Simulator.this.handleReset(true); Simulator.this.handleReset(true);
}
}); });
mainWindow.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); mainWindow.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
@@ -277,7 +262,7 @@ public class Simulator {
try { try {
commandMonitorObject.wait(); commandMonitorObject.wait();
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
ex.printStackTrace(); logger.error("Interrupted during wait on command monitor.");
} }
} }
return command; return command;
@@ -342,7 +327,6 @@ public class Simulator {
updateVisibleState(); updateVisibleState();
} catch (SymonException ex) { } catch (SymonException ex) {
logger.error("Exception during simulator step", ex); logger.error("Exception during simulator step", ex);
ex.printStackTrace();
} }
} }
@@ -365,7 +349,7 @@ public class Simulator {
// If a key has been pressed, fill the ACIA. // If a key has been pressed, fill the ACIA.
try { try {
if (machine.getAcia() != null && console.hasInput()) { if (machine.getAcia() != null && console.hasInput()) {
machine.getAcia().rxWrite((int) console.readInputChar()); machine.getAcia().rxWrite(console.readInputChar());
} }
} catch (FifoUnderrunException ex) { } catch (FifoUnderrunException ex) {
logger.error("Console type-ahead buffer underrun!"); logger.error("Console type-ahead buffer underrun!");
@@ -427,16 +411,13 @@ public class Simulator {
logger.debug("Starting main run loop."); logger.debug("Starting main run loop.");
isRunning = true; isRunning = true;
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(() -> {
@Override
public void run() {
// Don't allow step while the simulator is running // Don't allow step while the simulator is running
stepButton.setEnabled(false); stepButton.setEnabled(false);
stepCountBox.setEnabled(false); stepCountBox.setEnabled(false);
menuBar.simulatorDidStart(); menuBar.simulatorDidStart();
// Toggle the state of the run button // Toggle the state of the run button
runStopButton.setText("Stop"); runStopButton.setText("Stop");
}
}); });
try { try {
@@ -447,9 +428,7 @@ public class Simulator {
logger.error("Exception in main simulator run thread. Exiting run.", ex); logger.error("Exception in main simulator run thread. Exiting run.", ex);
} }
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(() -> {
@Override
public void run() {
statusPane.updateState(); statusPane.updateState();
memoryWindow.updateState(); memoryWindow.updateState();
runStopButton.setText("Run"); runStopButton.setText("Run");
@@ -460,7 +439,6 @@ public class Simulator {
} }
menuBar.simulatorDidStop(); menuBar.simulatorDidStop();
traceLog.simulatorDidStop(); traceLog.simulatorDidStop();
}
}); });
isRunning = false; isRunning = false;
@@ -513,12 +491,9 @@ public class Simulator {
// Now load the program at the starting address. // Now load the program at the starting address.
loadProgram(program, preferences.getProgramStartAddress()); loadProgram(program, preferences.getProgramStartAddress());
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(() -> {
@Override
public void run() {
console.reset(); console.reset();
breakpoints.refresh(); breakpoints.refresh();
}
}); });
// TODO: "Don't Show Again" checkbox // TODO: "Don't Show Again" checkbox
@@ -556,7 +531,7 @@ public class Simulator {
long fileSize = romFile.length(); long fileSize = romFile.length();
if (fileSize != machine.getRomSize()) { if (fileSize != machine.getRomSize()) {
throw new IOException("ROM file must be exactly " + String.valueOf(machine.getRomSize()) + " bytes."); throw new IOException("ROM file must be exactly " + machine.getRomSize() + " bytes.");
} }
// Load the new ROM image // Load the new ROM image
@@ -650,30 +625,27 @@ public class Simulator {
} }
class SetFontAction extends AbstractAction { class SetFontAction extends AbstractAction {
private int size; private final int size;
public SetFontAction(int size) { public SetFontAction(int size) {
super(Integer.toString(size) + " pt", null); super(size + " pt", null);
this.size = size; this.size = size;
putValue(SHORT_DESCRIPTION, "Set font to " + size + "pt."); putValue(SHORT_DESCRIPTION, "Set font to " + size + "pt.");
} }
public void actionPerformed(ActionEvent actionEvent) { public void actionPerformed(ActionEvent actionEvent) {
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(() -> {
@Override
public void run() {
console.setFont(new Font("Monospaced", Font.PLAIN, size)); console.setFont(new Font("Monospaced", Font.PLAIN, size));
mainWindow.pack(); mainWindow.pack();
}
}); });
} }
} }
class SetSpeedAction extends AbstractAction { class SetSpeedAction extends AbstractAction {
private int speed; private final int speed;
public SetSpeedAction(int speed) { public SetSpeedAction(int speed) {
super(Integer.toString(speed) + " MHz", null); super(speed + " MHz", null);
this.speed = speed; this.speed = speed;
putValue(SHORT_DESCRIPTION, "Set simulated speed to " + speed + " MHz."); putValue(SHORT_DESCRIPTION, "Set simulated speed to " + speed + " MHz.");
} }
@@ -689,7 +661,7 @@ public class Simulator {
} }
class SetCpuAction extends AbstractAction { class SetCpuAction extends AbstractAction {
private Cpu.CpuBehavior behavior; private final Cpu.CpuBehavior behavior;
public SetCpuAction(String cpu, Cpu.CpuBehavior behavior) { public SetCpuAction(String cpu, Cpu.CpuBehavior behavior) {
super(cpu, null); super(cpu, null);
@@ -729,11 +701,7 @@ public class Simulator {
public void actionPerformed(ActionEvent actionEvent) { public void actionPerformed(ActionEvent actionEvent) {
synchronized (memoryWindow) { synchronized (memoryWindow) {
if (memoryWindow.isVisible()) { memoryWindow.setVisible(!memoryWindow.isVisible());
memoryWindow.setVisible(false);
} else {
memoryWindow.setVisible(true);
}
} }
} }
} }
@@ -746,11 +714,7 @@ public class Simulator {
public void actionPerformed(ActionEvent actionEvent) { public void actionPerformed(ActionEvent actionEvent) {
synchronized (videoWindow) { synchronized (videoWindow) {
if (videoWindow.isVisible()) { videoWindow.setVisible(!videoWindow.isVisible());
videoWindow.setVisible(false);
} else {
videoWindow.setVisible(true);
}
} }
} }
} }
@@ -763,11 +727,7 @@ public class Simulator {
public void actionPerformed(ActionEvent actionEvent) { public void actionPerformed(ActionEvent actionEvent) {
synchronized (breakpointsWindow) { synchronized (breakpointsWindow) {
if (breakpointsWindow.isVisible()) { breakpointsWindow.setVisible(!breakpointsWindow.isVisible());
breakpointsWindow.setVisible(false);
} else {
breakpointsWindow.setVisible(true);
}
} }
} }
} }
@@ -963,16 +923,13 @@ public class Simulator {
private void updateVisibleState() { private void updateVisibleState() {
// Immediately update the UI. // Immediately update the UI.
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(() -> {
@Override
public void run() {
// Now update the state // Now update the state
statusPane.updateState(); statusPane.updateState();
memoryWindow.updateState(); memoryWindow.updateState();
if (traceLog.shouldUpdate()) { if (traceLog.shouldUpdate()) {
traceLog.refresh(); traceLog.refresh();
} }
}
}); });
} }
@@ -32,7 +32,7 @@ import com.loomcom.symon.exceptions.MemoryRangeException;
public abstract class Acia extends Device { public abstract class Acia extends Device {
private String name; private final String name;
/** /**
* Register addresses * Register addresses
@@ -121,9 +121,6 @@ public class Acia6551 extends Acia {
// Mask the lower four bits to get the baud rate. // Mask the lower four bits to get the baud rate.
int baudSelector = data & 0x0f; int baudSelector = data & 0x0f;
switch (baudSelector) { switch (baudSelector) {
case 0:
rate = 0;
break;
case 1: case 1:
rate = 50; rate = 50;
break; break;
@@ -169,6 +166,8 @@ public class Acia6551 extends Acia {
case 15: case 15:
rate = 19200; rate = 19200;
break; break;
default:
break;
} }
setBaudRate(rate); setBaudRate(rate);
@@ -31,7 +31,7 @@ import com.loomcom.symon.exceptions.MemoryRangeException;
/** /**
* This is a simulation of the Motorola 6850 ACIA, with limited * This is a simulation of the Motorola 6850 ACIA, with limited
* functionality. * functionality.
* * <p>
* Unlike a 16550 UART, the 6850 ACIA has only one-byte transmit and * Unlike a 16550 UART, the 6850 ACIA has only one-byte transmit and
* receive buffers. It is the programmer's responsibility to check the * receive buffers. It is the programmer's responsibility to check the
* status (full or empty) for transmit and receive buffers before * status (full or empty) for transmit and receive buffers before
@@ -26,8 +26,6 @@ package com.loomcom.symon.devices;
import com.loomcom.symon.exceptions.MemoryAccessException; import com.loomcom.symon.exceptions.MemoryAccessException;
import com.loomcom.symon.exceptions.MemoryRangeException; import com.loomcom.symon.exceptions.MemoryRangeException;
import java.io.IOException;
/** /**
* Simulation of a 6545 CRTC and virtual CRT output. * Simulation of a 6545 CRTC and virtual CRT output.
*/ */
@@ -87,9 +85,9 @@ public class Crtc extends Device {
private boolean displayEnableSkew = false; private boolean displayEnableSkew = false;
private boolean cursorSkew = false; private boolean cursorSkew = false;
private Memory memory; private final Memory memory;
public Crtc(int deviceAddress, Memory memory) throws MemoryRangeException, IOException { public Crtc(int deviceAddress, Memory memory) throws MemoryRangeException {
super(deviceAddress, deviceAddress + 2, "CRTC"); super(deviceAddress, deviceAddress + 2, "CRTC");
this.memory = memory; this.memory = memory;
@@ -120,8 +118,7 @@ public class Crtc extends Device {
@Override @Override
public int read(int address, boolean cpuAccess) throws MemoryAccessException { public int read(int address, boolean cpuAccess) throws MemoryAccessException {
switch (address) { if (address == REGISTER_RW) {
case REGISTER_RW:
switch (currentRegister) { switch (currentRegister) {
case CURSOR_POSITION_LOW: case CURSOR_POSITION_LOW:
return cursorPosition & 0xff; return cursorPosition & 0xff;
@@ -130,9 +127,8 @@ public class Crtc extends Device {
default: default:
return 0; return 0;
} }
default:
return 0;
} }
return 0;
} }
@Override @Override
@@ -45,7 +45,7 @@ public abstract class Device implements Comparable<Device> {
/** /**
* The memory range for this device. * The memory range for this device.
*/ */
private MemoryRange memoryRange; private final MemoryRange memoryRange;
/** /**
* The name of the device. * The name of the device.
@@ -60,7 +60,7 @@ public abstract class Device implements Comparable<Device> {
/** /**
* Listeners to notify on update. * Listeners to notify on update.
*/ */
private Set<DeviceChangeListener> deviceChangeListeners; private final Set<DeviceChangeListener> deviceChangeListeners;
public Device(int startAddress, int endAddress, String name) throws MemoryRangeException { public Device(int startAddress, int endAddress, String name) throws MemoryRangeException {
this.memoryRange = new MemoryRange(startAddress, endAddress); this.memoryRange = new MemoryRange(startAddress, endAddress);
@@ -30,8 +30,8 @@ import com.loomcom.symon.exceptions.*;
public class Memory extends Device { public class Memory extends Device {
private boolean readOnly; private final boolean readOnly;
private int[] mem; private final int[] mem;
/* Initialize all locations to 0x00 (BRK) */ /* Initialize all locations to 0x00 (BRK) */
private static final int DEFAULT_FILL = 0x00; private static final int DEFAULT_FILL = 0x00;
@@ -119,7 +119,10 @@ public class SdController extends Device {
if (sdImageFile != null) { if (sdImageFile != null) {
try { try {
FileInputStream fis = new FileInputStream(sdImageFile); FileInputStream fis = new FileInputStream(sdImageFile);
fis.skip(this.position); long bytesSkipped = fis.skip(this.position);
if (bytesSkipped < this.position) {
logger.log(Level.WARNING, "Failed to seek to position " + this.position);
}
int read = fis.read(readBuffer); int read = fis.read(readBuffer);
if (read < SECTOR_SIZE) { if (read < SECTOR_SIZE) {
logger.log(Level.WARNING, "not enough data to fill read buffer from SD image file"); logger.log(Level.WARNING, "not enough data to fill read buffer from SD image file");
@@ -27,83 +27,23 @@ import com.loomcom.symon.exceptions.MemoryAccessException;
import com.loomcom.symon.exceptions.MemoryRangeException; import com.loomcom.symon.exceptions.MemoryRangeException;
/** /**
* Very basic implementation of a MOS 6522 VIA. * Skeleton for future implementation of a MOS 6522 VIA.
*
* TODO: Implement timers as threads.
*/ */
public class Via6522 extends Pia { public class Via6522 extends Pia {
public static final int VIA_SIZE = 16; public static final int VIA_SIZE = 16;
enum Register {
ORB, ORA, DDRB, DDRA, T1C_L, T1C_H, T1L_L, T1L_H,
T2C_L, T2C_H, SR, ACR, PCR, IFR, IER, ORA_H
}
public Via6522(int address) throws MemoryRangeException { public Via6522(int address) throws MemoryRangeException {
super(address, address + VIA_SIZE - 1, "MOS 6522 VIA"); super(address, address + VIA_SIZE - 1, "MOS 6522 VIA");
} }
@Override @Override
public void write(int address, int data) throws MemoryAccessException { public void write(int address, int data) throws MemoryAccessException {
Register[] registers = Register.values(); // TODO: Implement write.
if (address >= registers.length) {
throw new MemoryAccessException("Unknown register: " + address);
}
Register r = registers[address];
switch (r) {
case ORA:
case ORB:
case DDRA:
case DDRB:
case T1C_L:
case T1C_H:
case T1L_L:
case T1L_H:
case T2C_L:
case T2C_H:
case SR:
case ACR:
case PCR:
case IFR:
case IER:
case ORA_H:
default:
}
} }
@Override @Override
public int read(int address, boolean cpuAccess) throws MemoryAccessException { public int read(int address, boolean cpuAccess) throws MemoryAccessException {
Register[] registers = Register.values(); // TODO: Implement read.
if (address >= registers.length) {
throw new MemoryAccessException("Unknown register: " + address);
}
Register r = registers[address];
switch (r) {
case ORA:
case ORB:
case DDRA:
case DDRB:
case T1C_L:
case T1C_H:
case T1L_L:
case T1L_H:
case T2C_L:
case T2C_H:
case SR:
case ACR:
case PCR:
case IFR:
case IER:
case ORA_H:
default:
}
return 0; return 0;
} }
} }
@@ -25,13 +25,8 @@
package com.loomcom.symon.jterminal; package com.loomcom.symon.jterminal;
import com.loomcom.symon.jterminal.vt100.Vt100TerminalModel; import com.loomcom.symon.jterminal.vt100.Vt100TerminalModel;
import java.awt.BorderLayout;
import java.awt.Dimension; import java.awt.*;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JScrollBar; import javax.swing.JScrollBar;
@@ -88,10 +83,6 @@ public class JTerminal extends JComponent {
revalidate(); revalidate();
} }
public int getBorderWidth() {
return borderWidth;
}
public void setFont(Font font) { public void setFont(Font font) {
this.font = font; this.font = font;
setCellWidthAndHeight(font); setCellWidthAndHeight(font);
@@ -113,13 +104,6 @@ public class JTerminal extends JComponent {
return model; return model;
} }
public void println(String str) {
if (str == null) {
throw new NullPointerException("str");
}
print(str.concat("\r\n"));
}
public void print(String str) { public void print(String str) {
model.print(str); model.print(str);
} }
@@ -177,12 +161,8 @@ public class JTerminal extends JComponent {
int bufferSize = model.getBufferSize(); int bufferSize = model.getBufferSize();
if (bufferSize > rows) { if (bufferSize > rows) {
scrollBar = new JScrollBar(1, 0, rows, 0, bufferSize + 1); scrollBar = new JScrollBar(Adjustable.VERTICAL, 0, rows, 0, bufferSize + 1);
scrollBar.addAdjustmentListener(new AdjustmentListener() { scrollBar.addAdjustmentListener(evt -> repaint());
public void adjustmentValueChanged(AdjustmentEvent evt) {
repaint();
}
});
add("After", scrollBar); add("After", scrollBar);
} }
@@ -32,51 +32,45 @@ import com.loomcom.symon.jterminal.bell.BellStrategy;
*/ */
public interface TerminalModel { public interface TerminalModel {
/**
* Gets the bell strategy.
* @return The bell strategy.
*/
public BellStrategy getBellStrategy();
/** /**
* Sets the bell strategy. * Sets the bell strategy.
* @param strategy The bell strategy. * @param strategy The bell strategy.
* @throws NullPointerException if the strategy is {@code null}. * @throws NullPointerException if the strategy is {@code null}.
*/ */
public void setBellStrategy(BellStrategy strategy); void setBellStrategy(BellStrategy strategy);
/** /**
* Clears the terminal. * Clears the terminal.
*/ */
public void clear(); void clear();
/** /**
* Moves the cursor back n characters. * Moves the cursor back n characters.
* @param n The number of characters. * @param n The number of characters.
* @throws IllegalArgumentException if n is not positive. * @throws IllegalArgumentException if n is not positive.
*/ */
public void moveCursorBack(int n); void moveCursorBack(int n);
/** /**
* Moves the cursor forward n characters. * Moves the cursor forward n characters.
* @param n The number of characters. * @param n The number of characters.
* @throws IllegalArgumentException if n is not positive. * @throws IllegalArgumentException if n is not positive.
*/ */
public void moveCursorForward(int n); void moveCursorForward(int n);
/** /**
* Moves the cursor down n characters. * Moves the cursor down n characters.
* @param n The number of characters. * @param n The number of characters.
* @throws IllegalArgumentException if n is not positive. * @throws IllegalArgumentException if n is not positive.
*/ */
public void moveCursorDown(int n); void moveCursorDown(int n);
/** /**
* Moves the cursor up n characters. * Moves the cursor up n characters.
* @param n The number of characters. * @param n The number of characters.
* @throws IllegalArgumentException if n is not positive. * @throws IllegalArgumentException if n is not positive.
*/ */
public void moveCursorUp(int n); void moveCursorUp(int n);
/** /**
* Sets a cell. * Sets a cell.
@@ -86,7 +80,7 @@ public interface TerminalModel {
* @throws IndexOutOfBoundsException if the column and/or row number(s) are * @throws IndexOutOfBoundsException if the column and/or row number(s) are
* out of bounds. * out of bounds.
*/ */
public void setCell(int column, int row, TerminalCell cell); void setCell(int column, int row, TerminalCell cell);
/** /**
* Gets a cell. * Gets a cell.
@@ -96,7 +90,7 @@ public interface TerminalModel {
* @throws IndexOutOfBoundsException if the column and/or row number(s) are * @throws IndexOutOfBoundsException if the column and/or row number(s) are
* out of bounds. * out of bounds.
*/ */
public TerminalCell getCell(int column, int row); TerminalCell getCell(int column, int row);
/** /**
* Prints the specified string to the terminal at the cursor position, * Prints the specified string to the terminal at the cursor position,
@@ -105,63 +99,63 @@ public interface TerminalModel {
* @param str The string to print. * @param str The string to print.
* @throws NullPointerException if the string is {@code null}. * @throws NullPointerException if the string is {@code null}.
*/ */
public void print(String str); void print(String str);
/** /**
* Gets the number of columns. * Gets the number of columns.
* @return The number of columns. * @return The number of columns.
*/ */
public int getColumns(); int getColumns();
/** /**
* Gets the number of rows. * Gets the number of rows.
* @return The number of rows. * @return The number of rows.
*/ */
public int getRows(); int getRows();
/** /**
* Gets the buffer size. * Gets the buffer size.
* @return The buffer size. * @return The buffer size.
*/ */
public int getBufferSize(); int getBufferSize();
/** /**
* Gets the cursor row. * Gets the cursor row.
* @return The cursor row. * @return The cursor row.
*/ */
public int getCursorRow(); int getCursorRow();
/** /**
* Sets the cursor row. * Sets the cursor row.
* @param row The cursor row. * @param row The cursor row.
* @throws IllegalArgumentException if the row is out of the valid range. * @throws IllegalArgumentException if the row is out of the valid range.
*/ */
public void setCursorRow(int row); void setCursorRow(int row);
/** /**
* Gets the cursor column. * Gets the cursor column.
* @return The cursor column. * @return The cursor column.
*/ */
public int getCursorColumn(); int getCursorColumn();
/** /**
* Sets the cursor column. * Sets the cursor column.
* @param column The cursor column. * @param column The cursor column.
* @throws IllegalArgumentException if the column is out of the valid range. * @throws IllegalArgumentException if the column is out of the valid range.
*/ */
public void setCursorColumn(int column); void setCursorColumn(int column);
/** /**
* Gets the default background color. * Gets the default background color.
* @return The default background color. * @return The default background color.
*/ */
public Color getDefaultBackgroundColor(); Color getDefaultBackgroundColor();
/** /**
* Gets the default foreground color. * Gets the default foreground color.
* @return The default foreground color. * @return The default foreground color.
*/ */
public Color getDefaultForegroundColor(); Color getDefaultForegroundColor();
} }
@@ -31,7 +31,7 @@ public interface BellStrategy {
/** /**
* Sounds the bell. * Sounds the bell.
*/ */
public void soundBell(); void soundBell();
} }
@@ -50,7 +50,7 @@ public class AnsiControlSequence {
throw new NullPointerException("parameters"); throw new NullPointerException("parameters");
} }
this.command = command; this.command = command;
if (parameters.length == 1 && parameters[0].equals("")) { if (parameters.length == 1 && parameters[0].isEmpty()) {
this.parameters = new String[0]; this.parameters = new String[0];
} else { } else {
this.parameters = parameters.clone(); this.parameters = parameters.clone();
@@ -32,13 +32,13 @@ public interface AnsiControlSequenceListener {
* Called when a control sequence has been parsed. * Called when a control sequence has been parsed.
* @param seq The control sequence. * @param seq The control sequence.
*/ */
public void parsedControlSequence(AnsiControlSequence seq); void parsedControlSequence(AnsiControlSequence seq);
/** /**
* Called when a string has been parsed. * Called when a string has been parsed.
* @param str The string. * @param str The string.
*/ */
public void parsedString(String str); void parsedString(String str);
} }
@@ -33,7 +33,7 @@ import java.io.StringReader;
public class AnsiControlSequenceParser { public class AnsiControlSequenceParser {
/** /**
* The multi-byte control sequence introducer. * The multibyte control sequence introducer.
*/ */
private static final char[] MULTI_CSI = new char[] { 27, '[' }; private static final char[] MULTI_CSI = new char[] { 27, '[' };
@@ -43,7 +43,7 @@ public class AnsiControlSequenceParser {
private static final char SINGLE_CSI = 155; private static final char SINGLE_CSI = 155;
/** /**
* The buffer of data from the last call to {@link #parse()}. This is * The buffer of data from the last call to "parse()". This is
* populated with data if an escape sequence is not complete. * populated with data if an escape sequence is not complete.
*/ */
private StringBuilder buffer = new StringBuilder(); private StringBuilder buffer = new StringBuilder();
@@ -70,12 +70,9 @@ public class AnsiControlSequenceParser {
str = buffer.toString().concat(str); str = buffer.toString().concat(str);
buffer = new StringBuilder(); buffer = new StringBuilder();
} }
Reader reader = new StringReader(str);
try {
try { try {
try (Reader reader = new StringReader(str)) {
parse(reader); parse(reader);
} finally {
reader.close();
} }
} catch (IOException ex) { } catch (IOException ex) {
/* ignore */ /* ignore */
@@ -147,7 +144,7 @@ public class AnsiControlSequenceParser {
if (!finishedSequence) { if (!finishedSequence) {
// not an ideal solution if they used the two byte CSI, but it's // not an ideal solution if they used the two byte CSI, but it's
// easier and cleaner than keeping track of it // easier and cleaner than keeping track of it
buffer.append((char) SINGLE_CSI); buffer.append(SINGLE_CSI);
buffer.append(parameters); buffer.append(parameters);
} }
} }
@@ -56,6 +56,7 @@ public class Vt100TerminalModel extends AbstractTerminalModel {
@Override @Override
public void parsedControlSequence(AnsiControlSequence seq) { public void parsedControlSequence(AnsiControlSequence seq) {
char command = seq.getCommand(); char command = seq.getCommand();
int n;
String[] parameters = seq.getParameters(); String[] parameters = seq.getParameters();
switch (command) { switch (command) {
@@ -63,7 +64,7 @@ public class Vt100TerminalModel extends AbstractTerminalModel {
case 'B': case 'B':
case 'C': case 'C':
case 'D': case 'D':
int n = 1; n = 1;
if (parameters.length == 1) { if (parameters.length == 1) {
n = Integer.parseInt(parameters[0]); n = Integer.parseInt(parameters[0]);
} }
@@ -73,7 +74,7 @@ public class Vt100TerminalModel extends AbstractTerminalModel {
moveCursorDown(n); moveCursorDown(n);
} else if (command == 'C') { } else if (command == 'C') {
moveCursorForward(n); moveCursorForward(n);
} else if (command == 'D') { } else {
moveCursorBack(n); moveCursorBack(n);
} }
break; break;
@@ -85,7 +86,7 @@ public class Vt100TerminalModel extends AbstractTerminalModel {
} }
if (command == 'E') { if (command == 'E') {
moveCursorDown(n); moveCursorDown(n);
} else if (command == 'F') { } else {
moveCursorUp(n); moveCursorUp(n);
} }
setCursorColumn(0); setCursorColumn(0);
@@ -465,11 +466,6 @@ public class Vt100TerminalModel extends AbstractTerminalModel {
return bufferSize; return bufferSize;
} }
@Override
public BellStrategy getBellStrategy() {
return bellStrategy;
}
@Override @Override
public void setBellStrategy(BellStrategy strategy) { public void setBellStrategy(BellStrategy strategy) {
if (strategy == null) { if (strategy == null) {
@@ -91,7 +91,7 @@ public class SimpleMachine implements Machine {
} }
@Override @Override
public void setRom(Memory rom) throws MemoryRangeException { public void setRom(Memory rom) {
// No-op // No-op
} }
@@ -30,10 +30,7 @@ import org.slf4j.LoggerFactory;
import javax.swing.*; import javax.swing.*;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*; import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
/** /**
@@ -46,8 +43,8 @@ public class BreakpointsWindow extends JFrame {
private static final Dimension FRAME_SIZE = new Dimension(240, 280); private static final Dimension FRAME_SIZE = new Dimension(240, 280);
private static final String EMPTY_STRING = ""; private static final String EMPTY_STRING = "";
private JFrame mainWindow; private final JFrame mainWindow;
private Breakpoints breakpoints; private final Breakpoints breakpoints;
public BreakpointsWindow(Breakpoints breakpoints, public BreakpointsWindow(Breakpoints breakpoints,
JFrame mainWindow) { JFrame mainWindow) {
@@ -75,16 +72,7 @@ public class BreakpointsWindow extends JFrame {
breakpointsTable.setShowGrid(true); breakpointsTable.setShowGrid(true);
breakpointsTable.setGridColor(Color.LIGHT_GRAY); breakpointsTable.setGridColor(Color.LIGHT_GRAY);
breakpointsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); breakpointsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
breakpointsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { breakpointsTable.getSelectionModel().addListSelectionListener(e -> removeButton.setEnabled(e.getFirstIndex() > -1));
@Override
public void valueChanged(ListSelectionEvent e) {
if (e.getFirstIndex() > -1) {
removeButton.setEnabled(true);
} else {
removeButton.setEnabled(false);
}
}
});
JScrollPane scrollPane = new JScrollPane(breakpointsTable); JScrollPane scrollPane = new JScrollPane(breakpointsTable);
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
@@ -92,9 +80,7 @@ public class BreakpointsWindow extends JFrame {
breakpointsPanel.add(scrollPane, BorderLayout.CENTER); breakpointsPanel.add(scrollPane, BorderLayout.CENTER);
ActionListener addBreakpointListener = new ActionListener() { ActionListener addBreakpointListener = e -> {
@Override
public void actionPerformed(ActionEvent e) {
int value; int value;
String newBreakpoint = addTextField.getText(); String newBreakpoint = addTextField.getText();
@@ -110,27 +96,17 @@ public class BreakpointsWindow extends JFrame {
return; return;
} }
if (value < 0) {
return;
}
breakpoints.addBreakpoint(value); breakpoints.addBreakpoint(value);
logger.debug("Added breakpoint ${}", Utils.wordToHex(value)); logger.debug("Added breakpoint ${}", Utils.wordToHex(value));
addTextField.setText(EMPTY_STRING); addTextField.setText(EMPTY_STRING);
}
}; };
addButton.addActionListener(addBreakpointListener); addButton.addActionListener(addBreakpointListener);
addTextField.addActionListener(addBreakpointListener); addTextField.addActionListener(addBreakpointListener);
removeButton.addActionListener(new ActionListener() { removeButton.addActionListener(e -> breakpoints.removeBreakpointAtIndex(breakpointsTable.getSelectedRow()));
@Override
public void actionPerformed(ActionEvent e) {
breakpoints.removeBreakpointAtIndex(breakpointsTable.getSelectedRow());
}
});
controlPanel.add(addTextField); controlPanel.add(addTextField);
controlPanel.add(addButton); controlPanel.add(addButton);
@@ -51,8 +51,8 @@ public class Console extends JTerminal implements KeyListener, MouseListener {
private static final boolean SWAP_CR_AND_LF = true; private static final boolean SWAP_CR_AND_LF = true;
// If true, send CRLF (0x0d 0x0a) whenever CR is typed // If true, send CRLF (0x0d 0x0a) whenever CR is typed
private boolean sendCrForLf; private final boolean sendCrForLf;
private FifoRingBuffer<Character> typeAheadBuffer; private final FifoRingBuffer<Character> typeAheadBuffer;
public Console(int columns, int rows, Font font, boolean sendCrForLf) { public Console(int columns, int rows, Font font, boolean sendCrForLf) {
super(new Vt100TerminalModel(columns, rows), font); super(new Vt100TerminalModel(columns, rows), font);
@@ -49,7 +49,7 @@ public class MemoryWindow extends JFrame implements ActionListener {
private static final Logger logger = LoggerFactory.getLogger(MemoryWindow.class); private static final Logger logger = LoggerFactory.getLogger(MemoryWindow.class);
private MemoryTableModel memoryTableModel; private final MemoryTableModel memoryTableModel;
private JTable memoryTable; private JTable memoryTable;
private JTextField pageNumberTextField; private JTextField pageNumberTextField;
private JButton previousPageButton; private JButton previousPageButton;
@@ -111,7 +111,7 @@ public class MemoryWindow extends JFrame implements ActionListener {
} }
/** /**
* Set-up the UI. * Set up the UI.
*/ */
private void createUi() { private void createUi() {
setTitle("Memory Contents"); setTitle("Memory Contents");
@@ -230,7 +230,7 @@ public class MemoryWindow extends JFrame implements ActionListener {
* A JTable that will automatically select all text in a cell * A JTable that will automatically select all text in a cell
* being edited. * being edited.
*/ */
private class MemoryTable extends JTable { private static class MemoryTable extends JTable {
public MemoryTable(TableModel tableModel) { public MemoryTable(TableModel tableModel) {
super(tableModel); super(tableModel);
@@ -242,7 +242,7 @@ public class MemoryWindow extends JFrame implements ActionListener {
final Component editor = getEditorComponent(); final Component editor = getEditorComponent();
if (editor != null && editor instanceof JTextComponent) { if (editor instanceof JTextComponent) {
((JTextComponent) editor).selectAll(); ((JTextComponent) editor).selectAll();
} }
@@ -250,7 +250,7 @@ public class MemoryWindow extends JFrame implements ActionListener {
} }
} }
private class MemoryTableCellRenderer extends DefaultTableCellRenderer { private static class MemoryTableCellRenderer extends DefaultTableCellRenderer {
@Override @Override
public Component getTableCellRendererComponent(JTable table, Object value, public Component getTableCellRendererComponent(JTable table, Object value,
@@ -272,9 +272,9 @@ public class MemoryWindow extends JFrame implements ActionListener {
/** /**
* The model that backs the Memory Table. * The model that backs the Memory Table.
*/ */
private class MemoryTableModel extends AbstractTableModel { private static class MemoryTableModel extends AbstractTableModel {
private Bus bus; private final Bus bus;
private int pageNumber; private int pageNumber;
private static final int COLUMN_COUNT = 17; private static final int COLUMN_COUNT = 17;
@@ -64,12 +64,13 @@ public class VideoWindow extends JFrame implements DeviceChangeListener {
private static final long WINDOW_REPAINT_INTERVAL = 66; // 30fps rate private static final long WINDOW_REPAINT_INTERVAL = 66; // 30fps rate
private static final int CHAR_WIDTH = 8; private static final int CHAR_WIDTH = 8;
private static final int CHAR_HEIGHT = 8; private static final int CHAR_HEIGHT = 8;
private static final String ASCII_ROM = "/ascii.rom";
private final int scaleX, scaleY; private final int scaleX, scaleY;
private final boolean shouldScale; private final boolean shouldScale;
private BufferedImage image; private BufferedImage image;
private int[] charRom; private final int[] charRom;
private int horizontalDisplayed; private int horizontalDisplayed;
private int verticalDisplayed; private int verticalDisplayed;
@@ -78,9 +79,9 @@ public class VideoWindow extends JFrame implements DeviceChangeListener {
private boolean hideCursor; private boolean hideCursor;
private Dimension dimensions; private Dimension dimensions;
private Crtc crtc; private final Crtc crtc;
private ScheduledExecutorService scheduler; private final ScheduledExecutorService scheduler;
private ScheduledFuture<?> cursorBlinker; private ScheduledFuture<?> cursorBlinker;
/** /**
@@ -123,26 +124,20 @@ public class VideoWindow extends JFrame implements DeviceChangeListener {
*/ */
private class CursorBlinker implements Runnable { private class CursorBlinker implements Runnable {
public void run() { public void run() {
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(() -> {
@Override
public void run() {
if (cursorBlinkRate > 0) { if (cursorBlinkRate > 0) {
hideCursor = !hideCursor; hideCursor = !hideCursor;
} }
}
}); });
} }
} }
private class WindowPainter implements Runnable { private class WindowPainter implements Runnable {
public void run() { public void run() {
SwingUtilities.invokeLater(new Runnable () { SwingUtilities.invokeLater(() -> {
@Override
public void run() {
if (VideoWindow.this.isVisible()) { if (VideoWindow.this.isVisible()) {
VideoWindow.this.repaint(); VideoWindow.this.repaint();
} }
}
}); });
} }
} }
@@ -152,7 +147,7 @@ public class VideoWindow extends JFrame implements DeviceChangeListener {
this.scheduler = Executors.newSingleThreadScheduledExecutor(); this.scheduler = Executors.newSingleThreadScheduledExecutor();
this.crtc = crtc; this.crtc = crtc;
this.charRom = loadCharRom("/ascii.rom"); this.charRom = loadCharRom();
this.scaleX = scaleX; this.scaleX = scaleX;
this.scaleY = scaleY; this.scaleY = scaleY;
this.shouldScale = (scaleX > 1 || scaleY > 1); this.shouldScale = (scaleX > 1 || scaleY > 1);
@@ -292,14 +287,17 @@ public class VideoWindow extends JFrame implements DeviceChangeListener {
* Since the BufferedImage is a TYPE_BYTE_BINARY, the data must be converted * Since the BufferedImage is a TYPE_BYTE_BINARY, the data must be converted
* into a single byte per pixel, 0 for black and 255 for white. * into a single byte per pixel, 0 for black and 255 for white.
* @param resource The ROM file resource to load.
* @return An array of glyphs, each ready for insertion. * @return An array of glyphs, each ready for insertion.
* @throws IOException * @throws IOException Failure to load character ROM.
*/ */
private int[] loadCharRom(String resource) throws IOException { private int[] loadCharRom() throws IOException {
BufferedInputStream bis = null; var resource = this.getClass().getResourceAsStream(ASCII_ROM);
try {
bis = new BufferedInputStream(this.getClass().getResourceAsStream(resource)); if (resource == null) {
throw new IOException("Resource " + ASCII_ROM + " not found");
}
try (BufferedInputStream bis = new BufferedInputStream(resource)) {
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
while (bis.available() > 0) { while (bis.available() > 0) {
bos.write(bis.read()); bos.write(bis.read());
@@ -322,10 +320,6 @@ public class VideoWindow extends JFrame implements DeviceChangeListener {
} }
} }
return converted; return converted;
} finally {
if (bis != null) {
bis.close();
}
} }
} }
} }
@@ -34,8 +34,8 @@ import java.util.Queue;
*/ */
public class FifoRingBuffer<E> implements Iterable<E> { public class FifoRingBuffer<E> implements Iterable<E> {
private Queue<E> fifoBuffer; private final Queue<E> fifoBuffer;
private int maxLength; private final int maxLength;
public FifoRingBuffer(int maxLength) { public FifoRingBuffer(int maxLength) {
this.fifoBuffer = new LinkedList<>(); this.fifoBuffer = new LinkedList<>();