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:
parent
a4a110dcef
commit
6e8fd40014
25
pom.xml
25
pom.xml
|
@ -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>
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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' : '.') +
|
||||
"]";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -24,5 +24,5 @@
|
|||
package com.loomcom.symon.devices;
|
||||
|
||||
public interface DeviceChangeListener {
|
||||
public void deviceStateChanged();
|
||||
void deviceStateChanged();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -31,7 +31,4 @@ public class SymonException extends Exception {
|
|||
public SymonException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
public SymonException() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user