More cleanup of the monitor. Added binary file load command.
This commit is contained in:
1 parent
a3e57274a2
commit
e157f4a972
3 files changed
+133
-87
No files matched your search
@@ -107,8 +107,7 @@ public class Bus {
|
|||||||
return d.read(devAddr);
|
return d.read(devAddr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: Raise access error.
|
throw new MemoryAccessException("Read failed! No device at address.");
|
||||||
throw new RuntimeException("Read failed! Device not found.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(int address, int value) throws MemoryAccessException {
|
public void write(int address, int value) throws MemoryAccessException {
|
||||||
@@ -121,8 +120,7 @@ public class Bus {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: Raise access error.
|
throw new MemoryAccessException("Write failed! No device at address.");
|
||||||
throw new RuntimeException("Write failed! Device not found.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SortedSet<Device> getDevices() {
|
public SortedSet<Device> getDevices() {
|
||||||
|
|||||||
@@ -148,10 +148,8 @@ public class Cpu implements InstructionTable {
|
|||||||
|
|
||||||
// Get the data from the effective address (if any)
|
// Get the data from the effective address (if any)
|
||||||
|
|
||||||
// TODO: Proper initialization.
|
effectiveAddress = 0;
|
||||||
// Using 0xfffffff is to help catch bugs by reading out of bounds.
|
effectiveData = 0;
|
||||||
effectiveAddress = 0xffffff;
|
|
||||||
effectiveData = -1;
|
|
||||||
|
|
||||||
switch(irOpMode) {
|
switch(irOpMode) {
|
||||||
case 0:
|
case 0:
|
||||||
|
|||||||
@@ -1,13 +1,6 @@
|
|||||||
package com.loomcom.symon;
|
package com.loomcom.symon;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.*;
|
||||||
import java.io.BufferedWriter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.OutputStreamWriter;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
import com.loomcom.symon.devices.*;
|
import com.loomcom.symon.devices.*;
|
||||||
@@ -34,6 +27,7 @@ public class Simulator {
|
|||||||
|
|
||||||
/* If true, trace execution of the CPU */
|
/* If true, trace execution of the CPU */
|
||||||
private boolean trace = false;
|
private boolean trace = false;
|
||||||
|
private int nextExamineAddress = 0;
|
||||||
|
|
||||||
public Simulator() throws MemoryRangeException {
|
public Simulator() throws MemoryRangeException {
|
||||||
cpu = new Cpu();
|
cpu = new Cpu();
|
||||||
@@ -57,7 +51,7 @@ public class Simulator {
|
|||||||
}
|
}
|
||||||
prompt();
|
prompt();
|
||||||
}
|
}
|
||||||
writeLine("\n\nGoodbye!");
|
writeLine("\nGoodbye!");
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
System.err.println("Error: " + ex.toString());
|
System.err.println("Error: " + ex.toString());
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
@@ -72,10 +66,12 @@ public class Simulator {
|
|||||||
Command c = new Command(commandLine);
|
Command c = new Command(commandLine);
|
||||||
String cmd = c.getCommand();
|
String cmd = c.getCommand();
|
||||||
if (cmd != null) {
|
if (cmd != null) {
|
||||||
if ("test".equals(cmd)) {
|
if (cmd.startsWith("ste")) {
|
||||||
doTest();
|
doStep(c);
|
||||||
} else if (cmd.startsWith("s")) {
|
} else if (cmd.startsWith("sta")) {
|
||||||
doGetState();
|
doGetState();
|
||||||
|
} else if (cmd.startsWith("se")) {
|
||||||
|
doSet(c);
|
||||||
} else if (cmd.startsWith("r")) {
|
} else if (cmd.startsWith("r")) {
|
||||||
doReset();
|
doReset();
|
||||||
} else if (cmd.startsWith("e")) {
|
} else if (cmd.startsWith("e")) {
|
||||||
@@ -90,6 +86,8 @@ public class Simulator {
|
|||||||
doToggleTrace();
|
doToggleTrace();
|
||||||
} else if (cmd.startsWith("f")) {
|
} else if (cmd.startsWith("f")) {
|
||||||
doFill(c);
|
doFill(c);
|
||||||
|
} else if (cmd.startsWith("l")) {
|
||||||
|
doLoad(c);
|
||||||
} else {
|
} else {
|
||||||
writeLine("? Type h for help");
|
writeLine("? Type h for help");
|
||||||
}
|
}
|
||||||
@@ -99,18 +97,23 @@ public class Simulator {
|
|||||||
public void doHelp(Command c) throws IOException {
|
public void doHelp(Command c) throws IOException {
|
||||||
writeLine("Symon 6502 Simulator");
|
writeLine("Symon 6502 Simulator");
|
||||||
writeLine("");
|
writeLine("");
|
||||||
writeLine("All addresses must be in hexadecimal. Commands may be short or");
|
writeLine("All addresses must be in hexadecimal.");
|
||||||
writeLine("long (e.g. 'e' or 'ex' or 'examine'). Note that 'go' clears the");
|
writeLine("Commands may be short or long (e.g. 'e' or 'ex' or 'examine').");
|
||||||
writeLine("Break processor status flag");
|
writeLine("Note that 'go' clears the BREAK processor status flag.");
|
||||||
writeLine("");
|
writeLine("");
|
||||||
writeLine("g [address [steps]] Start running at address.");
|
writeLine("g [address] [steps] Start running at address, or at PC");
|
||||||
writeLine("e [start [end]] Examine memory.");
|
writeLine("e [start] [end] Examine memory at PC, or at start, " +
|
||||||
writeLine("d [address] [data] Deposit data into address.");
|
"or from start to end");
|
||||||
writeLine("f [start] [end] [data] Fill memory with data.");
|
writeLine("d <address> <data> Deposit data into address.");
|
||||||
writeLine("r Reset simulator.");
|
writeLine("f <start> <end> <data> Fill memory with data.");
|
||||||
writeLine("s Show CPU state.");
|
writeLine("reset Reset simulator.");
|
||||||
writeLine("t Toggle trace.");
|
writeLine("set {pc,a,x,y} [data] Set register to data value.");
|
||||||
writeLine("q (or Control-D) Quit.");
|
writeLine("stat Show CPU state.");
|
||||||
|
writeLine("step [address] Step once, optionally starting at " +
|
||||||
|
"address");
|
||||||
|
writeLine("trace Toggle trace.");
|
||||||
|
writeLine("load <filename> Load binary file.");
|
||||||
|
writeLine("q (or Control-D) Quit.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void doGetState() throws IOException, MemoryAccessException {
|
public void doGetState() throws IOException, MemoryAccessException {
|
||||||
@@ -118,7 +121,66 @@ public class Simulator {
|
|||||||
writeLine("Trace is " + (trace ? "on" : "off"));
|
writeLine("Trace is " + (trace ? "on" : "off"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void doExamine(Command c) throws IOException, MemoryAccessException, CommandFormatException {
|
public void doLoad(Command c) throws IOException, MemoryAccessException,
|
||||||
|
CommandFormatException {
|
||||||
|
if (c.numArgs() != 2) {
|
||||||
|
throw new CommandFormatException("load <file> <address>");
|
||||||
|
}
|
||||||
|
|
||||||
|
File binFile = new File(c.getArg(0));
|
||||||
|
int address = stringToWord(c.getArg(1));
|
||||||
|
|
||||||
|
if (!binFile.exists()) {
|
||||||
|
throw new CommandFormatException("File '" + binFile +
|
||||||
|
"' does not exist.");
|
||||||
|
}
|
||||||
|
writeLine("Loading file '" + binFile + "' at address " +
|
||||||
|
String.format("%04x", address) + "...");
|
||||||
|
|
||||||
|
int bytesLoaded = 0;
|
||||||
|
|
||||||
|
FileInputStream fis = new FileInputStream(binFile);
|
||||||
|
|
||||||
|
try {
|
||||||
|
int b = 0;
|
||||||
|
while ((b = fis.read()) > -1 && address <= bus.endAddress()) {
|
||||||
|
bus.write(address++, b);
|
||||||
|
bytesLoaded++;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
fis.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
writeLine("Loaded " + bytesLoaded + " (" +
|
||||||
|
String.format("$%x", bytesLoaded) + ") bytes");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doSet(Command c) throws MemoryAccessException,
|
||||||
|
CommandFormatException {
|
||||||
|
if (c.numArgs() != 2) {
|
||||||
|
throw new CommandFormatException("set {a, x, y, pc} <value>");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
String reg = c.getArg(0).toLowerCase();
|
||||||
|
String data = c.getArg(1);
|
||||||
|
if ("a".equals(reg)) {
|
||||||
|
cpu.setAccumulator(stringToByte(data));
|
||||||
|
} else if ("x".equals(reg)) {
|
||||||
|
cpu.setXRegister(stringToByte(data));
|
||||||
|
} else if ("y".equals(reg)) {
|
||||||
|
cpu.setYRegister(stringToByte(data));
|
||||||
|
} else if ("pc".equals(reg)) {
|
||||||
|
cpu.setProgramCounter(stringToWord(data));
|
||||||
|
} else {
|
||||||
|
throw new CommandFormatException("set {a, x, y, pc} <value>");
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
throw new CommandFormatException("Illegal address");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doExamine(Command c) throws IOException, MemoryAccessException,
|
||||||
|
CommandFormatException {
|
||||||
try {
|
try {
|
||||||
if (c.numArgs() == 2) {
|
if (c.numArgs() == 2) {
|
||||||
int startAddress = stringToWord(c.getArgs()[0]);
|
int startAddress = stringToWord(c.getArgs()[0]);
|
||||||
@@ -127,23 +189,33 @@ public class Simulator {
|
|||||||
StringBuffer line = new StringBuffer();
|
StringBuffer line = new StringBuffer();
|
||||||
int numBytes = 0;
|
int numBytes = 0;
|
||||||
line.append(String.format("%04x ", startAddress));
|
line.append(String.format("%04x ", startAddress));
|
||||||
while (numBytes++ < 8 && startAddress <= endAddress) {
|
while (numBytes++ < 16 && startAddress <= endAddress) {
|
||||||
line.append(String.format("%02x ", bus.read(startAddress++)));
|
line.append(String.format("%02x ", bus.read(startAddress++)));
|
||||||
|
if (numBytes % 8 == 0) {
|
||||||
|
line.append(" ");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
writeLine(line.toString());
|
writeLine(line.toString());
|
||||||
}
|
}
|
||||||
|
nextExamineAddress = endAddress + 1;
|
||||||
} else if (c.numArgs() == 1) {
|
} else if (c.numArgs() == 1) {
|
||||||
int address = stringToWord(c.getArgs()[0]);
|
int address = stringToWord(c.getArgs()[0]);
|
||||||
writeLine(String.format("%04x %02x", address, bus.read(address)));
|
writeLine(String.format("%04x %02x", address, bus.read(address)));
|
||||||
|
nextExamineAddress = address + 1;
|
||||||
|
} else if (c.numArgs() == 0) {
|
||||||
|
writeLine(String.format("%04x %02x", nextExamineAddress,
|
||||||
|
bus.read(nextExamineAddress)));
|
||||||
|
nextExamineAddress++;
|
||||||
} else {
|
} else {
|
||||||
throw new CommandFormatException("e [start [end]]");
|
throw new CommandFormatException("e [start [end]]");
|
||||||
}
|
}
|
||||||
} catch (NumberFormatException ex) {
|
} catch (NumberFormatException ex) {
|
||||||
throw new CommandFormatException("Address not understood");
|
throw new CommandFormatException("Illegal Address");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void doDeposit(Command c) throws MemoryAccessException, CommandFormatException {
|
public void doDeposit(Command c) throws MemoryAccessException,
|
||||||
|
CommandFormatException {
|
||||||
if (c.numArgs() != 2) {
|
if (c.numArgs() != 2) {
|
||||||
throw new CommandFormatException("d [address] [data]");
|
throw new CommandFormatException("d [address] [data]");
|
||||||
}
|
}
|
||||||
@@ -152,11 +224,12 @@ public class Simulator {
|
|||||||
int data = stringToByte(c.getArg(1));
|
int data = stringToByte(c.getArg(1));
|
||||||
bus.write(address, data);
|
bus.write(address, data);
|
||||||
} catch (NumberFormatException ex) {
|
} catch (NumberFormatException ex) {
|
||||||
throw new CommandFormatException("Address not understood");
|
throw new CommandFormatException("Illegal Address");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void doFill(Command c) throws MemoryAccessException, CommandFormatException {
|
public void doFill(Command c) throws MemoryAccessException,
|
||||||
|
CommandFormatException {
|
||||||
if (c.numArgs() != 3) {
|
if (c.numArgs() != 3) {
|
||||||
throw new CommandFormatException("f [start] [end] [data]");
|
throw new CommandFormatException("f [start] [end] [data]");
|
||||||
}
|
}
|
||||||
@@ -169,17 +242,37 @@ public class Simulator {
|
|||||||
start++;
|
start++;
|
||||||
}
|
}
|
||||||
} catch (NumberFormatException ex) {
|
} catch (NumberFormatException ex) {
|
||||||
throw new CommandFormatException("Address not understood");
|
throw new CommandFormatException("Illegal Address");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void doGo(Command c) throws IOException, MemoryAccessException, CommandFormatException {
|
public void doStep(Command c) throws IOException, MemoryAccessException,
|
||||||
if (c.numArgs() != 1 && c.numArgs() != 2) {
|
CommandFormatException {
|
||||||
throw new CommandFormatException("g [address [steps]]");
|
try {
|
||||||
|
if (c.numArgs() > 0) {
|
||||||
|
cpu.setProgramCounter(stringToWord(c.getArg(1)));
|
||||||
|
}
|
||||||
|
cpu.step();
|
||||||
|
writeLine(cpu.toString()); // Always show status after stepping
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
throw new CommandFormatException("Illegal Address");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doGo(Command c) throws IOException, MemoryAccessException,
|
||||||
|
CommandFormatException {
|
||||||
|
if (c.numArgs() > 2) {
|
||||||
|
throw new CommandFormatException("g [address] [steps]");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
int start = stringToWord(c.getArg(0));
|
int start = 0;
|
||||||
int steps = -1;
|
int steps = -1;
|
||||||
|
|
||||||
|
if (c.numArgs() > 0) {
|
||||||
|
start = stringToWord(c.getArg(0));
|
||||||
|
} else {
|
||||||
|
start = cpu.getProgramCounter();
|
||||||
|
}
|
||||||
if (c.numArgs() == 2) {
|
if (c.numArgs() == 2) {
|
||||||
steps = stringToWord(c.getArg(1));
|
steps = stringToWord(c.getArg(1));
|
||||||
}
|
}
|
||||||
@@ -200,7 +293,7 @@ public class Simulator {
|
|||||||
writeLine(cpu.toString());
|
writeLine(cpu.toString());
|
||||||
}
|
}
|
||||||
} catch (NumberFormatException ex) {
|
} catch (NumberFormatException ex) {
|
||||||
throw new CommandFormatException("Address not understood");
|
throw new CommandFormatException("Illegal Address");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,49 +307,6 @@ public class Simulator {
|
|||||||
this.trace = false;
|
this.trace = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Run a very simple test program that doesn't do
|
|
||||||
* much other than exercise the accumulator a bit.
|
|
||||||
*/
|
|
||||||
public void doTest() throws MemoryAccessException {
|
|
||||||
int[] zpData = {
|
|
||||||
0x39, // $0000
|
|
||||||
0x21, // $0001
|
|
||||||
0x12 // $0002
|
|
||||||
};
|
|
||||||
int[] data = {
|
|
||||||
0xae, // $c800
|
|
||||||
0x13, // $c801
|
|
||||||
0x29 // $c802
|
|
||||||
};
|
|
||||||
int[] program = {
|
|
||||||
0xa9, 0xff, // LDA #$FF
|
|
||||||
0xa0, 0x1a, // LDY #$1A
|
|
||||||
0xa2, 0x90, // LDX #$90
|
|
||||||
0xa2, 0x02, // LDX #$02
|
|
||||||
0x49, 0xff, // EOR #$FF
|
|
||||||
0xa9, 0x00, // LDA #$00
|
|
||||||
0xa2, 0x00, // LDX #$00
|
|
||||||
0x29, 0xff, // AND #$FF
|
|
||||||
0xa0, 0x00, // LDY #$00
|
|
||||||
0xa5, 0x00, // LDA $00
|
|
||||||
0xad, 0x00, 0xc8, // LDA $c800
|
|
||||||
0x4c, 0x00, 0x03 // JMP #$0300
|
|
||||||
};
|
|
||||||
int programLength = 12;
|
|
||||||
|
|
||||||
load(0x0000, zpData);
|
|
||||||
load(0x0300, program);
|
|
||||||
load(0xc800, data);
|
|
||||||
cpu.setResetVector(0x0300);
|
|
||||||
cpu.reset();
|
|
||||||
|
|
||||||
for (int i = 0; i <= programLength; i++) {
|
|
||||||
cpu.step();
|
|
||||||
System.out.println(cpu.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main simulator routine.
|
* Main simulator routine.
|
||||||
*/
|
*/
|
||||||
@@ -289,7 +339,7 @@ public class Simulator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void greeting() throws IOException {
|
private void greeting() throws IOException {
|
||||||
writeLine("Welcome to the Symon Simulator!");
|
writeLine("Welcome to the Symon 6502 Simulator. Type 'help' for help.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void prompt() throws IOException {
|
private void prompt() throws IOException {
|
||||||
|
|||||||
Reference in new issue
Block a user