From 107aca7777e227c5faa1d3bf2716c0596a77c98b Mon Sep 17 00:00:00 2001 From: Seth Morabito Date: Mon, 29 Dec 2008 20:46:48 -0800 Subject: [PATCH] Implemented Zero Page,X, Zero Page,Y, and Indirect addressing mode instructions, along with unit tests. --- README | 6 +- src/main/java/com/loomcom/symon/Cpu.java | 126 +- .../loomcom/symon/CpuIndirectModeTest.java | 53 + src/test/java/com/loomcom/symon/CpuTest.java | 40 + .../loomcom/symon/CpuZeroPageXModeTest.java | 1102 +++++++++++++++++ .../loomcom/symon/CpuZeroPageYModeTest.java | 101 ++ 6 files changed, 1406 insertions(+), 22 deletions(-) create mode 100644 src/test/java/com/loomcom/symon/CpuIndirectModeTest.java create mode 100644 src/test/java/com/loomcom/symon/CpuZeroPageXModeTest.java create mode 100644 src/test/java/com/loomcom/symon/CpuZeroPageYModeTest.java diff --git a/README b/README index 8eb300b..b629a67 100644 --- a/README +++ b/README @@ -52,14 +52,14 @@ ACIAs. More functionality may be considered as time goes on. o Zero Page o Accumulator o Absolute - - INCOMPLETE ADDRESSING MODES: + o Indirect [used only by JMP] o Zero Page, X-indexed o Zero Page, Y-indexed + + INCOMPLETE ADDRESSING MODES: o Relative o Absolute, X-indexed o Absolute, Y-indexed - o Indirect o Indexed Indirect [ (Indirect ,X) ] o Indirect Indexed [ (Indirect),Y ] diff --git a/src/main/java/com/loomcom/symon/Cpu.java b/src/main/java/com/loomcom/symon/Cpu.java index 5f777aa..be17e5b 100644 --- a/src/main/java/com/loomcom/symon/Cpu.java +++ b/src/main/java/com/loomcom/symon/Cpu.java @@ -192,9 +192,15 @@ public class Cpu implements InstructionTable { break; case 0x11: // TODO: implement break; - case 0x15: // TODO: implement + case 0x15: // ORA - Logical Inclusive OR - Zero Page,X + a |= bus.read(zpxAddress(operands[0])); + setArithmeticFlags(a); break; - case 0x16: // TODO: implement + case 0x16: // ASL - Arithmetic Shift Left - Zero Page,X + j = bus.read(zpxAddress(operands[0])); + k = asl(j); + bus.write(zpxAddress(operands[0]), k); + setArithmeticFlags(k); break; case 0x18: // CLC - Clear Carry Flag - Implied clearCarryFlag(); @@ -265,9 +271,16 @@ public class Cpu implements InstructionTable { break; case 0x31: // TODO: implement break; - case 0x35: // TODO: implement + case 0x35: // AND - Logical And - Zero Page,X + j = bus.read(zpxAddress(operands[0])); + a &= j; + setArithmeticFlags(a); break; - case 0x36: // TODO: implement + case 0x36: // ROL - Rotate Shift Left - Zero Page,X + j = bus.read(zpxAddress(operands[0])); + k = rol(j); + bus.write(zpxAddress(operands[0]), k); + setArithmeticFlags(k); break; case 0x38: // SEC - Set Carry Flag - Implied setCarryFlag(); @@ -327,9 +340,15 @@ public class Cpu implements InstructionTable { break; case 0x51: // TODO: implement break; - case 0x55: // TODO: implement + case 0x55: // EOR - Exclusive OR - Zero Page,X + a ^= bus.read(zpxAddress(operands[0])); + setArithmeticFlags(a); break; - case 0x56: // TODO: implement + case 0x56: // LSR - Logical Shift Right - Zero Page,X + j = bus.read(zpxAddress(operands[0])); + k = lsr(j); + bus.write(zpxAddress(operands[0]), k); + setArithmeticFlags(k); break; case 0x58: // CLI - Clear Interrupt Disable - Implied clearIrqDisableFlag(); @@ -377,7 +396,25 @@ public class Cpu implements InstructionTable { a = ror(a); setArithmeticFlags(a); break; - case 0x6c: // TODO: implement + case 0x6c: // JMP - Jump - Indirect + lo = address(operands[0], operands[1]); // Address of low byte + hi = lo+1; // Address of high byte + + pc = address(bus.read(lo), bus.read(hi)); + + /* TODO: For accuracy, allow a flag to enable broken behavior + * of early 6502s: + * + * "An original 6502 has does not correctly fetch the target + * address if the indirect vector falls on a page boundary + * (e.g. $xxFF where xx is and value from $00 to $FF). In this + * case fetches the LSB from $xxFF as expected but takes the MSB + * from $xx00. This is fixed in some later chips like the 65SC02 + * so for compatibility always ensure the indirect vector is not + * at the end of the page." + * (http://www.obelisk.demon.co.uk/6502/reference.html#JMP) + */ + break; case 0x6d: // ADC - Add with Carry - Absolute j = bus.read(address(operands[0], operands[1])); @@ -398,9 +435,19 @@ public class Cpu implements InstructionTable { break; case 0x71: // TODO: implement break; - case 0x75: // TODO: implement + case 0x75: // ADC - Add with Carry - Zero Page,X + j = bus.read(zpxAddress(operands[0])); + if (decimalModeFlag) { + a = adcDecimal(a, j); + } else { + a = adc(a, j); + } break; - case 0x76: // TODO: implement + case 0x76: // ROR - Rotate Right - Zero Page,X + j = bus.read(zpxAddress(operands[0])); + k = ror(j); + bus.write(zpxAddress(operands[0]), k); + setArithmeticFlags(k); break; case 0x78: // SEI - Set Interrupt Disable - Implied setIrqDisableFlag(); @@ -451,11 +498,17 @@ public class Cpu implements InstructionTable { break; case 0x91: // TODO: implement break; - case 0x94: // TODO: implement + case 0x94: // STY - Store Y Register - Zero Page,X + bus.write(zpxAddress(operands[0]), y); + setArithmeticFlags(y); break; - case 0x95: // TODO: implement + case 0x95: // STA - Store Accumulator - Zero Page,X + bus.write(zpxAddress(operands[0]), a); + setArithmeticFlags(a); break; - case 0x96: // TODO: implement + case 0x96: // STX - Store X Register - Zero Page,Y + bus.write(zpyAddress(operands[0]), x); + setArithmeticFlags(x); break; case 0x98: // TYA - Transfer Y to Accumulator - Implied a = y; @@ -518,11 +571,17 @@ public class Cpu implements InstructionTable { break; case 0xb1: // TODO: implement break; - case 0xb4: // TODO: implement + case 0xb4: // LDY - Load Y Register - Zero Page,X + y = bus.read(zpxAddress(operands[0])); + setArithmeticFlags(y); break; - case 0xb5: // TODO: implement + case 0xb5: // LDA - Load Accumulator - Zero Page,X + a = bus.read(zpxAddress(operands[0])); + setArithmeticFlags(a); break; - case 0xb6: // TODO: implement + case 0xb6: // LDX - Load X Register - Zero Page,Y + x = bus.read(zpyAddress(operands[0])); + setArithmeticFlags(x); break; case 0xb8: // CLV - Clear Overflow Flag - Implied clearOverflowFlag(); @@ -587,9 +646,14 @@ public class Cpu implements InstructionTable { break; case 0xd1: // TODO: implement break; - case 0xd5: // TODO: implement + case 0xd5: // CMP - Compare Accumulator - Zero Page,X + cmp(a, bus.read(zpxAddress(operands[0]))); break; - case 0xd6: // TODO: implement + case 0xd6: // DEC - Decrement Memory - Zero Page, X + j = bus.read(zpxAddress(operands[0])); + k = --j & 0xff; + bus.write(zpxAddress(operands[0]), k); + setArithmeticFlags(k); break; case 0xd8: // CLD - Clear Decimal Mode - Implied clearDecimalModeFlag(); @@ -659,9 +723,19 @@ public class Cpu implements InstructionTable { break; case 0xf1: // TODO: implement break; - case 0xf5: // TODO: implement + case 0xf5: // SBC - Subtract with Carry - Zero Page,X + j = bus.read(zpxAddress(operands[0])); + if (decimalModeFlag) { + a = sbcDecimal(a, j); + } else { + a = sbc(a, j); + } break; - case 0xf6: // TODO: implement + case 0xf6: // INC - Increment Memory Location - Zero Page,X + j = bus.read(zpxAddress(operands[0])); + k = ++j & 0xff; + bus.write(zpxAddress(operands[0]), k); + setArithmeticFlags(k); break; case 0xf8: // SED - Set Decimal Flag - Implied setDecimalModeFlag(); @@ -1387,6 +1461,20 @@ public class Cpu implements InstructionTable { return ((hiByte<<8)|lowByte); } + /** + * Given a single byte, compute the Zero Page,X offset address. + */ + int zpxAddress(int zp) { + return (zp+getXRegister())&0xff; + } + + /** + * Given a single byte, compute the Zero Page,Y offset address. + */ + int zpyAddress(int zp) { + return (zp+getYRegister())&0xff; + } + /** * Given an opcode and its operands, return a formatted name. * diff --git a/src/test/java/com/loomcom/symon/CpuIndirectModeTest.java b/src/test/java/com/loomcom/symon/CpuIndirectModeTest.java new file mode 100644 index 0000000..33bceb0 --- /dev/null +++ b/src/test/java/com/loomcom/symon/CpuIndirectModeTest.java @@ -0,0 +1,53 @@ +package com.loomcom.symon; + +import com.loomcom.symon.devices.Memory; +import com.loomcom.symon.exceptions.MemoryRangeException; +import junit.framework.TestCase; + +public class CpuIndirectModeTest extends TestCase { + + protected Cpu cpu; + protected Bus bus; + protected Memory mem; + + protected void setUp() throws Exception { + this.cpu = new Cpu(); + this.bus = new Bus(0x0000, 0xffff); + this.mem = new Memory(0x0000, 0x10000); + bus.addCpu(cpu); + bus.addDevice(mem); + + // Load the reset vector. + bus.write(0xfffc, Cpu.DEFAULT_BASE_ADDRESS & 0x00ff); + bus.write(0xfffd, (Cpu.DEFAULT_BASE_ADDRESS & 0xff00)>>>8); + + cpu.reset(); + // Assert initial state + assertEquals(0, cpu.getAccumulator()); + assertEquals(0, cpu.getXRegister()); + assertEquals(0, cpu.getYRegister()); + assertEquals(0x200, cpu.getProgramCounter()); + assertEquals(0xff, cpu.getStackPointer()); + assertEquals(0x20, cpu.getProcessorStatus()); + } + + /* + * The following opcodes are tested for correctness in this file: + * + * JMP - $6c + * + */ + + /* JMP - Jump - $6c */ + + public void test_JMP() { + bus.write(0x3400, 0x00); + bus.write(0x3401, 0x54); + bus.loadProgram(0x6c, 0x00, 0x34); + cpu.step(); + assertEquals(0x5400, cpu.getProgramCounter()); + // No change to status flags. + assertEquals(0x20, cpu.getProcessorStatus()); + } + +} \ No newline at end of file diff --git a/src/test/java/com/loomcom/symon/CpuTest.java b/src/test/java/com/loomcom/symon/CpuTest.java index 7dbb33b..7fb9e53 100644 --- a/src/test/java/com/loomcom/symon/CpuTest.java +++ b/src/test/java/com/loomcom/symon/CpuTest.java @@ -355,4 +355,44 @@ public class CpuTest extends TestCase { assertEquals(0xffff, cpu.address(0xff, 0xff)); } + public void testZpxAddress() { + cpu.setXRegister(0x00); + assertEquals(0x10, cpu.zpxAddress(0x10)); + cpu.setXRegister(0x10); + assertEquals(0x20, cpu.zpxAddress(0x10)); + cpu.setXRegister(0x25); + assertEquals(0x35, cpu.zpxAddress(0x10)); + cpu.setXRegister(0xf5); + assertEquals(0x05, cpu.zpxAddress(0x10)); + + cpu.setXRegister(0x00); + assertEquals(0x80, cpu.zpxAddress(0x80)); + cpu.setXRegister(0x10); + assertEquals(0x90, cpu.zpxAddress(0x80)); + cpu.setXRegister(0x25); + assertEquals(0xa5, cpu.zpxAddress(0x80)); + cpu.setXRegister(0x95); + assertEquals(0x15, cpu.zpxAddress(0x80)); + } + + public void testZpyAddress() { + cpu.setYRegister(0x00); + assertEquals(0x10, cpu.zpyAddress(0x10)); + cpu.setYRegister(0x10); + assertEquals(0x20, cpu.zpyAddress(0x10)); + cpu.setYRegister(0x25); + assertEquals(0x35, cpu.zpyAddress(0x10)); + cpu.setYRegister(0xf5); + assertEquals(0x05, cpu.zpyAddress(0x10)); + + cpu.setYRegister(0x00); + assertEquals(0x80, cpu.zpyAddress(0x80)); + cpu.setYRegister(0x10); + assertEquals(0x90, cpu.zpyAddress(0x80)); + cpu.setYRegister(0x25); + assertEquals(0xa5, cpu.zpyAddress(0x80)); + cpu.setYRegister(0x95); + assertEquals(0x15, cpu.zpyAddress(0x80)); + } + } \ No newline at end of file diff --git a/src/test/java/com/loomcom/symon/CpuZeroPageXModeTest.java b/src/test/java/com/loomcom/symon/CpuZeroPageXModeTest.java new file mode 100644 index 0000000..93f2088 --- /dev/null +++ b/src/test/java/com/loomcom/symon/CpuZeroPageXModeTest.java @@ -0,0 +1,1102 @@ +package com.loomcom.symon; + +import com.loomcom.symon.devices.Memory; +import com.loomcom.symon.exceptions.MemoryRangeException; +import junit.framework.TestCase; + +public class CpuZeroPageXModeTest extends TestCase { + + protected Cpu cpu; + protected Bus bus; + protected Memory mem; + + protected void setUp() throws Exception { + this.cpu = new Cpu(); + this.bus = new Bus(0x0000, 0xffff); + this.mem = new Memory(0x0000, 0x10000); + bus.addCpu(cpu); + bus.addDevice(mem); + + // Load the reset vector. + bus.write(0xfffc, Cpu.DEFAULT_BASE_ADDRESS & 0x00ff); + bus.write(0xfffd, (Cpu.DEFAULT_BASE_ADDRESS & 0xff00)>>>8); + + cpu.reset(); + // Assert initial state + assertEquals(0, cpu.getAccumulator()); + assertEquals(0, cpu.getXRegister()); + assertEquals(0, cpu.getYRegister()); + assertEquals(0x200, cpu.getProgramCounter()); + assertEquals(0xff, cpu.getStackPointer()); + assertEquals(0x20, cpu.getProcessorStatus()); + } + + /* + * The following opcodes are tested for correctness in this file: + * + * ORA - $15 + * ASL - $16 + * AND - $35 + * ROL - $36 + * EOR - $55 + * + * LSR - $56 + * ADC - $75 + * ROR - $76 + * STY - $94 + * STA - $95 + * + * LDY - $b4 + * LDA - $b5 + * CMP - $d5 + * DEC - $d6 + * SBC - $f5 + * + * INC - $f6 + */ + + /* ORA - Logical Inclusive OR - $15 */ + + public void test_ORA() { + // Set some initial values in zero page. + bus.write(0x30, 0x00); + bus.write(0x32, 0x11); + bus.write(0x34, 0x22); + bus.write(0x38, 0x44); + bus.write(0x40, 0x88); + bus.write(0x02, 0x88); + + // Set offset in X register. + cpu.setXRegister(0x30); + + bus.loadProgram(0x15, 0x00, // ORA $00,X + 0x15, 0x02, // ORA $02,X + 0x15, 0x04, // ORA $04,X + 0x15, 0x08, // ORA $08,X + 0x15, 0x10, // ORA $10,X + 0xa9, 0x00, // LDA #$00 + 0x15, 0xd2); // ORA $d2,X - should wrap around + + cpu.step(); + assertEquals(0x00, cpu.getAccumulator()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x11, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x33, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x77, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0xff, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + + // Should wrap around and ORA with value in 0x02 + cpu.step(2); + assertEquals(0x88, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + } + + /* ASL - Arithmetic Shift Left - $16 */ + + public void test_ASL() { + bus.write(0x30, 0x00); + bus.write(0x31, 0x01); + bus.write(0x32, 0x02); + bus.write(0x33, 0x44); + bus.write(0x34, 0x80); + bus.write(0x02, 0x01); + + // Set offset in X register. + cpu.setXRegister(0x30); + + bus.loadProgram(0x16, 0x00, // ASL $00,X + 0x16, 0x01, // ASL $01,X + 0x16, 0x02, // ASL $02,X + 0x16, 0x03, // ASL $03,X + 0x16, 0x04, // ASL $04,X + 0x16, 0xd2); // ASL $d2,X + + cpu.step(); + assertEquals(0x00, bus.read(0x30)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x02, bus.read(0x31)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x04, bus.read(0x32)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x88, bus.read(0x33)); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x00, bus.read(0x34)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertTrue(cpu.getCarryFlag()); + + // Should wrap around, d2 + 30 = 02 + cpu.step(); + assertEquals(0x02, bus.read(0x02)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + } + + /* AND - Logical AND - $35 */ + + public void test_AND() { + bus.write(0x30, 0x00); + bus.write(0x31, 0x11); + bus.write(0x32, 0xff); + bus.write(0x33, 0x99); + bus.write(0x34, 0x11); + bus.write(0x35, 0x0f); + bus.write(0x02, 0x11); + + // Set offset in X register. + cpu.setXRegister(0x30); + + bus.loadProgram(0x35, 0x00, // AND $00 + 0x35, 0x01, // AND $01,X + 0xa9, 0xaa, // LDA #$aa + 0x35, 0x02, // AND $02,X + 0x35, 0x03, // AND $03 + 0x35, 0x04, // AND $04,X + 0xa9, 0xff, // LDA #$ff + 0x35, 0x05, // AND $05,X + 0xa9, 0x01, // LDA #$01 + 0x35, 0xd2); // AND $d2,X + cpu.step(); + assertEquals(0x00, cpu.getAccumulator()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x00, cpu.getAccumulator()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(2); + assertEquals(0xaa, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x88, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x00, cpu.getAccumulator()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(2); + assertEquals(0x0f, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(2); + assertEquals(0x01, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + } + + /* ROL - Rotate Shift Left - $36 */ + + public void test_ROL() { + + bus.write(0x70, 0x00); + bus.write(0x71, 0x01); + + // Set offset in X register + cpu.setXRegister(0x70); + + bus.loadProgram(0x36, 0x00, // ROL $00,X (m=%00000000, c=0) + 0x36, 0x01, // ROL $01,X (m=%00000010, c=0) + 0x38, // SEC (m=%00000010, c=1) + 0x36, 0x01, // ROL $01,X (m=%00000101, c=0) + 0x36, 0x01, // ROL $01,X (m=%00001010, c=0) + 0x36, 0x01, // ROL $01,X (m=%00010100, c=0) + 0x36, 0x01, // ROL $01,X (m=%00101000, c=0) + 0x36, 0x01, // ROL $01,X (m=%01010000, c=0) + 0x36, 0x01, // ROL $01,X (m=%10100000, c=0) + 0x36, 0x01, // ROL $01,X (m=%01000000, c=1) + 0x36, 0x01); // ROL $01,X (m=%10000001, c=0) + + cpu.step(); + assertEquals(0x00, bus.read(0x70)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x02, bus.read(0x71)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(2); + assertEquals(0x05, bus.read(0x71)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x0a, bus.read(0x71)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x14, bus.read(0x71)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x28, bus.read(0x71)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x50, bus.read(0x71)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0xa0, bus.read(0x71)); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x40, bus.read(0x71)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x81, bus.read(0x71)); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + } + + /* EOR - Exclusive OR - $55 */ + + public void test_EOR() { + bus.write(0x40, 0x00); + bus.write(0x41, 0xff); + bus.write(0x42, 0x33); + bus.write(0x43, 0x44); + + cpu.setXRegister(0x30); + + bus.loadProgram(0xa9, 0x88, // LDA #$88 + 0x55, 0x10, // EOR $10,X + 0x55, 0x11, // EOR $11,X + 0x55, 0x12, // EOR $12,X + 0x55, 0x13); // EOR $13,X + cpu.step(2); + assertEquals(0x88, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getZeroFlag()); + + cpu.step(); + assertEquals(0x77, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getZeroFlag()); + + cpu.step(); + assertEquals(0x44, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getZeroFlag()); + + cpu.step(); + assertEquals(0x00, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertTrue(cpu.getZeroFlag()); + } + + /* LSR - Logical Shift Right - $56 */ + + public void test_LSR() { + bus.write(0x30, 0x00); + bus.write(0x31, 0x01); + bus.write(0x32, 0x02); + bus.write(0x33, 0x44); + bus.write(0x34, 0x80); + bus.write(0x35, 0x02); + + cpu.setXRegister(0x30); + + bus.loadProgram(0x56, 0x00, // LSR $00,X + 0x56, 0x01, // LSR $01,X + 0x56, 0x02, // LSR $02,X + 0x56, 0x03, // LSR $03,X + 0x56, 0x04, // LSR $04,X + 0x38, // SEC + 0x56, 0x05); // LSR $05,X + + cpu.step(); + assertEquals(0x00, bus.read(0x30)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x00, bus.read(0x31)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x01, bus.read(0x32)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x22, bus.read(0x33)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x40, bus.read(0x34)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + // Setting Carry should not affect the result. + cpu.step(2); + assertEquals(0x01, bus.read(0x35)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + } + + /* ADC - Add with Carry - $75 */ + + public void test_ADC() { + bus.write(0x40, 0x01); + bus.write(0x41, 0xff); + + cpu.setXRegister(0x30); + + bus.loadProgram(0xa9, 0x00, // LDA #$00 + 0x75, 0x10); // ADC $10,X + cpu.step(2); + assertEquals(0x01, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + bus.loadProgram(0xa9, 0x7f, // LDA #$7f + 0x75, 0x10); // ADC $10,X + cpu.step(2); + assertEquals(0x80, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertTrue(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + bus.loadProgram(0xa9, 0x80, // LDA #$80 + 0x75, 0x10); // ADC $10,X + cpu.step(2); + assertEquals(0x81, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + bus.loadProgram(0xa9, 0xff, // LDA #$ff + 0x75, 0x10); // ADC $10,X + cpu.step(2); + assertEquals(0x00, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertTrue(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + bus.loadProgram(0xa9, 0x00, // LDA #$00 + 0x75, 0x11); // ADC $11,X + cpu.step(2); + assertEquals(0xff, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + bus.loadProgram(0xa9, 0x7f, // LDA #$7f + 0x75, 0x11); // ADC $11,X + cpu.step(2); + assertEquals(0x7e, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + bus.loadProgram(0xa9, 0x80, // LDA #$80 + 0x75, 0x11); // ADC $11,X + cpu.step(2); + assertEquals(0x7f, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertTrue(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + bus.loadProgram(0xa9, 0xff, // LDA #$ff + 0x75, 0x11); // ADC $11,X + cpu.step(2); + assertEquals(0xfe, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + } + + public void test_ADC_IncludesCarry() { + bus.write(0x40, 0x01); + + bus.loadProgram(0xa9, 0x00, // LDA #$00 + 0x38, // SEC + 0x75, 0x10); // ADC $10,X + + cpu.setXRegister(0x30); + + cpu.step(3); + assertEquals(0x02, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + } + + public void test_ADC_DecimalMode() { + bus.write(0x40, 0x01); + bus.write(0x41, 0x99); + + bus.loadProgram(0xf8, // SED + 0xa9, 0x01, // LDA #$01 + 0x75, 0x10); // ADC $10,X + + cpu.setXRegister(0x30); + + cpu.step(3); + assertEquals(0x02, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + bus.loadProgram(0xf8, // SED + 0xa9, 0x49, // LDA #$49 + 0x75, 0x10); // ADC $10,X + cpu.step(3); + assertEquals(0x50, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + bus.loadProgram(0xf8, // SED + 0xa9, 0x50, // LDA #$50 + 0x75, 0x10); // ADC $10,X + cpu.step(3); + assertEquals(0x51, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + bus.loadProgram(0xf8, // SED + 0xa9, 0x99, // LDA #$99 + 0x75, 0x10); // ADC $10,X + cpu.step(3); + assertEquals(0x00, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertTrue(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + bus.loadProgram(0xf8, // SED + 0xa9, 0x00, // LDA #$00 + 0x75, 0x11); // ADC $10,X + cpu.step(3); + assertEquals(0x99, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + bus.loadProgram(0xf8, // SED + 0xa9, 0x49, // LDA #$49 + 0x75, 0x11); // ADC $11,X + cpu.step(3); + assertEquals(0x48, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + bus.loadProgram(0xf8, // SED + 0xa9, 0x50, // LDA #$59 + 0x75, 0x11); // ADC $11,X + cpu.step(3); + assertEquals(0x49, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + } + + /* ROR - Rotate Right - $76 */ + + public void test_ROR() { + + bus.write(0x40, 0x00); + bus.write(0x41, 0x10); + + bus.loadProgram(0x76, 0x10, // ROR $00 (m=%00000000, c=0) + 0x76, 0x11, // ROR $01 (m=%00001000, c=0) + 0x76, 0x11, // ROR $01 (m=%00000100, c=0) + 0x76, 0x11, // ROR $01 (m=%00000010, c=0) + 0x76, 0x11, // ROR $01 (m=%00000001, c=0) + 0x76, 0x11, // ROR $01 (m=%00000000, c=1) + 0x76, 0x11, // ROR $01 (m=%10000000, c=0) + 0x76, 0x11, // ROR $01 (m=%01000000, c=0) + 0x76, 0x11, // ROR $01 (m=%00100000, c=0) + 0x76, 0x11); // ROR $01 (m=%00010000, c=0) + + cpu.setXRegister(0x30); + + cpu.step(); + assertEquals(0x00, bus.read(0x40)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x08, bus.read(0x41)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x04, bus.read(0x41)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x02, bus.read(0x41)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x01, bus.read(0x41)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x00, bus.read(0x41)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x80, bus.read(0x41)); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x40, bus.read(0x41)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x20, bus.read(0x41)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x10, bus.read(0x41)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + } + + /* STY - Store Y Register - $94 */ + + public void test_STY() { + cpu.setXRegister(0x30); + + cpu.setYRegister(0x00); + bus.loadProgram(0x94, 0x10); // STY $10,X + cpu.step(); + assertEquals(0x00, bus.read(0x40)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.reset(); + + cpu.setYRegister(0x0f); + bus.loadProgram(0x94, 0x10); // STY $10,X + cpu.step(); + assertEquals(0x0f, bus.read(0x40)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.reset(); + + cpu.setYRegister(0x80); + bus.loadProgram(0x94, 0x10); // STY $10,X + cpu.step(); + assertEquals(0x80, bus.read(0x40)); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + } + + /* STA - Store Accumulator - $95 */ + + public void test_STA() { + cpu.setXRegister(0x30); + + cpu.setAccumulator(0x00); + bus.loadProgram(0x95, 0x10); // STA $10,X + cpu.step(); + assertEquals(0x00, bus.read(0x40)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.reset(); + + cpu.setAccumulator(0x0f); + bus.loadProgram(0x95, 0x10); // STA $10,X + cpu.step(); + assertEquals(0x0f, bus.read(0x40)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.reset(); + + cpu.setAccumulator(0x80); + bus.loadProgram(0x95, 0x10); // STA $10,X + cpu.step(); + assertEquals(0x80, bus.read(0x40)); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + } + + /* LDY - Load Y Register - $b4 */ + + public void test_LDY() { + bus.write(0x45, 0x00); + bus.write(0x46, 0x0f); + bus.write(0x47, 0x80); + + bus.loadProgram(0xb4, 0x10, // LDY $10,X + 0xb4, 0x11, // LDY $11,X + 0xb4, 0x12); // LDY $12,X + + cpu.setXRegister(0x35); + + cpu.step(); + assertEquals(0x00, cpu.getYRegister()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x0f, cpu.getYRegister()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x80, cpu.getYRegister()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + } + + /* LDA - Load Accumulator - $b5 */ + + public void test_LDA() { + bus.write(0x42, 0x00); + bus.write(0x43, 0x0f); + bus.write(0x44, 0x80); + + bus.loadProgram(0xb5, 0x10, // LDA $10,X + 0xb5, 0x11, // LDA $11,X + 0xb5, 0x12); // LDA $12,X + + cpu.setXRegister(0x32); + + cpu.step(); + assertEquals(0x00, cpu.getAccumulator()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x0f, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x80, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + } + + /* CMP - Compare Accumulator - $d5 */ + + public void test_CMP() { + bus.write(0x40, 0x00); + bus.write(0x41, 0x80); + bus.write(0x42, 0xff); + + cpu.setAccumulator(0x80); + + bus.loadProgram(0xd5, 0x10, + 0xd5, 0x11, + 0xd5, 0x12); + + cpu.setXRegister(0x30); + + cpu.step(); + assertTrue(cpu.getCarryFlag()); // m > y + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); // m - y < 0 + + cpu.step(); + assertTrue(cpu.getCarryFlag()); // m = y + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); // m - y == 0 + + cpu.step(); + assertFalse(cpu.getCarryFlag()); // m < y + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); // m - y > 0 + } + + /* DEC - Decrement Memory Location - $d6 */ + + public void test_DEC() { + bus.write(0x40, 0x00); + bus.write(0x41, 0x01); + bus.write(0x42, 0x80); + bus.write(0x43, 0xff); + + bus.loadProgram(0xd6, 0x10, // DEC $10,X + 0xd6, 0x11, // DEC $11,X + 0xd6, 0x12, // DEC $12,X + 0xd6, 0x13); // DEC $13,X + + cpu.setXRegister(0x30); + + cpu.step(); + assertEquals(0xff, bus.read(0x40)); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x00, bus.read(0x41)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x7f, bus.read(0x42)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0xfe, bus.read(0x43)); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + } + + /* SBC - Subtract with Carry - $f5 */ + + public void test_SBC() { + bus.write(0x40, 0x01); + + bus.loadProgram(0xa9, 0x00, // LDA #$00 + 0xf5, 0x10); // SBC $10,X + cpu.setXRegister(0x30); + cpu.step(2); + assertEquals(0xfe, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.reset(); + bus.loadProgram(0xa9, 0x7f, // LDA #$7f + 0xf5, 0x10); // SBC $10,X + cpu.setXRegister(0x30); + cpu.step(2); + assertEquals(0x7d, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + bus.loadProgram(0xa9, 0x80, // LDA #$80 + 0xf5, 0x10); // SBC $10,X + cpu.setXRegister(0x30); + cpu.step(2); + assertEquals(0x7e, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertTrue(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + bus.loadProgram(0xa9, 0xff, // LDA #$ff + 0xf5, 0x10); // SBC $10,X + cpu.setXRegister(0x30); + cpu.step(2); + assertEquals(0xfd, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + bus.loadProgram(0xa9, 0x02, // LDA #$02 + 0xf5, 0x10); // SBC $10,X + cpu.setXRegister(0x30); + cpu.step(2); + assertEquals(0x00, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertTrue(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + } + + public void test_SBC_IncludesNotOfCarry() { + bus.write(0x40, 0x01); + + // Subtrace with Carry Flag cleared + bus.loadProgram(0x18, // CLC + 0xa9, 0x05, // LDA #$00 + 0xf5, 0x10); // SBC $10,X + cpu.setXRegister(0x30); + cpu.step(3); + assertEquals(0x03, cpu.getAccumulator()); + + cpu.reset(); + + // Subtrace with Carry Flag cleared + bus.loadProgram(0x18, // CLC + 0xa9, 0x00, // LDA #$00 + 0xf5, 0x10); // SBC $10,X + cpu.setXRegister(0x30); + cpu.step(3); + assertEquals(0xfe, cpu.getAccumulator()); + + cpu.reset(); + + // Subtract with Carry Flag set + bus.loadProgram(0x38, // SEC + 0xa9, 0x05, // LDA #$00 + 0xf5, 0x10); // SBC $10,X + cpu.setXRegister(0x30); + cpu.step(3); + assertEquals(0x04, cpu.getAccumulator()); + assertTrue(cpu.getCarryFlag()); + + cpu.reset(); + + // Subtract with Carry Flag set + bus.loadProgram(0x38, // SEC + 0xa9, 0x00, // LDA #$00 + 0xf5, 0x10); // SBC $10,X + cpu.setXRegister(0x30); + cpu.step(3); + assertEquals(0xff, cpu.getAccumulator()); + assertFalse(cpu.getCarryFlag()); + + } + + public void test_SBC_DecimalMode() { + bus.write(0x40, 0x01); + bus.write(0x50, 0x11); + + bus.loadProgram(0xf8, + 0xa9, 0x00, + 0xf5, 0x10); + cpu.setXRegister(0x30); + cpu.step(3); + assertEquals(0x98, cpu.getAccumulator()); + assertFalse(cpu.getCarryFlag()); // borrow = set flag + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getDecimalModeFlag()); + + cpu.reset(); + + bus.loadProgram(0xf8, + 0xa9, 0x99, + 0xf5, 0x10); + cpu.setXRegister(0x30); + cpu.step(3); + assertEquals(0x97, cpu.getAccumulator()); + assertTrue(cpu.getCarryFlag()); // No borrow = clear flag + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getDecimalModeFlag()); + + cpu.reset(); + + bus.loadProgram(0xf8, + 0xa9, 0x50, + 0xf5, 0x10); + cpu.setXRegister(0x30); + cpu.step(3); + assertEquals(0x48, cpu.getAccumulator()); + assertTrue(cpu.getCarryFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getDecimalModeFlag()); + + + cpu.reset(); + + bus.loadProgram(0xf8, // SED + 0xa9, 0x02, // LDA #$02 + 0xf5, 0x10); // SBC $10 + cpu.setXRegister(0x30); + cpu.step(3); + assertEquals(0x00, cpu.getAccumulator()); + assertTrue(cpu.getCarryFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertTrue(cpu.getZeroFlag()); + assertTrue(cpu.getDecimalModeFlag()); + + cpu.reset(); + + bus.loadProgram(0xf8, // SED + 0xa9, 0x10, // LDA #$10 + 0xf5, 0x20); // SBC $20 + cpu.setXRegister(0x30); + cpu.step(3); + assertEquals(0x98, cpu.getAccumulator()); + assertFalse(cpu.getCarryFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getDecimalModeFlag()); + + cpu.reset(); + + bus.loadProgram(0x38, // SEC + 0xf8, // SED + 0xa9, 0x05, // LDA #$05 + 0xf5, 0x10); // SBC $10 + cpu.setXRegister(0x30); + cpu.step(4); + assertEquals(0x04, cpu.getAccumulator()); + assertTrue(cpu.getCarryFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getDecimalModeFlag()); + + cpu.reset(); + + bus.loadProgram(0x38, // SEC + 0xf8, // SED + 0xa9, 0x00, // LDA #$00 + 0xf5, 0x10); // SBC $10 + cpu.setXRegister(0x30); + cpu.step(4); + assertEquals(0x99, cpu.getAccumulator()); + assertFalse(cpu.getCarryFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getDecimalModeFlag()); + } + + /* INC - Increment Memory Location - $f6 */ + + public void test_INC() { + bus.write(0x30, 0x00); + bus.write(0x31, 0x7f); + bus.write(0x32, 0xff); + + cpu.setXRegister(0x20); + + bus.loadProgram(0xf6, 0x10, // INC $10,X + 0xf6, 0x11, // INC $11,X + 0xf6, 0x12); // INC $12,X + + cpu.step(); + assertEquals(0x01, bus.read(0x30)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x80, bus.read(0x31)); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x00, bus.read(0x32)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + } + +} diff --git a/src/test/java/com/loomcom/symon/CpuZeroPageYModeTest.java b/src/test/java/com/loomcom/symon/CpuZeroPageYModeTest.java new file mode 100644 index 0000000..535a548 --- /dev/null +++ b/src/test/java/com/loomcom/symon/CpuZeroPageYModeTest.java @@ -0,0 +1,101 @@ +package com.loomcom.symon; + +import com.loomcom.symon.devices.Memory; +import com.loomcom.symon.exceptions.MemoryRangeException; +import junit.framework.TestCase; + +public class CpuZeroPageYModeTest extends TestCase { + + protected Cpu cpu; + protected Bus bus; + protected Memory mem; + + protected void setUp() throws Exception { + this.cpu = new Cpu(); + this.bus = new Bus(0x0000, 0xffff); + this.mem = new Memory(0x0000, 0x10000); + bus.addCpu(cpu); + bus.addDevice(mem); + + // Load the reset vector. + bus.write(0xfffc, Cpu.DEFAULT_BASE_ADDRESS & 0x00ff); + bus.write(0xfffd, (Cpu.DEFAULT_BASE_ADDRESS & 0xff00)>>>8); + + cpu.reset(); + // Assert initial state + assertEquals(0, cpu.getAccumulator()); + assertEquals(0, cpu.getXRegister()); + assertEquals(0, cpu.getYRegister()); + assertEquals(0x200, cpu.getProgramCounter()); + assertEquals(0xff, cpu.getStackPointer()); + assertEquals(0x20, cpu.getProcessorStatus()); + } + + /* + * The following opcodes are tested for correctness in this file: + * + * STX - $96 + * LDX - $b6 + * + */ + + /* STX - Store X Register - $96 */ + + public void test_STX() { + cpu.setYRegister(0x30); + cpu.setXRegister(0x00); + bus.loadProgram(0x96, 0x10); // STX $10,Y + cpu.step(); + assertEquals(0x00, bus.read(0x40)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.reset(); + cpu.setYRegister(0x30); + cpu.setXRegister(0x0f); + bus.loadProgram(0x96, 0x10); // STX $10,Y + cpu.step(); + assertEquals(0x0f, bus.read(0x40)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.reset(); + cpu.setYRegister(0x30); + cpu.setXRegister(0x80); + bus.loadProgram(0x96, 0x10); // STX $10,Y + cpu.step(); + assertEquals(0x80, bus.read(0x40)); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + } + + /* LDX - Load X Register - $b6 */ + + public void test_LDX() { + bus.write(0x40, 0x00); + bus.write(0x41, 0x0f); + bus.write(0x42, 0x80); + + bus.loadProgram(0xb6, 0x10, + 0xb6, 0x11, + 0xb6, 0x12); + + cpu.setYRegister(0x30); + + cpu.step(); + assertEquals(0x00, cpu.getXRegister()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x0f, cpu.getXRegister()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x80, cpu.getXRegister()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + } + +}