1
0
mirror of https://github.com/sethm/symon.git synced 2024-06-14 17:29:38 +00:00

* Add Support for All 65C02 Opcodes and all Rockwell/WDC opcodes except WAI/STP

* Add 65C02 Opcode tests
* All tests pass, Klaus' 6502_functional_tests pass & Klaus' 65C02_extended_opcodes_test also all pass
This commit is contained in:
Matt Harlum 2017-06-06 13:24:29 +10:00
parent faf5d22660
commit a9c6d5964f
13 changed files with 2655 additions and 153 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) {
@ -104,6 +104,10 @@ public class Cpu implements InstructionTable {
this.behavior = behavior; this.behavior = behavior;
} }
public CpuBehavior getBehavior() {
return behavior;
}
/** /**
* Reset the CPU to known initial values. * Reset the CPU to known initial values.
*/ */
@ -204,15 +208,28 @@ 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], true),
bus.read((state.args[0] + 1) & 0xff, true));
}
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 == 0x14) { // 65C02 TRB Zero Page
effectiveAddress = state.args[0];
}
else if (state.ir == 0x96 || state.ir == 0xb6) {
effectiveAddress = zpyAddress(state.args[0]); effectiveAddress = zpyAddress(state.args[0]);
} else { } else {
effectiveAddress = zpxAddress(state.args[0]); effectiveAddress = zpxAddress(state.args[0]);
} }
break; break;
case 7: // Absolute,X / Absolute,Y case 7:
if (state.ir == 0xbe) { if (state.ir == 0x9c || state.ir == 0x1c) { // 65C02 STZ & TRB Absolute
effectiveAddress = Utils.address(state.args[0], state.args[1]);
}
else if (state.ir == 0xbe) { // Absolute,X / Absolute,Y
effectiveAddress = yAddress(state.args[0], state.args[1]); effectiveAddress = yAddress(state.args[0], state.args[1]);
} else { } else {
effectiveAddress = xAddress(state.args[0], state.args[1]); effectiveAddress = xAddress(state.args[0], state.args[1]);
@ -220,6 +237,16 @@ public class Cpu implements InstructionTable {
break; break;
} }
break; break;
case 3: // Rockwell/WDC 65C02
switch (irAddressMode) {
case 1: // Zero Page
case 3:
case 5:
case 7: // Zero Page, Relative
effectiveAddress = state.args[0];
break;
}
break;
case 1: case 1:
switch (irAddressMode) { switch (irAddressMode) {
case 0: // (Zero Page,X) case 0: // (Zero Page,X)
@ -262,7 +289,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()) {
@ -305,6 +332,13 @@ public class Cpu implements InstructionTable {
case 0x58: // CLI - Clear Interrupt Disable - Implied case 0x58: // CLI - Clear Interrupt Disable - Implied
clearIrqDisableFlag(); clearIrqDisableFlag();
break; break;
case 0x5a: // 65C02 PHY - Push Y to stack
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
stackPush(state.y);
break;
case 0x60: // RTS - Return from Subroutine - Implied case 0x60: // RTS - Return from Subroutine - Implied
lo = stackPop(); lo = stackPop();
hi = stackPop(); hi = stackPop();
@ -322,6 +356,20 @@ public class Cpu implements InstructionTable {
case 0x78: // SEI - Set Interrupt Disable - Implied case 0x78: // SEI - Set Interrupt Disable - Implied
setIrqDisableFlag(); setIrqDisableFlag();
break; break;
case 0x7a: // 65C02 PLY - Pull Y from Stack
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
state.y = stackPop();
setArithmeticFlags(state.y);
break;
case 0x80: // 65C02 BRA - Branch Always
if (behavior == CpuBehavior.CMOS_6502 ||
behavior == CpuBehavior.CMOS_65816) {
state.pc = relAddress(state.args[0]);
}
break;
case 0x88: // DEY - Decrement Y Register - Implied case 0x88: // DEY - Decrement Y Register - Implied
state.y = --state.y & 0xff; state.y = --state.y & 0xff;
setArithmeticFlags(state.y); setArithmeticFlags(state.y);
@ -378,6 +426,13 @@ public class Cpu implements InstructionTable {
case 0xd8: // CLD - Clear Decimal Mode - Implied case 0xd8: // CLD - Clear Decimal Mode - Implied
clearDecimalModeFlag(); clearDecimalModeFlag();
break; break;
case 0xda: // 65C02 PHX - Push X to stack
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
stackPush(state.x);
break;
case 0xe8: // INX - Increment X Register - Implied case 0xe8: // INX - Increment X Register - Implied
state.x = ++state.x & 0xff; state.x = ++state.x & 0xff;
setArithmeticFlags(state.x); setArithmeticFlags(state.x);
@ -393,6 +448,14 @@ public class Cpu implements InstructionTable {
case 0xf8: // SED - Set Decimal Flag - Implied case 0xf8: // SED - Set Decimal Flag - Implied
setDecimalModeFlag(); setDecimalModeFlag();
break; break;
case 0xfa: // 65C02 PLX - Pull X from Stack
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
state.x = stackPop();
setArithmeticFlags(state.x);
break;
/** JMP *****************************************************************/ /** JMP *****************************************************************/
case 0x4c: // JMP - Absolute case 0x4c: // JMP - Absolute
@ -402,7 +465,7 @@ public class Cpu implements InstructionTable {
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 +485,26 @@ 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 Indexed Indirect,X)
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
lo = (((state.args[1] << 8) | state.args[0]) + state.x) & 0xffff;
hi = lo + 1;
state.pc = Utils.address(bus.read(lo, true), bus.read(hi, true));
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
@ -457,8 +533,17 @@ public class Cpu implements InstructionTable {
/** BIT - Bit Test ******************************************************/ /** BIT - Bit Test ******************************************************/
case 0x89: // 65C02 #Immediate
setZeroFlag((state.a & state.args[0]) == 0);
break;
case 0x34: // 65C02 Zero Page,X
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
case 0x24: // Zero Page case 0x24: // Zero Page
case 0x2c: // Absolute case 0x2c: // Absolute
case 0x3c: // Absolute,X
tmp = bus.read(effectiveAddress, true); tmp = bus.read(effectiveAddress, true);
setZeroFlag((state.a & tmp) == 0); setZeroFlag((state.a & tmp) == 0);
setNegativeFlag((tmp & 0x80) != 0); setNegativeFlag((tmp & 0x80) != 0);
@ -471,6 +556,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 +593,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 +633,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 +669,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
@ -595,6 +700,17 @@ public class Cpu implements InstructionTable {
bus.write(effectiveAddress, state.x); bus.write(effectiveAddress, state.x);
break; break;
/** STZ - 65C02 Store Zero ****************************************************/
case 0x64: // Zero Page
case 0x74: // Zero Page,X
case 0x9c: // Absolute
case 0x9e: // Absolute,X
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
bus.write(effectiveAddress, 0);
break;
/** LDY - Load Y Register ***********************************************/ /** LDY - Load Y Register ***********************************************/
case 0xa0: // #Immediate case 0xa0: // #Immediate
@ -629,6 +745,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 +776,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
@ -667,6 +793,14 @@ public class Cpu implements InstructionTable {
/** DEC - Decrement Memory **********************************************/ /** DEC - Decrement Memory **********************************************/
case 0x3a: // 65C02 Immediate
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
state.a = --state.a & 0xFF;
setArithmeticFlags(state.a);
break;
case 0xc6: // Zero Page case 0xc6: // Zero Page
case 0xce: // Absolute case 0xce: // Absolute
case 0xd6: // Zero Page,X case 0xd6: // Zero Page,X
@ -695,6 +829,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
@ -711,6 +850,14 @@ public class Cpu implements InstructionTable {
/** INC - Increment Memory **********************************************/ /** INC - Increment Memory **********************************************/
case 0x1a: // 65C02 Increment Immediate
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
state.a = ++state.a & 0xff;
setArithmeticFlags(state.a);
break;
case 0xe6: // Zero Page case 0xe6: // Zero Page
case 0xee: // Absolute case 0xee: // Absolute
case 0xf6: // Zero Page,X case 0xf6: // Zero Page,X
@ -720,6 +867,364 @@ public class Cpu implements InstructionTable {
setArithmeticFlags(tmp); setArithmeticFlags(tmp);
break; break;
/** 65C02 RMB - Reset Memory Bit **************************************/
case 0x07: // 65C02 RMB0 - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true) & 0xff;
tmp &= ~(1 << 0);
bus.write(effectiveAddress, tmp);
break;
case 0x17: // 65C02 RMB1 - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true) & 0xff;
tmp &= ~(1 << 1);
bus.write(effectiveAddress, tmp);
break;
case 0x27: // 65C02 RMB2 - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true) & 0xff;
tmp &= ~(1 << 2);
bus.write(effectiveAddress, tmp);
break;
case 0x37: // 65C02 RMB3 - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true) & 0xff;
tmp &= ~(1 << 3);
bus.write(effectiveAddress, tmp);
break;
case 0x47: // 65C02 RMB4 - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true) & 0xff;
tmp &= ~(1 << 4);
bus.write(effectiveAddress, tmp);
break;
case 0x57: // 65C02 RMB5 - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true) & 0xff;
tmp &= ~(1 << 5);
bus.write(effectiveAddress, tmp);
break;
case 0x67: // 65C02 RMB6 - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true) & 0xff;
tmp &= ~(1 << 6);
bus.write(effectiveAddress, tmp);
break;
case 0x77: // 65C02 RMB7 - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true) & 0xff;
tmp &= ~(1 << 7);
bus.write(effectiveAddress, tmp);
break;
/** 65C02 SMB - Set Memory Bit **************************************/
case 0x87: // 65C02 SMB0 - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true) & 0xff;
tmp |= (1);
bus.write(effectiveAddress, tmp);
break;
case 0x97: // 65C02 SMB1 - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true) & 0xff;
tmp |= (1 << 1);
bus.write(effectiveAddress, tmp);
break;
case 0xa7: // 65C02 SMB2 - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true) & 0xff;
tmp |= (1 << 2);
bus.write(effectiveAddress, tmp);
break;
case 0xb7: // 65C02 SMB3 - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true) & 0xff;
tmp |= (1 << 3);
bus.write(effectiveAddress, tmp);
break;
case 0xc7: // 65C02 SMB4 - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true) & 0xff;
tmp |= (1 << 4);
bus.write(effectiveAddress, tmp);
break;
case 0xd7: // 65C02 SMB5 - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true) & 0xff;
tmp |= (1 << 5);
bus.write(effectiveAddress, tmp);
break;
case 0xe7: // 65C02 SMB6 - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true) & 0xff;
tmp |= (1 << 6);
bus.write(effectiveAddress, tmp);
break;
case 0xf7: // 65C02 SMB7 - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true) & 0xff;
tmp |= (1 << 7);
bus.write(effectiveAddress, tmp);
break;
/** 65C02 TRB/TSB - Test and Reset Bit/Test and Set Bit ***************/
case 0x14: // 65C02 TRB - Test and Reset bit - Zero Page
case 0x1c: // 65C02 TRB - Test and Reset bit - Absolute
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true);
setZeroFlag((state.a & tmp) == 0);
tmp = (tmp &= ~(state.a)) & 0xff;
bus.write(effectiveAddress,tmp);
break;
case 0x04: // 65C02 TSB - Test and Set bit - Zero Page
case 0x0c: // 65C02 TSB - Test and Set bit - Absolute
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true);
setZeroFlag((state.a & tmp) == 0);
tmp = (tmp |= (state.a)) & 0xff;
bus.write(effectiveAddress,tmp);
break;
/** 65C02 BBR - Branch if Bit Reset *************************************/
case 0x0f: // 65C02 BBR - Branch if bit 0 reset - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true);
if ((tmp & 1 << 0) == 0) {
state.pc = relAddress(state.args[1]);
}
break;
case 0x1f: // 65C02 BBR - Branch if bit 1 reset - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true);
if ((tmp & 1 << 1) == 0) {
state.pc = relAddress(state.args[1]);
}
break;
case 0x2f: // 65C02 BBR - Branch if bit 2 reset - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true);
if ((tmp & 1 << 2) == 0) {
state.pc = relAddress(state.args[1]);
}
break;
case 0x3f: // 65C02 BBR - Branch if bit 3 reset - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true);
if ((tmp & 1 << 3) == 0) {
state.pc = relAddress(state.args[1]);
}
break;
case 0x4f: // 65C02 BBR - Branch if bit 4 reset - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true);
if ((tmp & 1 << 4) == 0) {
state.pc = relAddress(state.args[1]);
}
break;
case 0x5f: // 65C02 BBR - Branch if bit 5 reset - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true);
if ((tmp & 1 << 5) == 0) {
state.pc = relAddress(state.args[1]);
}
break;
case 0x6f: // 65C02 BBR - Branch if bit 6 reset - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true);
if ((tmp & 1 << 6) == 0) {
state.pc = relAddress(state.args[1]);
}
break;
case 0x7f: // 65C02 BBR - Branch if bit 5 reset - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true);
if ((tmp & 1 << 7) == 0) {
state.pc = relAddress(state.args[1]);
}
break;
/** 65C02 BBS - Branch if Bit Set ************************************/
case 0x8f: // 65C02 BBS - Branch if bit 0 set - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true);
if ((tmp & 1 << 0) > 0) {
state.pc = relAddress(state.args[1]);
}
break;
case 0x9f: // 65C02 BBS - Branch if bit 1 set - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true);
if ((tmp & 1 << 1) > 0) {
state.pc = relAddress(state.args[1]);
}
break;
case 0xaf: // 65C02 BBS - Branch if bit 2 set - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true);
if ((tmp & 1 << 2) > 0) {
state.pc = relAddress(state.args[1]);
}
break;
case 0xbf: // 65C02 BBS - Branch if bit 3 set - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true);
if ((tmp & 1 << 3) > 0) {
state.pc = relAddress(state.args[1]);
}
break;
case 0xcf: // 65C02 BBS - Branch if bit 4 set - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true);
if ((tmp & 1 << 4) > 0) {
state.pc = relAddress(state.args[1]);
}
break;
case 0xdf: // 65C02 BBS - Branch if bit 5 set - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true);
if ((tmp & 1 << 5) > 0) {
state.pc = relAddress(state.args[1]);
}
break;
case 0xef: // 65C02 BBS - Branch if bit 6 set - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true);
if ((tmp & 1 << 6) > 0) {
state.pc = relAddress(state.args[1]);
}
break;
case 0xff: // 65C02 BBS - Branch if bit 5 set - Zero Page
if (behavior == CpuBehavior.NMOS_6502 ||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
break;
}
tmp = bus.read(effectiveAddress, true);
if ((tmp & 1 << 7) > 0) {
state.pc = relAddress(state.args[1]);
}
break;
/** Unimplemented Instructions ****************************************/ /** Unimplemented Instructions ****************************************/
// TODO: Create a flag to enable highly-accurate emulation of unimplemented instructions. // TODO: Create a flag to enable highly-accurate emulation of unimplemented instructions.
default: default:
@ -782,6 +1287,12 @@ public class Cpu implements InstructionTable {
// Set the Interrupt Disabled flag. RTI will clear it. // Set the Interrupt Disabled flag. RTI will clear it.
setIrqDisableFlag(); setIrqDisableFlag();
// 65C02 & 65816 clear Decimal flag after pushing Processor status to the stack
if (behavior == CpuBehavior.CMOS_6502||
behavior == CpuBehavior.CMOS_65816) {
clearDecimalModeFlag();
}
// Load interrupt vector address into PC // Load interrupt vector address into PC
state.pc = Utils.address(bus.read(vectorLow, true), bus.read(vectorHigh, true)); state.pc = Utils.address(bus.read(vectorLow, true), bus.read(vectorHigh, true));
} }
@ -819,8 +1330,15 @@ public class Cpu implements InstructionTable {
result &= 0xff; result &= 0xff;
setCarryFlag(h > 15); setCarryFlag(h > 15);
setZeroFlag(result == 0); setZeroFlag(result == 0);
setNegativeFlag(false); // BCD is never negative
setOverflowFlag(false); // BCD never sets overflow flag setOverflowFlag(false); // BCD never sets overflow flag
if (behavior == CpuBehavior.NMOS_6502||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
setNegativeFlag(false); // BCD is never negative on NMOS 6502
}
else {
state.negativeFlag = (result & 0x80) != 0; // N Flag is valid on CMOS 6502/65816
}
return result; return result;
} }
@ -845,11 +1363,18 @@ public class Cpu implements InstructionTable {
if ((l & 0x10) != 0) l -= 6; if ((l & 0x10) != 0) l -= 6;
h = (acc >> 4) - (operand >> 4) - ((l & 0x10) != 0 ? 1 : 0); h = (acc >> 4) - (operand >> 4) - ((l & 0x10) != 0 ? 1 : 0);
if ((h & 0x10) != 0) h -= 6; if ((h & 0x10) != 0) h -= 6;
result = (l & 0x0f) | (h << 4); result = (l & 0x0f) | (h << 4) & 0xff;
setCarryFlag((h & 0xff) < 15); setCarryFlag((h & 0xff) < 15);
setZeroFlag(result == 0); setZeroFlag(result == 0);
setNegativeFlag(false); // BCD is never negative
setOverflowFlag(false); // BCD never sets overflow flag setOverflowFlag(false); // BCD never sets overflow flag
if (behavior == CpuBehavior.NMOS_6502||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
setNegativeFlag(false); // BCD is never negative on NMOS 6502
}
else {
state.negativeFlag = (result & 0x80) != 0; // N Flag is valid on CMOS 6502/65816
}
return (result & 0xff); return (result & 0xff);
} }
@ -1334,6 +1859,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 +1874,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;
} }
@ -1387,6 +1919,8 @@ public class Cpu implements InstructionTable {
case ABS: case ABS:
sb.append(" $").append(Utils.wordToHex(Utils.address(args[0], args[1]))); sb.append(" $").append(Utils.wordToHex(Utils.address(args[0], args[1])));
break; break;
case AIX:
sb.append(" ($").append(Utils.wordToHex(Utils.address(args[0], args[1]))).append(",X)");
case ABX: case ABX:
sb.append(" $").append(Utils.wordToHex(Utils.address(args[0], args[1]))).append(",X"); sb.append(" $").append(Utils.wordToHex(Utils.address(args[0], args[1]))).append(",X");
break; break;
@ -1406,6 +1940,7 @@ public class Cpu implements InstructionTable {
sb.append(" ($").append(Utils.byteToHex(args[0])).append("),Y"); sb.append(" ($").append(Utils.byteToHex(args[0])).append("),Y");
break; break;
case REL: case REL:
case ZPR:
case ZPG: case ZPG:
sb.append(" $").append(Utils.byteToHex(args[0])); sb.append(" $").append(Utils.byteToHex(args[0]));
break; break;

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
} }
/** /**
@ -71,7 +68,11 @@ public interface InstructionTable {
return "Accumulator"; return "Accumulator";
} }
}, },
AIX {
public String toString() {
return "Absolute, X-Indexed Indirect";
}
},
ABS { ABS {
public String toString() { public String toString() {
return "Absolute"; return "Absolute";
@ -128,19 +129,31 @@ public interface InstructionTable {
ZPG { ZPG {
public String toString() { public String toString() {
return "Zeropage"; return "Zero Page";
}
},
ZPR {
public String toString() {
return "Zero Page, Relative";
} }
}, },
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,156 +167,185 @@ 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", "NOP", "NOP", "TSB", "ORA", "ASL", "RMB0", // 0x00-0x07
"PHP", "ORA", "ASL", null, null, "ORA", "ASL", null, "PHP", "ORA", "ASL", "NOP", "TSB", "ORA", "ASL", "BBR0", // 0x08-0x0f
"BPL", "ORA", null, null, null, "ORA", "ASL", null, "BPL", "ORA", "ORA", "NOP", "TRB", "ORA", "ASL", "RMB1", // 0x10-0x17
"CLC", "ORA", null, null, null, "ORA", "ASL", null, "CLC", "ORA", "INC", "NOP", "TRB", "ORA", "ASL", "BBR1", // 0x18-0x1f
"JSR", "AND", null, null, "BIT", "AND", "ROL", null, "JSR", "AND", "NOP", "NOP", "BIT", "AND", "ROL", "RMB2", // 0x20-0x27
"PLP", "AND", "ROL", null, "BIT", "AND", "ROL", null, "PLP", "AND", "ROL", "NOP", "BIT", "AND", "ROL", "BBR2", // 0x28-0x2f
"BMI", "AND", null, null, null, "AND", "ROL", null, "BMI", "AND", "AND", "NOP", "BIT", "AND", "ROL", "RMB3", // 0x30-0x37
"SEC", "AND", null, null, null, "AND", "ROL", null, "SEC", "AND", "DEC", "NOP", "BIT", "AND", "ROL", "BBR3", // 0x38-0x3f
"RTI", "EOR", null, null, null, "EOR", "LSR", null, "RTI", "EOR", "NOP", "NOP", "NOP", "EOR", "LSR", "RMB4", // 0x40-0x47
"PHA", "EOR", "LSR", null, "JMP", "EOR", "LSR", null, "PHA", "EOR", "LSR", "NOP", "JMP", "EOR", "LSR", "BBR4", // 0x48-0x4f
"BVC", "EOR", null, null, null, "EOR", "LSR", null, "BVC", "EOR", "EOR", "NOP", "NOP", "EOR", "LSR", "RMB5", // 0x50-0x57
"CLI", "EOR", null, null, null, "EOR", "LSR", null, "CLI", "EOR", "PHY", "NOP", "NOP", "EOR", "LSR", "BBR5", // 0x58-0x5f
"RTS", "ADC", null, null, null, "ADC", "ROR", null, "RTS", "ADC", "NOP", "NOP", "STZ", "ADC", "ROR", "RMB6", // 0x60-0x67
"PLA", "ADC", "ROR", null, "JMP", "ADC", "ROR", null, "PLA", "ADC", "ROR", "NOP", "JMP", "ADC", "ROR", "BBR6", // 0x68-0x6f
"BVS", "ADC", null, null, null, "ADC", "ROR", null, "BVS", "ADC", "ADC", "NOP", "STZ", "ADC", "ROR", "RMB7", // 0x70-0x77
"SEI", "ADC", null, null, null, "ADC", "ROR", null, "SEI", "ADC", "PLY", "NOP", "JMP", "ADC", "ROR", "BBR7", // 0x78-0x7f
"BCS", "STA", null, null, "STY", "STA", "STX", null, "BRA", "STA", "NOP", "NOP", "STY", "STA", "STX", "SMB0", // 0x80-0x87
"DEY", null, "TXA", null, "STY", "STA", "STX", null, "DEY", "BIT", "TXA", "NOP", "STY", "STA", "STX", "BBS0", // 0x88-0x8f
"BCC", "STA", null, null, "STY", "STA", "STX", null, "BCC", "STA", "STA", "NOP", "STY", "STA", "STX", "SMB1", // 0x90-0x97
"TYA", "STA", "TXS", null, null, "STA", null, null, "TYA", "STA", "TXS", "NOP", "STZ", "STA", "STZ", "BBS1", // 0x98-0x9f
"LDY", "LDA", "LDX", null, "LDY", "LDA", "LDX", null, "LDY", "LDA", "LDX", "NOP", "LDY", "LDA", "LDX", "SMB2", // 0xa0-0xa7
"TAY", "LDA", "TAX", null, "LDY", "LDA", "LDX", null, "TAY", "LDA", "TAX", "NOP", "LDY", "LDA", "LDX", "BBS2", // 0xa8-0xaf
"BCS", "LDA", null, null, "LDY", "LDA", "LDX", null, "BCS", "LDA", "LDA", "NOP", "LDY", "LDA", "LDX", "SMB3", // 0xb0-0xb7
"CLV", "LDA", "TSX", null, "LDY", "LDA", "LDX", null, "CLV", "LDA", "TSX", "NOP", "LDY", "LDA", "LDX", "BBS3", // 0xb8-0xbf
"CPY", "CMP", null, null, "CPY", "CMP", "DEC", null, "CPY", "CMP", "NOP", "NOP", "CPY", "CMP", "DEC", "SMB4", // 0xc0-0xc7
"INY", "CMP", "DEX", null, "CPY", "CMP", "DEC", null, "INY", "CMP", "DEX", "NOP", "CPY", "CMP", "DEC", "BBS4", // 0xc8-0xcf
"BNE", "CMP", null, null, null, "CMP", "DEC", null, "BNE", "CMP", "CMP", "NOP", "NOP", "CMP", "DEC", "SMB5", // 0xd0-0xd7
"CLD", "CMP", null, null, null, "CMP", "DEC", null, "CLD", "CMP", "PHX", "NOP", "NOP", "CMP", "DEC", "BBS5", // 0xd8-0xdf
"CPX", "SBC", null, null, "CPX", "SBC", "INC", null, "CPX", "SBC", "NOP", "NOP", "CPX", "SBC", "INC", "SMB6", // 0xe0-0xe7
"INX", "SBC", "NOP", null, "CPX", "SBC", "INC", null, "INX", "SBC", "NOP", "NOP", "CPX", "SBC", "INC", "BBS6", // 0xe8-0xef
"BEQ", "SBC", null, null, null, "SBC", "INC", null, "BEQ", "SBC", "SBC", "NOP", "NOP", "SBC", "INC", "SMB7", // 0xf0-0xf7
"SED", "SBC", null, null, null, "SBC", "INC", null "SED", "SBC", "PLX", "NOP", "NOP", "SBC", "INC", "BBS7" // 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.ZPG, Mode.ZPG, Mode.ZPG, Mode.ZPG, // 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.ABS, Mode.ABS, Mode.ABS, Mode.ZPR, // 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.ZPG, Mode.ZPX, Mode.ZPX, Mode.ZPG, // 0x14-0x17
Mode.IMP, Mode.ABY, Mode.NUL, Mode.NUL, // 0x18-0x1b Mode.IMP, Mode.ABY, Mode.IMP, Mode.NUL, // 0x18-0x1b
Mode.NUL, Mode.ABX, Mode.ABX, Mode.NUL, // 0x1c-0x1f Mode.ABS, Mode.ABX, Mode.ABX, Mode.ZPR, // 0x1c-0x1f
Mode.ABS, Mode.XIN, Mode.NUL, Mode.NUL, // 0x20-0x23 Mode.ABS, Mode.XIN, Mode.NUL, Mode.NUL, // 0x20-0x23
Mode.ZPG, Mode.ZPG, Mode.ZPG, Mode.NUL, // 0x24-0x27 Mode.ZPG, Mode.ZPG, Mode.ZPG, Mode.ZPG, // 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.ZPR, // 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.ZPX, Mode.ZPX, Mode.ZPX, Mode.ZPG, // 0x34-0x37
Mode.IMP, Mode.ABY, Mode.NUL, Mode.NUL, // 0x38-0x3b Mode.IMP, Mode.ABY, Mode.IMP, Mode.NUL, // 0x38-0x3b
Mode.NUL, Mode.ABX, Mode.ABX, Mode.NUL, // 0x3c-0x3f Mode.NUL, Mode.ABX, Mode.ABX, Mode.ZPR, // 0x3c-0x3f
Mode.IMP, Mode.XIN, Mode.NUL, Mode.NUL, // 0x40-0x43 Mode.IMP, Mode.XIN, Mode.NUL, Mode.NUL, // 0x40-0x43
Mode.NUL, Mode.ZPG, Mode.ZPG, Mode.NUL, // 0x44-0x47 Mode.NUL, Mode.ZPG, Mode.ZPG, Mode.ZPG, // 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.ZPR, // 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.ZPG, // 0x54-0x57
Mode.IMP, Mode.ABY, Mode.NUL, Mode.NUL, // 0x58-0x5b Mode.IMP, Mode.ABY, Mode.IMM, Mode.NUL, // 0x58-0x5b
Mode.NUL, Mode.ABX, Mode.ABX, Mode.NUL, // 0x5c-0x5f Mode.NUL, Mode.ABX, Mode.ABX, Mode.ZPR, // 0x5c-0x5f
Mode.IMP, Mode.XIN, Mode.NUL, Mode.NUL, // 0x60-0x63 Mode.IMP, Mode.XIN, Mode.NUL, Mode.NUL, // 0x60-0x63
Mode.NUL, Mode.ZPG, Mode.ZPG, Mode.NUL, // 0x64-0x67 Mode.ZPG, Mode.ZPG, Mode.ZPG, Mode.ZPG, // 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.ZPR, // 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.ZPX, Mode.ZPX, Mode.ZPX, Mode.ZPG, // 0x74-0x77
Mode.IMP, Mode.ABY, Mode.NUL, Mode.NUL, // 0x78-0x7b Mode.IMP, Mode.ABY, Mode.IMM, Mode.NUL, // 0x78-0x7b
Mode.NUL, Mode.ABX, Mode.ABX, Mode.NUL, // 0x7c-0x7f Mode.AIX, Mode.ABX, Mode.ABX, Mode.ZPR, // 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.ZPG, // 0x84-0x87
Mode.IMP, Mode.NUL, Mode.IMP, Mode.NUL, // 0x88-0x8b Mode.IMP, Mode.IMM, Mode.IMP, Mode.NUL, // 0x88-0x8b
Mode.ABS, Mode.ABS, Mode.ABS, Mode.NUL, // 0x8c-0x8f Mode.ABS, Mode.ABS, Mode.ABS, Mode.ZPR, // 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.ZPG, // 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.ABS, Mode.ABX, Mode.ABX, Mode.ZPR, // 0x9c-0x9f
Mode.IMM, Mode.XIN, Mode.IMM, Mode.NUL, // 0xa0-0xa3 Mode.IMM, Mode.XIN, Mode.IMM, Mode.NUL, // 0xa0-0xa3
Mode.ZPG, Mode.ZPG, Mode.ZPG, Mode.NUL, // 0xa4-0xa7 Mode.ZPG, Mode.ZPG, Mode.ZPG, Mode.ZPG, // 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.ZPR, // 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.ZPG, // 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.ZPR, // 0xbc-0xbf
Mode.IMM, Mode.XIN, Mode.NUL, Mode.NUL, // 0xc0-0xc3 Mode.IMM, Mode.XIN, Mode.NUL, Mode.NUL, // 0xc0-0xc3
Mode.ZPG, Mode.ZPG, Mode.ZPG, Mode.NUL, // 0xc4-0xc7 Mode.ZPG, Mode.ZPG, Mode.ZPG, Mode.ZPG, // 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.ZPR, // 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.ZPG, // 0xd4-0xd7
Mode.IMP, Mode.ABY, Mode.NUL, Mode.NUL, // 0xd8-0xdb Mode.IMP, Mode.ABY, Mode.IMP, Mode.NUL, // 0xd8-0xdb
Mode.NUL, Mode.ABX, Mode.ABX, Mode.NUL, // 0xdc-0xdf Mode.NUL, Mode.ABX, Mode.ABX, Mode.ZPR, // 0xdc-0xdf
Mode.IMM, Mode.XIN, Mode.NUL, Mode.NUL, // 0xe0-0xe3 Mode.IMM, Mode.XIN, Mode.NUL, Mode.NUL, // 0xe0-0xe3
Mode.ZPG, Mode.ZPG, Mode.ZPG, Mode.NUL, // 0xe4-0xe7 Mode.ZPG, Mode.ZPG, Mode.ZPG, Mode.ZPG, // 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.ZPR, // 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.ZPG, // 0xf4-0xf7
Mode.IMP, Mode.ABY, Mode.NUL, Mode.NUL, // 0xf8-0xfb Mode.IMP, Mode.ABY, Mode.IMP, Mode.NUL, // 0xf8-0xfb
Mode.NUL, Mode.ABX, Mode.ABX, Mode.NUL // 0xfc-0xff Mode.NUL, Mode.ABX, Mode.ABX, Mode.ZPR // 0xfc-0xff
}; };
/** /**
* 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, 2, 1, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 3, // 0x00-0x0f
2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0, 2, 2, 2, 1, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 3, // 0x10-0x1f
3, 2, 0, 0, 2, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0, 3, 2, 2, 1, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 3, // 0x20-0x2f
2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0, 2, 2, 2, 1, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 3, // 0x30-0x3f
1, 2, 0, 0, 0, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0, 1, 2, 2, 1, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 3, // 0x40-0x4f
2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0, 2, 2, 2, 1, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 3, // 0x50-0x5f
1, 2, 0, 0, 0, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0, 1, 2, 2, 1, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 3, // 0x60-0x6f
2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0, 2, 2, 2, 1, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 3, // 0x70-0x7f
2, 2, 0, 0, 2, 2, 2, 0, 1, 0, 1, 0, 3, 3, 3, 0, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 3, // 0x80-0x8f
2, 2, 0, 0, 2, 2, 2, 0, 1, 3, 1, 0, 0, 3, 0, 0, 2, 2, 2, 1, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 3, // 0x90-0x9f
2, 2, 2, 0, 2, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 3, // 0xa0-0xaf
2, 2, 0, 0, 2, 2, 2, 0, 1, 3, 1, 0, 3, 3, 3, 0, 2, 2, 2, 1, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 3, // 0xb0-0xbf
2, 2, 0, 0, 2, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 3, // 0xc0-0xcf
2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0, 2, 2, 2, 1, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 3, // 0xd0-0xdf
2, 2, 0, 0, 2, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 3, // 0xe0-0xef
2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0 2, 2, 2, 1, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 3 // 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, 2, 1, 5, 3, 5, 5, 3, 2, 2, 1, 6, 4, 6, 5, // 0x00-0x0f
2, 5, 5, 1, 5, 4, 6, 5, 2, 4, 2, 1, 6, 4, 6, 5, // 0x10-0x1f
6, 6, 2, 1, 3, 3, 5, 5, 4, 2, 2, 1, 4, 4, 6, 5, // 0x20-0x2f
2, 5, 5, 1, 4, 4, 6, 5, 2, 4, 2, 1, 4, 4, 6, 5, // 0x30-0x3f
6, 6, 2, 1, 2, 3, 5, 3, 3, 2, 2, 1, 3, 4, 6, 5, // 0x40-0x4f
2, 5, 5, 1, 4, 4, 6, 5, 2, 4, 3, 1, 8, 4, 6, 5, // 0x50-0x5f
6, 6, 2, 1, 3, 3, 5, 5, 4, 2, 2, 1, 6, 4, 6, 5, // 0x60-0x6f
2, 5, 5, 1, 4, 4, 6, 5, 2, 4, 4, 3, 6, 4, 6, 5, // 0x70-0x7f
3, 6, 2, 1, 3, 3, 3, 5, 2, 2, 2, 1, 4, 4, 4, 5, // 0x80-0x8f
2, 6, 5, 1, 4, 4, 4, 5, 2, 5, 2, 1, 4, 5, 5, 5, // 0x90-0x9f
2, 6, 2, 1, 3, 3, 3, 5, 2, 2, 2, 1, 4, 4, 4, 5, // 0xa0-0xaf
2, 5, 5, 1, 4, 4, 4, 5, 2, 4, 2, 1, 4, 4, 4, 5, // 0xb0-0xbf
2, 6, 2, 1, 3, 3, 5, 5, 2, 2, 2, 3, 4, 4, 6, 5, // 0xc0-0xcf
2, 5, 5, 1, 4, 4, 6, 5, 2, 4, 3, 3, 4, 4, 7, 5, // 0xd0-0xdf
2, 6, 2, 1, 3, 3, 5, 5, 2, 2, 2, 1, 4, 4, 6, 5, // 0xe0-0xef
2, 5, 5, 1, 4, 4, 6, 5, 2, 4, 4, 1, 4, 4, 7, 5 // 0xf0-0xff
}; };
} }

View File

@ -678,6 +678,21 @@ public class Simulator {
} }
} }
class SetCpuAction extends AbstractAction {
private Cpu.CpuBehavior behavior;
public SetCpuAction(String cpu, Cpu.CpuBehavior behavior) {
super(cpu, null);
this.behavior = behavior;
putValue(SHORT_DESCRIPTION, "Set CPU to " + cpu);
}
@Override
public void actionPerformed(ActionEvent actionEvent) {
machine.getCpu().setBehavior(behavior);
}
}
class ToggleTraceWindowAction extends AbstractAction { class ToggleTraceWindowAction extends AbstractAction {
public ToggleTraceWindowAction() { public ToggleTraceWindowAction() {
super("Trace Log", null); super("Trace Log", null);
@ -868,6 +883,13 @@ public class Simulator {
JMenuItem selectMachineItem = new JMenuItem(new SelectMachineAction()); JMenuItem selectMachineItem = new JMenuItem(new SelectMachineAction());
simulatorMenu.add(selectMachineItem); simulatorMenu.add(selectMachineItem);
// "CPU" sub-menu
JMenu cpuTypeMenu = new JMenu("CPU");
ButtonGroup cpuGroup = new ButtonGroup();
makeCpuMenuItem("NMOS 6502", Cpu.CpuBehavior.NMOS_6502, cpuTypeMenu, cpuGroup);
makeCpuMenuItem("CMOS 65C02", Cpu.CpuBehavior.CMOS_6502, cpuTypeMenu, cpuGroup);
// "Clock Speed" sub-menu // "Clock Speed" sub-menu
JMenu speedSubMenu = new JMenu("Clock Speed"); JMenu speedSubMenu = new JMenu("Clock Speed");
ButtonGroup speedGroup = new ButtonGroup(); ButtonGroup speedGroup = new ButtonGroup();
@ -878,6 +900,7 @@ public class Simulator {
makeSpeedMenuItem(8, speedSubMenu, speedGroup); makeSpeedMenuItem(8, speedSubMenu, speedGroup);
simulatorMenu.add(speedSubMenu); simulatorMenu.add(speedSubMenu);
simulatorMenu.add(cpuTypeMenu);
// "Breakpoints" // "Breakpoints"
final JCheckBoxMenuItem showBreakpoints = new JCheckBoxMenuItem(new ToggleBreakpointWindowAction()); final JCheckBoxMenuItem showBreakpoints = new JCheckBoxMenuItem(new ToggleBreakpointWindowAction());
@ -914,6 +937,17 @@ public class Simulator {
subMenu.add(item); subMenu.add(item);
group.add(item); group.add(item);
} }
private void makeCpuMenuItem(String cpu, Cpu.CpuBehavior behavior, JMenu subMenu, ButtonGroup group) {
Action action = new SetCpuAction(cpu, behavior);
JCheckBoxMenuItem item = new JCheckBoxMenuItem(action);
item.setSelected(machine.getCpu().getBehavior() == behavior);
subMenu.add(item);
group.add(item);
}
} }
private void updateVisibleState() { private void updateVisibleState() {

View File

@ -0,0 +1,125 @@
package com.loomcom.symon;
import com.loomcom.symon.devices.Memory;
import com.loomcom.symon.exceptions.MemoryAccessException;
import junit.framework.*;
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 Cpu65C02AbsoluteModeTest extends TestCase {
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();
}
public void test_STZ() throws Exception {
makeCmosCpu();
bus.write(0x0010,0xff);
bus.loadProgram(0x9c, 0x10, 0x00); // STZ Absolute
// Test STZ Absolute ($0010)
assertEquals(0xff, bus.read(0x0010, true));
cpu.step();
assertEquals(0x00, bus.read(0x0010, true));
}
public void test_STZRequiresCmosCpu() throws Exception {
makeNmosCpu();
bus.write(0x0010,0xff);
bus.loadProgram(0x9c, 0x10, 0x00); // STZ Absolute
// Test STZ Absolute ($0010)
assertEquals(0xff, bus.read(0x0010, true));
cpu.step();
assertEquals(0xff, bus.read(0x0010, true));
}
public void test_TSB() throws Exception {
makeCmosCpu();
bus.loadProgram(0x0c, 0x10, 0x00); // 65C02 TSB Absolute $0010
bus.write(0x10, 0x01);
cpu.setAccumulator(0x01);
cpu.step();
assertEquals(0x01,bus.read(0x10,true)); // 0x01 & 0x01 = 0x01
assertFalse(cpu.getZeroFlag());
cpu.reset();
cpu.setAccumulator(0x02);
cpu.step();
assertEquals(0x03,bus.read(0x0010,true));
assertTrue(cpu.getZeroFlag());
}
public void test_TSBRequiresCmosCpu() throws Exception {
makeNmosCpu();
bus.loadProgram(0x0c, 0x10, 0x00); // 65C02 TSB Absolute $0010
bus.write(0x10, 0x00);
cpu.setAccumulator(0x01);
cpu.step();
assertEquals(0x00,bus.read(0x0010,true));
}
public void test_TRB() throws Exception {
makeCmosCpu();
bus.loadProgram(0x1c, 0x00, 0x01); // 65C02 TRB Absolute $0010
bus.write(0x0100, 0x03);
cpu.setAccumulator(0x01);
cpu.step();
assertEquals(0x02,bus.read(0x0100,true)); // $03 &= ~($01) = $02
assertFalse(cpu.getZeroFlag()); // Z = !(A & M)
cpu.reset();
cpu.setAccumulator(0x01);
cpu.step();
assertEquals(0x02,bus.read(0x0100,true)); // $02 &= ~($01) = $02
assertTrue(cpu.getZeroFlag()); // Z = !(A & M)
}
public void test_TRBRequiresCmosCpu() throws Exception {
makeNmosCpu();
bus.loadProgram(0x1c, 0x00, 0x01); // 65C02 TRB Absolute $0010
bus.write(0x0100, 0xff);
cpu.setAccumulator(0x01);
cpu.step();
assertEquals(0xff,bus.read(0x0100,true));
}
}

View File

@ -0,0 +1,87 @@
package com.loomcom.symon;
import com.loomcom.symon.devices.Memory;
import com.loomcom.symon.exceptions.MemoryAccessException;
import junit.framework.*;
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 Cpu65C02AbsoluteXModeTest extends TestCase {
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();
}
public void test_STZ() throws Exception {
makeCmosCpu();
bus.write(0x0011,0xff);
bus.loadProgram(0x9e, 0x10, 0x00); // STZ Absolute,X
// Test STZ Absolute,X ($0011)
cpu.setXRegister(0x01);
assertEquals(0xff, bus.read(0x0011, true));
cpu.step();
assertEquals(0x00, bus.read(0x0011, true));
}
public void test_STZRequiresCmosCpu() throws Exception {
makeNmosCpu();
bus.write(0x0011,0xff);
bus.loadProgram(0x9e, 0x10, 0x00); // STZ Absolute,X
// Test STZ Absolute,X ($0011)
cpu.setXRegister(0x01);
assertEquals(0xff, bus.read(0x0011, true));
cpu.step();
assertEquals(0xff, bus.read(0x0011, true));
}
public void test_JMP_Indirect_Absolute_X () throws Exception {
makeCmosCpu();
bus.write(0x304,00);
bus.write(0x0305,04);
bus.loadProgram(0x7c, 0x00, 0x03);
cpu.setXRegister(0x04);
cpu.step();
assertEquals(0x0400,cpu.getProgramCounter());
}
public void test_JMP_Indirect_Absolute_XRequiresCmosCpu () throws Exception {
makeNmosCpu();
bus.write(0x304,00);
bus.write(0x0305,04);
bus.loadProgram(0x7c, 0x00, 0x03);
cpu.setXRegister(0x04);
cpu.step();
assertEquals(0x0203,cpu.getProgramCounter());
}
}

View File

@ -0,0 +1,72 @@
package com.loomcom.symon;
import com.loomcom.symon.devices.Memory;
import com.loomcom.symon.exceptions.MemoryAccessException;
import junit.framework.*;
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 Cpu65C02ImmediateModeTest extends TestCase {
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();
}
public void test_BIT_Immediate() throws Exception {
makeCmosCpu();
bus.loadProgram(0x89, 0xF1); // 65C02 BIT #$01
cpu.setAccumulator(0x02);
cpu.step();
assertTrue(cpu.getZeroFlag()); // #$02 & #$F1 = 0
assertEquals(0x02,cpu.getAccumulator()); // Accumulator should not be modified
assertFalse(cpu.getNegativeFlag()); // BIT #Immediate should not set N or V Flags
assertFalse(cpu.getOverflowFlag());
cpu.reset();
cpu.setAccumulator(0x01);
cpu.step();
assertFalse(cpu.getZeroFlag()); // #$F1 & #$01 = 1
assertEquals(0x01,cpu.getAccumulator());
}
public void test_BIT_ImmediateRequiresCmosCpu() throws Exception {
makeNmosCpu();
bus.loadProgram(0x89, 0xF1); // 65C02 BIT #$01
cpu.step();
cpu.setAccumulator(0x01);
assertTrue(cpu.getZeroFlag());
assertEquals(0x01,cpu.getAccumulator());
}
}

View File

@ -0,0 +1,252 @@
package com.loomcom.symon;
import com.loomcom.symon.devices.Memory;
import com.loomcom.symon.exceptions.MemoryAccessException;
import junit.framework.*;
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 Cpu65C02ImpliedModeTest extends TestCase {
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();
}
public void test_PHX() throws Exception {
makeCmosCpu();
cpu.stackPush(0x00);
cpu.setXRegister(0xff);
bus.loadProgram(0xda);
assertEquals(cpu.stackPeek(), 0x00);
cpu.step();
assertEquals(cpu.stackPeek(), 0xff);
}
public void test_PHXRequiresCmosCpu() throws Exception {
makeNmosCpu();
cpu.stackPush(0x00);
cpu.setXRegister(0xff);
bus.loadProgram(0xda);
assertEquals(cpu.stackPeek(), 0x00);
cpu.step();
assertEquals(cpu.stackPeek(), 0x00);
}
public void test_PLX() throws Exception {
makeCmosCpu();
cpu.stackPush(0xff);
cpu.setXRegister(0x00);
bus.loadProgram(0xfa);
assertEquals(0x00, cpu.getXRegister());
cpu.step();
assertEquals(0xff, cpu.getXRegister());
}
public void test_PLXRequiresCmosCpu() throws Exception {
makeNmosCpu();
cpu.stackPush(0xff);
cpu.setXRegister(0x00);
bus.loadProgram(0xfa);
assertEquals(0x00, cpu.getXRegister());
cpu.step();
assertEquals(0x00, cpu.getXRegister());
}
public void test_PHY() throws Exception {
makeCmosCpu();
cpu.stackPush(0x00);
cpu.setYRegister(0xff);
bus.loadProgram(0x5a);
assertEquals(0x00, cpu.stackPeek());
cpu.step();
assertEquals(0xff, cpu.stackPeek());
}
public void test_PHYRequiresCmosCpu() throws Exception {
makeNmosCpu();
cpu.stackPush(0x00);
cpu.setYRegister(0xff);
bus.loadProgram(0x5a);
assertEquals(0x00, cpu.stackPeek());
cpu.step();
assertEquals(0x00, cpu.stackPeek());
}
public void test_PLY() throws Exception {
makeCmosCpu();
cpu.stackPush(0xff);
cpu.setYRegister(0x00);
bus.loadProgram(0x7a);
assertEquals(0x00, cpu.getYRegister());
cpu.step();
assertEquals(0xff, cpu.getYRegister());
}
public void test_PLYRequiresCmosCpu() throws Exception {
makeNmosCpu();
cpu.stackPush(0xff);
cpu.setYRegister(0x00);
bus.loadProgram(0x7a);
assertEquals(0x00, cpu.getYRegister());
cpu.step();
assertEquals(0x00, cpu.getYRegister());
}
public void test_INC_A() throws Exception {
makeCmosCpu();
cpu.setAccumulator(0x10);
bus.loadProgram(0x1a);
cpu.step();
assertEquals(0x11, cpu.getAccumulator());
assertFalse(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag());
// Incrementing to 0 should set Zero Flag
cpu.reset();
cpu.setAccumulator(0xff);
cpu.step();
assertTrue(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag());
// Should set Negative Flag
cpu.reset();
cpu.setAccumulator(0x7F);
cpu.step();
assertTrue(cpu.getNegativeFlag());
assertFalse(cpu.getZeroFlag());
}
public void test_INC_ARequiresCmosCpu() throws Exception {
makeNmosCpu();
cpu.setAccumulator(0x10);
bus.loadProgram(0x1a);
cpu.step();
assertEquals(0x10, cpu.getAccumulator());
}
public void test_DEC_A() throws Exception {
makeCmosCpu();
cpu.setAccumulator(0x10);
bus.loadProgram(0x3a);
cpu.step();
assertEquals(0x0F, cpu.getAccumulator());
assertFalse(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag());
// Decrementing to 0 should set Zero Flag
cpu.reset();
cpu.setAccumulator(0x01);
cpu.step();
assertTrue(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag());
// Should set Negative Flag
cpu.reset();
cpu.setAccumulator(0x00);
cpu.step();
assertTrue(cpu.getNegativeFlag());
assertFalse(cpu.getZeroFlag());
}
public void test_DEC_ARequiresCmosCpu() throws Exception {
makeNmosCpu();
cpu.setAccumulator(0x10);
bus.loadProgram(0x3a);
cpu.step();
assertEquals(0x10, cpu.getAccumulator());
assertFalse(cpu.getZeroFlag());
assertFalse(cpu.getNegativeFlag());
}
public void test_BRK_clearsDecimalModeFlag() throws Exception {
makeCmosCpu();
cpu.setDecimalModeFlag();
assertEquals(0x00, cpu.stackPeek());
assertFalse(cpu.getBreakFlag());
assertTrue(cpu.getDecimalModeFlag());
assertEquals(0x0200, cpu.getProgramCounter());
assertEquals(0xff, cpu.getStackPointer());
// Set the IRQ vector
bus.write(0xffff, 0x12);
bus.write(0xfffe, 0x34);
bus.loadProgram(0xea, // NOP
0xea, // NOP
0xea, // NOP
0x00, // BRK
0xea, // NOP
0xea); // NOP
cpu.step(3); // Three NOP instructions
assertEquals(0x203, cpu.getProgramCounter());
assertTrue(cpu.getDecimalModeFlag());
cpu.step(); // Triggers the BRK
// Was at PC = 0x204. PC+1 should now be on the stack
assertEquals(0x02, bus.read(0x1ff, true)); // PC high byte
assertEquals(0x05, bus.read(0x1fe, true)); // PC low byte
// Interrupt vector held 0x1234, so we should be there.
assertEquals(0x1234, cpu.getProgramCounter());
assertEquals(0xfc, cpu.getStackPointer());
// B and I flags should have been set on P
assertTrue(cpu.getBreakFlag());
assertFalse(cpu.getDecimalModeFlag());
}
}

View File

@ -0,0 +1,372 @@
package com.loomcom.symon;
import com.loomcom.symon.devices.Memory;
import com.loomcom.symon.exceptions.MemoryAccessException;
import junit.framework.*;
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 Cpu65C02ZeroPageModeTest extends TestCase {
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();
}
public void test_STZ() throws Exception {
makeCmosCpu();
bus.write(0x0000,0xff);
bus.loadProgram(0x64,0x00); // STZ Zero Page $00
// Test STZ Zero Page
assertEquals(0xff,bus.read(0x00, true));
cpu.step();
assertEquals(0x00,bus.read(0x00, true));
}
public void test_STZRequiresCmosCpu() throws Exception {
makeNmosCpu();
bus.write(0x0000,0xff);
bus.loadProgram(0x64,0x00); // STZ Zero Page $00
// Test STZ Zero Page
assertEquals(0xff,bus.read(0x00, true));
cpu.step();
assertEquals(0xff,bus.read(0x00, true));
}
public void test_SMB() throws Exception {
makeCmosCpu();
bus.loadProgram(0x87,0x01, // SMB0 $01
0x97,0x01, // SMB1 $01
0xa7,0x01, // SMB2 $01
0xb7,0x01, // SMB3 $01
0xc7,0x01, // SMB4 $01
0xd7,0x01, // SMB5 $01
0xe7,0x01, // SMB6 $01
0xf7,0x01); // SMB7 $01
// SMB0
bus.write(0x01,0x00);
assertEquals(0x00,bus.read(0x0001, true));
cpu.step();
assertEquals(1 << 0,bus.read(0x0001, true));
// SMB1
bus.write(0x01,0x00);
assertEquals(0x00,bus.read(0x0001, true));
cpu.step();
assertEquals(1 << 1,bus.read(0x0001, true));
// SMB2
bus.write(0x01,0x00);
assertEquals(0x00,bus.read(0x0001, true));
cpu.step();
assertEquals(1 << 2,bus.read(0x0001, true));
// SMB3
bus.write(0x01,0x00);
assertEquals(0x00,bus.read(0x0001, true));
cpu.step();
assertEquals(1 << 3,bus.read(0x0001, true));
// SMB4
bus.write(0x01,0x00);
assertEquals(0x00,bus.read(0x0001, true));
cpu.step();
assertEquals(1 << 4,bus.read(0x0001, true));
// SMB5
bus.write(0x01,0x00);
assertEquals(0x00,bus.read(0x0001, true));
cpu.step();
assertEquals(1 << 5,bus.read(0x0001, true));
// SMB6
bus.write(0x01,0x00);
assertEquals(0x00,bus.read(0x0001, true));
cpu.step();
assertEquals(1 << 6,bus.read(0x0001, true));
// SMB7
bus.write(0x01,0x00);
assertEquals(0x00,bus.read(0x0001, true));
cpu.step();
assertEquals(1 << 7,bus.read(0x0001, true));
}
public void test_SMBRequiresCmosCpu() throws Exception {
makeNmosCpu();
bus.loadProgram(0x87,0x01, // SMB0 $01
0x97,0x01, // SMB1 $01
0xa7,0x01, // SMB2 $01
0xb7,0x01, // SMB3 $01
0xc7,0x01, // SMB4 $01
0xd7,0x01, // SMB5 $01
0xe7,0x01, // SMB6 $01
0xf7,0x01); // SMB7 $01
// SMB0
bus.write(0x01,0x00);
assertEquals(0x00,bus.read(0x0001, true));
cpu.step();
assertEquals(0x00,bus.read(0x0001, true));
// SMB1
bus.write(0x01,0x00);
assertEquals(0x00,bus.read(0x0001, true));
cpu.step();
assertEquals(0x00,bus.read(0x0001, true));
// SMB2
bus.write(0x01,0x00);
assertEquals(0x00,bus.read(0x0001, true));
cpu.step();
assertEquals(0x00,bus.read(0x0001, true));
// SMB3
bus.write(0x01,0x00);
assertEquals(0x00,bus.read(0x0001, true));
cpu.step();
assertEquals(0x00,bus.read(0x0001, true));
// SMB4
bus.write(0x01,0x00);
assertEquals(0x00,bus.read(0x0001, true));
cpu.step();
assertEquals(0x00,bus.read(0x0001, true));
// SMB5
bus.write(0x01,0x00);
assertEquals(0x00,bus.read(0x0001, true));
cpu.step();
assertEquals(0x00,bus.read(0x0001, true));
// SMB6
bus.write(0x01,0x00);
assertEquals(0x00,bus.read(0x0001, true));
cpu.step();
assertEquals(0x00,bus.read(0x0001, true));
// SMB7
bus.write(0x01,0x00);
assertEquals(0x00,bus.read(0x0001, true));
cpu.step();
assertEquals(0x00,bus.read(0x0001, true));
}
public void test_RMB() throws Exception {
makeCmosCpu();
bus.loadProgram(0x07,0x01, // SMB0 $01
0x17,0x01, // SMB1 $01
0x27,0x01, // SMB2 $01
0x37,0x01, // SMB3 $01
0x47,0x01, // SMB4 $01
0x57,0x01, // SMB5 $01
0x67,0x01, // SMB6 $01
0x77,0x01); // SMB7 $01
// RMB0
bus.write(0x01,0xff);
assertEquals(0xff,bus.read(0x0001, true));
cpu.step();
assertEquals(0xfe,bus.read(0x0001, true));
// RMB1
bus.write(0x01,0xff);
assertEquals(0xff,bus.read(0x0001, true));
cpu.step();
assertEquals(0xfd,bus.read(0x0001, true));
// RMB2
bus.write(0x01,0xff);
assertEquals(0xff,bus.read(0x0001, true));
cpu.step();
assertEquals(0xfb,bus.read(0x0001, true));
// RMB3
bus.write(0x01,0xff);
assertEquals(0xff,bus.read(0x0001, true));
cpu.step();
assertEquals(0xf7,bus.read(0x0001, true));
// RMB4
bus.write(0x01,0xff);
assertEquals(0xff,bus.read(0x0001, true));
cpu.step();
assertEquals(0xef,bus.read(0x0001, true));
// RMB5
bus.write(0x01,0xff);
assertEquals(0xff,bus.read(0x0001, true));
cpu.step();
assertEquals(0xdf,bus.read(0x0001, true));
// RMB6
bus.write(0x01,0xff);
assertEquals(0xff,bus.read(0x0001, true));
cpu.step();
assertEquals(0xbf,bus.read(0x0001, true));
// RMB7
bus.write(0x01,0xff);
assertEquals(0xff,bus.read(0x0001, true));
cpu.step();
assertEquals(0x7f,bus.read(0x0001, true));
}
public void test_RMBRequiresCmosCpu() throws Exception {
makeNmosCpu();
bus.loadProgram(0x07,0x01, // SMB0 $01
0x17,0x01, // SMB1 $01
0x27,0x01, // SMB2 $01
0x37,0x01, // SMB3 $01
0x47,0x01, // SMB4 $01
0x57,0x01, // SMB5 $01
0x67,0x01, // SMB6 $01
0x77,0x01); // SMB7 $01
// RMB0
bus.write(0x01,0xff);
assertEquals(0xff,bus.read(0x0001, true));
cpu.step();
assertEquals(0xff,bus.read(0x0001, true));
// RMB1
bus.write(0x01,0xff);
assertEquals(0xff,bus.read(0x0001, true));
cpu.step();
assertEquals(0xff,bus.read(0x0001, true));
// RMB2
bus.write(0x01,0xff);
assertEquals(0xff,bus.read(0x0001, true));
cpu.step();
assertEquals(0xff,bus.read(0x0001, true));
// RMB3
bus.write(0x01,0xff);
assertEquals(0xff,bus.read(0x0001, true));
cpu.step();
assertEquals(0xff,bus.read(0x0001, true));
// RMB4
bus.write(0x01,0xff);
assertEquals(0xff,bus.read(0x0001, true));
cpu.step();
assertEquals(0xff,bus.read(0x0001, true));
// RMB5
bus.write(0x01,0xff);
assertEquals(0xff,bus.read(0x0001, true));
cpu.step();
assertEquals(0xff,bus.read(0x0001, true));
// RMB6
bus.write(0x01,0xff);
assertEquals(0xff,bus.read(0x0001, true));
cpu.step();
assertEquals(0xff,bus.read(0x0001, true));
// RMB7
bus.write(0x01,0xff);
assertEquals(0xff,bus.read(0x0001, true));
cpu.step();
assertEquals(0xff,bus.read(0x0001, true));
}
public void test_TSB() throws Exception {
makeCmosCpu();
bus.loadProgram(0x04, 0x10); // 65C02 TSB Zero Page $10
bus.write(0x10, 0x01);
cpu.setAccumulator(0x03);
cpu.step();
assertEquals(0x03,bus.read(0x10,true));
assertFalse(cpu.getZeroFlag());
cpu.reset();
bus.write(0x10, 0x01);
cpu.setAccumulator(0x02);
cpu.step();
assertEquals(0x03,bus.read(0x10,true));
assertTrue(cpu.getZeroFlag());
}
public void test_TSBRequiresCmosCpu() throws Exception {
makeNmosCpu();
bus.loadProgram(0x04, 0x10); // 65C02 TSB Zero Page $10
bus.write(0x10, 0x01);
cpu.setAccumulator(0x03);
cpu.step();
assertEquals(0x01,bus.read(0x10,true));
}
public void test_TRB() throws Exception {
makeCmosCpu();
cpu.reset();
bus.loadProgram(0x14, 0x40); // 65C02 TRB Zero Page $40
bus.write(0x0040, 0xff);
cpu.setAccumulator(0x01);
cpu.step();
assertEquals(0xfe,bus.read(0x0040,true)); // $03 &= ~($01) = $02
assertFalse(cpu.getZeroFlag()); // Z = !(A & M)
cpu.reset();
cpu.setAccumulator(0x01);
cpu.step();
assertEquals(0xfe,bus.read(0x0040,true)); // $02 &= ~($01) = $02
assertTrue(cpu.getZeroFlag()); // Z = !(A & M)
}
public void test_TRBRequiresCmosCpu() throws Exception {
makeNmosCpu();
cpu.reset();
bus.loadProgram(0x14, 0x40); // 65C02 TRB Zero Page $40
bus.write(0x0040, 0xff);
cpu.setAccumulator(0x01);
cpu.step();
assertEquals(0xff,bus.read(0x0040,true)); // $03 &= ~($01) = $02
}
}

View File

@ -0,0 +1,585 @@
package com.loomcom.symon;
import com.loomcom.symon.devices.Memory;
import com.loomcom.symon.exceptions.MemoryAccessException;
import junit.framework.*;
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 Cpu65C02ZeroPageRelativeTest extends TestCase {
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();
}
public void test_BRA() throws Exception {
makeCmosCpu();
// Positive Offset
bus.loadProgram(0x80, 0x05); // 65C02 BRA $05 ; *=$0202+$05 ($0207)
cpu.step();
assertEquals(0x207, cpu.getProgramCounter());
// Negative Offset
cpu.reset();
bus.loadProgram(0x80, 0xfb); // 65C02 BRA $fb ; *=$0202-$05 ($01fd)
cpu.step();
assertEquals(0x1fd, cpu.getProgramCounter());
}
public void test_BRArequiresCmosCpu() throws Exception {
makeNmosCpu();
// Should be a NOOP on NMOS and end up at $0202
// Positive Offset
bus.loadProgram(0x80, 0x05); // BRA $05 ; *=$0202+$05 ($0207)
cpu.step();
assertEquals(0x202, cpu.getProgramCounter());
// Negative Offset
cpu.reset();
bus.loadProgram(0x80, 0xfb); // BRA $fb ; *=$0202-$05 ($01fd)
cpu.step();
assertEquals(0x202, cpu.getProgramCounter());
}
public void test_BBR() throws Exception {
makeCmosCpu();
/* BBR0 */
// Positive Offset
cpu.reset();
bus.write(0x0a,0xff);
bus.loadProgram(0x0f, 0x0a, 0x05); // 65C02 BBR0 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter()); // Shouldn't have branched
cpu.reset();
bus.write(0x0a,0xfe);
bus.loadProgram(0x0f, 0x0a, 0x05); // 65C02 BBR0 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x208, cpu.getProgramCounter()); // Should have branched
// Negative Offset
cpu.reset();
bus.write(0x0a,0xfe);
bus.loadProgram(0x0f, 0x0a, 0xfb); // 65C02 BBR0 $00 $fb ; *=$0203-$05 ($01fe)
cpu.step();
assertEquals(0x1fe, cpu.getProgramCounter());
/* BBR1 */
// Positive Offset
cpu.reset();
bus.write(0x0a,0xff);
bus.loadProgram(0x1f, 0x0a, 0x05); // 65C02 BBR1 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter()); // Shouldn't have branched
cpu.reset();
bus.write(0x0a,0xfd);
bus.loadProgram(0x1f, 0x0a, 0x05); // 65C02 BBR1 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x208, cpu.getProgramCounter()); // Should have branched
// Negative Offset
cpu.reset();
bus.write(0x0a,0xfd);
bus.loadProgram(0x1f, 0x0a, 0xfb); // 65C02 BBR1 $00 $fb ; *=$0203-$05 ($01fe)
cpu.step();
assertEquals(0x1fe, cpu.getProgramCounter());
/* BBR2 */
// Positive Offset
cpu.reset();
bus.write(0x0a,0xff);
bus.loadProgram(0x2f, 0x0a, 0x05); // 65C02 BBR2 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter()); // Shouldn't have branched
cpu.reset();
bus.write(0x0a,0xfb);
bus.loadProgram(0x2f, 0x0a, 0x05); // 65C02 BBR2 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x208, cpu.getProgramCounter()); // Should have branched
// Negative Offset
cpu.reset();
bus.write(0x0a,0xfb);
bus.loadProgram(0x2f, 0x0a, 0xfb); // 65C02 BBR2 $00 $fb ; *=$0203-$05 ($01fe)
cpu.step();
assertEquals(0x1fe, cpu.getProgramCounter());
/* BBR3 */
// Positive Offset
cpu.reset();
bus.write(0x0a,0xff);
bus.loadProgram(0x3f, 0x0a, 0x05); // 65C02 BBR3 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter()); // Shouldn't have branched
cpu.reset();
bus.write(0x0a,0xf7);
bus.loadProgram(0x3f, 0x0a, 0x05); // 65C02 BBR3 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x208, cpu.getProgramCounter()); // Should have branched
// Negative Offset
cpu.reset();
bus.write(0x0a,0xf7);
bus.loadProgram(0x3f, 0x0a, 0xfb); // 65C02 BBR3 $00 $fb ; *=$0203-$05 ($01fe)
cpu.step();
assertEquals(0x1fe, cpu.getProgramCounter());
/* BBR4 */
// Positive Offset
cpu.reset();
bus.write(0x0a,0xff);
bus.loadProgram(0x4f, 0x0a, 0x05); // 65C02 BBR4 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter()); // Shouldn't have branched
cpu.reset();
bus.write(0x0a,0xef);
bus.loadProgram(0x4f, 0x0a, 0x05); // 65C02 BBR4 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x208, cpu.getProgramCounter()); // Should have branched
// Negative Offset
cpu.reset();
bus.write(0x0a,0xef);
bus.loadProgram(0x4f, 0x0a, 0xfb); // 65C02 BBR4 $00 $fb ; *=$0203-$05 ($01fe)
cpu.step();
assertEquals(0x1fe, cpu.getProgramCounter());
/* BBR5 */
// Positive Offset
cpu.reset();
bus.write(0x0a,0xff);
bus.loadProgram(0x5f, 0x0a, 0x05); // 65C02 BBR5 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter()); // Shouldn't have branched
cpu.reset();
bus.write(0x0a,0xdf);
bus.loadProgram(0x5f, 0x0a, 0x05); // 65C02 BBR5 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x208, cpu.getProgramCounter()); // Should have branched
// Negative Offset
cpu.reset();
bus.write(0x0a,0xdf);
bus.loadProgram(0x5f, 0x0a, 0xfb); // 65C02 BBR5 $00 $fb ; *=$0203-$05 ($01fe)
cpu.step();
assertEquals(0x1fe, cpu.getProgramCounter());
/* BBR6 */
// Positive Offset
cpu.reset();
bus.write(0x0a,0xff);
bus.loadProgram(0x6f, 0x0a, 0x05); // 65C02 BBR6 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter()); // Shouldn't have branched
cpu.reset();
bus.write(0x0a,0xbf);
bus.loadProgram(0x6f, 0x0a, 0x05); // 65C02 BBR6 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x208, cpu.getProgramCounter()); // Should have branched
// Negative Offset
cpu.reset();
bus.write(0x0a,0xbf);
bus.loadProgram(0x6f, 0x0a, 0xfb); // 65C02 BBR6 $00 $fb ; *=$0203-$05 ($01fe)
cpu.step();
assertEquals(0x1fe, cpu.getProgramCounter());
/* BBR7 */
// Positive Offset
cpu.reset();
bus.write(0x0a,0xff);
bus.loadProgram(0x7f, 0x0a, 0x05); // 65C02 BBR7 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter()); // Shouldn't have branched
cpu.reset();
bus.write(0x0a,0x7f);
bus.loadProgram(0x7f, 0x0a, 0x05); // 65C02 BBR7 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x208, cpu.getProgramCounter()); // Should have branched
// Negative Offset
cpu.reset();
bus.write(0x0a,0x7f);
bus.loadProgram(0x7f, 0x0a, 0xfb); // 65C02 BBR7 $00 $fb ; *=$0203-$05 ($01fe)
cpu.step();
assertEquals(0x1fe, cpu.getProgramCounter());
}
public void test_BBRNeedsCmosCpu() throws Exception {
makeNmosCpu();
/* BBR0 */
bus.write(0x0a,0xfe);
bus.loadProgram(0x0f, 0x0a, 0x05); // 65C02 BBR0 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter());
/* BBR1 */
cpu.reset();
bus.write(0x0a,0xfd);
bus.loadProgram(0x1f, 0x0a, 0x05); // 65C02 BBR1 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter());
/* BBR2 */
cpu.reset();
bus.write(0x0a,0xfb);
bus.loadProgram(0x2f, 0x0a, 0x05); // 65C02 BBR2 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter());
/* BBR3 */
cpu.reset();
bus.write(0x0a,0xf7);
bus.loadProgram(0x3f, 0x0a, 0x05); // 65C02 BBR3 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter());
/* BBR4 */
cpu.reset();
bus.write(0x0a,0xef);
bus.loadProgram(0x4f, 0x0a, 0x05); // 65C02 BBR4 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter());
/* BBR5 */
cpu.reset();
bus.write(0x0a,0xdf);
bus.loadProgram(0x5f, 0x0a, 0x05); // 65C02 BBR5 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter());
/* BBR6 */
cpu.reset();
bus.write(0x0a,0xbf);
bus.loadProgram(0x6f, 0x0a, 0x05); // 65C02 BBR6 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter());
/* BBR7 */
cpu.reset();
bus.write(0x0a,0x7f);
bus.loadProgram(0x7f, 0x0a, 0x05); // 65C02 BBR7 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter());
}
public void test_BBS() throws Exception {
makeCmosCpu();
/* BBS0 */
// Positive Offset
cpu.reset();
bus.write(0x0a,0x00);
bus.loadProgram(0x8f, 0x0a, 0x05); // 65C02 BBS0 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter()); // Shouldn't have branched
cpu.reset();
bus.write(0x0a,0x01);
bus.loadProgram(0x8f, 0x0a, 0x05); // 65C02 BBS0 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x208, cpu.getProgramCounter()); // Should have branched
// Negative Offset
cpu.reset();
bus.write(0x0a,0x01);
bus.loadProgram(0x8f, 0x0a, 0xfb); // 65C02 BBS0 $00 $fb ; *=$0203-$05 ($01fe)
cpu.step();
assertEquals(0x1fe, cpu.getProgramCounter());
/* BBS1 */
// Positive Offset
cpu.reset();
bus.write(0x0a,0x00);
bus.loadProgram(0x9f, 0x00, 0x05); // 65C02 BBS1 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter()); // Shouldn't have branched
cpu.reset();
bus.write(0x0a,0x02);
bus.loadProgram(0x9f, 0x0a, 0x05); // 65C02 BBS1 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x208, cpu.getProgramCounter()); // Should have branched
// Negative Offset
cpu.reset();
bus.write(0x0a,0x02);
bus.loadProgram(0x9f, 0x0a, 0xfb); // 65C02 BBS1 $00 $fb ; *=$0203-$05 ($01fe)
cpu.step();
assertEquals(0x1fe, cpu.getProgramCounter());
/* BBS2 */
// Positive Offset
cpu.reset();
bus.write(0x0a,0x00);
bus.loadProgram(0xaf, 0x0a, 0x05); // 65C02 BBS2 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter()); // Shouldn't have branched
cpu.reset();
bus.write(0x0a,0x04);
bus.loadProgram(0xaf, 0x0a, 0x05); // 65C02 BBS2 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x208, cpu.getProgramCounter()); // Should have branched
// Negative Offset
cpu.reset();
bus.write(0x0a,0x04);
bus.loadProgram(0xaf, 0x0a, 0xfb); // 65C02 BBS2 $00 $fb ; *=$0203-$05 ($01fe)
cpu.step();
assertEquals(0x1fe, cpu.getProgramCounter());
/* BBS3 */
// Positive Offset
cpu.reset();
bus.write(0x0a,0x00);
bus.loadProgram(0xbf, 0x0a, 0x05); // 65C02 BBS3 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter()); // Shouldn't have branched
cpu.reset();
bus.write(0x0a,0x08);
bus.loadProgram(0xbf, 0x0a, 0x05); // 65C02 BBS3 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x208, cpu.getProgramCounter()); // Should have branched
// Negative Offset
cpu.reset();
bus.write(0x0a,0x08);
bus.loadProgram(0xbf, 0x0a, 0xfb); // 65C02 BBS3 $00 $fb ; *=$0203-$05 ($01fe)
cpu.step();
assertEquals(0x1fe, cpu.getProgramCounter());
/* BBS4 */
// Positive Offset
cpu.reset();
bus.write(0x0a,0x00);
bus.loadProgram(0xcf, 0x0a, 0x05); // 65C02 BBS4 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter()); // Shouldn't have branched
cpu.reset();
bus.write(0x0a,0x10);
bus.loadProgram(0xcf, 0x0a, 0x05); // 65C02 BBS4 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x208, cpu.getProgramCounter()); // Should have branched
// Negative Offset
cpu.reset();
bus.write(0x0a,0x10);
bus.loadProgram(0xcf, 0x0a, 0xfb); // 65C02 BBS4 $00 $fb ; *=$0203-$05 ($01fe)
cpu.step();
assertEquals(0x1fe, cpu.getProgramCounter());
/* BBS5 */
// Positive Offset
cpu.reset();
bus.write(0x0a,0x00);
bus.loadProgram(0xdf, 0x0a, 0x05); // 65C02 BBS5 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter()); // Shouldn't have branched
cpu.reset();
bus.write(0x0a,0x20);
bus.loadProgram(0xdf, 0x0a, 0x05); // 65C02 BBS5 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x208, cpu.getProgramCounter()); // Should have branched
// Negative Offset
cpu.reset();
bus.write(0x0a,0x20);
bus.loadProgram(0xdf, 0x0a, 0xfb); // 65C02 BBS5 $00 $fb ; *=$0203-$05 ($01fe)
cpu.step();
assertEquals(0x1fe, cpu.getProgramCounter());
/* BBS6 */
// Positive Offset
cpu.reset();
bus.write(0x0a,0x00);
bus.loadProgram(0xef, 0x0a, 0x05); // 65C02 BBS6 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter()); // Shouldn't have branched
cpu.reset();
bus.write(0x0a,0x40);
bus.loadProgram(0xef, 0x0a, 0x05); // 65C02 BBS6 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x208, cpu.getProgramCounter()); // Should have branched
// Negative Offset
cpu.reset();
bus.write(0x0a,0x40);
bus.loadProgram(0xef, 0x0a, 0xfb); // 65C02 BBS6 $00 $fb ; *=$0203-$05 ($01fe)
cpu.step();
assertEquals(0x1fe, cpu.getProgramCounter());
/* BBS7 */
// Positive Offset
cpu.reset();
bus.write(0x0a,0x00);
bus.loadProgram(0xff, 0x0a, 0x05); // 65C02 BBS7 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter()); // Shouldn't have branched
cpu.reset();
bus.write(0x0a,0x80);
bus.loadProgram(0xff, 0x0a, 0x05); // 65C02 BBS7 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x208, cpu.getProgramCounter()); // Should have branched
// Negative Offset
cpu.reset();
bus.write(0x0a,0x80);
bus.loadProgram(0xff, 0x0a, 0xfb); // 65C02 BBS7 $00 $fb ; *=$0203-$05 ($01fe)
cpu.step();
assertEquals(0x1fe, cpu.getProgramCounter());
}
public void test_BBSNeedsCmosCpu() throws Exception {
makeNmosCpu();
/* BBS0 */
cpu.reset();
bus.write(0x0a,0x01);
bus.loadProgram(0x8f, 0x0a, 0x05); // 65C02 BBS0 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter());
/* BBS1 */
cpu.reset();
bus.write(0x0a,0x02);
bus.loadProgram(0x9f, 0x0a, 0x05); // 65C02 BBS1 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter());
/* BBS2 */
cpu.reset();
bus.write(0x0a,0x04);
bus.loadProgram(0xaf, 0x0a, 0x05); // 65C02 BBS2 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter());
/* BBS3 */
cpu.reset();
bus.write(0x0a,0x08);
bus.loadProgram(0xbf, 0x0a, 0x05); // 65C02 BBS3 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter());
/* BBS4 */
cpu.reset();
bus.write(0x0a,0x10);
bus.loadProgram(0xcf, 0x0a, 0x05); // 65C02 BBS4 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter());
/* BBS5 */
cpu.reset();
bus.write(0x0a,0x20);
bus.loadProgram(0xdf, 0x0a, 0x05); // 65C02 BBS5 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter());
/* BBS6 */
cpu.reset();
bus.write(0x0a,0x40);
bus.loadProgram(0xef, 0x0a, 0x05); // 65C02 BBS6 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter());
/* BBS7 */
cpu.reset();
bus.write(0x0a,0x80);
bus.loadProgram(0xff, 0x0a, 0x05); // 65C02 BBS7 $00 $05 ; *=$0202+$05 ($0208)
cpu.step();
assertEquals(0x203, cpu.getProgramCounter());
}
}

View File

@ -0,0 +1,69 @@
package com.loomcom.symon;
import com.loomcom.symon.devices.Memory;
import com.loomcom.symon.exceptions.MemoryAccessException;
import junit.framework.*;
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 Cpu65C02ZeroPageXModeTest extends TestCase {
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();
}
public void test_STZ() throws Exception {
makeCmosCpu();
bus.write(0x0002,0xff);
bus.loadProgram(0x74,0x01); // STZ Zero Page,X $01
// Test STZ Zero Page,X ($01+1)
assertEquals(0xff,bus.read(0x02, true));
cpu.setXRegister(0x01);
cpu.step();
assertEquals(0x00,bus.read(0x02, true));
}
public void test_STZRequiresCmosCpu() throws Exception {
makeNmosCpu();
bus.write(0x0002,0xff);
bus.loadProgram(0x74,0x01); // STZ Zero Page,X $01
// Test STZ Zero Page,X ($01+1)
assertEquals(0xff,bus.read(0x02, true));
cpu.setXRegister(0x01);
cpu.step();
assertEquals(0xff,bus.read(0x02, true));
}
}

View File

@ -64,7 +64,7 @@ public class CpuIndirectModeTest extends TestCase {
} }
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);
@ -76,7 +76,7 @@ public class CpuIndirectModeTest extends TestCase {
} }
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);
@ -88,7 +88,7 @@ public class CpuIndirectModeTest extends TestCase {
} }
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

@ -162,7 +162,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

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());
}
}