Compare commits
1 Commits
Author | SHA1 | Date |
---|---|---|
Seth Morabito | 4cca0b4663 |
|
@ -79,7 +79,7 @@ public class Cpu implements InstructionTable {
|
|||
* Construct a new CPU.
|
||||
*/
|
||||
public Cpu() {
|
||||
this(CpuBehavior.NMOS_WITH_INDIRECT_JMP_BUG);
|
||||
this(CpuBehavior.NMOS_6502);
|
||||
}
|
||||
|
||||
public Cpu(CpuBehavior behavior) {
|
||||
|
@ -204,6 +204,13 @@ public class Cpu implements InstructionTable {
|
|||
case 3: // Absolute
|
||||
effectiveAddress = Utils.address(state.args[0], state.args[1]);
|
||||
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
|
||||
if (state.ir == 0x96 || state.ir == 0xb6) {
|
||||
effectiveAddress = zpyAddress(state.args[0]);
|
||||
|
@ -262,7 +269,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
case 0x08: // PHP - Push Processor Status - Implied
|
||||
// Break flag is always set in the stack value.
|
||||
stackPush(state.getStatusFlag() | 0x10);
|
||||
stackPush(state.getStatusFlag() | 0x10);
|
||||
break;
|
||||
case 0x10: // BPL - Branch if Positive - Relative
|
||||
if (!getNegativeFlag()) {
|
||||
|
@ -398,11 +405,12 @@ public class Cpu implements InstructionTable {
|
|||
case 0x4c: // JMP - Absolute
|
||||
state.pc = Utils.address(state.args[0], state.args[1]);
|
||||
break;
|
||||
// TODO: 65C02 instruction 0x7C, JMP (Indirect,X)
|
||||
case 0x6c: // JMP - Indirect
|
||||
lo = Utils.address(state.args[0], state.args[1]); // Address of low byte
|
||||
|
||||
if (state.args[0] == 0xff &&
|
||||
(behavior == CpuBehavior.NMOS_WITH_INDIRECT_JMP_BUG ||
|
||||
(behavior == CpuBehavior.NMOS_6502 ||
|
||||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG)) {
|
||||
hi = Utils.address(0x00, state.args[1]);
|
||||
} else {
|
||||
|
@ -422,13 +430,20 @@ public class Cpu implements InstructionTable {
|
|||
* (http://www.obelisk.demon.co.uk/6502/reference.html#JMP)
|
||||
*/
|
||||
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 ******************************************/
|
||||
case 0x09: // #Immediate
|
||||
state.a |= state.args[0];
|
||||
setArithmeticFlags(state.a);
|
||||
break;
|
||||
case 0x12: // 65C02 ORA (ZP)
|
||||
if (behavior == CpuBehavior.NMOS_6502 ||
|
||||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
|
||||
break;
|
||||
}
|
||||
case 0x01: // (Zero Page,X)
|
||||
case 0x05: // Zero Page
|
||||
case 0x0d: // Absolute
|
||||
|
@ -471,6 +486,11 @@ public class Cpu implements InstructionTable {
|
|||
state.a &= state.args[0];
|
||||
setArithmeticFlags(state.a);
|
||||
break;
|
||||
case 0x32: // 65C02 AND (ZP)
|
||||
if (behavior == CpuBehavior.NMOS_6502 ||
|
||||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
|
||||
break;
|
||||
}
|
||||
case 0x21: // (Zero Page,X)
|
||||
case 0x25: // Zero Page
|
||||
case 0x2d: // Absolute
|
||||
|
@ -503,6 +523,11 @@ public class Cpu implements InstructionTable {
|
|||
state.a ^= state.args[0];
|
||||
setArithmeticFlags(state.a);
|
||||
break;
|
||||
case 0x52: // 65C02 EOR (ZP)
|
||||
if (behavior == CpuBehavior.NMOS_6502 ||
|
||||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
|
||||
break;
|
||||
}
|
||||
case 0x41: // (Zero Page,X)
|
||||
case 0x45: // Zero Page
|
||||
case 0x4d: // Absolute
|
||||
|
@ -538,6 +563,11 @@ public class Cpu implements InstructionTable {
|
|||
state.a = adc(state.a, state.args[0]);
|
||||
}
|
||||
break;
|
||||
case 0x72: // 65C02 ADC (ZP)
|
||||
if (behavior == CpuBehavior.NMOS_6502 ||
|
||||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
|
||||
break;
|
||||
}
|
||||
case 0x61: // (Zero Page,X)
|
||||
case 0x65: // Zero Page
|
||||
case 0x6d: // Absolute
|
||||
|
@ -569,6 +599,11 @@ public class Cpu implements InstructionTable {
|
|||
|
||||
|
||||
/** 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 0x85: // Zero Page
|
||||
case 0x8d: // Absolute
|
||||
|
@ -629,6 +664,11 @@ public class Cpu implements InstructionTable {
|
|||
state.a = state.args[0];
|
||||
setArithmeticFlags(state.a);
|
||||
break;
|
||||
case 0xb2: // 65C02 LDA (ZP)
|
||||
if (behavior == CpuBehavior.NMOS_6502 ||
|
||||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
|
||||
break;
|
||||
}
|
||||
case 0xa1: // (Zero Page,X)
|
||||
case 0xa5: // Zero Page
|
||||
case 0xad: // Absolute
|
||||
|
@ -655,6 +695,11 @@ public class Cpu implements InstructionTable {
|
|||
case 0xc9: // #Immediate
|
||||
cmp(state.a, state.args[0]);
|
||||
break;
|
||||
case 0xd2: // 65C02 CMP (ZP)
|
||||
if (behavior == CpuBehavior.NMOS_6502 ||
|
||||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
|
||||
break;
|
||||
}
|
||||
case 0xc1: // (Zero Page,X)
|
||||
case 0xc5: // Zero Page
|
||||
case 0xcd: // Absolute
|
||||
|
@ -695,6 +740,11 @@ public class Cpu implements InstructionTable {
|
|||
state.a = sbc(state.a, state.args[0]);
|
||||
}
|
||||
break;
|
||||
case 0xf2: // 65C02 SBC (ZP)
|
||||
if (behavior == CpuBehavior.NMOS_6502 ||
|
||||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
|
||||
break;
|
||||
}
|
||||
case 0xe1: // (Zero Page,X)
|
||||
case 0xe5: // Zero Page
|
||||
case 0xed: // Absolute
|
||||
|
@ -1334,6 +1384,13 @@ public class Cpu implements InstructionTable {
|
|||
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.
|
||||
*/
|
||||
|
@ -1342,21 +1399,21 @@ public class Cpu implements InstructionTable {
|
|||
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
|
||||
*/
|
||||
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) {
|
||||
logger.warn("Opcode {} has clock step of 0!", opcode);
|
||||
logger.warn("Opcode {} has clock step of 0!", String.format("0x%02x", opcode));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,20 +46,17 @@ public interface InstructionTable {
|
|||
*
|
||||
* NB: Does NOT implement "unimplemented" NMOS instructions.
|
||||
*/
|
||||
NMOS_WITH_INDIRECT_JMP_BUG,
|
||||
|
||||
/**
|
||||
* 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,
|
||||
NMOS_6502,
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
public String toString() {
|
||||
return "Zeropage";
|
||||
return "Zero Page";
|
||||
}
|
||||
},
|
||||
|
||||
ZPX {
|
||||
public String toString() {
|
||||
return "Zeropage, X-indexed";
|
||||
return "Zero Page, X-indexed";
|
||||
}
|
||||
},
|
||||
|
||||
ZPY {
|
||||
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.
|
||||
|
||||
/**
|
||||
* Instruction opcode names.
|
||||
* Instruction opcode names. This lists all opcodes for
|
||||
* NMOS 6502, CMOS 65C02, and CMOS 65C816
|
||||
*/
|
||||
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,
|
||||
"CLC", "ORA", null, null, null, "ORA", "ASL", null,
|
||||
"JSR", "AND", null, null, "BIT", "AND", "ROL", null,
|
||||
"PLP", "AND", "ROL", null, "BIT", "AND", "ROL", null,
|
||||
"BMI", "AND", null, null, null, "AND", "ROL", null,
|
||||
"SEC", "AND", null, null, null, "AND", "ROL", null,
|
||||
"RTI", "EOR", null, null, null, "EOR", "LSR", null,
|
||||
"PHA", "EOR", "LSR", null, "JMP", "EOR", "LSR", null,
|
||||
"BVC", "EOR", null, null, null, "EOR", "LSR", null,
|
||||
"CLI", "EOR", null, null, null, "EOR", "LSR", null,
|
||||
"RTS", "ADC", null, null, null, "ADC", "ROR", null,
|
||||
"PLA", "ADC", "ROR", null, "JMP", "ADC", "ROR", null,
|
||||
"BVS", "ADC", null, null, null, "ADC", "ROR", null,
|
||||
"SEI", "ADC", null, null, null, "ADC", "ROR", null,
|
||||
"BCS", "STA", null, null, "STY", "STA", "STX", null,
|
||||
"DEY", null, "TXA", null, "STY", "STA", "STX", null,
|
||||
"BCC", "STA", null, null, "STY", "STA", "STX", null,
|
||||
"TYA", "STA", "TXS", null, null, "STA", null, null,
|
||||
"LDY", "LDA", "LDX", null, "LDY", "LDA", "LDX", null,
|
||||
"TAY", "LDA", "TAX", null, "LDY", "LDA", "LDX", null,
|
||||
"BCS", "LDA", null, null, "LDY", "LDA", "LDX", null,
|
||||
"CLV", "LDA", "TSX", null, "LDY", "LDA", "LDX", null,
|
||||
"CPY", "CMP", null, null, "CPY", "CMP", "DEC", null,
|
||||
"INY", "CMP", "DEX", null, "CPY", "CMP", "DEC", null,
|
||||
"BNE", "CMP", null, null, null, "CMP", "DEC", null,
|
||||
"CLD", "CMP", null, null, null, "CMP", "DEC", null,
|
||||
"CPX", "SBC", null, null, "CPX", "SBC", "INC", null,
|
||||
"INX", "SBC", "NOP", null, "CPX", "SBC", "INC", null,
|
||||
"BEQ", "SBC", null, null, null, "SBC", "INC", null,
|
||||
"SED", "SBC", null, null, null, "SBC", "INC", null
|
||||
"BRK", "ORA", null, null, null, "ORA", "ASL", null, // 0x00-0x07
|
||||
"PHP", "ORA", "ASL", null, null, "ORA", "ASL", null, // 0x08-0x0f
|
||||
"BPL", "ORA", "ORA", null, null, "ORA", "ASL", null, // 0x10-0x17
|
||||
"CLC", "ORA", null, null, null, "ORA", "ASL", null, // 0x18-0x1f
|
||||
"JSR", "AND", null, null, "BIT", "AND", "ROL", null, // 0x20-0x27
|
||||
"PLP", "AND", "ROL", null, "BIT", "AND", "ROL", null, // 0x28-0x2f
|
||||
"BMI", "AND", "AND", null, null, "AND", "ROL", null, // 0x30-0x37
|
||||
"SEC", "AND", null, null, null, "AND", "ROL", null, // 0x38-0x3f
|
||||
"RTI", "EOR", null, null, null, "EOR", "LSR", null, // 0x40-0x47
|
||||
"PHA", "EOR", "LSR", null, "JMP", "EOR", "LSR", null, // 0x48-0x4f
|
||||
"BVC", "EOR", "EOR", null, null, "EOR", "LSR", null, // 0x50-0x57
|
||||
"CLI", "EOR", null, null, null, "EOR", "LSR", null, // 0x58-0x5f
|
||||
"RTS", "ADC", null, null, null, "ADC", "ROR", null, // 0x60-0x67
|
||||
"PLA", "ADC", "ROR", null, "JMP", "ADC", "ROR", null, // 0x68-0x6f
|
||||
"BVS", "ADC", "ADC", null, null, "ADC", "ROR", null, // 0x70-0x77
|
||||
"SEI", "ADC", null, null, "JMP", "ADC", "ROR", null, // 0x78-0x7f
|
||||
"BCS", "STA", null, null, "STY", "STA", "STX", null, // 0x80-0x87
|
||||
"DEY", null, "TXA", null, "STY", "STA", "STX", null, // 0x88-0x8f
|
||||
"BCC", "STA", "STA", null, "STY", "STA", "STX", null, // 0x90-0x97
|
||||
"TYA", "STA", "TXS", null, null, "STA", null, null, // 0x98-0x9f
|
||||
"LDY", "LDA", "LDX", null, "LDY", "LDA", "LDX", null, // 0xa0-0xa7
|
||||
"TAY", "LDA", "TAX", null, "LDY", "LDA", "LDX", null, // 0xa8-0xaf
|
||||
"BCS", "LDA", "LDA", null, "LDY", "LDA", "LDX", null, // 0xb0-0xb7
|
||||
"CLV", "LDA", "TSX", null, "LDY", "LDA", "LDX", null, // 0xb8-0xbf
|
||||
"CPY", "CMP", null, null, "CPY", "CMP", "DEC", null, // 0xc0-0xc7
|
||||
"INY", "CMP", "DEX", null, "CPY", "CMP", "DEC", null, // 0xc8-0xcf
|
||||
"BNE", "CMP", "CMP", null, null, "CMP", "DEC", null, // 0xd0-0xd7
|
||||
"CLD", "CMP", null, null, null, "CMP", "DEC", null, // 0xd8-0xdf
|
||||
"CPX", "SBC", null, null, "CPX", "SBC", "INC", null, // 0xe0-0xe7
|
||||
"INX", "SBC", "NOP", null, "CPX", "SBC", "INC", null, // 0xe8-0xef
|
||||
"BEQ", "SBC", "SBC", null, null, "SBC", "INC", null, // 0xf0-0xf7
|
||||
"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.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
|
||||
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.IMP, Mode.ABY, Mode.NUL, Mode.NUL, // 0x18-0x1b
|
||||
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.IMP, Mode.IMM, Mode.ACC, Mode.NUL, // 0x28-0x2b
|
||||
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.IMP, Mode.ABY, Mode.NUL, Mode.NUL, // 0x38-0x3b
|
||||
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.IMP, Mode.IMM, Mode.ACC, Mode.NUL, // 0x48-0x4b
|
||||
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.IMP, Mode.ABY, Mode.NUL, Mode.NUL, // 0x58-0x5b
|
||||
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.IMP, Mode.IMM, Mode.ACC, Mode.NUL, // 0x68-0x6b
|
||||
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.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.ZPG, Mode.ZPG, Mode.ZPG, Mode.NUL, // 0x84-0x87
|
||||
Mode.IMP, Mode.NUL, Mode.IMP, Mode.NUL, // 0x88-0x8b
|
||||
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.IMP, Mode.ABY, Mode.IMP, Mode.NUL, // 0x98-0x9b
|
||||
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.IMP, Mode.IMM, Mode.IMP, Mode.NUL, // 0xa8-0xab
|
||||
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.IMP, Mode.ABY, Mode.IMP, Mode.NUL, // 0xb8-0xbb
|
||||
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.IMP, Mode.IMM, Mode.IMP, Mode.NUL, // 0xc8-0xcb
|
||||
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.IMP, Mode.ABY, Mode.NUL, Mode.NUL, // 0xd8-0xdb
|
||||
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.IMP, Mode.IMM, Mode.IMP, Mode.NUL, // 0xe8-0xeb
|
||||
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.IMP, Mode.ABY, Mode.NUL, Mode.NUL, // 0xf8-0xfb
|
||||
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 = {
|
||||
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,
|
||||
2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0,
|
||||
1, 2, 0, 0, 0, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0,
|
||||
2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0,
|
||||
1, 2, 0, 0, 0, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0,
|
||||
2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0,
|
||||
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, 3, 1, 0, 0, 3, 0, 0,
|
||||
2, 2, 2, 0, 2, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0,
|
||||
2, 2, 0, 0, 2, 2, 2, 0, 1, 3, 1, 0, 3, 3, 3, 0,
|
||||
2, 2, 0, 0, 2, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0,
|
||||
2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0,
|
||||
2, 2, 0, 0, 2, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0,
|
||||
2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 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, 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, // 0x20-0x2f
|
||||
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, // 0x40-0x4f
|
||||
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, // 0x60-0x6f
|
||||
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, // 0x80-0x8f
|
||||
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, // 0xa0-0xaf
|
||||
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, // 0xc0-0xcf
|
||||
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, // 0xe0-0xef
|
||||
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 = {
|
||||
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,
|
||||
2, 5, 0, 0, 0, 4, 6, 0, 2, 4, 0, 0, 0, 4, 7, 0,
|
||||
6, 6, 0, 0, 0, 3, 5, 0, 3, 2, 2, 0, 3, 4, 6, 0,
|
||||
2, 5, 0, 0, 0, 4, 6, 0, 2, 4, 0, 0, 0, 4, 7, 0,
|
||||
6, 6, 0, 0, 0, 3, 5, 0, 4, 2, 2, 0, 5, 4, 6, 0,
|
||||
2, 5, 0, 0, 0, 4, 6, 0, 2, 4, 0, 0, 0, 4, 7, 0,
|
||||
2, 6, 0, 0, 3, 3, 3, 0, 2, 0, 2, 0, 4, 4, 4, 0,
|
||||
2, 6, 0, 0, 4, 4, 4, 0, 2, 5, 2, 0, 0, 5, 0, 0,
|
||||
2, 6, 2, 0, 3, 3, 3, 0, 2, 2, 2, 0, 4, 4, 4, 0,
|
||||
2, 5, 0, 0, 4, 4, 4, 0, 2, 4, 2, 0, 4, 4, 4, 0,
|
||||
2, 6, 0, 0, 3, 3, 5, 0, 2, 2, 2, 0, 4, 4, 6, 0,
|
||||
2, 5, 0, 0, 0, 4, 6, 0, 2, 4, 0, 0, 0, 4, 7, 0,
|
||||
2, 6, 0, 0, 3, 3, 5, 0, 2, 2, 2, 0, 4, 4, 6, 0,
|
||||
2, 5, 0, 0, 0, 4, 6, 0, 2, 4, 0, 0, 0, 4, 7, 0
|
||||
int[] instructionClocksNmos = {
|
||||
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, // 0x10-0x1f
|
||||
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, // 0x30-0x3f
|
||||
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, // 0x50-0x5f
|
||||
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, // 0x70-0x7f
|
||||
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, // 0x90-0x9f
|
||||
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, // 0xb0-0xbf
|
||||
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, // 0xd0-0xdf
|
||||
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 // 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
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -25,18 +25,10 @@ public class CpuIndirectIndexedModeTest {
|
|||
bus.write(0xfffd, (Bus.DEFAULT_LOAD_ADDRESS & 0xff00) >>> 8);
|
||||
|
||||
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
|
||||
public void test_LDA() throws Exception {
|
||||
assertEquals(cpu.toString(), 0x00, cpu.getAccumulator());
|
||||
bus.write(0x0014, 0x00);
|
||||
bus.write(0x0015, 0xd8);
|
||||
bus.write(0xd828, 0x03);
|
||||
|
|
|
@ -3,15 +3,19 @@ package com.loomcom.symon;
|
|||
import com.loomcom.symon.devices.Memory;
|
||||
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 Bus bus;
|
||||
protected Memory mem;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
this.cpu = new Cpu();
|
||||
this.bus = new Bus(0x0000, 0xffff);
|
||||
this.mem = new Memory(0x0000, 0xffff);
|
||||
|
@ -41,6 +45,7 @@ public class CpuIndirectModeTest extends TestCase {
|
|||
|
||||
/* JMP - Jump - $6c */
|
||||
|
||||
@Test
|
||||
public void test_JMP_notOnPageBoundary() throws MemoryAccessException {
|
||||
bus.write(0x3400, 0x00);
|
||||
bus.write(0x3401, 0x54);
|
||||
|
@ -51,6 +56,7 @@ public class CpuIndirectModeTest extends TestCase {
|
|||
assertEquals(0x20, cpu.getProcessorStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_JMP_with_ROR_Bug() throws MemoryAccessException {
|
||||
cpu.setBehavior(Cpu.CpuBehavior.NMOS_WITH_ROR_BUG);
|
||||
bus.write(0x3400, 0x22);
|
||||
|
@ -63,8 +69,9 @@ public class CpuIndirectModeTest extends TestCase {
|
|||
assertEquals(0x20, cpu.getProcessorStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
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(0x34ff, 0x00);
|
||||
bus.write(0x3500, 0x54);
|
||||
|
@ -75,8 +82,9 @@ public class CpuIndirectModeTest extends TestCase {
|
|||
assertEquals(0x20, cpu.getProcessorStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
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(0x34ff, 0x00);
|
||||
bus.write(0x3500, 0x54);
|
||||
|
@ -87,8 +95,9 @@ public class CpuIndirectModeTest extends TestCase {
|
|||
assertEquals(0x20, cpu.getProcessorStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_JMP_cmos() throws MemoryAccessException {
|
||||
cpu.setBehavior(Cpu.CpuBehavior.CMOS);
|
||||
cpu.setBehavior(Cpu.CpuBehavior.CMOS_6502);
|
||||
bus.write(0x3400, 0x22);
|
||||
bus.write(0x34ff, 0x00);
|
||||
bus.write(0x3500, 0x54);
|
||||
|
|
|
@ -3,14 +3,21 @@ package com.loomcom.symon;
|
|||
import com.loomcom.symon.devices.Memory;
|
||||
import com.loomcom.symon.exceptions.MemoryAccessException;
|
||||
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 Bus bus;
|
||||
protected Memory mem;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
this.cpu = new Cpu();
|
||||
this.bus = new Bus(0x0000, 0xffff);
|
||||
this.mem = new Memory(0x0000, 0xffff);
|
||||
|
@ -47,7 +54,7 @@ public class CpuIndirectXModeTest extends TestCase {
|
|||
*/
|
||||
|
||||
/* ORA - Logical Inclusive OR - $1d */
|
||||
|
||||
@Test
|
||||
public void test_ORA() throws MemoryAccessException {
|
||||
// Set some initial values in memory
|
||||
bus.write(0x2c30, 0x00);
|
||||
|
@ -93,7 +100,7 @@ public class CpuIndirectXModeTest extends TestCase {
|
|||
}
|
||||
|
||||
/* AND - Logical AND - $3d */
|
||||
|
||||
@Test
|
||||
public void test_AND() throws MemoryAccessException {
|
||||
bus.write(0x1a30, 0x00);
|
||||
bus.write(0x1a31, 0x11);
|
||||
|
@ -153,7 +160,7 @@ public class CpuIndirectXModeTest extends TestCase {
|
|||
}
|
||||
|
||||
/* EOR - Exclusive OR - $5d */
|
||||
|
||||
@Test
|
||||
public void test_EOR() throws MemoryAccessException {
|
||||
bus.write(0xab40, 0x00);
|
||||
bus.write(0xab41, 0xff);
|
||||
|
@ -162,7 +169,7 @@ public class CpuIndirectXModeTest extends TestCase {
|
|||
|
||||
cpu.setXRegister(0x30);
|
||||
|
||||
bus.loadProgram(0xa9, 0x88, // LDA #$88
|
||||
bus.loadProgram(0xa9, 0x88, // LDA #$88
|
||||
0x5d, 0x10, 0xab, // EOR $ab10,X
|
||||
0x5d, 0x11, 0xab, // EOR $ab11,X
|
||||
0x5d, 0x12, 0xab, // EOR $ab12,X
|
||||
|
@ -189,7 +196,7 @@ public class CpuIndirectXModeTest extends TestCase {
|
|||
}
|
||||
|
||||
/* ADC - Add with Carry - $7d */
|
||||
|
||||
@Test
|
||||
public void test_ADC() throws MemoryAccessException {
|
||||
bus.write(0xab40, 0x01);
|
||||
bus.write(0xab41, 0xff);
|
||||
|
@ -290,6 +297,7 @@ public class CpuIndirectXModeTest extends TestCase {
|
|||
assertTrue(cpu.getCarryFlag());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_ADC_IncludesCarry() throws MemoryAccessException {
|
||||
bus.write(0xab40, 0x01);
|
||||
|
||||
|
@ -307,6 +315,7 @@ public class CpuIndirectXModeTest extends TestCase {
|
|||
assertFalse(cpu.getCarryFlag());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_ADC_DecimalMode() throws MemoryAccessException {
|
||||
bus.write(0xab40, 0x01);
|
||||
bus.write(0xab41, 0x99);
|
||||
|
@ -404,7 +413,7 @@ public class CpuIndirectXModeTest extends TestCase {
|
|||
}
|
||||
|
||||
/* STA - Store Accumulator - $9d */
|
||||
|
||||
@Test
|
||||
public void test_STA() throws MemoryAccessException {
|
||||
cpu.setXRegister(0x30);
|
||||
|
||||
|
@ -438,7 +447,7 @@ public class CpuIndirectXModeTest extends TestCase {
|
|||
}
|
||||
|
||||
/* LDA - Load Accumulator - $bd */
|
||||
|
||||
@Test
|
||||
public void test_LDA() throws MemoryAccessException {
|
||||
bus.write(0xab42, 0x00);
|
||||
bus.write(0xab43, 0x0f);
|
||||
|
@ -467,7 +476,7 @@ public class CpuIndirectXModeTest extends TestCase {
|
|||
}
|
||||
|
||||
/* CMP - Compare Accumulator - $dd */
|
||||
|
||||
@Test
|
||||
public void test_CMP() throws MemoryAccessException {
|
||||
bus.write(0xab40, 0x00);
|
||||
bus.write(0xab41, 0x80);
|
||||
|
@ -498,7 +507,7 @@ public class CpuIndirectXModeTest extends TestCase {
|
|||
}
|
||||
|
||||
/* SBC - Subtract with Carry - $fd */
|
||||
|
||||
@Test
|
||||
public void test_SBC() throws MemoryAccessException {
|
||||
bus.write(0xab40, 0x01);
|
||||
|
||||
|
@ -557,6 +566,7 @@ public class CpuIndirectXModeTest extends TestCase {
|
|||
assertTrue(cpu.getCarryFlag());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_SBC_IncludesNotOfCarry() throws MemoryAccessException {
|
||||
bus.write(0xab40, 0x01);
|
||||
|
||||
|
@ -602,6 +612,7 @@ public class CpuIndirectXModeTest extends TestCase {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_SBC_DecimalMode() throws MemoryAccessException {
|
||||
bus.write(0xab40, 0x01);
|
||||
bus.write(0xab50, 0x11);
|
||||
|
|
|
@ -241,6 +241,7 @@ public class CpuTest extends TestCase {
|
|||
|
||||
public void testSetProcessorStatus() {
|
||||
// Default
|
||||
|
||||
assertFalse(cpu.getZeroFlag());
|
||||
assertFalse(cpu.getZeroFlag());
|
||||
assertFalse(cpu.getIrqDisableFlag());
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue