CPU bug fixes and Simulator enhancements.
Bug Fixes: - Fixed several bugs in the CPU that caused processor status flags to be set incorrectly. Instructions affected were: STA, STX, STY, CMP, CPX, CPY, BIT. - Made some internal-use-only methods on the CPU class private. - Fixed incorrect disassembly of (Indirect,X) and (Indirect),Y instructions. Although this didn't affect behavior, it certainly caused me some confusion in debugging. - Added missing "BCS" instruction to instruction table. Enhancements: - Now includes a full version of Lee Davison's Enhanced 6502 BASIC bundled as source code and a ROM image. Get that REAL COMPUTER EXPERIENCE!(tm) - If a file named "rom.bin" exists in the same directory where the simulator is executed, it will be loaded at addresses $d000-$ffff. - Gave the CPU an idle loop to make simulated timing a little more realistic (but this is still an area needing major improvement) - Changed the CPU's toString() method to give better debugging output. - Added a small typeahead buffer to the Console. - Better exception messaging. Misc: - Bumped version to 0.5, updated README.
This commit is contained in:
1 parent
c1caf8c6b4
commit
795ccfde5d
25 files changed
+13622
-4508
No files matched your search
@@ -29,6 +29,10 @@ public class Cpu implements InstructionTable {
|
||||
public static final int NMI_VECTOR_L = 0xfffe;
|
||||
public static final int NMI_VECTOR_H = 0xffff;
|
||||
|
||||
// The delay in microseconds between steps.
|
||||
// TODO: Make configurable
|
||||
private static final int CLOCK_IN_NS = 1000;
|
||||
|
||||
/* The Bus */
|
||||
private Bus bus;
|
||||
|
||||
@@ -41,11 +45,13 @@ public class Cpu implements InstructionTable {
|
||||
private int pc; // Program Counter register
|
||||
private int sp; // Stack Pointer register, offset into page 1
|
||||
private int ir; // Instruction register
|
||||
|
||||
private int lastPc; // The program counter before the most recent step.
|
||||
private int[] args = new int[3]; // Decoded instruction args
|
||||
private int instSize; // # of operands for the instruction
|
||||
|
||||
/* Scratch space for addressing mode and effective address
|
||||
* calculations */
|
||||
* 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;
|
||||
@@ -435,8 +441,8 @@ public class Cpu implements InstructionTable {
|
||||
/** BIT - Bit Test ******************************************************/
|
||||
case 0x24: // Zero Page
|
||||
case 0x2c: // Absolute
|
||||
tmp = a & bus.read(effectiveAddress);
|
||||
setZeroFlag(tmp == 0);
|
||||
tmp = bus.read(effectiveAddress);
|
||||
setZeroFlag((a & tmp) == 0);
|
||||
setNegativeFlag((tmp & 0x80) != 0);
|
||||
setOverflowFlag((tmp & 0x40) != 0);
|
||||
break;
|
||||
@@ -553,7 +559,6 @@ public class Cpu implements InstructionTable {
|
||||
case 0x99: // Absolute,Y
|
||||
case 0x9d: // Absolute,X
|
||||
bus.write(effectiveAddress, a);
|
||||
setArithmeticFlags(a);
|
||||
break;
|
||||
|
||||
|
||||
@@ -562,7 +567,6 @@ public class Cpu implements InstructionTable {
|
||||
case 0x8c: // Absolute
|
||||
case 0x94: // Zero Page,X
|
||||
bus.write(effectiveAddress, y);
|
||||
setArithmeticFlags(y);
|
||||
break;
|
||||
|
||||
|
||||
@@ -571,7 +575,6 @@ public class Cpu implements InstructionTable {
|
||||
case 0x8e: // Absolute
|
||||
case 0x96: // Zero Page,Y
|
||||
bus.write(effectiveAddress, x);
|
||||
setArithmeticFlags(x);
|
||||
break;
|
||||
|
||||
|
||||
@@ -704,6 +707,8 @@ public class Cpu implements InstructionTable {
|
||||
setOpTrap();
|
||||
break;
|
||||
}
|
||||
|
||||
delayLoop(ir);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -715,7 +720,7 @@ public class Cpu implements InstructionTable {
|
||||
* @param operand The operand
|
||||
* @return
|
||||
*/
|
||||
public int adc(int acc, int operand) {
|
||||
private int adc(int acc, int operand) {
|
||||
int result = (operand & 0xff) + (acc & 0xff) + getCarryBit();
|
||||
int carry6 = (operand & 0x7f) + (acc & 0x7f) + getCarryBit();
|
||||
setCarryFlag((result & 0x100) != 0);
|
||||
@@ -729,7 +734,7 @@ public class Cpu implements InstructionTable {
|
||||
* Add with Carry (BCD).
|
||||
*/
|
||||
|
||||
public int adcDecimal(int acc, int operand) {
|
||||
private int adcDecimal(int acc, int operand) {
|
||||
int l, h, result;
|
||||
l = (acc & 0x0f) + (operand & 0x0f) + getCarryBit();
|
||||
if ((l & 0xff) > 9) l += 6;
|
||||
@@ -748,12 +753,8 @@ public class Cpu implements InstructionTable {
|
||||
* Common code for Subtract with Carry. Just calls ADC of the
|
||||
* one's complement of the operand. This lets the N, V, C, and Z
|
||||
* flags work out nicely without any additional logic.
|
||||
*
|
||||
* @param acc
|
||||
* @param operand
|
||||
* @return
|
||||
*/
|
||||
public int sbc(int acc, int operand) {
|
||||
private int sbc(int acc, int operand) {
|
||||
int result;
|
||||
result = adc(acc, ~operand);
|
||||
setArithmeticFlags(result);
|
||||
@@ -762,12 +763,8 @@ public class Cpu implements InstructionTable {
|
||||
|
||||
/**
|
||||
* Subtract with Carry, BCD mode.
|
||||
*
|
||||
* @param acc
|
||||
* @param operand
|
||||
* @return
|
||||
*/
|
||||
public int sbcDecimal(int acc, int operand) {
|
||||
private int sbcDecimal(int acc, int operand) {
|
||||
int l, h, result;
|
||||
l = (acc & 0x0f) - (operand & 0x0f) - (carryFlag ? 0 : 1);
|
||||
if ((l & 0x10) != 0) l -= 6;
|
||||
@@ -784,23 +781,19 @@ public class Cpu implements InstructionTable {
|
||||
/**
|
||||
* Compare two values, and set carry, zero, and negative flags
|
||||
* appropriately.
|
||||
*
|
||||
* @param reg
|
||||
* @param operand
|
||||
*/
|
||||
public void cmp(int reg, int operand) {
|
||||
private void cmp(int reg, int operand) {
|
||||
int tmp = (reg - operand) & 0xff;
|
||||
setCarryFlag(reg >= operand);
|
||||
setZeroFlag(reg == operand);
|
||||
setNegativeFlag((reg - operand) > 0);
|
||||
setZeroFlag(tmp == 0);
|
||||
setNegativeFlag((tmp & 0x80) != 0); // Negative bit set
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Negative and Zero flags based on the current value of the
|
||||
* register operand.
|
||||
*
|
||||
* @param reg The register.
|
||||
*/
|
||||
public void setArithmeticFlags(int reg) {
|
||||
private void setArithmeticFlags(int reg) {
|
||||
zeroFlag = (reg == 0);
|
||||
negativeFlag = (reg & 0x80) != 0;
|
||||
}
|
||||
@@ -1134,6 +1127,10 @@ public class Cpu implements InstructionTable {
|
||||
this.y = val;
|
||||
}
|
||||
|
||||
public int getLastProgramCounter() {
|
||||
return lastPc;
|
||||
}
|
||||
|
||||
public int getProgramCounter() {
|
||||
return pc;
|
||||
}
|
||||
@@ -1285,15 +1282,15 @@ public class Cpu implements InstructionTable {
|
||||
*/
|
||||
public String toString() {
|
||||
String opcode = opcode(ir, args[0], args[1]);
|
||||
StringBuffer sb = new StringBuffer(String.format("$%04X", addr) +
|
||||
" ");
|
||||
StringBuffer sb = new StringBuffer(getInstructionByteStatus());
|
||||
sb.append(" ");
|
||||
sb.append(String.format("%-14s", opcode));
|
||||
sb.append("A=" + getAccumulatorStatus() + " ");
|
||||
sb.append("X=" + getXRegisterStatus() + " ");
|
||||
sb.append("Y=" + getYRegisterStatus() + " ");
|
||||
sb.append("PC=" + getProgramCounterStatus() + " ");
|
||||
sb.append("SP=" + getStackPointerStatus() + " ");
|
||||
sb.append("P=" + getProcessorStatusString());
|
||||
sb.append("A:" + String.format("%02x", a) + " ");
|
||||
sb.append("X:" + String.format("%02x", x) + " ");
|
||||
sb.append("Y:" + String.format("%02x", y) + " ");
|
||||
sb.append("F:" + String.format("%02x", getProcessorStatus()) + " ");
|
||||
sb.append("S:" + String.format("1%02x", sp) + " ");
|
||||
sb.append(getProcessorStatusString());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -1397,6 +1394,19 @@ public class Cpu implements InstructionTable {
|
||||
bus.write(RST_VECTOR_L, address & 0x00ff);
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform a busy-loop for CLOCK_IN_NS nanoseconds
|
||||
*/
|
||||
private void delayLoop(int opcode) {
|
||||
int clockSteps = Cpu.instructionClocks[0xff & opcode];
|
||||
// Just a precaution. This could be better.
|
||||
if (clockSteps == 0) { clockSteps = 1; }
|
||||
long startTime = System.nanoTime();
|
||||
long stopTime = startTime + (CLOCK_IN_NS * clockSteps);
|
||||
// Busy loop
|
||||
while (System.nanoTime() < stopTime) { ; }
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an opcode and its operands, return a formatted name.
|
||||
*
|
||||
@@ -1430,10 +1440,10 @@ public class Cpu implements InstructionTable {
|
||||
sb.append(String.format(" ($%04X)", address(op1, op2)));
|
||||
break;
|
||||
case XIN:
|
||||
sb.append(String.format(" ($%02X),X", op1));
|
||||
sb.append(String.format(" ($%02X,X)", op1));
|
||||
break;
|
||||
case INY:
|
||||
sb.append(String.format(" ($%02X,Y)", op1));
|
||||
sb.append(String.format(" ($%02X),Y", op1));
|
||||
break;
|
||||
case REL:
|
||||
case ZPG:
|
||||
@@ -1449,4 +1459,19 @@ public class Cpu implements InstructionTable {
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public String getInstructionByteStatus() {
|
||||
switch (Cpu.instructionSizes[ir]) {
|
||||
case 0:
|
||||
case 1:
|
||||
return String.format("%04X %02X ", addr, ir);
|
||||
case 2:
|
||||
return String.format("%04X %02X %02X ", addr, ir, args[0]);
|
||||
case 3:
|
||||
return String.format("%04X %02X %02X %02X", addr, ir, args[0], args[1]);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user