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 committed 2015-12-29 17:55:41 -08:00
1 parent a4a110dcef
commit 6e8fd40014
28 files changed
+340 -477

No files matched your search

+2 -23
View File
@@ -61,27 +61,6 @@
<build> <build>
<plugins> <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> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId> <artifactId>maven-assembly-plugin</artifactId>
@@ -112,8 +91,8 @@
<version>3.1</version> <version>3.1</version>
<configuration> <configuration>
<compilerArgument>-Xlint:unchecked</compilerArgument> <compilerArgument>-Xlint:unchecked</compilerArgument>
<source>1.6</source> <source>1.8</source>
<target>1.6</target> <target>1.8</target>
</configuration> </configuration>
</plugin> </plugin>
+16 -15
View File
@@ -34,6 +34,7 @@ import java.util.Map;
import java.util.SortedSet; import java.util.SortedSet;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.stream.Collectors;
/** /**
* The Bus ties the whole thing together, man. * The Bus ties the whole thing together, man.
@@ -62,7 +63,7 @@ public class Bus {
} }
public Bus(int startAddress, int endAddress) { public Bus(int startAddress, int endAddress) {
this.deviceMap = new HashMap<Integer, SortedSet<Device>>(); this.deviceMap = new HashMap<>();
this.startAddress = startAddress; this.startAddress = startAddress;
this.endAddress = endAddress; this.endAddress = endAddress;
} }
@@ -92,24 +93,26 @@ public class Bus {
/** /**
* Add a device to the bus. * Add a device to the bus.
* *
* @param device * @param device Device to add
* @param priority * @param priority Bus prioirity.
* @throws MemoryRangeException * @throws MemoryRangeException
*/ */
public void addDevice(Device device, int priority) throws MemoryRangeException { public void addDevice(Device device, int priority) throws MemoryRangeException {
MemoryRange range = device.getMemoryRange(); 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"); 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"); 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.get(priority);
if(deviceSet == null) {
deviceSet = new TreeSet<Device>(); if (deviceSet == null) {
deviceSet = new TreeSet<>();
deviceMap.put(priority, deviceSet); 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. * 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 * @throws MemoryRangeException
*/ */
public void addDevice(Device device) throws MemoryRangeException { public void addDevice(Device device) throws MemoryRangeException {
@@ -132,7 +135,7 @@ public class Bus {
/** /**
* Remove a device from the bus. * Remove a device from the bus.
* *
* @param device * @param device Device to remove
*/ */
public void removeDevice(Device device) { public void removeDevice(Device device) {
for(SortedSet<Device> deviceSet : deviceMap.values()) { for(SortedSet<Device> deviceSet : deviceMap.values()) {
@@ -214,16 +217,14 @@ public class Bus {
public SortedSet<Device> getDevices() { public SortedSet<Device> getDevices() {
// create an ordered set of devices, ordered by device priorities // 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); Collections.sort(priorities);
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.stream().collect(Collectors.toList()));
devices.add(device);
}
} }
return devices; return devices;
+36 -53
View File
@@ -59,7 +59,7 @@ public class Cpu implements InstructionTable {
public static final int IRQ_VECTOR_H = 0xffff; public static final int IRQ_VECTOR_H = 0xffff;
/* Simulated behavior */ /* Simulated behavior */
private static CpuBehavior behavior; private CpuBehavior behavior;
/* The Bus */ /* The Bus */
private Bus bus; private Bus bus;
@@ -67,16 +67,6 @@ public class Cpu implements InstructionTable {
/* The CPU state */ /* The CPU state */
private static final CpuState state = new CpuState(); 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 */ /* start time of op execution, needed for speed simulation */
private long opBeginTime; private long opBeginTime;
@@ -109,10 +99,6 @@ public class Cpu implements InstructionTable {
this.behavior = behavior; this.behavior = behavior;
} }
public CpuBehavior getBehavior() {
return behavior;
}
/** /**
* Reset the CPU to known initial values. * Reset the CPU to known initial values.
*/ */
@@ -177,8 +163,8 @@ public class Cpu implements InstructionTable {
// Fetch memory location for this instruction. // Fetch memory location for this instruction.
state.ir = bus.read(state.pc); state.ir = bus.read(state.pc);
irAddressMode = (state.ir >> 2) & 0x07; int irAddressMode = (state.ir >> 2) & 0x07; // Bits 3-5 of IR: [ | | |X|X|X| | ]
irOpMode = state.ir & 0x03; int irOpMode = state.ir & 0x03; // Bits 6-7 of IR: [ | | | | | |X|X]
incrementPC(); incrementPC();
@@ -195,7 +181,8 @@ public class Cpu implements InstructionTable {
state.stepCounter++; state.stepCounter++;
// Get the data from the effective address (if any) // Get the data from the effective address (if any)
effectiveAddress = 0; int effectiveAddress = 0;
int tmp; // Temporary storage
switch (irOpMode) { switch (irOpMode) {
case 0: case 0:
@@ -299,8 +286,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());
lo = stackPop(); int lo = stackPop();
hi = stackPop(); int hi = stackPop();
setProgramCounter(address(lo, hi)); setProgramCounter(address(lo, hi));
break; break;
case 0x48: // PHA - Push Accumulator - Implied case 0x48: // PHA - Push Accumulator - Implied
@@ -787,7 +774,7 @@ public class Cpu implements InstructionTable {
* *
* @param acc The current value of the accumulator * @param acc The current value of the accumulator
* @param operand The operand * @param operand The operand
* @return * @return The sum of the accumulator and the operand
*/ */
private int adc(int acc, int operand) { private int adc(int acc, int operand) {
int result = (operand & 0xff) + (acc & 0xff) + getCarryBit(); int result = (operand & 0xff) + (acc & 0xff) + getCarryBit();
@@ -1455,20 +1442,18 @@ public class Cpu implements InstructionTable {
*/ */
public String toTraceEvent() { public String toTraceEvent() {
String opcode = disassembleLastOp(); String opcode = disassembleLastOp();
StringBuilder sb = new StringBuilder(getInstructionByteStatus()); return getInstructionByteStatus() + " " +
sb.append(" "); String.format("%-14s", opcode) +
sb.append(String.format("%-14s", opcode)); "A:" + HexUtil.byteToHex(a) + " " +
sb.append("A:" + HexUtil.byteToHex(a) + " "); "X:" + HexUtil.byteToHex(x) + " " +
sb.append("X:" + HexUtil.byteToHex(x) + " "); "Y:" + HexUtil.byteToHex(y) + " " +
sb.append("Y:" + HexUtil.byteToHex(y) + " "); "F:" + HexUtil.byteToHex(getStatusFlag()) + " " +
sb.append("F:" + HexUtil.byteToHex(getStatusFlag()) + " "); "S:1" + HexUtil.byteToHex(sp) + " " +
sb.append("S:1" + HexUtil.byteToHex(sp) + " "); getProcessorStatusString() + "\n";
sb.append(getProcessorStatusString() + "\n");
return sb.toString();
} }
/** /**
* @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() { public int getStatusFlag() {
int status = 0x20; int status = 0x20;
@@ -1533,35 +1518,35 @@ public class Cpu implements InstructionTable {
switch (instructionModes[ir]) { switch (instructionModes[ir]) {
case ABS: case ABS:
sb.append(" $" + HexUtil.wordToHex(address(args[0], args[1]))); sb.append(" $").append(HexUtil.wordToHex(address(args[0], args[1])));
break; break;
case ABX: 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; break;
case ABY: 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; break;
case IMM: case IMM:
sb.append(" #$" + HexUtil.byteToHex(args[0])); sb.append(" #$").append(HexUtil.byteToHex(args[0]));
break; break;
case IND: case IND:
sb.append(" ($" + HexUtil.wordToHex(address(args[0], args[1])) + ")"); sb.append(" ($").append(HexUtil.wordToHex(address(args[0], args[1]))).append(")");
break; break;
case XIN: case XIN:
sb.append(" ($" + HexUtil.byteToHex(args[0]) + ",X)"); sb.append(" ($").append(HexUtil.byteToHex(args[0])).append(",X)");
break; break;
case INY: case INY:
sb.append(" ($" + HexUtil.byteToHex(args[0]) + "),Y"); sb.append(" ($").append(HexUtil.byteToHex(args[0])).append("),Y");
break; break;
case REL: case REL:
case ZPG: case ZPG:
sb.append(" $" + HexUtil.byteToHex(args[0])); sb.append(" $").append(HexUtil.byteToHex(args[0]));
break; break;
case ZPX: case ZPX:
sb.append(" $" + HexUtil.byteToHex(args[0]) + ",X"); sb.append(" $").append(HexUtil.byteToHex(args[0])).append(",X");
break; break;
case ZPY: case ZPY:
sb.append(" $" + HexUtil.byteToHex(args[0]) + ",Y"); sb.append(" $").append(HexUtil.byteToHex(args[0])).append(",Y");
break; break;
} }
@@ -1594,17 +1579,15 @@ public class Cpu implements InstructionTable {
* @return A string representing the current status register state. * @return A string representing the current status register state.
*/ */
public String getProcessorStatusString() { public String getProcessorStatusString() {
StringBuilder sb = new StringBuilder("["); return "[" + (negativeFlag ? 'N' : '.') +
sb.append(negativeFlag ? 'N' : '.'); // Bit 7 (overflowFlag ? 'V' : '.') +
sb.append(overflowFlag ? 'V' : '.'); // Bit 6 "-" +
sb.append("-"); // Bit 5 (always 1) (breakFlag ? 'B' : '.') +
sb.append(breakFlag ? 'B' : '.'); // Bit 4 (decimalModeFlag ? 'D' : '.') +
sb.append(decimalModeFlag ? 'D' : '.'); // Bit 3 (irqDisableFlag ? 'I' : '.') +
sb.append(irqDisableFlag ? 'I' : '.'); // Bit 2 (zeroFlag ? 'Z' : '.') +
sb.append(zeroFlag ? 'Z' : '.'); // Bit 1 (carryFlag ? 'C' : '.') +
sb.append(carryFlag ? 'C' : '.'); // Bit 0 "]";
sb.append("]");
return sb.toString();
} }
} }
} }
@@ -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. * 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 * 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
@@ -65,7 +65,7 @@ public interface InstructionTable {
/** /**
* Enumeration of Addressing Modes. * Enumeration of Addressing Modes.
*/ */
public enum Mode { enum Mode {
ACC { ACC {
public String toString() { public String toString() {
return "Accumulator"; return "Accumulator";
@@ -156,7 +156,7 @@ public interface InstructionTable {
/** /**
* Instruction opcode names. * Instruction opcode names.
*/ */
public static final String[] opcodeNames = { String[] opcodeNames = {
"BRK", "ORA", null, null, null, "ORA", "ASL", null, "BRK", "ORA", null, null, null, "ORA", "ASL", null,
"PHP", "ORA", "ASL", null, null, "ORA", "ASL", null, "PHP", "ORA", "ASL", null, null, "ORA", "ASL", null,
"BPL", "ORA", null, null, null, "ORA", "ASL", null, "BPL", "ORA", null, null, null, "ORA", "ASL", null,
@@ -194,7 +194,7 @@ public interface InstructionTable {
/** /**
* Instruction addressing modes. * Instruction addressing modes.
*/ */
public static final Mode[] instructionModes = { Mode[] instructionModes = {
Mode.IMP, Mode.XIN, Mode.NUL, Mode.NUL, // 0x00-0x03 Mode.IMP, Mode.XIN, Mode.NUL, Mode.NUL, // 0x00-0x03
Mode.NUL, Mode.ZPG, Mode.ZPG, Mode.NUL, // 0x04-0x07 Mode.NUL, Mode.ZPG, Mode.ZPG, Mode.NUL, // 0x04-0x07
Mode.IMP, Mode.IMM, Mode.ACC, Mode.NUL, // 0x08-0x0b Mode.IMP, Mode.IMM, Mode.ACC, Mode.NUL, // 0x08-0x0b
@@ -265,7 +265,7 @@ public interface InstructionTable {
/** /**
* Size, in bytes, required for each instruction. * 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, 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, 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, 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 * 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, 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, 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, 6, 6, 0, 0, 3, 3, 5, 0, 4, 2, 2, 0, 4, 4, 6, 0,
+18 -16
View File
@@ -39,7 +39,7 @@ public class Main {
* 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
* window. * window.
* *
* @param args * @param args Program arguments
*/ */
public static void main(String args[]) throws Exception { public static void main(String args[]) throws Exception {
@@ -48,12 +48,16 @@ public class Main {
String arg = args[i].toLowerCase(Locale.ENGLISH); String arg = args[i].toLowerCase(Locale.ENGLISH);
if(arg.equals("-machine") && (i+1) < args.length) { if(arg.equals("-machine") && (i+1) < args.length) {
String machine = args[i+1].trim().toLowerCase(Locale.ENGLISH); String machine = args[i+1].trim().toLowerCase(Locale.ENGLISH);
if(machine.equals("symon")) { switch (machine) {
machineClass = SymonMachine.class; case "symon":
} else if(machine.equals("multicomp")) { machineClass = SymonMachine.class;
machineClass = MulticompMachine.class; break;
} else if (machine.equals("simple")) { case "multicomp":
machineClass = SimpleMachine.class; machineClass = MulticompMachine.class;
break;
case "simple":
machineClass = SimpleMachine.class;
break;
} }
} }
} }
@@ -82,15 +86,13 @@ public class Main {
final Simulator simulator = new Simulator(machineClass); final Simulator simulator = new Simulator(machineClass);
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(() -> {
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();
e.printStackTrace();
}
} }
}); });
@@ -34,77 +34,78 @@ import com.loomcom.symon.exceptions.*;
*/ */
public class MemoryRange implements Comparable<MemoryRange> { public class MemoryRange implements Comparable<MemoryRange> {
/** The starting address of the memory range. */ /**
public int startAddress; * The starting address of the memory range.
/** The ending address of the memory range. */ */
public int endAddress; public int startAddress;
/**
* The ending address of the memory range.
*/
public int endAddress;
public MemoryRange(int startAddress, int endAddress) public MemoryRange(int startAddress, int endAddress)
throws MemoryRangeException { throws MemoryRangeException {
if (startAddress < 0 || endAddress < 0) { if (startAddress < 0 || endAddress < 0) {
throw new MemoryRangeException("Addresses cannot be less than 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. * @return the ending address.
*/ */
public int startAddress() { public int endAddress() {
return startAddress; return endAddress;
}
/**
* @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.");
} }
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("@"); * Checks for address inclusion in the range.
desc.append(String.format("0x%04x", startAddress)); *
desc.append("-"); * @return true if the address is included within this range,
desc.append(String.format("0x%04x", endAddress)); * false otherwise.
return desc.toString(); */
} 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);
}
} }
@@ -27,15 +27,15 @@ import javax.swing.*;
public interface Preferences { 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();
} }
+67 -95
View File
@@ -73,7 +73,7 @@ public class Simulator {
// 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.
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 // A counter to keep track of the number of UI updates that have been
// requested // requested
@@ -93,14 +93,14 @@ public class Simulator {
/** /**
* The Trace Window shows the most recent 50,000 CPU states. * 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. * 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; private SimulatorMenu menuBar;
@@ -110,8 +110,6 @@ public class Simulator {
private JButton runStopButton; private JButton runStopButton;
private JButton stepButton; private JButton stepButton;
private JButton softResetButton;
private JButton hardResetButton;
private JComboBox<String> stepCountBox; private JComboBox<String> stepCountBox;
private JFileChooser fileChooser; private JFileChooser fileChooser;
@@ -119,7 +117,7 @@ public class Simulator {
private final Object commandMonitorObject = new Object(); private final Object commandMonitorObject = new Object();
private MAIN_CMD command = MAIN_CMD.NONE; private MAIN_CMD command = MAIN_CMD.NONE;
public static enum MAIN_CMD { public enum MAIN_CMD {
NONE, NONE,
SELECTMACHINE SELECTMACHINE
} }
@@ -131,6 +129,15 @@ public class Simulator {
public Simulator(Class machineClass) throws Exception { public Simulator(Class machineClass) throws Exception {
this.machine = (Machine) machineClass.getConstructors()[0].newInstance(); 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()); mainWindow.getContentPane().setLayout(new BorderLayout());
// UI components used for I/O. // 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); this.statusPane = new StatusPanel(machine);
console.setBorderWidth(CONSOLE_BORDER_WIDTH); console.setBorderWidth(CONSOLE_BORDER_WIDTH);
@@ -162,19 +169,17 @@ public class Simulator {
runStopButton = new JButton("Run"); runStopButton = new JButton("Run");
stepButton = new JButton("Step"); stepButton = new JButton("Step");
softResetButton = new JButton("Soft Reset"); JButton softResetButton = new JButton("Soft Reset");
hardResetButton = new JButton("Hard Reset"); JButton hardResetButton = new JButton("Hard Reset");
stepCountBox = new JComboBox<String>(STEPS); stepCountBox = new JComboBox<>(STEPS);
stepCountBox.addActionListener(new ActionListener() { stepCountBox.addActionListener(actionEvent -> {
public void actionPerformed(ActionEvent actionEvent) { try {
try { JComboBox cb = (JComboBox) actionEvent.getSource();
JComboBox cb = (JComboBox) actionEvent.getSource(); stepsPerClick = Integer.parseInt((String) cb.getSelectedItem());
stepsPerClick = Integer.parseInt((String) cb.getSelectedItem()); } catch (NumberFormatException ex) {
} catch (NumberFormatException ex) { stepsPerClick = 1;
stepsPerClick = 1; stepCountBox.setSelectedIndex(0);
stepCountBox.setSelectedIndex(0);
}
} }
}); });
@@ -194,48 +199,27 @@ 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 -> {
public void actionPerformed(ActionEvent actionEvent) { if (runLoop != null && runLoop.isRunning()) {
if (runLoop != null && runLoop.isRunning()) { handleStop();
handleStop(); } else {
} else { handleStart();
handleStart();
}
} }
}); });
stepButton.addActionListener(new ActionListener() { stepButton.addActionListener(actionEvent -> handleStep(stepsPerClick));
public void actionPerformed(ActionEvent actionEvent) {
handleStep(stepsPerClick); softResetButton.addActionListener(actionEvent -> {
} // If this was a CTRL-click, do a hard reset.
handleReset(false);
}); });
softResetButton.addActionListener(new ActionListener() { hardResetButton.addActionListener(actionEvent -> {
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. handleReset(true);
handleReset(false);
}
}); });
hardResetButton.addActionListener(new ActionListener() { mainWindow.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
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);
// The Menu. This comes last, because it relies on other components having // The Menu. This comes last, because it relies on other components having
// already been initialized. // already been initialized.
@@ -348,7 +332,7 @@ public class Simulator {
logger.error("Console type-ahead buffer underrun!"); logger.error("Console type-ahead buffer underrun!");
} }
if (videoWindow != null && stepsSinceLastCrtcRefresh++ > stepsBetweenCrtcRefreshes) { if (videoWindow != null && stepsSinceLastCrtcRefresh++ > STEPS_BETWEEN_CRTC_REFRESHES) {
stepsSinceLastCrtcRefresh = 0; stepsSinceLastCrtcRefresh = 0;
if (videoWindow.isVisible()) { if (videoWindow.isVisible()) {
videoWindow.repaint(); videoWindow.repaint();
@@ -405,15 +389,13 @@ public class Simulator {
logger.info("Starting main run loop."); logger.info("Starting main run loop.");
isRunning = true; isRunning = true;
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(() -> {
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 {
@@ -424,19 +406,17 @@ 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(() -> {
public void run() { statusPane.updateState();
statusPane.updateState(); memoryWindow.updateState();
memoryWindow.updateState(); runStopButton.setText("Run");
runStopButton.setText("Run"); stepButton.setEnabled(true);
stepButton.setEnabled(true); stepCountBox.setEnabled(true);
stepCountBox.setEnabled(true); if (traceLog.isVisible()) {
if (traceLog.isVisible()) { traceLog.refresh();
traceLog.refresh();
}
menuBar.simulatorDidStop();
traceLog.simulatorDidStop();
} }
menuBar.simulatorDidStop();
traceLog.simulatorDidStop();
}); });
isRunning = false; isRunning = false;
@@ -482,11 +462,7 @@ public class Simulator {
program[i++] = dis.readByte(); program[i++] = dis.readByte();
} }
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(() -> console.reset());
public void run() {
console.reset();
}
});
// Now load the program at the starting address. // Now load the program at the starting address.
loadProgram(program, preferences.getProgramStartAddress()); loadProgram(program, preferences.getProgramStartAddress());
@@ -625,11 +601,9 @@ public class Simulator {
} }
public void actionPerformed(ActionEvent actionEvent) { public void actionPerformed(ActionEvent actionEvent) {
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(() -> {
public void run() { console.setFont(new Font("Monospaced", Font.PLAIN, size));
console.setFont(new Font("Monospaced", Font.PLAIN, size)); mainWindow.pack();
mainWindow.pack();
}
}); });
} }
} }
@@ -812,14 +786,12 @@ public class Simulator {
private void updateVisibleState() { private void updateVisibleState() {
// Immediately update the UI. // Immediately update the UI.
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(() -> {
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();
}
} }
}); });
} }
@@ -82,6 +82,7 @@ public abstract class Acia extends Device {
/** /**
* @return The simulated baud rate in bps. * @return The simulated baud rate in bps.
*/ */
@SuppressWarnings("unused")
public int getBaudRate() { public int getBaudRate() {
return baudRate; return baudRate;
} }
@@ -153,6 +154,7 @@ public abstract class Acia extends Device {
/** /**
* @return true if there is character data in the RX register. * @return true if there is character data in the RX register.
*/ */
@SuppressWarnings("unused")
public boolean hasRxChar() { public boolean hasRxChar() {
return rxFull; return rxFull;
} }
@@ -26,7 +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;
/** /**
* This is a simulation of the MOS 6551 ACIA, with limited * This is a simulation of the MOS 6551 ACIA, with limited
* functionality. Interrupts are not supported. * functionality. Interrupts are not supported.
@@ -45,7 +44,6 @@ public class Acia6551 extends Acia {
static final int CMND_REG = 2; static final int CMND_REG = 2;
static final int CTRL_REG = 3; static final int CTRL_REG = 3;
/** /**
* Registers. These are ignored in the current implementation. * Registers. These are ignored in the current implementation.
*/ */
@@ -106,7 +104,7 @@ public class Acia6551 extends Acia {
/** /**
* Set the control register and associated state. * Set the control register and associated state.
* *
* @param data * @param data Data to write into the control register
*/ */
private void setControlRegister(int data) { private void setControlRegister(int data) {
controlRegister = data; controlRegister = data;
@@ -41,20 +41,12 @@ public class Acia6850 extends Acia {
public static final int ACIA_SIZE = 2; public static final int ACIA_SIZE = 2;
static final int STAT_REG = 0; // read-only static final int STAT_REG = 0; // read-only
static final int CTRL_REG = 0; // write-only static final int CTRL_REG = 0; // write-only
static final int RX_REG = 1; // read-only static final int RX_REG = 1; // read-only
static final int TX_REG = 1; // write-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 { public Acia6850(int address) throws MemoryRangeException {
super(address, ACIA_SIZE, "ACIA6850"); super(address, ACIA_SIZE, "ACIA6850");
setBaudRate(2400); setBaudRate(2400);
@@ -88,17 +80,15 @@ public class Acia6850 extends Acia {
} }
private void setCommandRegister(int data) { private void setCommandRegister(int data) {
commandRegister = data;
// Bits 0 & 1 control the master reset // Bits 0 & 1 control the master reset
if((commandRegister & 0x01) != 0 && (commandRegister & 0x02) != 0) { if((data & 0x01) != 0 && (data & 0x02) != 0) {
reset(); reset();
} }
// Bit 7 controls receiver IRQ behavior // Bit 7 controls receiver IRQ behavior
receiveIrqEnabled = (commandRegister & 0x80) != 0; receiveIrqEnabled = (data & 0x80) != 0;
// Bits 5 & 6 controls transmit IRQ behavior // Bits 5 & 6 controls transmit IRQ behavior
transmitIrqEnabled = (commandRegister & 0x20) != 0 && (commandRegister & 0x40) == 0; transmitIrqEnabled = (data & 0x20) != 0 && (data & 0x40) == 0;
} }
@@ -27,17 +27,11 @@ import com.loomcom.symon.exceptions.MemoryAccessException;
import com.loomcom.symon.exceptions.MemoryRangeException; import com.loomcom.symon.exceptions.MemoryRangeException;
import java.io.IOException; import java.io.IOException;
import java.util.logging.Logger;
/** /**
* Simulation of a 6545 CRTC and virtual CRT output. * Simulation of a 6545 CRTC and virtual CRT output.
*/ */
public class Crtc extends Device { public class Crtc extends Device {
private static final Logger logger = Logger.getLogger(Crtc.class.getName());
// Memory locations in the CRTC address space // Memory locations in the CRTC address space
public static final int REGISTER_SELECT = 0; public static final int REGISTER_SELECT = 0;
public static final int REGISTER_RW = 1; public static final int REGISTER_RW = 1;
@@ -62,16 +62,11 @@ public abstract class Device implements Comparable<Device> {
*/ */
private Set<DeviceChangeListener> deviceChangeListeners; private Set<DeviceChangeListener> deviceChangeListeners;
public Device(int startAddress, int endAddress, String name) public Device(int startAddress, int endAddress, String name) throws MemoryRangeException {
throws MemoryRangeException {
this.memoryRange = new MemoryRange(startAddress, endAddress); this.memoryRange = new MemoryRange(startAddress, endAddress);
this.size = endAddress - startAddress + 1; this.size = endAddress - startAddress + 1;
this.name = name; this.name = name;
this.deviceChangeListeners = new HashSet<DeviceChangeListener>(); this.deviceChangeListeners = new HashSet<>();
}
public Device(int startAddress, int endAddress) throws MemoryRangeException {
this(startAddress, endAddress, null);
} }
/* Methods required to be implemented by inheriting classes. */ /* Methods required to be implemented by inheriting classes. */
@@ -97,6 +92,7 @@ public abstract class Device implements Comparable<Device> {
return memoryRange.endAddress(); return memoryRange.endAddress();
} }
@SuppressWarnings("unused")
public int startAddress() { public int startAddress() {
return memoryRange.startAddress(); return memoryRange.startAddress();
} }
@@ -105,6 +101,7 @@ public abstract class Device implements Comparable<Device> {
return name; return name;
} }
@SuppressWarnings("unused")
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
@@ -118,9 +115,7 @@ public abstract class Device implements Comparable<Device> {
} }
public void notifyListeners() { public void notifyListeners() {
for (DeviceChangeListener l : deviceChangeListeners) { deviceChangeListeners.forEach(DeviceChangeListener::deviceStateChanged);
l.deviceStateChanged();
}
} }
/** /**
@@ -24,5 +24,5 @@
package com.loomcom.symon.devices; package com.loomcom.symon.devices;
public interface DeviceChangeListener { public interface DeviceChangeListener {
public void deviceStateChanged(); void deviceStateChanged();
} }
@@ -28,8 +28,6 @@ import java.util.*;
import com.loomcom.symon.exceptions.*; import com.loomcom.symon.exceptions.*;
import javax.swing.*;
public class Memory extends Device { public class Memory extends Device {
private boolean readOnly; private boolean readOnly;
@@ -57,8 +55,7 @@ public class Memory extends Device {
} }
public static Memory makeRAM(int startAddress, int endAddress) throws MemoryRangeException { public static Memory makeRAM(int startAddress, int endAddress) throws MemoryRangeException {
Memory memory = new Memory(startAddress, endAddress, false); return new Memory(startAddress, endAddress, false);
return memory;
} }
public void write(int address, int data) throws MemoryAccessException { public void write(int address, int data) throws MemoryAccessException {
@@ -108,8 +105,4 @@ public class Memory extends Device {
public String toString() { public String toString() {
return "Memory: " + getMemoryRange().toString(); return "Memory: " + getMemoryRange().toString();
} }
public int[] getDmaAccess() {
return mem;
}
} }
@@ -27,6 +27,8 @@ 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 jdk.nashorn.internal.ir.annotations.Ignore;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
@@ -37,7 +39,6 @@ import java.util.logging.Logger;
/** /**
* Emulation for the SD-card controller of the MULTICOMP system. * Emulation for the SD-card controller of the MULTICOMP system.
* Neiter comlete nor correct. * Neiter comlete nor correct.
*
*/ */
public class SdController extends Device { public class SdController extends Device {
@@ -52,8 +53,7 @@ public class SdController extends Device {
private final static Logger logger = Logger.getLogger(SdController.class.getName()); private final static Logger logger = Logger.getLogger(SdController.class.getName());
private File sdImageFile; private File sdImageFile;
private int lba0,lba1,lba2; private int lba0, lba1, lba2;
private int command;
private int position; private int position;
private Status status = Status.IDLE; private Status status = Status.IDLE;
@@ -67,7 +67,7 @@ public class SdController extends Device {
super(address, address + CONTROLLER_SIZE - 1, "SDCONTROLLER"); super(address, address + CONTROLLER_SIZE - 1, "SDCONTROLLER");
sdImageFile = new File("sd.img"); sdImageFile = new File("sd.img");
if(!sdImageFile.exists()) { if (!sdImageFile.exists()) {
sdImageFile = null; sdImageFile = null;
logger.log(Level.INFO, "Could not find SD card image 'sd.img'"); logger.log(Level.INFO, "Could not find SD card image 'sd.img'");
} }
@@ -76,27 +76,27 @@ public class SdController extends Device {
@Override @Override
public void write(int address, int data) throws MemoryAccessException { public void write(int address, int data) throws MemoryAccessException {
switch(address) { switch (address) {
case 0 : case 0:
writeData(data); writeData(data);
return; return;
case 1 : case 1:
writeCommand(data); writeCommand(data);
return; return;
case 2 : case 2:
this.lba0 = data; this.lba0 = data;
return; return;
case 3 : case 3:
this.lba1 = data; this.lba1 = data;
return; return;
case 4 : case 4:
this.lba2 = data; this.lba2 = data;
} }
} }
@Override @Override
public int read(int address) throws MemoryAccessException { public int read(int address) throws MemoryAccessException {
switch(address) { switch (address) {
case 0: case 0:
return readData(); return readData();
case 1: case 1:
@@ -117,12 +117,12 @@ public class SdController extends Device {
this.readPosition = 0; this.readPosition = 0;
computePosition(); computePosition();
if(sdImageFile != null) { if (sdImageFile != null) {
try { try {
FileInputStream fis = new FileInputStream(sdImageFile); FileInputStream fis = new FileInputStream(sdImageFile);
fis.skip(this.position); fis.skip(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");
} }
fis.close(); fis.close();
@@ -140,13 +140,13 @@ public class SdController extends Device {
private int readData() { private int readData() {
if(status != Status.READ) { if (status != Status.READ) {
return 0; return 0;
} }
int data = readBuffer[readPosition++]; int data = readBuffer[readPosition++];
if(readPosition >= SECTOR_SIZE) { if (readPosition >= SECTOR_SIZE) {
this.status = Status.IDLE; this.status = Status.IDLE;
} }
@@ -154,14 +154,14 @@ public class SdController extends Device {
} }
private void writeData(int data) { private void writeData(int data) {
if(status != Status.WRITE) { if (status != Status.WRITE) {
return; return;
} }
writeBuffer[writePosition++] = (byte) data; writeBuffer[writePosition++] = (byte) data;
if(writePosition >= SECTOR_SIZE) { if (writePosition >= SECTOR_SIZE) {
if(sdImageFile != null) { if (sdImageFile != null) {
try { try {
RandomAccessFile raf = new RandomAccessFile(sdImageFile, "rw"); RandomAccessFile raf = new RandomAccessFile(sdImageFile, "rw");
raf.skipBytes(this.position); raf.skipBytes(this.position);
@@ -178,7 +178,7 @@ public class SdController extends Device {
} }
private int readStatus() { private int readStatus() {
switch(this.status) { switch (this.status) {
case IDLE: case IDLE:
return 128; return 128;
case READ: case READ:
@@ -191,12 +191,11 @@ public class SdController extends Device {
} }
private void writeCommand(int data) { private void writeCommand(int data) {
this.command = data; switch (data) {
switch(this.command) { case 0:
case 0 :
prepareRead(); prepareRead();
return; return;
case 1 : case 1:
prepareWrite(); prepareWrite();
return; return;
default: default:
@@ -39,10 +39,6 @@ public class Via6522 extends Pia {
T2C_L, T2C_H, SR, ACR, PCR, IFR, IER, ORA_H 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 { public Via6522(int address) throws MemoryRangeException {
super(address, address + VIA_SIZE - 1, "MOS 6522 VIA"); super(address, address + VIA_SIZE - 1, "MOS 6522 VIA");
} }
@@ -31,7 +31,4 @@ public class SymonException extends Exception {
public SymonException(String msg) { public SymonException(String msg) {
super(msg); super(msg);
} }
public SymonException() {
super();
}
} }
@@ -35,27 +35,27 @@ import com.loomcom.symon.exceptions.MemoryRangeException;
public interface Machine { public interface Machine {
public Bus getBus(); Bus getBus();
public Cpu getCpu(); Cpu getCpu();
public Memory getRam(); Memory getRam();
public Acia getAcia(); Acia getAcia();
public Pia getPia(); Pia getPia();
public Crtc getCrtc(); Crtc getCrtc();
public Memory getRom(); Memory getRom();
public void setRom(Memory rom) throws MemoryRangeException; void setRom(Memory rom) throws MemoryRangeException;
public int getRomBase(); int getRomBase();
public int getRomSize(); int getRomSize();
public int getMemorySize(); int getMemorySize();
String getName(); String getName();
} }
@@ -65,7 +65,6 @@ public class MulticompMachine implements Machine {
private final Cpu cpu; private final Cpu cpu;
private final Acia acia; private final Acia acia;
private final Memory ram; private final Memory ram;
private final SdController sdController;
private Memory rom; 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.ram = new Memory(MEMORY_BASE, MEMORY_BASE + MEMORY_SIZE - 1, false);
this.acia = new Acia6850(ACIA_BASE); this.acia = new Acia6850(ACIA_BASE);
this.acia.setBaudRate(0); this.acia.setBaudRate(0);
this.sdController = new SdController(SD_BASE);
bus.addCpu(cpu); bus.addCpu(cpu);
bus.addDevice(ram); bus.addDevice(ram);
bus.addDevice(acia, 1); bus.addDevice(acia, 1);
bus.addDevice(sdController, 1); bus.addDevice(new SdController(SD_BASE), 1);
// TODO: Make this configurable, of course. // TODO: Make this configurable, of course.
File romImage = new File("rom.bin"); File romImage = new File("rom.bin");
@@ -44,21 +44,20 @@ import java.awt.event.MouseListener;
public class Console extends JTerminal implements KeyListener, 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; private static final int DEFAULT_BORDER_WIDTH = 10;
// If true, swap CR and LF characters. // If true, swap CR and LF characters.
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
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; 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); super(new Vt100TerminalModel(columns, rows), font);
// A small type-ahead buffer, as might be found in any real // A small type-ahead buffer, as might be found in any real
// VT100-style serial terminal. // VT100-style serial terminal.
this.typeAheadBuffer = new FifoRingBuffer<Character>(128); this.typeAheadBuffer = new FifoRingBuffer<>(128);
this.sendCrForLf = sendCrForLf;
setBorderWidth(DEFAULT_BORDER_WIDTH); setBorderWidth(DEFAULT_BORDER_WIDTH);
addKeyListener(this); addKeyListener(this);
addMouseListener(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. * 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() { public boolean hasInput() {
return !typeAheadBuffer.isEmpty(); 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) 0x0d);
typeAheadBuffer.push((char) 0x0a); typeAheadBuffer.push((char) 0x0a);
} else { } else {
@@ -346,12 +346,8 @@ public class MemoryWindow extends JFrame implements ActionListener {
int fullAddress = fullAddress(row, column); int fullAddress = fullAddress(row, column);
int newValue = Integer.parseInt(hexValue, 16) & 0xff; int newValue = Integer.parseInt(hexValue, 16) & 0xff;
bus.write(fullAddress, newValue); bus.write(fullAddress, newValue);
} catch (MemoryAccessException ex) { } catch (MemoryAccessException | NumberFormatException | ClassCastException ex) {
; // Intentionally swallow exception
} catch (NumberFormatException ex) {
;
} catch (ClassCastException ex) {
;
} }
fireTableCellUpdated(row, column); fireTableCellUpdated(row, column);
} }
@@ -97,23 +97,19 @@ public class PreferencesDialog extends Observable implements Preferences {
JButton applyButton = new JButton("Apply"); JButton applyButton = new JButton("Apply");
JButton cancelButton = new JButton("Cancel"); JButton cancelButton = new JButton("Cancel");
cancelButton.addActionListener(new ActionListener() { cancelButton.addActionListener(actionEvent -> {
public void actionPerformed(ActionEvent actionEvent) { updateUi();
updateUi(); dialog.setVisible(false);
dialog.setVisible(false);
}
}); });
applyButton.addActionListener(new ActionListener() { applyButton.addActionListener(actionEvent -> {
public void actionPerformed(ActionEvent actionEvent) { haltOnBreak = haltOnBreakCheckBox.isSelected();
haltOnBreak = haltOnBreakCheckBox.isSelected(); programLoadAddress = hexToInt(programLoadAddressField.getText());
programLoadAddress = hexToInt(programLoadAddressField.getText()); updateUi();
updateUi(); // TODO: Actually check to see if values have changed, don't assume.
// TODO: Actually check to see if values have changed, don't assume. setChanged();
setChanged(); PreferencesDialog.this.notifyObservers();
PreferencesDialog.this.notifyObservers(); dialog.setVisible(false);
dialog.setVisible(false);
}
}); });
buttonsContainer.add(applyButton); buttonsContainer.add(applyButton);
@@ -53,7 +53,6 @@ public class StatusPanel extends JPanel {
private ImageIcon negativeOn; private ImageIcon negativeOn;
private ImageIcon negativeOff; private ImageIcon negativeOff;
private JLabel statusFlagsLabel;
private JLabel carryFlagLabel; private JLabel carryFlagLabel;
private JLabel zeroFlagLabel; private JLabel zeroFlagLabel;
private JLabel irqDisableFlagLabel; private JLabel irqDisableFlagLabel;
@@ -69,13 +68,6 @@ public class StatusPanel extends JPanel {
private JTextField xField; private JTextField xField;
private JTextField yField; 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 Machine machine;
private static final int EMPTY_BORDER = 10; private static final int EMPTY_BORDER = 10;
@@ -150,13 +142,13 @@ public class StatusPanel extends JPanel {
statusFlagsPanel.add(carryFlagLabel); statusFlagsPanel.add(carryFlagLabel);
// Create and add register and address labels // Create and add register and address labels
statusFlagsLabel = makeLabel("Flags"); JLabel statusFlagsLabel = makeLabel("Flags");
opcodeLabel = makeLabel("Next IR"); JLabel opcodeLabel = makeLabel("Next IR");
pcLabel = makeLabel("PC"); JLabel pcLabel = makeLabel("PC");
spLabel = makeLabel("SP"); JLabel spLabel = makeLabel("SP");
aLabel = makeLabel("A"); JLabel aLabel = makeLabel("A");
xLabel = makeLabel("X"); JLabel xLabel = makeLabel("X");
yLabel = makeLabel("Y"); JLabel yLabel = makeLabel("Y");
statusFlagsLabel.setToolTipText("6502 Processor Status Flags"); statusFlagsLabel.setToolTipText("6502 Processor Status Flags");
opcodeLabel.setToolTipText("Instruction Register"); opcodeLabel.setToolTipText("Instruction Register");
@@ -171,74 +163,59 @@ public class StatusPanel extends JPanel {
yField = makeTextField(SMALL_TEXT_FIELD_SIZE, true); yField = makeTextField(SMALL_TEXT_FIELD_SIZE, true);
// Make fields editable // Make fields editable
pcField.addActionListener(new ActionListener() { pcField.addActionListener(e -> {
@Override try {
public void actionPerformed(ActionEvent e) { int newVal = getHexVal(pcField) & 0xffff;
try { machine.getCpu().setProgramCounter(newVal);
int newVal = getHexVal(pcField) & 0xffff; } catch (Exception ex) {
machine.getCpu().setProgramCounter(newVal); // Swallow exception
} catch (Exception ex) {
// Swallow exception
}
updateState();
} }
updateState();
}); });
spField.addActionListener(new ActionListener() { spField.addActionListener(e -> {
@Override try {
public void actionPerformed(ActionEvent e) { int newVal = getHexVal(spField) & 0xff;
try { machine.getCpu().setStackPointer(newVal);
int newVal = getHexVal(spField) & 0xff; } catch (Exception ex) {
machine.getCpu().setStackPointer(newVal); // Swallow exception
} catch (Exception ex) {
// Swallow exception
}
updateState();
} }
updateState();
}); });
aField.addActionListener(new ActionListener() { aField.addActionListener(e -> {
@Override try {
public void actionPerformed(ActionEvent e) { int newVal = getHexVal(aField) & 0xff;
try { machine.getCpu().setAccumulator(newVal);
int newVal = getHexVal(aField) & 0xff; } catch (Exception ex) {
machine.getCpu().setAccumulator(newVal); // Swallow exception
} catch (Exception ex) {
// Swallow exception
}
updateState();
} }
updateState();
}); });
xField.addActionListener(new ActionListener() { xField.addActionListener(e -> {
@Override try {
public void actionPerformed(ActionEvent e) { int newVal = getHexVal(xField) & 0xff;
try { machine.getCpu().setXRegister(newVal);
int newVal = getHexVal(xField) & 0xff; } catch (Exception ex) {
machine.getCpu().setXRegister(newVal); // Swallow exception
} catch (Exception ex) {
// Swallow exception
}
updateState();
} }
updateState();
}); });
yField.addActionListener(new ActionListener() { yField.addActionListener(e -> {
@Override try {
public void actionPerformed(ActionEvent e) { int newVal = getHexVal(yField) & 0xff;
try { machine.getCpu().setYRegister(newVal);
int newVal = getHexVal(yField) & 0xff; } catch (Exception ex) {
machine.getCpu().setYRegister(newVal); // Swallow exception
} catch (Exception ex) {
// Swallow exception
}
updateState();
} }
updateState();
}); });
constraints.anchor = GridBagConstraints.LINE_START; constraints.anchor = GridBagConstraints.LINE_START;
@@ -44,7 +44,7 @@ public class TraceLog extends JFrame {
private static final int MAX_LOG_LENGTH = 50000; private static final int MAX_LOG_LENGTH = 50000;
public TraceLog() { public TraceLog() {
traceLog = new FifoRingBuffer<Cpu.CpuState>(MAX_LOG_LENGTH); traceLog = new FifoRingBuffer<>(MAX_LOG_LENGTH);
setMinimumSize(MIN_SIZE); setMinimumSize(MIN_SIZE);
setPreferredSize(PREFERRED_SIZE); setPreferredSize(PREFERRED_SIZE);
setResizable(true); setResizable(true);
@@ -122,12 +122,10 @@ 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(() -> {
public void run() { if (cursorBlinkRate > 0) {
if (cursorBlinkRate > 0) { hideCursor = !hideCursor;
hideCursor = !hideCursor; repaint();
repaint();
}
} }
}); });
} }
@@ -38,7 +38,7 @@ public class FifoRingBuffer<E> implements Iterable<E> {
private int maxLength; private int maxLength;
public FifoRingBuffer(int maxLength) { public FifoRingBuffer(int maxLength) {
this.fifoBuffer = new LinkedList<E>(); this.fifoBuffer = new LinkedList<>();
this.maxLength = maxLength; this.maxLength = maxLength;
} }
@@ -121,9 +121,6 @@ public class HexUtil {
* @return Four digit, zero padded hexadecimal string. * @return Four digit, zero padded hexadecimal string.
*/ */
public static String wordToHex(int val) { public static String wordToHex(int val) {
StringBuilder sb = new StringBuilder(4); return HEX_CONSTANTS[(val >> 8) & 0xff] + HEX_CONSTANTS[val & 0xff];
sb.append(HEX_CONSTANTS[(val >> 8) & 0xff]);
sb.append(HEX_CONSTANTS[val & 0xff]);
return sb.toString();
} }
} }