1
0
mirror of https://github.com/sethm/symon.git synced 2024-06-03 07:29:30 +00:00

Initial 65C02 Support

First pass at adding CMOS 65C02 support for the following instructions
and addressing modes:

   * ORA (ZP Indirect)
   * AND (ZP Indirect)
   * EOR (ZP Indirect)
   * ADC (ZP Indirect)
   * STA (ZP Indirect)
   * LDA (ZP Indirect)
   * CMP (ZP Indirect)
   * SBC (ZP Indirect)
This commit is contained in:
Seth Morabito 2016-06-12 18:55:09 -07:00
parent 5a2e057e69
commit 4cca0b4663
7 changed files with 560 additions and 129 deletions

View File

@ -79,7 +79,7 @@ public class Cpu implements InstructionTable {
* Construct a new CPU. * Construct a new CPU.
*/ */
public Cpu() { public Cpu() {
this(CpuBehavior.NMOS_WITH_INDIRECT_JMP_BUG); this(CpuBehavior.NMOS_6502);
} }
public Cpu(CpuBehavior behavior) { public Cpu(CpuBehavior behavior) {
@ -204,6 +204,13 @@ public class Cpu implements InstructionTable {
case 3: // Absolute case 3: // Absolute
effectiveAddress = Utils.address(state.args[0], state.args[1]); effectiveAddress = Utils.address(state.args[0], state.args[1]);
break; break;
case 4: // 65C02 (Zero Page)
if (behavior == CpuBehavior.CMOS_6502 ||
behavior == CpuBehavior.CMOS_65816) {
effectiveAddress = Utils.address(bus.read(state.args[0]),
bus.read((state.args[0] + 1) & 0xff));
}
break;
case 5: // Zero Page,X / Zero Page,Y case 5: // Zero Page,X / Zero Page,Y
if (state.ir == 0x96 || state.ir == 0xb6) { if (state.ir == 0x96 || state.ir == 0xb6) {
effectiveAddress = zpyAddress(state.args[0]); effectiveAddress = zpyAddress(state.args[0]);
@ -262,7 +269,7 @@ public class Cpu implements InstructionTable {
break; break;
case 0x08: // PHP - Push Processor Status - Implied case 0x08: // PHP - Push Processor Status - Implied
// Break flag is always set in the stack value. // Break flag is always set in the stack value.
stackPush(state.getStatusFlag() | 0x10); stackPush(state.getStatusFlag() | 0x10);
break; break;
case 0x10: // BPL - Branch if Positive - Relative case 0x10: // BPL - Branch if Positive - Relative
if (!getNegativeFlag()) { if (!getNegativeFlag()) {
@ -398,11 +405,12 @@ public class Cpu implements InstructionTable {
case 0x4c: // JMP - Absolute case 0x4c: // JMP - Absolute
state.pc = Utils.address(state.args[0], state.args[1]); state.pc = Utils.address(state.args[0], state.args[1]);
break; break;
// TODO: 65C02 instruction 0x7C, JMP (Indirect,X)
case 0x6c: // JMP - Indirect case 0x6c: // JMP - Indirect
lo = Utils.address(state.args[0], state.args[1]); // Address of low byte lo = Utils.address(state.args[0], state.args[1]); // Address of low byte
if (state.args[0] == 0xff && if (state.args[0] == 0xff &&
(behavior == CpuBehavior.NMOS_WITH_INDIRECT_JMP_BUG || (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG)) { behavior == CpuBehavior.NMOS_WITH_ROR_BUG)) {
hi = Utils.address(0x00, state.args[1]); hi = Utils.address(0x00, state.args[1]);
} else { } else {
@ -422,13 +430,20 @@ public class Cpu implements InstructionTable {
* (http://www.obelisk.demon.co.uk/6502/reference.html#JMP) * (http://www.obelisk.demon.co.uk/6502/reference.html#JMP)
*/ */
break; break;
case 0x7C: // 65C02 JMP - Absolute,X
state.pc = (Utils.address(state.args[0], state.args[1]) + state.x) & 0xffff;
break;
/** ORA - Logical Inclusive Or ******************************************/ /** ORA - Logical Inclusive Or ******************************************/
case 0x09: // #Immediate case 0x09: // #Immediate
state.a |= state.args[0]; state.a |= state.args[0];
setArithmeticFlags(state.a); setArithmeticFlags(state.a);
break; break;
case 0x12: // 65C02 ORA (ZP)
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
case 0x01: // (Zero Page,X) case 0x01: // (Zero Page,X)
case 0x05: // Zero Page case 0x05: // Zero Page
case 0x0d: // Absolute case 0x0d: // Absolute
@ -471,6 +486,11 @@ public class Cpu implements InstructionTable {
state.a &= state.args[0]; state.a &= state.args[0];
setArithmeticFlags(state.a); setArithmeticFlags(state.a);
break; break;
case 0x32: // 65C02 AND (ZP)
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
case 0x21: // (Zero Page,X) case 0x21: // (Zero Page,X)
case 0x25: // Zero Page case 0x25: // Zero Page
case 0x2d: // Absolute case 0x2d: // Absolute
@ -503,6 +523,11 @@ public class Cpu implements InstructionTable {
state.a ^= state.args[0]; state.a ^= state.args[0];
setArithmeticFlags(state.a); setArithmeticFlags(state.a);
break; break;
case 0x52: // 65C02 EOR (ZP)
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
case 0x41: // (Zero Page,X) case 0x41: // (Zero Page,X)
case 0x45: // Zero Page case 0x45: // Zero Page
case 0x4d: // Absolute case 0x4d: // Absolute
@ -538,6 +563,11 @@ public class Cpu implements InstructionTable {
state.a = adc(state.a, state.args[0]); state.a = adc(state.a, state.args[0]);
} }
break; break;
case 0x72: // 65C02 ADC (ZP)
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
case 0x61: // (Zero Page,X) case 0x61: // (Zero Page,X)
case 0x65: // Zero Page case 0x65: // Zero Page
case 0x6d: // Absolute case 0x6d: // Absolute
@ -569,6 +599,11 @@ public class Cpu implements InstructionTable {
/** STA - Store Accumulator *********************************************/ /** STA - Store Accumulator *********************************************/
case 0x92: // 65C02 STA (ZP)
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
case 0x81: // (Zero Page,X) case 0x81: // (Zero Page,X)
case 0x85: // Zero Page case 0x85: // Zero Page
case 0x8d: // Absolute case 0x8d: // Absolute
@ -629,6 +664,11 @@ public class Cpu implements InstructionTable {
state.a = state.args[0]; state.a = state.args[0];
setArithmeticFlags(state.a); setArithmeticFlags(state.a);
break; break;
case 0xb2: // 65C02 LDA (ZP)
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
case 0xa1: // (Zero Page,X) case 0xa1: // (Zero Page,X)
case 0xa5: // Zero Page case 0xa5: // Zero Page
case 0xad: // Absolute case 0xad: // Absolute
@ -655,6 +695,11 @@ public class Cpu implements InstructionTable {
case 0xc9: // #Immediate case 0xc9: // #Immediate
cmp(state.a, state.args[0]); cmp(state.a, state.args[0]);
break; break;
case 0xd2: // 65C02 CMP (ZP)
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
case 0xc1: // (Zero Page,X) case 0xc1: // (Zero Page,X)
case 0xc5: // Zero Page case 0xc5: // Zero Page
case 0xcd: // Absolute case 0xcd: // Absolute
@ -695,6 +740,11 @@ public class Cpu implements InstructionTable {
state.a = sbc(state.a, state.args[0]); state.a = sbc(state.a, state.args[0]);
} }
break; break;
case 0xf2: // 65C02 SBC (ZP)
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
case 0xe1: // (Zero Page,X) case 0xe1: // (Zero Page,X)
case 0xe5: // Zero Page case 0xe5: // Zero Page
case 0xed: // Absolute case 0xed: // Absolute
@ -1334,6 +1384,13 @@ public class Cpu implements InstructionTable {
return (zp + state.x) & 0xff; return (zp + state.x) & 0xff;
} }
/**
* Given a single byte, compute the Zero Page,Y offset address.
*/
int zpyAddress(int zp) {
return (zp + state.y) & 0xff;
}
/** /**
* Given a single byte, compute the offset address. * Given a single byte, compute the offset address.
*/ */
@ -1342,21 +1399,21 @@ public class Cpu implements InstructionTable {
return (state.pc + (byte) offset) & 0xffff; return (state.pc + (byte) offset) & 0xffff;
} }
/**
* Given a single byte, compute the Zero Page,Y offset address.
*/
int zpyAddress(int zp) {
return (zp + state.y) & 0xff;
}
/* /*
* Perform a busy-loop until the instruction should complete on the wall clock * Perform a busy-loop until the instruction should complete on the wall clock
*/ */
private void delayLoop(int opcode) { private void delayLoop(int opcode) {
int clockSteps = Cpu.instructionClocks[0xff & opcode]; final int clockSteps;
if (behavior == CpuBehavior.NMOS_WITH_ROR_BUG ||
behavior == CpuBehavior.NMOS_6502) {
clockSteps = Cpu.instructionClocksNmos[0xff & opcode];
} else {
clockSteps = Cpu.instructionClocksCmos[0xff & opcode];
}
if (clockSteps == 0) { if (clockSteps == 0) {
logger.warn("Opcode {} has clock step of 0!", opcode); logger.warn("Opcode {} has clock step of 0!", String.format("0x%02x", opcode));
return; return;
} }

View File

@ -46,20 +46,17 @@ public interface InstructionTable {
* *
* NB: Does NOT implement "unimplemented" NMOS instructions. * NB: Does NOT implement "unimplemented" NMOS instructions.
*/ */
NMOS_WITH_INDIRECT_JMP_BUG, NMOS_6502,
/**
* Emulate an NMOS 6502 without the indirect JMP bug. This type of 6502
* does not actually exist in the wild.
*
* NB: Does NOT implement "unimplemented" NMOS instructions.
*/
NMOS_WITHOUT_INDIRECT_JMP_BUG,
/** /**
* Emulate a CMOS 65C02, with all CMOS instructions and addressing modes. * Emulate a CMOS 65C02, with all CMOS instructions and addressing modes.
*/ */
CMOS CMOS_6502,
/**
* Emulate a CMOS 65C816.
*/
CMOS_65816
} }
/** /**
@ -128,19 +125,25 @@ public interface InstructionTable {
ZPG { ZPG {
public String toString() { public String toString() {
return "Zeropage"; return "Zero Page";
} }
}, },
ZPX { ZPX {
public String toString() { public String toString() {
return "Zeropage, X-indexed"; return "Zero Page, X-indexed";
} }
}, },
ZPY { ZPY {
public String toString() { public String toString() {
return "Zeropage, Y-indexed"; return "Zero Page, Y-indexed";
}
},
ZPI {
public String toString() {
return "Zero Page Indirect";
} }
}, },
@ -154,52 +157,55 @@ public interface InstructionTable {
// 6502 opcodes. No 65C02 opcodes implemented. // 6502 opcodes. No 65C02 opcodes implemented.
/** /**
* Instruction opcode names. * Instruction opcode names. This lists all opcodes for
* NMOS 6502, CMOS 65C02, and CMOS 65C816
*/ */
String[] opcodeNames = { String[] opcodeNames = {
"BRK", "ORA", null, null, null, "ORA", "ASL", null, "BRK", "ORA", null, null, null, "ORA", "ASL", null, // 0x00-0x07
"PHP", "ORA", "ASL", null, null, "ORA", "ASL", null, "PHP", "ORA", "ASL", null, null, "ORA", "ASL", null, // 0x08-0x0f
"BPL", "ORA", null, null, null, "ORA", "ASL", null, "BPL", "ORA", "ORA", null, null, "ORA", "ASL", null, // 0x10-0x17
"CLC", "ORA", null, null, null, "ORA", "ASL", null, "CLC", "ORA", null, null, null, "ORA", "ASL", null, // 0x18-0x1f
"JSR", "AND", null, null, "BIT", "AND", "ROL", null, "JSR", "AND", null, null, "BIT", "AND", "ROL", null, // 0x20-0x27
"PLP", "AND", "ROL", null, "BIT", "AND", "ROL", null, "PLP", "AND", "ROL", null, "BIT", "AND", "ROL", null, // 0x28-0x2f
"BMI", "AND", null, null, null, "AND", "ROL", null, "BMI", "AND", "AND", null, null, "AND", "ROL", null, // 0x30-0x37
"SEC", "AND", null, null, null, "AND", "ROL", null, "SEC", "AND", null, null, null, "AND", "ROL", null, // 0x38-0x3f
"RTI", "EOR", null, null, null, "EOR", "LSR", null, "RTI", "EOR", null, null, null, "EOR", "LSR", null, // 0x40-0x47
"PHA", "EOR", "LSR", null, "JMP", "EOR", "LSR", null, "PHA", "EOR", "LSR", null, "JMP", "EOR", "LSR", null, // 0x48-0x4f
"BVC", "EOR", null, null, null, "EOR", "LSR", null, "BVC", "EOR", "EOR", null, null, "EOR", "LSR", null, // 0x50-0x57
"CLI", "EOR", null, null, null, "EOR", "LSR", null, "CLI", "EOR", null, null, null, "EOR", "LSR", null, // 0x58-0x5f
"RTS", "ADC", null, null, null, "ADC", "ROR", null, "RTS", "ADC", null, null, null, "ADC", "ROR", null, // 0x60-0x67
"PLA", "ADC", "ROR", null, "JMP", "ADC", "ROR", null, "PLA", "ADC", "ROR", null, "JMP", "ADC", "ROR", null, // 0x68-0x6f
"BVS", "ADC", null, null, null, "ADC", "ROR", null, "BVS", "ADC", "ADC", null, null, "ADC", "ROR", null, // 0x70-0x77
"SEI", "ADC", null, null, null, "ADC", "ROR", null, "SEI", "ADC", null, null, "JMP", "ADC", "ROR", null, // 0x78-0x7f
"BCS", "STA", null, null, "STY", "STA", "STX", null, "BCS", "STA", null, null, "STY", "STA", "STX", null, // 0x80-0x87
"DEY", null, "TXA", null, "STY", "STA", "STX", null, "DEY", null, "TXA", null, "STY", "STA", "STX", null, // 0x88-0x8f
"BCC", "STA", null, null, "STY", "STA", "STX", null, "BCC", "STA", "STA", null, "STY", "STA", "STX", null, // 0x90-0x97
"TYA", "STA", "TXS", null, null, "STA", null, null, "TYA", "STA", "TXS", null, null, "STA", null, null, // 0x98-0x9f
"LDY", "LDA", "LDX", null, "LDY", "LDA", "LDX", null, "LDY", "LDA", "LDX", null, "LDY", "LDA", "LDX", null, // 0xa0-0xa7
"TAY", "LDA", "TAX", null, "LDY", "LDA", "LDX", null, "TAY", "LDA", "TAX", null, "LDY", "LDA", "LDX", null, // 0xa8-0xaf
"BCS", "LDA", null, null, "LDY", "LDA", "LDX", null, "BCS", "LDA", "LDA", null, "LDY", "LDA", "LDX", null, // 0xb0-0xb7
"CLV", "LDA", "TSX", null, "LDY", "LDA", "LDX", null, "CLV", "LDA", "TSX", null, "LDY", "LDA", "LDX", null, // 0xb8-0xbf
"CPY", "CMP", null, null, "CPY", "CMP", "DEC", null, "CPY", "CMP", null, null, "CPY", "CMP", "DEC", null, // 0xc0-0xc7
"INY", "CMP", "DEX", null, "CPY", "CMP", "DEC", null, "INY", "CMP", "DEX", null, "CPY", "CMP", "DEC", null, // 0xc8-0xcf
"BNE", "CMP", null, null, null, "CMP", "DEC", null, "BNE", "CMP", "CMP", null, null, "CMP", "DEC", null, // 0xd0-0xd7
"CLD", "CMP", null, null, null, "CMP", "DEC", null, "CLD", "CMP", null, null, null, "CMP", "DEC", null, // 0xd8-0xdf
"CPX", "SBC", null, null, "CPX", "SBC", "INC", null, "CPX", "SBC", null, null, "CPX", "SBC", "INC", null, // 0xe0-0xe7
"INX", "SBC", "NOP", null, "CPX", "SBC", "INC", null, "INX", "SBC", "NOP", null, "CPX", "SBC", "INC", null, // 0xe8-0xef
"BEQ", "SBC", null, null, null, "SBC", "INC", null, "BEQ", "SBC", "SBC", null, null, "SBC", "INC", null, // 0xf0-0xf7
"SED", "SBC", null, null, null, "SBC", "INC", null "SED", "SBC", null, null, null, "SBC", "INC", null // 0xf8-0xff
}; };
/** /**
* Instruction addressing modes. * Instruction addressing modes. This table includes sizes
* for all instructions for NMOS 6502, CMOS 65C02,
* and CMOS 65C816
*/ */
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
Mode.NUL, Mode.ABS, Mode.ABS, Mode.NUL, // 0x0c-0x0f Mode.NUL, Mode.ABS, Mode.ABS, Mode.NUL, // 0x0c-0x0f
Mode.REL, Mode.INY, Mode.NUL, Mode.NUL, // 0x10-0x13 Mode.REL, Mode.INY, Mode.ZPI, Mode.NUL, // 0x10-0x13
Mode.NUL, Mode.ZPX, Mode.ZPX, Mode.NUL, // 0x14-0x17 Mode.NUL, Mode.ZPX, Mode.ZPX, Mode.NUL, // 0x14-0x17
Mode.IMP, Mode.ABY, Mode.NUL, Mode.NUL, // 0x18-0x1b Mode.IMP, Mode.ABY, Mode.NUL, Mode.NUL, // 0x18-0x1b
Mode.NUL, Mode.ABX, Mode.ABX, Mode.NUL, // 0x1c-0x1f Mode.NUL, Mode.ABX, Mode.ABX, Mode.NUL, // 0x1c-0x1f
@ -207,7 +213,7 @@ public interface InstructionTable {
Mode.ZPG, Mode.ZPG, Mode.ZPG, Mode.NUL, // 0x24-0x27 Mode.ZPG, Mode.ZPG, Mode.ZPG, Mode.NUL, // 0x24-0x27
Mode.IMP, Mode.IMM, Mode.ACC, Mode.NUL, // 0x28-0x2b Mode.IMP, Mode.IMM, Mode.ACC, Mode.NUL, // 0x28-0x2b
Mode.ABS, Mode.ABS, Mode.ABS, Mode.NUL, // 0x2c-0x2f Mode.ABS, Mode.ABS, Mode.ABS, Mode.NUL, // 0x2c-0x2f
Mode.REL, Mode.INY, Mode.NUL, Mode.NUL, // 0x30-0x33 Mode.REL, Mode.INY, Mode.ZPI, Mode.NUL, // 0x30-0x33
Mode.NUL, Mode.ZPX, Mode.ZPX, Mode.NUL, // 0x34-0x37 Mode.NUL, Mode.ZPX, Mode.ZPX, Mode.NUL, // 0x34-0x37
Mode.IMP, Mode.ABY, Mode.NUL, Mode.NUL, // 0x38-0x3b Mode.IMP, Mode.ABY, Mode.NUL, Mode.NUL, // 0x38-0x3b
Mode.NUL, Mode.ABX, Mode.ABX, Mode.NUL, // 0x3c-0x3f Mode.NUL, Mode.ABX, Mode.ABX, Mode.NUL, // 0x3c-0x3f
@ -215,7 +221,7 @@ public interface InstructionTable {
Mode.NUL, Mode.ZPG, Mode.ZPG, Mode.NUL, // 0x44-0x47 Mode.NUL, Mode.ZPG, Mode.ZPG, Mode.NUL, // 0x44-0x47
Mode.IMP, Mode.IMM, Mode.ACC, Mode.NUL, // 0x48-0x4b Mode.IMP, Mode.IMM, Mode.ACC, Mode.NUL, // 0x48-0x4b
Mode.ABS, Mode.ABS, Mode.ABS, Mode.NUL, // 0x4c-0x4f Mode.ABS, Mode.ABS, Mode.ABS, Mode.NUL, // 0x4c-0x4f
Mode.REL, Mode.INY, Mode.NUL, Mode.NUL, // 0x50-0x53 Mode.REL, Mode.INY, Mode.ZPI, Mode.NUL, // 0x50-0x53
Mode.NUL, Mode.ZPX, Mode.ZPX, Mode.NUL, // 0x54-0x57 Mode.NUL, Mode.ZPX, Mode.ZPX, Mode.NUL, // 0x54-0x57
Mode.IMP, Mode.ABY, Mode.NUL, Mode.NUL, // 0x58-0x5b Mode.IMP, Mode.ABY, Mode.NUL, Mode.NUL, // 0x58-0x5b
Mode.NUL, Mode.ABX, Mode.ABX, Mode.NUL, // 0x5c-0x5f Mode.NUL, Mode.ABX, Mode.ABX, Mode.NUL, // 0x5c-0x5f
@ -223,15 +229,15 @@ public interface InstructionTable {
Mode.NUL, Mode.ZPG, Mode.ZPG, Mode.NUL, // 0x64-0x67 Mode.NUL, Mode.ZPG, Mode.ZPG, Mode.NUL, // 0x64-0x67
Mode.IMP, Mode.IMM, Mode.ACC, Mode.NUL, // 0x68-0x6b Mode.IMP, Mode.IMM, Mode.ACC, Mode.NUL, // 0x68-0x6b
Mode.IND, Mode.ABS, Mode.ABS, Mode.NUL, // 0x6c-0x6f Mode.IND, Mode.ABS, Mode.ABS, Mode.NUL, // 0x6c-0x6f
Mode.REL, Mode.INY, Mode.NUL, Mode.NUL, // 0x70-0x73 Mode.REL, Mode.INY, Mode.ZPI, Mode.NUL, // 0x70-0x73
Mode.NUL, Mode.ZPX, Mode.ZPX, Mode.NUL, // 0x74-0x77 Mode.NUL, Mode.ZPX, Mode.ZPX, Mode.NUL, // 0x74-0x77
Mode.IMP, Mode.ABY, Mode.NUL, Mode.NUL, // 0x78-0x7b Mode.IMP, Mode.ABY, Mode.NUL, Mode.NUL, // 0x78-0x7b
Mode.NUL, Mode.ABX, Mode.ABX, Mode.NUL, // 0x7c-0x7f Mode.ABX, Mode.ABX, Mode.ABX, Mode.NUL, // 0x7c-0x7f
Mode.REL, Mode.XIN, Mode.NUL, Mode.NUL, // 0x80-0x83 Mode.REL, Mode.XIN, Mode.NUL, Mode.NUL, // 0x80-0x83
Mode.ZPG, Mode.ZPG, Mode.ZPG, Mode.NUL, // 0x84-0x87 Mode.ZPG, Mode.ZPG, Mode.ZPG, Mode.NUL, // 0x84-0x87
Mode.IMP, Mode.NUL, Mode.IMP, Mode.NUL, // 0x88-0x8b Mode.IMP, Mode.NUL, Mode.IMP, Mode.NUL, // 0x88-0x8b
Mode.ABS, Mode.ABS, Mode.ABS, Mode.NUL, // 0x8c-0x8f Mode.ABS, Mode.ABS, Mode.ABS, Mode.NUL, // 0x8c-0x8f
Mode.REL, Mode.INY, Mode.NUL, Mode.NUL, // 0x90-0x93 Mode.REL, Mode.INY, Mode.ZPI, Mode.NUL, // 0x90-0x93
Mode.ZPX, Mode.ZPX, Mode.ZPY, Mode.NUL, // 0x94-0x97 Mode.ZPX, Mode.ZPX, Mode.ZPY, Mode.NUL, // 0x94-0x97
Mode.IMP, Mode.ABY, Mode.IMP, Mode.NUL, // 0x98-0x9b Mode.IMP, Mode.ABY, Mode.IMP, Mode.NUL, // 0x98-0x9b
Mode.NUL, Mode.ABX, Mode.NUL, Mode.NUL, // 0x9c-0x9f Mode.NUL, Mode.ABX, Mode.NUL, Mode.NUL, // 0x9c-0x9f
@ -239,7 +245,7 @@ public interface InstructionTable {
Mode.ZPG, Mode.ZPG, Mode.ZPG, Mode.NUL, // 0xa4-0xa7 Mode.ZPG, Mode.ZPG, Mode.ZPG, Mode.NUL, // 0xa4-0xa7
Mode.IMP, Mode.IMM, Mode.IMP, Mode.NUL, // 0xa8-0xab Mode.IMP, Mode.IMM, Mode.IMP, Mode.NUL, // 0xa8-0xab
Mode.ABS, Mode.ABS, Mode.ABS, Mode.NUL, // 0xac-0xaf Mode.ABS, Mode.ABS, Mode.ABS, Mode.NUL, // 0xac-0xaf
Mode.REL, Mode.INY, Mode.NUL, Mode.NUL, // 0xb0-0xb3 Mode.REL, Mode.INY, Mode.ZPI, Mode.NUL, // 0xb0-0xb3
Mode.ZPX, Mode.ZPX, Mode.ZPY, Mode.NUL, // 0xb4-0xb7 Mode.ZPX, Mode.ZPX, Mode.ZPY, Mode.NUL, // 0xb4-0xb7
Mode.IMP, Mode.ABY, Mode.IMP, Mode.NUL, // 0xb8-0xbb Mode.IMP, Mode.ABY, Mode.IMP, Mode.NUL, // 0xb8-0xbb
Mode.ABX, Mode.ABX, Mode.ABY, Mode.NUL, // 0xbc-0xbf Mode.ABX, Mode.ABX, Mode.ABY, Mode.NUL, // 0xbc-0xbf
@ -247,7 +253,7 @@ public interface InstructionTable {
Mode.ZPG, Mode.ZPG, Mode.ZPG, Mode.NUL, // 0xc4-0xc7 Mode.ZPG, Mode.ZPG, Mode.ZPG, Mode.NUL, // 0xc4-0xc7
Mode.IMP, Mode.IMM, Mode.IMP, Mode.NUL, // 0xc8-0xcb Mode.IMP, Mode.IMM, Mode.IMP, Mode.NUL, // 0xc8-0xcb
Mode.ABS, Mode.ABS, Mode.ABS, Mode.NUL, // 0xcc-0xcf Mode.ABS, Mode.ABS, Mode.ABS, Mode.NUL, // 0xcc-0xcf
Mode.REL, Mode.INY, Mode.NUL, Mode.NUL, // 0xd0-0xd3 Mode.REL, Mode.INY, Mode.ZPI, Mode.NUL, // 0xd0-0xd3
Mode.NUL, Mode.ZPX, Mode.ZPX, Mode.NUL, // 0xd4-0xd7 Mode.NUL, Mode.ZPX, Mode.ZPX, Mode.NUL, // 0xd4-0xd7
Mode.IMP, Mode.ABY, Mode.NUL, Mode.NUL, // 0xd8-0xdb Mode.IMP, Mode.ABY, Mode.NUL, Mode.NUL, // 0xd8-0xdb
Mode.NUL, Mode.ABX, Mode.ABX, Mode.NUL, // 0xdc-0xdf Mode.NUL, Mode.ABX, Mode.ABX, Mode.NUL, // 0xdc-0xdf
@ -255,7 +261,7 @@ public interface InstructionTable {
Mode.ZPG, Mode.ZPG, Mode.ZPG, Mode.NUL, // 0xe4-0xe7 Mode.ZPG, Mode.ZPG, Mode.ZPG, Mode.NUL, // 0xe4-0xe7
Mode.IMP, Mode.IMM, Mode.IMP, Mode.NUL, // 0xe8-0xeb Mode.IMP, Mode.IMM, Mode.IMP, Mode.NUL, // 0xe8-0xeb
Mode.ABS, Mode.ABS, Mode.ABS, Mode.NUL, // 0xec-0xef Mode.ABS, Mode.ABS, Mode.ABS, Mode.NUL, // 0xec-0xef
Mode.REL, Mode.INY, Mode.NUL, Mode.NUL, // 0xf0-0xf3 Mode.REL, Mode.INY, Mode.ZPI, Mode.NUL, // 0xf0-0xf3
Mode.NUL, Mode.ZPX, Mode.ZPX, Mode.NUL, // 0xf4-0xf7 Mode.NUL, Mode.ZPX, Mode.ZPX, Mode.NUL, // 0xf4-0xf7
Mode.IMP, Mode.ABY, Mode.NUL, Mode.NUL, // 0xf8-0xfb Mode.IMP, Mode.ABY, Mode.NUL, Mode.NUL, // 0xf8-0xfb
Mode.NUL, Mode.ABX, Mode.ABX, Mode.NUL // 0xfc-0xff Mode.NUL, Mode.ABX, Mode.ABX, Mode.NUL // 0xfc-0xff
@ -263,47 +269,73 @@ public interface InstructionTable {
/** /**
* Size, in bytes, required for each instruction. * Size, in bytes, required for each instruction. This table
* includes sizes for all instructions for NMOS 6502, CMOS 65C02,
* and CMOS 65C816
*/ */
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, // 0x00-0x0f
2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0, 2, 2, 2, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0, // 0x10-0x1f
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, // 0x20-0x2f
2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0, 2, 2, 2, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0, // 0x30-0x3f
1, 2, 0, 0, 0, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0, 1, 2, 0, 0, 0, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0, // 0x40-0x4f
2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0, 2, 2, 2, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0, // 0x50-0x5f
1, 2, 0, 0, 0, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0, 1, 2, 0, 0, 0, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0, // 0x60-0x6f
2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0, 2, 2, 2, 0, 0, 2, 2, 0, 1, 3, 0, 0, 3, 3, 3, 0, // 0x70-0x7f
2, 2, 0, 0, 2, 2, 2, 0, 1, 0, 1, 0, 3, 3, 3, 0, 2, 2, 0, 0, 2, 2, 2, 0, 1, 0, 1, 0, 3, 3, 3, 0, // 0x80-0x8f
2, 2, 0, 0, 2, 2, 2, 0, 1, 3, 1, 0, 0, 3, 0, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 3, 1, 0, 0, 3, 0, 0, // 0x90-0x9f
2, 2, 2, 0, 2, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0, // 0xa0-0xaf
2, 2, 0, 0, 2, 2, 2, 0, 1, 3, 1, 0, 3, 3, 3, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 3, 1, 0, 3, 3, 3, 0, // 0xb0-0xbf
2, 2, 0, 0, 2, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0, 2, 2, 0, 0, 2, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0, // 0xc0-0xcf
2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0, 2, 2, 2, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0, // 0xd0-0xdf
2, 2, 0, 0, 2, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0, 2, 2, 0, 0, 2, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0, // 0xe0-0xef
2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0 2, 2, 2, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0 // 0xf0-0xff
}; };
/** /**
* Number of clock cycles required for each instruction * Number of clock cycles required for each instruction when
* in NMOS mode.
*/ */
int[] instructionClocks = { int[] instructionClocksNmos = {
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, // 0x00-0x0f
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, // 0x10-0x1f
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, // 0x20-0x2f
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, // 0x30-0x3f
6, 6, 0, 0, 0, 3, 5, 0, 3, 2, 2, 0, 3, 4, 6, 0, 6, 6, 0, 0, 0, 3, 5, 0, 3, 2, 2, 0, 3, 4, 6, 0, // 0x40-0x4f
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, // 0x50-0x5f
6, 6, 0, 0, 0, 3, 5, 0, 4, 2, 2, 0, 5, 4, 6, 0, 6, 6, 0, 0, 0, 3, 5, 0, 4, 2, 2, 0, 5, 4, 6, 0, // 0x60-0x6f
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, // 0x70-0x7f
2, 6, 0, 0, 3, 3, 3, 0, 2, 0, 2, 0, 4, 4, 4, 0, 2, 6, 0, 0, 3, 3, 3, 0, 2, 0, 2, 0, 4, 4, 4, 0, // 0x80-0x8f
2, 6, 0, 0, 4, 4, 4, 0, 2, 5, 2, 0, 0, 5, 0, 0, 2, 6, 0, 0, 4, 4, 4, 0, 2, 5, 2, 0, 0, 5, 0, 0, // 0x90-0x9f
2, 6, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 4, 4, 4, 0, 2, 6, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 4, 4, 4, 0, // 0xa0-0xaf
2, 5, 0, 0, 4, 4, 4, 0, 2, 4, 2, 0, 4, 4, 4, 0, 2, 5, 0, 0, 4, 4, 4, 0, 2, 4, 2, 0, 4, 4, 4, 0, // 0xb0-0xbf
2, 6, 0, 0, 3, 3, 5, 0, 2, 2, 2, 0, 4, 4, 6, 0, 2, 6, 0, 0, 3, 3, 5, 0, 2, 2, 2, 0, 4, 4, 6, 0, // 0xc0-0xcf
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, // 0xd0-0xdf
2, 6, 0, 0, 3, 3, 5, 0, 2, 2, 2, 0, 4, 4, 6, 0, 2, 6, 0, 0, 3, 3, 5, 0, 2, 2, 2, 0, 4, 4, 6, 0, // 0xe0-0xef
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 // 0xf0-0xff
};
/**
* Number of clock cycles required for each instruction when
* in CMOS mode
*/
int[] instructionClocksCmos = {
7, 6, 0, 0, 0, 3, 5, 0, 3, 2, 2, 0, 0, 4, 6, 0, // 0x00-0x0f
2, 5, 5, 0, 0, 4, 6, 0, 2, 4, 0, 0, 0, 4, 7, 0, // 0x10-0x1f
6, 6, 0, 0, 3, 3, 5, 0, 4, 2, 2, 0, 4, 4, 6, 0, // 0x20-0x2f
2, 5, 5, 0, 0, 4, 6, 0, 2, 4, 0, 0, 0, 4, 7, 0, // 0x30-0x3f
6, 6, 0, 0, 0, 3, 5, 0, 3, 2, 2, 0, 3, 4, 6, 0, // 0x40-0x4f
2, 5, 5, 0, 0, 4, 6, 0, 2, 4, 0, 0, 0, 4, 7, 0, // 0x50-0x5f
6, 6, 0, 0, 0, 3, 5, 0, 4, 2, 2, 0, 5, 4, 6, 0, // 0x60-0x6f
2, 5, 5, 0, 0, 4, 6, 0, 2, 4, 0, 0, 0, 4, 7, 0, // 0x70-0x7f
2, 6, 0, 0, 3, 3, 3, 0, 2, 0, 2, 0, 4, 4, 4, 0, // 0x80-0x8f
2, 6, 5, 0, 4, 4, 4, 0, 2, 5, 2, 0, 0, 5, 0, 0, // 0x90-0x9f
2, 6, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 4, 4, 4, 0, // 0xa0-0xaf
2, 5, 5, 0, 4, 4, 4, 0, 2, 4, 2, 0, 4, 4, 4, 0, // 0xb0-0xbf
2, 6, 0, 0, 3, 3, 5, 0, 2, 2, 2, 0, 4, 4, 6, 0, // 0xc0-0xcf
2, 5, 5, 0, 0, 4, 6, 0, 2, 4, 0, 0, 0, 4, 7, 0, // 0xd0-0xdf
2, 6, 0, 0, 3, 3, 5, 0, 2, 2, 2, 0, 4, 4, 6, 0, // 0xe0-0xef
2, 5, 5, 0, 0, 4, 6, 0, 2, 4, 0, 0, 0, 4, 7, 0 // 0xf0-0xff
}; };
} }

View File

@ -25,18 +25,10 @@ public class CpuIndirectIndexedModeTest {
bus.write(0xfffd, (Bus.DEFAULT_LOAD_ADDRESS & 0xff00) >>> 8); bus.write(0xfffd, (Bus.DEFAULT_LOAD_ADDRESS & 0xff00) >>> 8);
cpu.reset(); cpu.reset();
// Assert initial state
assertEquals(0, cpu.getAccumulator());
assertEquals(0, cpu.getXRegister());
assertEquals(0, cpu.getYRegister());
assertEquals(0x200, cpu.getProgramCounter());
assertEquals(0xff, cpu.getStackPointer());
assertEquals(0x20, cpu.getProcessorStatus());
} }
@Test @Test
public void test_LDA() throws Exception { public void test_LDA() throws Exception {
assertEquals(cpu.toString(), 0x00, cpu.getAccumulator());
bus.write(0x0014, 0x00); bus.write(0x0014, 0x00);
bus.write(0x0015, 0xd8); bus.write(0x0015, 0xd8);
bus.write(0xd828, 0x03); bus.write(0xd828, 0x03);

View File

@ -3,15 +3,19 @@ package com.loomcom.symon;
import com.loomcom.symon.devices.Memory; import com.loomcom.symon.devices.Memory;
import com.loomcom.symon.exceptions.MemoryAccessException; import com.loomcom.symon.exceptions.MemoryAccessException;
import junit.framework.TestCase; import org.junit.Before;
import org.junit.Test;
public class CpuIndirectModeTest extends TestCase { import static org.junit.Assert.assertEquals;
public class CpuIndirectModeTest {
protected Cpu cpu; protected Cpu cpu;
protected Bus bus; protected Bus bus;
protected Memory mem; protected Memory mem;
protected void setUp() throws Exception { @Before
public void setUp() throws Exception {
this.cpu = new Cpu(); this.cpu = new Cpu();
this.bus = new Bus(0x0000, 0xffff); this.bus = new Bus(0x0000, 0xffff);
this.mem = new Memory(0x0000, 0xffff); this.mem = new Memory(0x0000, 0xffff);
@ -41,6 +45,7 @@ public class CpuIndirectModeTest extends TestCase {
/* JMP - Jump - $6c */ /* JMP - Jump - $6c */
@Test
public void test_JMP_notOnPageBoundary() throws MemoryAccessException { public void test_JMP_notOnPageBoundary() throws MemoryAccessException {
bus.write(0x3400, 0x00); bus.write(0x3400, 0x00);
bus.write(0x3401, 0x54); bus.write(0x3401, 0x54);
@ -51,6 +56,7 @@ public class CpuIndirectModeTest extends TestCase {
assertEquals(0x20, cpu.getProcessorStatus()); assertEquals(0x20, cpu.getProcessorStatus());
} }
@Test
public void test_JMP_with_ROR_Bug() throws MemoryAccessException { public void test_JMP_with_ROR_Bug() throws MemoryAccessException {
cpu.setBehavior(Cpu.CpuBehavior.NMOS_WITH_ROR_BUG); cpu.setBehavior(Cpu.CpuBehavior.NMOS_WITH_ROR_BUG);
bus.write(0x3400, 0x22); bus.write(0x3400, 0x22);
@ -63,8 +69,9 @@ public class CpuIndirectModeTest extends TestCase {
assertEquals(0x20, cpu.getProcessorStatus()); assertEquals(0x20, cpu.getProcessorStatus());
} }
@Test
public void test_JMP_withIndirectBug() throws MemoryAccessException { public void test_JMP_withIndirectBug() throws MemoryAccessException {
cpu.setBehavior(Cpu.CpuBehavior.NMOS_WITH_INDIRECT_JMP_BUG); cpu.setBehavior(Cpu.CpuBehavior.NMOS_6502);
bus.write(0x3400, 0x22); bus.write(0x3400, 0x22);
bus.write(0x34ff, 0x00); bus.write(0x34ff, 0x00);
bus.write(0x3500, 0x54); bus.write(0x3500, 0x54);
@ -75,8 +82,9 @@ public class CpuIndirectModeTest extends TestCase {
assertEquals(0x20, cpu.getProcessorStatus()); assertEquals(0x20, cpu.getProcessorStatus());
} }
@Test
public void test_JMP_withOutIndirectBug() throws MemoryAccessException { public void test_JMP_withOutIndirectBug() throws MemoryAccessException {
cpu.setBehavior(Cpu.CpuBehavior.NMOS_WITHOUT_INDIRECT_JMP_BUG); cpu.setBehavior(Cpu.CpuBehavior.CMOS_6502);
bus.write(0x3400, 0x22); bus.write(0x3400, 0x22);
bus.write(0x34ff, 0x00); bus.write(0x34ff, 0x00);
bus.write(0x3500, 0x54); bus.write(0x3500, 0x54);
@ -87,8 +95,9 @@ public class CpuIndirectModeTest extends TestCase {
assertEquals(0x20, cpu.getProcessorStatus()); assertEquals(0x20, cpu.getProcessorStatus());
} }
@Test
public void test_JMP_cmos() throws MemoryAccessException { public void test_JMP_cmos() throws MemoryAccessException {
cpu.setBehavior(Cpu.CpuBehavior.CMOS); cpu.setBehavior(Cpu.CpuBehavior.CMOS_6502);
bus.write(0x3400, 0x22); bus.write(0x3400, 0x22);
bus.write(0x34ff, 0x00); bus.write(0x34ff, 0x00);
bus.write(0x3500, 0x54); bus.write(0x3500, 0x54);

View File

@ -3,14 +3,21 @@ package com.loomcom.symon;
import com.loomcom.symon.devices.Memory; import com.loomcom.symon.devices.Memory;
import com.loomcom.symon.exceptions.MemoryAccessException; import com.loomcom.symon.exceptions.MemoryAccessException;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.junit.Before;
import org.junit.Test;
public class CpuIndirectXModeTest extends TestCase { import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class CpuIndirectXModeTest {
protected Cpu cpu; protected Cpu cpu;
protected Bus bus; protected Bus bus;
protected Memory mem; protected Memory mem;
protected void setUp() throws Exception { @Before
public void setUp() throws Exception {
this.cpu = new Cpu(); this.cpu = new Cpu();
this.bus = new Bus(0x0000, 0xffff); this.bus = new Bus(0x0000, 0xffff);
this.mem = new Memory(0x0000, 0xffff); this.mem = new Memory(0x0000, 0xffff);
@ -47,7 +54,7 @@ public class CpuIndirectXModeTest extends TestCase {
*/ */
/* ORA - Logical Inclusive OR - $1d */ /* ORA - Logical Inclusive OR - $1d */
@Test
public void test_ORA() throws MemoryAccessException { public void test_ORA() throws MemoryAccessException {
// Set some initial values in memory // Set some initial values in memory
bus.write(0x2c30, 0x00); bus.write(0x2c30, 0x00);
@ -93,7 +100,7 @@ public class CpuIndirectXModeTest extends TestCase {
} }
/* AND - Logical AND - $3d */ /* AND - Logical AND - $3d */
@Test
public void test_AND() throws MemoryAccessException { public void test_AND() throws MemoryAccessException {
bus.write(0x1a30, 0x00); bus.write(0x1a30, 0x00);
bus.write(0x1a31, 0x11); bus.write(0x1a31, 0x11);
@ -153,7 +160,7 @@ public class CpuIndirectXModeTest extends TestCase {
} }
/* EOR - Exclusive OR - $5d */ /* EOR - Exclusive OR - $5d */
@Test
public void test_EOR() throws MemoryAccessException { public void test_EOR() throws MemoryAccessException {
bus.write(0xab40, 0x00); bus.write(0xab40, 0x00);
bus.write(0xab41, 0xff); bus.write(0xab41, 0xff);
@ -162,7 +169,7 @@ public class CpuIndirectXModeTest extends TestCase {
cpu.setXRegister(0x30); cpu.setXRegister(0x30);
bus.loadProgram(0xa9, 0x88, // LDA #$88 bus.loadProgram(0xa9, 0x88, // LDA #$88
0x5d, 0x10, 0xab, // EOR $ab10,X 0x5d, 0x10, 0xab, // EOR $ab10,X
0x5d, 0x11, 0xab, // EOR $ab11,X 0x5d, 0x11, 0xab, // EOR $ab11,X
0x5d, 0x12, 0xab, // EOR $ab12,X 0x5d, 0x12, 0xab, // EOR $ab12,X
@ -189,7 +196,7 @@ public class CpuIndirectXModeTest extends TestCase {
} }
/* ADC - Add with Carry - $7d */ /* ADC - Add with Carry - $7d */
@Test
public void test_ADC() throws MemoryAccessException { public void test_ADC() throws MemoryAccessException {
bus.write(0xab40, 0x01); bus.write(0xab40, 0x01);
bus.write(0xab41, 0xff); bus.write(0xab41, 0xff);
@ -290,6 +297,7 @@ public class CpuIndirectXModeTest extends TestCase {
assertTrue(cpu.getCarryFlag()); assertTrue(cpu.getCarryFlag());
} }
@Test
public void test_ADC_IncludesCarry() throws MemoryAccessException { public void test_ADC_IncludesCarry() throws MemoryAccessException {
bus.write(0xab40, 0x01); bus.write(0xab40, 0x01);
@ -307,6 +315,7 @@ public class CpuIndirectXModeTest extends TestCase {
assertFalse(cpu.getCarryFlag()); assertFalse(cpu.getCarryFlag());
} }
@Test
public void test_ADC_DecimalMode() throws MemoryAccessException { public void test_ADC_DecimalMode() throws MemoryAccessException {
bus.write(0xab40, 0x01); bus.write(0xab40, 0x01);
bus.write(0xab41, 0x99); bus.write(0xab41, 0x99);
@ -404,7 +413,7 @@ public class CpuIndirectXModeTest extends TestCase {
} }
/* STA - Store Accumulator - $9d */ /* STA - Store Accumulator - $9d */
@Test
public void test_STA() throws MemoryAccessException { public void test_STA() throws MemoryAccessException {
cpu.setXRegister(0x30); cpu.setXRegister(0x30);
@ -438,7 +447,7 @@ public class CpuIndirectXModeTest extends TestCase {
} }
/* LDA - Load Accumulator - $bd */ /* LDA - Load Accumulator - $bd */
@Test
public void test_LDA() throws MemoryAccessException { public void test_LDA() throws MemoryAccessException {
bus.write(0xab42, 0x00); bus.write(0xab42, 0x00);
bus.write(0xab43, 0x0f); bus.write(0xab43, 0x0f);
@ -467,7 +476,7 @@ public class CpuIndirectXModeTest extends TestCase {
} }
/* CMP - Compare Accumulator - $dd */ /* CMP - Compare Accumulator - $dd */
@Test
public void test_CMP() throws MemoryAccessException { public void test_CMP() throws MemoryAccessException {
bus.write(0xab40, 0x00); bus.write(0xab40, 0x00);
bus.write(0xab41, 0x80); bus.write(0xab41, 0x80);
@ -498,7 +507,7 @@ public class CpuIndirectXModeTest extends TestCase {
} }
/* SBC - Subtract with Carry - $fd */ /* SBC - Subtract with Carry - $fd */
@Test
public void test_SBC() throws MemoryAccessException { public void test_SBC() throws MemoryAccessException {
bus.write(0xab40, 0x01); bus.write(0xab40, 0x01);
@ -557,6 +566,7 @@ public class CpuIndirectXModeTest extends TestCase {
assertTrue(cpu.getCarryFlag()); assertTrue(cpu.getCarryFlag());
} }
@Test
public void test_SBC_IncludesNotOfCarry() throws MemoryAccessException { public void test_SBC_IncludesNotOfCarry() throws MemoryAccessException {
bus.write(0xab40, 0x01); bus.write(0xab40, 0x01);
@ -602,6 +612,7 @@ public class CpuIndirectXModeTest extends TestCase {
} }
@Test
public void test_SBC_DecimalMode() throws MemoryAccessException { public void test_SBC_DecimalMode() throws MemoryAccessException {
bus.write(0xab40, 0x01); bus.write(0xab40, 0x01);
bus.write(0xab50, 0x11); bus.write(0xab50, 0x11);

View File

@ -241,6 +241,7 @@ public class CpuTest extends TestCase {
public void testSetProcessorStatus() { public void testSetProcessorStatus() {
// Default // Default
assertFalse(cpu.getZeroFlag()); assertFalse(cpu.getZeroFlag());
assertFalse(cpu.getZeroFlag()); assertFalse(cpu.getZeroFlag());
assertFalse(cpu.getIrqDisableFlag()); assertFalse(cpu.getIrqDisableFlag());

View File

@ -0,0 +1,329 @@
package com.loomcom.symon;
import com.loomcom.symon.devices.Memory;
import org.junit.Test;
import static junit.framework.TestCase.assertFalse;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* Test for Zero Page Indirect addressing mode, found on some instructions
* in the 65C02 and 65816
*/
public class CpuZeroPageIndirectTest {
protected Cpu cpu;
protected Bus bus;
protected Memory mem;
private void makeCmosCpu() throws Exception {
makeCpu(InstructionTable.CpuBehavior.CMOS_6502);
}
private void makeNmosCpu() throws Exception {
makeCpu(InstructionTable.CpuBehavior.NMOS_6502);
}
private void makeCpu(InstructionTable.CpuBehavior behavior) throws Exception {
this.cpu = new Cpu(behavior);
this.bus = new Bus(0x0000, 0xffff);
this.mem = new Memory(0x0000, 0xffff);
bus.addCpu(cpu);
bus.addDevice(mem);
// Load the reset vector.
bus.write(0xfffc, Bus.DEFAULT_LOAD_ADDRESS & 0x00ff);
bus.write(0xfffd, (Bus.DEFAULT_LOAD_ADDRESS & 0xff00) >>> 8);
cpu.reset();
}
@Test
public void test_ora() throws Exception {
makeCmosCpu();
// Set some initial values in zero page.
bus.write(0x30, 0x00);
bus.write(0x31, 0x10);
bus.write(0x40, 0x01);
bus.write(0x41, 0x10);
bus.write(0x50, 0x02);
bus.write(0x51, 0x10);
bus.write(0x60, 0x03);
bus.write(0x61, 0x10);
bus.write(0x1000, 0x11);
bus.write(0x1001, 0x22);
bus.write(0x1002, 0x44);
bus.write(0x1003, 0x88);
bus.loadProgram(0x12, 0x30, // ORA ($30)
0x12, 0x40, // ORA ($40)
0x12, 0x50, // ORA ($50)
0x12, 0x60); // ORA ($60)
assertEquals(0x00, cpu.getAccumulator());
// 0x00 | 0x11 = 0x11
cpu.step();
assertEquals(0x11, cpu.getAccumulator());
assertFalse(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag());
// 0x11 | 0x22 = 0x33
cpu.step();
assertEquals(0x33, cpu.getAccumulator());
assertFalse(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag());
// 0x33 | 0x44 = 0x77
cpu.step();
assertEquals(0x77, cpu.getAccumulator());
assertFalse(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag());
// 0x77 | 0x88 = 0xff
cpu.step();
assertEquals(0xff, cpu.getAccumulator());
assertFalse(cpu.getZeroFlag());
assertTrue(cpu.getNegativeFlag());
}
@Test
public void test_ora_requiresCmosCpu() throws Exception {
makeNmosCpu();
// Set some initial values in zero page.
bus.write(0x30, 0x00);
bus.write(0x31, 0x10);
bus.write(0x40, 0x01);
bus.write(0x41, 0x10);
bus.write(0x50, 0x02);
bus.write(0x51, 0x10);
bus.write(0x60, 0x03);
bus.write(0x61, 0x10);
bus.write(0x1000, 0x11);
bus.write(0x1001, 0x22);
bus.write(0x1002, 0x44);
bus.write(0x1003, 0x88);
bus.loadProgram(0x12, 0x30, // ORA ($30)
0x12, 0x40, // ORA ($40)
0x12, 0x50, // ORA ($50)
0x12, 0x60); // ORA ($60)
assertEquals(0x00, cpu.getAccumulator());
boolean zState = cpu.getZeroFlag();
boolean nState = cpu.getNegativeFlag();
// 0x00 | 0x11 = 0x11, but not implemented in NMOS cpu
cpu.step();
assertEquals(0x00, cpu.getAccumulator());
assertEquals(zState, cpu.getZeroFlag()); // unchanged
assertEquals(nState, cpu.getNegativeFlag()); // unchanged
// 0x11 | 0x22 = 0x33, but not implemented in NMOS cpu
cpu.step();
assertEquals(0x00, cpu.getAccumulator());
assertEquals(zState, cpu.getZeroFlag()); // unchanged
assertEquals(nState, cpu.getNegativeFlag()); // unchanged
// 0x33 | 0x44 = 0x77, but not implemented in NMOS cpu
cpu.step();
assertEquals(0x00, cpu.getAccumulator());
assertEquals(zState, cpu.getZeroFlag()); // unchanged
assertEquals(nState, cpu.getNegativeFlag()); // unchanged
// 0x77 | 0x88 = 0xff, but not implemented in NMOS cpu
cpu.step();
assertEquals(0x00, cpu.getAccumulator());
assertEquals(zState, cpu.getZeroFlag()); // unchanged
assertEquals(nState, cpu.getNegativeFlag()); // unchanged
}
@Test
public void test_and() throws Exception {
makeCmosCpu();
// Set some initial values in zero page.
bus.write(0x30, 0x00);
bus.write(0x31, 0x10);
bus.write(0x40, 0x01);
bus.write(0x41, 0x10);
bus.write(0x50, 0x02);
bus.write(0x51, 0x10);
bus.write(0x1000, 0x33);
bus.write(0x1001, 0x11);
bus.write(0x1002, 0x88);
bus.loadProgram(0x32, 0x30, // AND ($30)
0x32, 0x40, // AND ($40)
0x32, 0x50); // AND ($50)
cpu.setAccumulator(0xff);
// 0xFF & 0x33 == 0x33
cpu.step();
assertEquals(0x33, cpu.getAccumulator());
assertFalse(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag());
// 0x33 & 0x11 == 0x11
cpu.step();
assertEquals(0x11, cpu.getAccumulator());
assertFalse(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag());
// 0x11 & 0x80 == 0
cpu.step();
assertEquals(0, cpu.getAccumulator());
assertTrue(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag());
}
@Test
public void test_and_requiresCmosCpu() throws Exception {
makeNmosCpu();
// Set some initial values in zero page.
bus.write(0x30, 0x00);
bus.write(0x31, 0x10);
bus.write(0x40, 0x01);
bus.write(0x41, 0x10);
bus.write(0x50, 0x02);
bus.write(0x51, 0x10);
bus.write(0x1000, 0x33);
bus.write(0x1001, 0x11);
bus.write(0x1002, 0x88);
bus.loadProgram(0x32, 0x30, // AND ($30)
0x32, 0x40, // AND ($40)
0x32, 0x50); // AND ($50)
cpu.setAccumulator(0xff);
boolean zState = cpu.getZeroFlag();
boolean nState = cpu.getNegativeFlag();
// 0xFF & 0x33 == 0x33, but not implemented in NMOS cpu
cpu.step();
assertEquals(0xff, cpu.getAccumulator());
assertEquals(zState, cpu.getZeroFlag());
assertEquals(nState, cpu.getNegativeFlag());
// 0x33 & 0x11 == 0x11, but not implemented in NMOS cpu
cpu.step();
assertEquals(0xff, cpu.getAccumulator());
assertEquals(zState, cpu.getZeroFlag());
assertEquals(nState, cpu.getNegativeFlag());
// 0x11 & 0x80 == 0, but not implemented in NMOS cpu
cpu.step();
assertEquals(0xff, cpu.getAccumulator());
assertEquals(zState, cpu.getZeroFlag());
assertEquals(nState, cpu.getNegativeFlag());
}
@Test
public void test_eor() throws Exception {
makeCmosCpu();
// Set some initial values in zero page.
bus.write(0x30, 0x00);
bus.write(0x31, 0x10);
bus.write(0x40, 0x01);
bus.write(0x41, 0x10);
bus.write(0x50, 0x02);
bus.write(0x51, 0x10);
bus.write(0x60, 0x03);
bus.write(0x61, 0x10);
bus.write(0x1000, 0x00);
bus.write(0x1001, 0xff);
bus.write(0x1002, 0x33);
bus.write(0x1003, 0x44);
bus.loadProgram(0x52, 0x30, // AND ($30)
0x52, 0x40, // AND ($40)
0x52, 0x50, // EOR ($50)
0x52, 0x60); // AND ($60)
cpu.setAccumulator(0x88);
cpu.step();
assertEquals(0x88, cpu.getAccumulator());
cpu.step();
assertEquals(0x77, cpu.getAccumulator());
cpu.step();
assertEquals(0x44, cpu.getAccumulator());
cpu.step();
assertEquals(0x00, cpu.getAccumulator());
}
@Test
public void test_eor_requiresCmosCpu() throws Exception {
makeNmosCpu();
// Set some initial values in zero page.
bus.write(0x30, 0x00);
bus.write(0x31, 0x10);
bus.write(0x40, 0x01);
bus.write(0x41, 0x10);
bus.write(0x50, 0x02);
bus.write(0x51, 0x10);
bus.write(0x60, 0x03);
bus.write(0x61, 0x10);
bus.write(0x1000, 0x00);
bus.write(0x1001, 0xff);
bus.write(0x1002, 0x33);
bus.write(0x1003, 0x44);
bus.loadProgram(0x52, 0x30, // AND ($30)
0x52, 0x40, // AND ($40)
0x52, 0x50, // EOR ($50)
0x52, 0x60); // AND ($60)
cpu.setAccumulator(0x88);
cpu.step();
assertEquals(0x88, cpu.getAccumulator());
cpu.step();
assertEquals(0x88, cpu.getAccumulator());
cpu.step();
assertEquals(0x88, cpu.getAccumulator());
cpu.step();
assertEquals(0x88, cpu.getAccumulator());
}
}