1
0
mirror of https://github.com/sethm/symon.git synced 2024-06-01 08:41:32 +00:00

Refactor for Java 1.8

- Clean up and refactor code

- Add 1.8 features

- Clean up IntelliJ inspector warnings
This commit is contained in:
Seth Morabito 2015-12-29 17:55:41 -08:00
parent a4a110dcef
commit 6e8fd40014
28 changed files with 366 additions and 503 deletions

25
pom.xml
View File

@ -61,27 +61,6 @@
<build>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/target/classes/com/loomcom/symon/ui/images</outputDirectory>
<resources>
<resource>
<directory>src/main/java/com/loomcom/symon/ui/images</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
@ -112,8 +91,8 @@
<version>3.1</version>
<configuration>
<compilerArgument>-Xlint:unchecked</compilerArgument>
<source>1.6</source>
<target>1.6</target>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>

View File

@ -34,6 +34,7 @@ import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.stream.Collectors;
/**
* The Bus ties the whole thing together, man.
@ -62,7 +63,7 @@ public class Bus {
}
public Bus(int startAddress, int endAddress) {
this.deviceMap = new HashMap<Integer, SortedSet<Device>>();
this.deviceMap = new HashMap<>();
this.startAddress = startAddress;
this.endAddress = endAddress;
}
@ -92,24 +93,26 @@ public class Bus {
/**
* Add a device to the bus.
*
* @param device
* @param priority
* @param device Device to add
* @param priority Bus prioirity.
* @throws MemoryRangeException
*/
public void addDevice(Device device, int priority) throws MemoryRangeException {
MemoryRange range = device.getMemoryRange();
if(range.startAddress() < this.startAddress || range.startAddress() > this.endAddress) {
if (range.startAddress() < this.startAddress || range.startAddress() > this.endAddress) {
throw new MemoryRangeException("start address of device " + device.getName() + " does not fall within the address range of the bus");
}
if(range.endAddress() < this.startAddress || range.endAddress() > this.endAddress) {
if (range.endAddress() < this.startAddress || range.endAddress() > this.endAddress) {
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);
if(deviceSet == null) {
deviceSet = new TreeSet<Device>();
if (deviceSet == null) {
deviceSet = new TreeSet<>();
deviceMap.put(priority, deviceSet);
}
@ -121,7 +124,7 @@ public class Bus {
/**
* Add a device to the bus. Throws a MemoryRangeException if the device overlaps with any others.
*
* @param device
* @param device Device to add
* @throws MemoryRangeException
*/
public void addDevice(Device device) throws MemoryRangeException {
@ -132,7 +135,7 @@ public class Bus {
/**
* Remove a device from the bus.
*
* @param device
* @param device Device to remove
*/
public void removeDevice(Device device) {
for(SortedSet<Device> deviceSet : deviceMap.values()) {
@ -214,16 +217,14 @@ public class Bus {
public SortedSet<Device> getDevices() {
// create an ordered set of devices, ordered by device priorities
SortedSet<Device> devices = new TreeSet<Device>();
SortedSet<Device> devices = new TreeSet<>();
List<Integer> priorities = new ArrayList<Integer>(deviceMap.keySet());
List<Integer> priorities = new ArrayList<>(deviceMap.keySet());
Collections.sort(priorities);
for(int priority : priorities) {
SortedSet<Device> deviceSet = deviceMap.get(priority);
for(Device device : deviceSet) {
devices.add(device);
}
devices.addAll(deviceSet.stream().collect(Collectors.toList()));
}
return devices;

View File

@ -59,7 +59,7 @@ public class Cpu implements InstructionTable {
public static final int IRQ_VECTOR_H = 0xffff;
/* Simulated behavior */
private static CpuBehavior behavior;
private CpuBehavior behavior;
/* The Bus */
private Bus bus;
@ -67,16 +67,6 @@ public class Cpu implements InstructionTable {
/* The CPU state */
private static final CpuState state = new CpuState();
/* Scratch space for addressing mode and effective address
* calculations */
private int irAddressMode; // Bits 3-5 of IR: [ | | |X|X|X| | ]
private int irOpMode; // Bits 6-7 of IR: [ | | | | | |X|X]
private int effectiveAddress;
/* Internal scratch space */
private int lo = 0, hi = 0; // Used in address calculation
private int tmp; // Temporary storage
/* start time of op execution, needed for speed simulation */
private long opBeginTime;
@ -109,10 +99,6 @@ public class Cpu implements InstructionTable {
this.behavior = behavior;
}
public CpuBehavior getBehavior() {
return behavior;
}
/**
* Reset the CPU to known initial values.
*/
@ -177,8 +163,8 @@ public class Cpu implements InstructionTable {
// Fetch memory location for this instruction.
state.ir = bus.read(state.pc);
irAddressMode = (state.ir >> 2) & 0x07;
irOpMode = state.ir & 0x03;
int irAddressMode = (state.ir >> 2) & 0x07; // Bits 3-5 of IR: [ | | |X|X|X| | ]
int irOpMode = state.ir & 0x03; // Bits 6-7 of IR: [ | | | | | |X|X]
incrementPC();
@ -195,7 +181,8 @@ public class Cpu implements InstructionTable {
state.stepCounter++;
// Get the data from the effective address (if any)
effectiveAddress = 0;
int effectiveAddress = 0;
int tmp; // Temporary storage
switch (irOpMode) {
case 0:
@ -299,8 +286,8 @@ public class Cpu implements InstructionTable {
break;
case 0x40: // RTI - Return from Interrupt - Implied
setProcessorStatus(stackPop());
lo = stackPop();
hi = stackPop();
int lo = stackPop();
int hi = stackPop();
setProgramCounter(address(lo, hi));
break;
case 0x48: // PHA - Push Accumulator - Implied
@ -787,7 +774,7 @@ public class Cpu implements InstructionTable {
*
* @param acc The current value of the accumulator
* @param operand The operand
* @return
* @return The sum of the accumulator and the operand
*/
private int adc(int acc, int operand) {
int result = (operand & 0xff) + (acc & 0xff) + getCarryBit();
@ -1455,20 +1442,18 @@ public class Cpu implements InstructionTable {
*/
public String toTraceEvent() {
String opcode = disassembleLastOp();
StringBuilder sb = new StringBuilder(getInstructionByteStatus());
sb.append(" ");
sb.append(String.format("%-14s", opcode));
sb.append("A:" + HexUtil.byteToHex(a) + " ");
sb.append("X:" + HexUtil.byteToHex(x) + " ");
sb.append("Y:" + HexUtil.byteToHex(y) + " ");
sb.append("F:" + HexUtil.byteToHex(getStatusFlag()) + " ");
sb.append("S:1" + HexUtil.byteToHex(sp) + " ");
sb.append(getProcessorStatusString() + "\n");
return sb.toString();
return getInstructionByteStatus() + " " +
String.format("%-14s", opcode) +
"A:" + HexUtil.byteToHex(a) + " " +
"X:" + HexUtil.byteToHex(x) + " " +
"Y:" + HexUtil.byteToHex(y) + " " +
"F:" + HexUtil.byteToHex(getStatusFlag()) + " " +
"S:1" + HexUtil.byteToHex(sp) + " " +
getProcessorStatusString() + "\n";
}
/**
* @returns The value of the Process Status Register, as a byte.
* @return The value of the Process Status Register, as a byte.
*/
public int getStatusFlag() {
int status = 0x20;
@ -1533,35 +1518,35 @@ public class Cpu implements InstructionTable {
switch (instructionModes[ir]) {
case ABS:
sb.append(" $" + HexUtil.wordToHex(address(args[0], args[1])));
sb.append(" $").append(HexUtil.wordToHex(address(args[0], args[1])));
break;
case ABX:
sb.append(" $" + HexUtil.wordToHex(address(args[0], args[1])) + ",X");
sb.append(" $").append(HexUtil.wordToHex(address(args[0], args[1]))).append(",X");
break;
case ABY:
sb.append(" $" + HexUtil.wordToHex(address(args[0], args[1])) + ",Y");
sb.append(" $").append(HexUtil.wordToHex(address(args[0], args[1]))).append(",Y");
break;
case IMM:
sb.append(" #$" + HexUtil.byteToHex(args[0]));
sb.append(" #$").append(HexUtil.byteToHex(args[0]));
break;
case IND:
sb.append(" ($" + HexUtil.wordToHex(address(args[0], args[1])) + ")");
sb.append(" ($").append(HexUtil.wordToHex(address(args[0], args[1]))).append(")");
break;
case XIN:
sb.append(" ($" + HexUtil.byteToHex(args[0]) + ",X)");
sb.append(" ($").append(HexUtil.byteToHex(args[0])).append(",X)");
break;
case INY:
sb.append(" ($" + HexUtil.byteToHex(args[0]) + "),Y");
sb.append(" ($").append(HexUtil.byteToHex(args[0])).append("),Y");
break;
case REL:
case ZPG:
sb.append(" $" + HexUtil.byteToHex(args[0]));
sb.append(" $").append(HexUtil.byteToHex(args[0]));
break;
case ZPX:
sb.append(" $" + HexUtil.byteToHex(args[0]) + ",X");
sb.append(" $").append(HexUtil.byteToHex(args[0])).append(",X");
break;
case ZPY:
sb.append(" $" + HexUtil.byteToHex(args[0]) + ",Y");
sb.append(" $").append(HexUtil.byteToHex(args[0])).append(",Y");
break;
}
@ -1594,17 +1579,15 @@ public class Cpu implements InstructionTable {
* @return A string representing the current status register state.
*/
public String getProcessorStatusString() {
StringBuilder sb = new StringBuilder("[");
sb.append(negativeFlag ? 'N' : '.'); // Bit 7
sb.append(overflowFlag ? 'V' : '.'); // Bit 6
sb.append("-"); // Bit 5 (always 1)
sb.append(breakFlag ? 'B' : '.'); // Bit 4
sb.append(decimalModeFlag ? 'D' : '.'); // Bit 3
sb.append(irqDisableFlag ? 'I' : '.'); // Bit 2
sb.append(zeroFlag ? 'Z' : '.'); // Bit 1
sb.append(carryFlag ? 'C' : '.'); // Bit 0
sb.append("]");
return sb.toString();
return "[" + (negativeFlag ? 'N' : '.') +
(overflowFlag ? 'V' : '.') +
"-" +
(breakFlag ? 'B' : '.') +
(decimalModeFlag ? 'D' : '.') +
(irqDisableFlag ? 'I' : '.') +
(zeroFlag ? 'Z' : '.') +
(carryFlag ? 'C' : '.') +
"]";
}
}
}

View File

@ -31,7 +31,7 @@ public interface InstructionTable {
*
* TODO: As of version 0.6, this is still not used! All CPUs are "idealized" NMOS 6502 only.
*/
public enum CpuBehavior {
enum CpuBehavior {
/**
* 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
@ -65,7 +65,7 @@ public interface InstructionTable {
/**
* Enumeration of Addressing Modes.
*/
public enum Mode {
enum Mode {
ACC {
public String toString() {
return "Accumulator";
@ -156,7 +156,7 @@ public interface InstructionTable {
/**
* Instruction opcode names.
*/
public static final String[] opcodeNames = {
String[] opcodeNames = {
"BRK", "ORA", null, null, null, "ORA", "ASL", null,
"PHP", "ORA", "ASL", null, null, "ORA", "ASL", null,
"BPL", "ORA", null, null, null, "ORA", "ASL", null,
@ -194,7 +194,7 @@ public interface InstructionTable {
/**
* Instruction addressing modes.
*/
public static final Mode[] instructionModes = {
Mode[] instructionModes = {
Mode.IMP, Mode.XIN, Mode.NUL, Mode.NUL, // 0x00-0x03
Mode.NUL, Mode.ZPG, Mode.ZPG, Mode.NUL, // 0x04-0x07
Mode.IMP, Mode.IMM, Mode.ACC, Mode.NUL, // 0x08-0x0b
@ -265,7 +265,7 @@ public interface InstructionTable {
/**
* Size, in bytes, required for each instruction.
*/
public static final int[] instructionSizes = {
int[] instructionSizes = {
1, 2, 0, 0, 0, 2, 2, 0, 1, 2, 1, 0, 0, 3, 3, 0,
2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0,
3, 2, 0, 0, 2, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0,
@ -287,7 +287,7 @@ public interface InstructionTable {
/**
* Number of clock cycles required for each instruction
*/
public static final int[] instructionClocks = {
int[] instructionClocks = {
7, 6, 0, 0, 0, 3, 5, 0, 3, 2, 2, 0, 0, 4, 6, 0,
2, 5, 0, 0, 0, 4, 6, 0, 2, 4, 0, 0, 0, 4, 7, 0,
6, 6, 0, 0, 3, 3, 5, 0, 4, 2, 2, 0, 4, 4, 6, 0,

View File

@ -39,7 +39,7 @@ public class Main {
* Main entry point to the simulator. Creates a simulator and shows the main
* window.
*
* @param args
* @param args Program arguments
*/
public static void main(String args[]) throws Exception {
@ -48,12 +48,16 @@ public class Main {
String arg = args[i].toLowerCase(Locale.ENGLISH);
if(arg.equals("-machine") && (i+1) < args.length) {
String machine = args[i+1].trim().toLowerCase(Locale.ENGLISH);
if(machine.equals("symon")) {
machineClass = SymonMachine.class;
} else if(machine.equals("multicomp")) {
machineClass = MulticompMachine.class;
} else if (machine.equals("simple")) {
machineClass = SimpleMachine.class;
switch (machine) {
case "symon":
machineClass = SymonMachine.class;
break;
case "multicomp":
machineClass = MulticompMachine.class;
break;
case "simple":
machineClass = SimpleMachine.class;
break;
}
}
}
@ -82,15 +86,13 @@ public class Main {
final Simulator simulator = new Simulator(machineClass);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
// Create the main UI window
simulator.createAndShowUi();
} catch (Exception e) {
e.printStackTrace();
}
SwingUtilities.invokeLater(() -> {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
// Create the main UI window
simulator.createAndShowUi();
} catch (Exception e) {
e.printStackTrace();
}
});

View File

@ -34,77 +34,78 @@ import com.loomcom.symon.exceptions.*;
*/
public class MemoryRange implements Comparable<MemoryRange> {
/** The starting address of the memory range. */
public int startAddress;
/** The ending address of the memory range. */
public int endAddress;
/**
* The starting address of the memory range.
*/
public int startAddress;
/**
* The ending address of the memory range.
*/
public int endAddress;
public MemoryRange(int startAddress, int endAddress)
throws MemoryRangeException {
if (startAddress < 0 || endAddress < 0) {
throw new MemoryRangeException("Addresses cannot be less than 0.");
public MemoryRange(int startAddress, int endAddress)
throws MemoryRangeException {
if (startAddress < 0 || endAddress < 0) {
throw new MemoryRangeException("Addresses cannot be less than 0.");
}
if (startAddress >= endAddress) {
throw new MemoryRangeException("End address must be greater " +
"than start address.");
}
this.startAddress = startAddress;
this.endAddress = endAddress;
}
if (startAddress >= endAddress) {
throw new MemoryRangeException("End address must be greater " +
"than start address.");
/**
* @return the starting address.
*/
public int startAddress() {
return startAddress;
}
this.startAddress = startAddress;
this.endAddress = endAddress;
}
/**
* @returns the starting address.
*/
public int startAddress() {
return startAddress;
}
/**
* @returns the ending address.
*/
public int endAddress() {
return endAddress;
}
/**
* Checks for address inclusion in the range.
*
* @returns true if the address is included within this range,
* false otherwise.
*/
public boolean includes(int address) {
return (address <= endAddress &&
address >= startAddress);
}
/**
* Checks for overlapping memory ranges.
*
* @returns true if this range overlaps in any way with the other.
*/
public boolean overlaps(MemoryRange other) {
return (this.includes(other.startAddress()) ||
other.includes(this.startAddress()));
}
// Implementation of Comparable interface
public int compareTo(MemoryRange other) {
if (other == null) {
throw new NullPointerException("Cannot compare to null.");
/**
* @return the ending address.
*/
public int endAddress() {
return endAddress;
}
if (this == other) {
return 0;
}
Integer thisStartAddr = new Integer(this.startAddress());
Integer thatStartAddr = new Integer(other.startAddress());
return thisStartAddr.compareTo(thatStartAddr);
}
public String toString() {
StringBuffer desc = new StringBuffer("@");
desc.append(String.format("0x%04x", startAddress));
desc.append("-");
desc.append(String.format("0x%04x", endAddress));
return desc.toString();
}
/**
* Checks for address inclusion in the range.
*
* @return true if the address is included within this range,
* false otherwise.
*/
public boolean includes(int address) {
return (address <= endAddress &&
address >= startAddress);
}
/**
* Checks for overlapping memory ranges.
*
* @return true if this range overlaps in any way with the other.
*/
public boolean overlaps(MemoryRange other) {
return (this.includes(other.startAddress()) ||
other.includes(this.startAddress()));
}
// Implementation of Comparable interface
public int compareTo(MemoryRange other) {
if (other == null) {
throw new NullPointerException("Cannot compare to null.");
}
if (this == other) {
return 0;
}
Integer thisStartAddr = this.startAddress();
Integer thatStartAddr = other.startAddress();
return thisStartAddr.compareTo(thatStartAddr);
}
public String toString() {
return "@" + String.format("0x%04x", startAddress) + "-" +
String.format("0x%04x", endAddress);
}
}

View File

@ -27,15 +27,15 @@ import javax.swing.*;
public interface Preferences {
public static final int DEFAULT_PROGRAM_LOAD_ADDRESS = 0x0300;
int DEFAULT_PROGRAM_LOAD_ADDRESS = 0x0300;
public static final boolean DEFAULT_HALT_ON_BREAK = true;
boolean DEFAULT_HALT_ON_BREAK = true;
public JDialog getDialog();
JDialog getDialog();
public int getProgramStartAddress();
int getProgramStartAddress();
public boolean getHaltOnBreak();
boolean getHaltOnBreak();
public void updateUi();
void updateUi();
}

View File

@ -73,7 +73,7 @@ public class Simulator {
// Number of CPU steps between CRT repaints.
// TODO: Dynamically refresh the value at runtime based on performance figures to reach ~ 30fps.
private long stepsBetweenCrtcRefreshes = 2500;
private static final long STEPS_BETWEEN_CRTC_REFRESHES = 2500;
// A counter to keep track of the number of UI updates that have been
// requested
@ -93,14 +93,14 @@ public class Simulator {
/**
* The Trace Window shows the most recent 50,000 CPU states.
*/
private TraceLog traceLog;
private final TraceLog traceLog;
/**
* The Memory Window shows the contents of one page of memory.
*/
private MemoryWindow memoryWindow;
private final MemoryWindow memoryWindow;
private VideoWindow videoWindow;
private final VideoWindow videoWindow;
private SimulatorMenu menuBar;
@ -110,8 +110,6 @@ public class Simulator {
private JButton runStopButton;
private JButton stepButton;
private JButton softResetButton;
private JButton hardResetButton;
private JComboBox<String> stepCountBox;
private JFileChooser fileChooser;
@ -119,7 +117,7 @@ public class Simulator {
private final Object commandMonitorObject = new Object();
private MAIN_CMD command = MAIN_CMD.NONE;
public static enum MAIN_CMD {
public enum MAIN_CMD {
NONE,
SELECTMACHINE
}
@ -131,6 +129,15 @@ public class Simulator {
public Simulator(Class machineClass) throws Exception {
this.machine = (Machine) machineClass.getConstructors()[0].newInstance();
// Initialize final fields in the constructor.
this.traceLog = new TraceLog();
this.memoryWindow = new MemoryWindow(machine.getBus());
if(machine.getCrtc() != null) {
videoWindow = new VideoWindow(machine.getCrtc(), 2, 2);
} else {
videoWindow = null;
}
}
/**
@ -143,7 +150,7 @@ public class Simulator {
mainWindow.getContentPane().setLayout(new BorderLayout());
// UI components used for I/O.
this.console = new com.loomcom.symon.ui.Console(80, 25, DEFAULT_FONT);
this.console = new com.loomcom.symon.ui.Console(80, 25, DEFAULT_FONT, false);
this.statusPane = new StatusPanel(machine);
console.setBorderWidth(CONSOLE_BORDER_WIDTH);
@ -162,19 +169,17 @@ public class Simulator {
runStopButton = new JButton("Run");
stepButton = new JButton("Step");
softResetButton = new JButton("Soft Reset");
hardResetButton = new JButton("Hard Reset");
JButton softResetButton = new JButton("Soft Reset");
JButton hardResetButton = new JButton("Hard Reset");
stepCountBox = new JComboBox<String>(STEPS);
stepCountBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
try {
JComboBox cb = (JComboBox) actionEvent.getSource();
stepsPerClick = Integer.parseInt((String) cb.getSelectedItem());
} catch (NumberFormatException ex) {
stepsPerClick = 1;
stepCountBox.setSelectedIndex(0);
}
stepCountBox = new JComboBox<>(STEPS);
stepCountBox.addActionListener(actionEvent -> {
try {
JComboBox cb = (JComboBox) actionEvent.getSource();
stepsPerClick = Integer.parseInt((String) cb.getSelectedItem());
} catch (NumberFormatException ex) {
stepsPerClick = 1;
stepCountBox.setSelectedIndex(0);
}
});
@ -194,48 +199,27 @@ public class Simulator {
// Bottom - buttons.
mainWindow.getContentPane().add(buttonContainer, BorderLayout.PAGE_END);
runStopButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
if (runLoop != null && runLoop.isRunning()) {
handleStop();
} else {
handleStart();
}
runStopButton.addActionListener(actionEvent -> {
if (runLoop != null && runLoop.isRunning()) {
handleStop();
} else {
handleStart();
}
});
stepButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
handleStep(stepsPerClick);
}
stepButton.addActionListener(actionEvent -> handleStep(stepsPerClick));
softResetButton.addActionListener(actionEvent -> {
// If this was a CTRL-click, do a hard reset.
handleReset(false);
});
softResetButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
// If this was a CTRL-click, do a hard reset.
handleReset(false);
}
hardResetButton.addActionListener(actionEvent -> {
// If this was a CTRL-click, do a hard reset.
handleReset(true);
});
hardResetButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
// If this was a CTRL-click, do a hard reset.
handleReset(true);
}
});
// Prepare the log window
traceLog = new TraceLog();
// Prepare the memory window
memoryWindow = new MemoryWindow(machine.getBus());
// Composite Video and 6545 CRTC
if(machine.getCrtc() != null) {
videoWindow = new VideoWindow(machine.getCrtc(), 2, 2);
}
mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainWindow.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
// The Menu. This comes last, because it relies on other components having
// already been initialized.
@ -348,7 +332,7 @@ public class Simulator {
logger.error("Console type-ahead buffer underrun!");
}
if (videoWindow != null && stepsSinceLastCrtcRefresh++ > stepsBetweenCrtcRefreshes) {
if (videoWindow != null && stepsSinceLastCrtcRefresh++ > STEPS_BETWEEN_CRTC_REFRESHES) {
stepsSinceLastCrtcRefresh = 0;
if (videoWindow.isVisible()) {
videoWindow.repaint();
@ -405,15 +389,13 @@ public class Simulator {
logger.info("Starting main run loop.");
isRunning = true;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// Don't allow step while the simulator is running
stepButton.setEnabled(false);
stepCountBox.setEnabled(false);
menuBar.simulatorDidStart();
// Toggle the state of the run button
runStopButton.setText("Stop");
}
SwingUtilities.invokeLater(() -> {
// Don't allow step while the simulator is running
stepButton.setEnabled(false);
stepCountBox.setEnabled(false);
menuBar.simulatorDidStart();
// Toggle the state of the run button
runStopButton.setText("Stop");
});
try {
@ -424,19 +406,17 @@ public class Simulator {
logger.error("Exception in main simulator run thread. Exiting run.", ex);
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
statusPane.updateState();
memoryWindow.updateState();
runStopButton.setText("Run");
stepButton.setEnabled(true);
stepCountBox.setEnabled(true);
if (traceLog.isVisible()) {
traceLog.refresh();
}
menuBar.simulatorDidStop();
traceLog.simulatorDidStop();
SwingUtilities.invokeLater(() -> {
statusPane.updateState();
memoryWindow.updateState();
runStopButton.setText("Run");
stepButton.setEnabled(true);
stepCountBox.setEnabled(true);
if (traceLog.isVisible()) {
traceLog.refresh();
}
menuBar.simulatorDidStop();
traceLog.simulatorDidStop();
});
isRunning = false;
@ -482,11 +462,7 @@ public class Simulator {
program[i++] = dis.readByte();
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
console.reset();
}
});
SwingUtilities.invokeLater(() -> console.reset());
// Now load the program at the starting address.
loadProgram(program, preferences.getProgramStartAddress());
@ -625,11 +601,9 @@ public class Simulator {
}
public void actionPerformed(ActionEvent actionEvent) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
console.setFont(new Font("Monospaced", Font.PLAIN, size));
mainWindow.pack();
}
SwingUtilities.invokeLater(() -> {
console.setFont(new Font("Monospaced", Font.PLAIN, size));
mainWindow.pack();
});
}
}
@ -812,14 +786,12 @@ public class Simulator {
private void updateVisibleState() {
// Immediately update the UI.
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// Now update the state
statusPane.updateState();
memoryWindow.updateState();
if (traceLog.shouldUpdate()) {
traceLog.refresh();
}
SwingUtilities.invokeLater(() -> {
// Now update the state
statusPane.updateState();
memoryWindow.updateState();
if (traceLog.shouldUpdate()) {
traceLog.refresh();
}
});
}

View File

@ -82,6 +82,7 @@ public abstract class Acia extends Device {
/**
* @return The simulated baud rate in bps.
*/
@SuppressWarnings("unused")
public int getBaudRate() {
return baudRate;
}
@ -153,6 +154,7 @@ public abstract class Acia extends Device {
/**
* @return true if there is character data in the RX register.
*/
@SuppressWarnings("unused")
public boolean hasRxChar() {
return rxFull;
}

View File

@ -26,7 +26,6 @@ package com.loomcom.symon.devices;
import com.loomcom.symon.exceptions.MemoryAccessException;
import com.loomcom.symon.exceptions.MemoryRangeException;
/**
* This is a simulation of the MOS 6551 ACIA, with limited
* functionality. Interrupts are not supported.
@ -45,7 +44,6 @@ public class Acia6551 extends Acia {
static final int CMND_REG = 2;
static final int CTRL_REG = 3;
/**
* Registers. These are ignored in the current implementation.
*/
@ -106,7 +104,7 @@ public class Acia6551 extends Acia {
/**
* Set the control register and associated state.
*
* @param data
* @param data Data to write into the control register
*/
private void setControlRegister(int data) {
controlRegister = data;

View File

@ -41,20 +41,12 @@ public class Acia6850 extends Acia {
public static final int ACIA_SIZE = 2;
static final int STAT_REG = 0; // read-only
static final int CTRL_REG = 0; // write-only
static final int RX_REG = 1; // read-only
static final int TX_REG = 1; // write-only
/**
* Registers. These are ignored in the current implementation.
*/
private int commandRegister;
public Acia6850(int address) throws MemoryRangeException {
super(address, ACIA_SIZE, "ACIA6850");
setBaudRate(2400);
@ -88,17 +80,15 @@ public class Acia6850 extends Acia {
}
private void setCommandRegister(int data) {
commandRegister = data;
// Bits 0 & 1 control the master reset
if((commandRegister & 0x01) != 0 && (commandRegister & 0x02) != 0) {
if((data & 0x01) != 0 && (data & 0x02) != 0) {
reset();
}
// Bit 7 controls receiver IRQ behavior
receiveIrqEnabled = (commandRegister & 0x80) != 0;
receiveIrqEnabled = (data & 0x80) != 0;
// Bits 5 & 6 controls transmit IRQ behavior
transmitIrqEnabled = (commandRegister & 0x20) != 0 && (commandRegister & 0x40) == 0;
transmitIrqEnabled = (data & 0x20) != 0 && (data & 0x40) == 0;
}

View File

@ -27,17 +27,11 @@ import com.loomcom.symon.exceptions.MemoryAccessException;
import com.loomcom.symon.exceptions.MemoryRangeException;
import java.io.IOException;
import java.util.logging.Logger;
/**
* Simulation of a 6545 CRTC and virtual CRT output.
*/
public class Crtc extends Device {
private static final Logger logger = Logger.getLogger(Crtc.class.getName());
// Memory locations in the CRTC address space
public static final int REGISTER_SELECT = 0;
public static final int REGISTER_RW = 1;

View File

@ -62,16 +62,11 @@ public abstract class Device implements Comparable<Device> {
*/
private 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.size = endAddress - startAddress + 1;
this.name = name;
this.deviceChangeListeners = new HashSet<DeviceChangeListener>();
}
public Device(int startAddress, int endAddress) throws MemoryRangeException {
this(startAddress, endAddress, null);
this.deviceChangeListeners = new HashSet<>();
}
/* Methods required to be implemented by inheriting classes. */
@ -97,6 +92,7 @@ public abstract class Device implements Comparable<Device> {
return memoryRange.endAddress();
}
@SuppressWarnings("unused")
public int startAddress() {
return memoryRange.startAddress();
}
@ -105,6 +101,7 @@ public abstract class Device implements Comparable<Device> {
return name;
}
@SuppressWarnings("unused")
public void setName(String name) {
this.name = name;
}
@ -118,9 +115,7 @@ public abstract class Device implements Comparable<Device> {
}
public void notifyListeners() {
for (DeviceChangeListener l : deviceChangeListeners) {
l.deviceStateChanged();
}
deviceChangeListeners.forEach(DeviceChangeListener::deviceStateChanged);
}
/**

View File

@ -24,5 +24,5 @@
package com.loomcom.symon.devices;
public interface DeviceChangeListener {
public void deviceStateChanged();
void deviceStateChanged();
}

View File

@ -28,8 +28,6 @@ import java.util.*;
import com.loomcom.symon.exceptions.*;
import javax.swing.*;
public class Memory extends Device {
private boolean readOnly;
@ -57,8 +55,7 @@ public class Memory extends Device {
}
public static Memory makeRAM(int startAddress, int endAddress) throws MemoryRangeException {
Memory memory = new Memory(startAddress, endAddress, false);
return memory;
return new Memory(startAddress, endAddress, false);
}
public void write(int address, int data) throws MemoryAccessException {
@ -108,8 +105,4 @@ public class Memory extends Device {
public String toString() {
return "Memory: " + getMemoryRange().toString();
}
public int[] getDmaAccess() {
return mem;
}
}

View File

@ -27,6 +27,8 @@ package com.loomcom.symon.devices;
import com.loomcom.symon.exceptions.MemoryAccessException;
import com.loomcom.symon.exceptions.MemoryRangeException;
import jdk.nashorn.internal.ir.annotations.Ignore;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@ -37,66 +39,64 @@ import java.util.logging.Logger;
/**
* Emulation for the SD-card controller of the MULTICOMP system.
* Neiter comlete nor correct.
*
*/
public class SdController extends Device {
private enum Status {
IDLE,
READ,
WRITE
}
public static final int CONTROLLER_SIZE = 8;
private final int SECTOR_SIZE = 512;
private final static Logger logger = Logger.getLogger(SdController.class.getName());
private File sdImageFile;
private int lba0,lba1,lba2;
private int command;
private int lba0, lba1, lba2;
private int position;
private Status status = Status.IDLE;
private final byte[] readBuffer = new byte[SECTOR_SIZE];
private final byte[] writeBuffer = new byte[SECTOR_SIZE];
private int readPosition = 0;
private int writePosition = 0;
public SdController(int address) throws MemoryRangeException {
super(address, address + CONTROLLER_SIZE - 1, "SDCONTROLLER");
sdImageFile = new File("sd.img");
if(!sdImageFile.exists()) {
if (!sdImageFile.exists()) {
sdImageFile = null;
logger.log(Level.INFO, "Could not find SD card image 'sd.img'");
}
}
@Override
public void write(int address, int data) throws MemoryAccessException {
switch(address) {
case 0 :
switch (address) {
case 0:
writeData(data);
return;
case 1 :
case 1:
writeCommand(data);
return;
case 2 :
case 2:
this.lba0 = data;
return;
case 3 :
case 3:
this.lba1 = data;
return;
case 4 :
case 4:
this.lba2 = data;
}
}
@Override
public int read(int address) throws MemoryAccessException {
switch(address) {
switch (address) {
case 0:
return readData();
case 1:
@ -105,63 +105,63 @@ public class SdController extends Device {
return 0;
}
}
private void computePosition() {
this.position = lba0 + (lba1 << 8) + (lba2 << 16);
// each sector is 512 bytes, so multiply accordingly
this.position <<= 9;
}
private void prepareRead() {
this.status = Status.READ;
this.readPosition = 0;
computePosition();
if(sdImageFile != null) {
if (sdImageFile != null) {
try {
FileInputStream fis = new FileInputStream(sdImageFile);
fis.skip(this.position);
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");
}
fis.close();
} catch (IOException ex) {
logger.log(Level.WARNING, "could not fill read buffer from SD image file", ex);
}
}
}
}
private void prepareWrite() {
this.status = Status.WRITE;
this.writePosition = 0;
computePosition();
}
private int readData() {
if(status != Status.READ) {
if (status != Status.READ) {
return 0;
}
int data = readBuffer[readPosition++];
if(readPosition >= SECTOR_SIZE) {
if (readPosition >= SECTOR_SIZE) {
this.status = Status.IDLE;
}
return data;
}
private void writeData(int data) {
if(status != Status.WRITE) {
if (status != Status.WRITE) {
return;
}
writeBuffer[writePosition++] = (byte) data;
if(writePosition >= SECTOR_SIZE) {
if(sdImageFile != null) {
if (writePosition >= SECTOR_SIZE) {
if (sdImageFile != null) {
try {
RandomAccessFile raf = new RandomAccessFile(sdImageFile, "rw");
raf.skipBytes(this.position);
@ -171,14 +171,14 @@ public class SdController extends Device {
logger.log(Level.WARNING, "could not write data back to SD image file!", ex);
}
}
this.status = Status.IDLE;
}
}
private int readStatus() {
switch(this.status) {
switch (this.status) {
case IDLE:
return 128;
case READ:
@ -189,14 +189,13 @@ public class SdController extends Device {
return 0;
}
}
private void writeCommand(int data) {
this.command = data;
switch(this.command) {
case 0 :
switch (data) {
case 0:
prepareRead();
return;
case 1 :
case 1:
prepareWrite();
return;
default:
@ -208,5 +207,5 @@ public class SdController extends Device {
public String toString() {
return getName() + "@" + String.format("%04X", this.getMemoryRange().startAddress);
}
}

View File

@ -39,10 +39,6 @@ public class Via6522 extends Pia {
T2C_L, T2C_H, SR, ACR, PCR, IFR, IER, ORA_H
}
// Ports A and B
private char[] portData = {0, 0};
private char[] portDirections = {0, 0};
public Via6522(int address) throws MemoryRangeException {
super(address, address + VIA_SIZE - 1, "MOS 6522 VIA");
}

View File

@ -31,7 +31,4 @@ public class SymonException extends Exception {
public SymonException(String msg) {
super(msg);
}
public SymonException() {
super();
}
}

View File

@ -35,27 +35,27 @@ import com.loomcom.symon.exceptions.MemoryRangeException;
public interface Machine {
public Bus getBus();
Bus getBus();
Cpu getCpu();
public Cpu getCpu();
Memory getRam();
public Memory getRam();
Acia getAcia();
public Acia getAcia();
Pia getPia();
public Pia getPia();
Crtc getCrtc();
public Crtc getCrtc();
Memory getRom();
public Memory getRom();
void setRom(Memory rom) throws MemoryRangeException;
public void setRom(Memory rom) throws MemoryRangeException;
int getRomBase();
public int getRomBase();
int getRomSize();
public int getRomSize();
public int getMemorySize();
int getMemorySize();
String getName();
}

View File

@ -65,7 +65,6 @@ public class MulticompMachine implements Machine {
private final Cpu cpu;
private final Acia acia;
private final Memory ram;
private final SdController sdController;
private Memory rom;
@ -75,12 +74,11 @@ public class MulticompMachine implements Machine {
this.ram = new Memory(MEMORY_BASE, MEMORY_BASE + MEMORY_SIZE - 1, false);
this.acia = new Acia6850(ACIA_BASE);
this.acia.setBaudRate(0);
this.sdController = new SdController(SD_BASE);
bus.addCpu(cpu);
bus.addDevice(ram);
bus.addDevice(acia, 1);
bus.addDevice(sdController, 1);
bus.addDevice(new SdController(SD_BASE), 1);
// TODO: Make this configurable, of course.
File romImage = new File("rom.bin");

View File

@ -44,21 +44,20 @@ import java.awt.event.MouseListener;
public class Console extends JTerminal implements KeyListener, MouseListener {
private static final int DEFAULT_COLUMNS = 80;
private static final int DEFAULT_ROWS = 24;
private static final int DEFAULT_BORDER_WIDTH = 10;
// If true, swap CR and LF characters.
private static final boolean SWAP_CR_AND_LF = true;
// If true, send CRLF (0x0d 0x0a) whenever CR is typed
private static final boolean SEND_CR_LF_FOR_CR = false;
// If true, send CRLF (0x0d 0x0a) whenever CR is typed
private boolean sendCrForLf = false;
private FifoRingBuffer<Character> typeAheadBuffer;
public Console(int columns, int rows, Font font) {
public Console(int columns, int rows, Font font, boolean sendCrForLf) {
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);
this.typeAheadBuffer = new FifoRingBuffer<>(128);
this.sendCrForLf = sendCrForLf;
setBorderWidth(DEFAULT_BORDER_WIDTH);
addKeyListener(this);
addMouseListener(this);
@ -83,7 +82,7 @@ public class Console extends JTerminal implements KeyListener, MouseListener {
/**
* Returns true if a key has been pressed since the last time input was read.
*
* @return
* @return true if the type-ahead buffer has data
*/
public boolean hasInput() {
return !typeAheadBuffer.isEmpty();
@ -105,7 +104,7 @@ public class Console extends JTerminal implements KeyListener, MouseListener {
}
}
if (SEND_CR_LF_FOR_CR && keyTyped == 0x0d) {
if (sendCrForLf && keyTyped == 0x0d) {
typeAheadBuffer.push((char) 0x0d);
typeAheadBuffer.push((char) 0x0a);
} else {

View File

@ -346,12 +346,8 @@ public class MemoryWindow extends JFrame implements ActionListener {
int fullAddress = fullAddress(row, column);
int newValue = Integer.parseInt(hexValue, 16) & 0xff;
bus.write(fullAddress, newValue);
} catch (MemoryAccessException ex) {
;
} catch (NumberFormatException ex) {
;
} catch (ClassCastException ex) {
;
} catch (MemoryAccessException | NumberFormatException | ClassCastException ex) {
// Intentionally swallow exception
}
fireTableCellUpdated(row, column);
}

View File

@ -97,23 +97,19 @@ public class PreferencesDialog extends Observable implements Preferences {
JButton applyButton = new JButton("Apply");
JButton cancelButton = new JButton("Cancel");
cancelButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
updateUi();
dialog.setVisible(false);
}
cancelButton.addActionListener(actionEvent -> {
updateUi();
dialog.setVisible(false);
});
applyButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
haltOnBreak = haltOnBreakCheckBox.isSelected();
programLoadAddress = hexToInt(programLoadAddressField.getText());
updateUi();
// TODO: Actually check to see if values have changed, don't assume.
setChanged();
PreferencesDialog.this.notifyObservers();
dialog.setVisible(false);
}
applyButton.addActionListener(actionEvent -> {
haltOnBreak = haltOnBreakCheckBox.isSelected();
programLoadAddress = hexToInt(programLoadAddressField.getText());
updateUi();
// TODO: Actually check to see if values have changed, don't assume.
setChanged();
PreferencesDialog.this.notifyObservers();
dialog.setVisible(false);
});
buttonsContainer.add(applyButton);

View File

@ -53,7 +53,6 @@ public class StatusPanel extends JPanel {
private ImageIcon negativeOn;
private ImageIcon negativeOff;
private JLabel statusFlagsLabel;
private JLabel carryFlagLabel;
private JLabel zeroFlagLabel;
private JLabel irqDisableFlagLabel;
@ -69,13 +68,6 @@ public class StatusPanel extends JPanel {
private JTextField xField;
private JTextField yField;
private JLabel opcodeLabel;
private JLabel pcLabel;
private JLabel spLabel;
private JLabel aLabel;
private JLabel xLabel;
private JLabel yLabel;
private Machine machine;
private static final int EMPTY_BORDER = 10;
@ -150,13 +142,13 @@ public class StatusPanel extends JPanel {
statusFlagsPanel.add(carryFlagLabel);
// Create and add register and address labels
statusFlagsLabel = makeLabel("Flags");
opcodeLabel = makeLabel("Next IR");
pcLabel = makeLabel("PC");
spLabel = makeLabel("SP");
aLabel = makeLabel("A");
xLabel = makeLabel("X");
yLabel = makeLabel("Y");
JLabel statusFlagsLabel = makeLabel("Flags");
JLabel opcodeLabel = makeLabel("Next IR");
JLabel pcLabel = makeLabel("PC");
JLabel spLabel = makeLabel("SP");
JLabel aLabel = makeLabel("A");
JLabel xLabel = makeLabel("X");
JLabel yLabel = makeLabel("Y");
statusFlagsLabel.setToolTipText("6502 Processor Status Flags");
opcodeLabel.setToolTipText("Instruction Register");
@ -171,74 +163,59 @@ public class StatusPanel extends JPanel {
yField = makeTextField(SMALL_TEXT_FIELD_SIZE, true);
// Make fields editable
pcField.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
int newVal = getHexVal(pcField) & 0xffff;
machine.getCpu().setProgramCounter(newVal);
} catch (Exception ex) {
// Swallow exception
}
updateState();
pcField.addActionListener(e -> {
try {
int newVal = getHexVal(pcField) & 0xffff;
machine.getCpu().setProgramCounter(newVal);
} catch (Exception ex) {
// Swallow exception
}
updateState();
});
spField.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
int newVal = getHexVal(spField) & 0xff;
machine.getCpu().setStackPointer(newVal);
} catch (Exception ex) {
// Swallow exception
}
updateState();
spField.addActionListener(e -> {
try {
int newVal = getHexVal(spField) & 0xff;
machine.getCpu().setStackPointer(newVal);
} catch (Exception ex) {
// Swallow exception
}
updateState();
});
aField.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
int newVal = getHexVal(aField) & 0xff;
machine.getCpu().setAccumulator(newVal);
} catch (Exception ex) {
// Swallow exception
}
updateState();
aField.addActionListener(e -> {
try {
int newVal = getHexVal(aField) & 0xff;
machine.getCpu().setAccumulator(newVal);
} catch (Exception ex) {
// Swallow exception
}
updateState();
});
xField.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
int newVal = getHexVal(xField) & 0xff;
machine.getCpu().setXRegister(newVal);
} catch (Exception ex) {
// Swallow exception
}
updateState();
xField.addActionListener(e -> {
try {
int newVal = getHexVal(xField) & 0xff;
machine.getCpu().setXRegister(newVal);
} catch (Exception ex) {
// Swallow exception
}
updateState();
});
yField.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
int newVal = getHexVal(yField) & 0xff;
machine.getCpu().setYRegister(newVal);
} catch (Exception ex) {
// Swallow exception
}
updateState();
yField.addActionListener(e -> {
try {
int newVal = getHexVal(yField) & 0xff;
machine.getCpu().setYRegister(newVal);
} catch (Exception ex) {
// Swallow exception
}
updateState();
});
constraints.anchor = GridBagConstraints.LINE_START;

View File

@ -44,7 +44,7 @@ public class TraceLog extends JFrame {
private static final int MAX_LOG_LENGTH = 50000;
public TraceLog() {
traceLog = new FifoRingBuffer<Cpu.CpuState>(MAX_LOG_LENGTH);
traceLog = new FifoRingBuffer<>(MAX_LOG_LENGTH);
setMinimumSize(MIN_SIZE);
setPreferredSize(PREFERRED_SIZE);
setResizable(true);

View File

@ -122,12 +122,10 @@ public class VideoWindow extends JFrame implements DeviceChangeListener {
*/
private class CursorBlinker implements Runnable {
public void run() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (cursorBlinkRate > 0) {
hideCursor = !hideCursor;
repaint();
}
SwingUtilities.invokeLater(() -> {
if (cursorBlinkRate > 0) {
hideCursor = !hideCursor;
repaint();
}
});
}

View File

@ -38,7 +38,7 @@ public class FifoRingBuffer<E> implements Iterable<E> {
private int maxLength;
public FifoRingBuffer(int maxLength) {
this.fifoBuffer = new LinkedList<E>();
this.fifoBuffer = new LinkedList<>();
this.maxLength = maxLength;
}

View File

@ -121,9 +121,6 @@ public class HexUtil {
* @return Four digit, zero padded hexadecimal string.
*/
public static String wordToHex(int val) {
StringBuilder sb = new StringBuilder(4);
sb.append(HEX_CONSTANTS[(val >> 8) & 0xff]);
sb.append(HEX_CONSTANTS[val & 0xff]);
return sb.toString();
return HEX_CONSTANTS[(val >> 8) & 0xff] + HEX_CONSTANTS[val & 0xff];
}
}