diff --git a/src/main/java/com/loomcom/symon/Cpu.java b/src/main/java/com/loomcom/symon/Cpu.java index a6489e1..6f5828a 100644 --- a/src/main/java/com/loomcom/symon/Cpu.java +++ b/src/main/java/com/loomcom/symon/Cpu.java @@ -158,8 +158,10 @@ public class Cpu implements InstructionTable { setArithmeticFlags(a); break; case 0x06: // ASL - Arithmetic Shift Left - Zero Page - bus.write(operands[0], asl(bus.read(operands[0]))); - setArithmeticFlags(bus.read(operands[0])); + j = bus.read(operands[0]); + k = asl(j); + bus.write(operands[0], k); + setArithmeticFlags(k); break; case 0x07: // n/a break; @@ -232,9 +234,16 @@ public class Cpu implements InstructionTable { setNegativeFlag((k & 0x80) != 0); setOverflowFlag((k & 0x40) != 0); break; - case 0x25: // n/a + case 0x25: // AND - Logical And - Zero Page + j = bus.read(operands[0]); + a &= j; + setArithmeticFlags(a); break; - case 0x26: // n/a + case 0x26: // ROL - Rotate Left - Zero Page + j = bus.read(operands[0]); + k = rol(j); + bus.write(operands[0], k); + setArithmeticFlags(k); break; case 0x27: // n/a break; @@ -306,9 +315,16 @@ public class Cpu implements InstructionTable { break; case 0x44: // n/a break; - case 0x45: // n/a + case 0x45: // EOR - Exclusive OR - Zero Page + j = bus.read(operands[0]); + a ^= j; + setArithmeticFlags(a); break; - case 0x46: // n/a + case 0x46: // LSR - Logical Shift Right - Zero Page + j = bus.read(operands[0]); + k = lsr(j); + bus.write(operands[0], k); + setArithmeticFlags(k); break; case 0x47: // n/a break; @@ -380,9 +396,19 @@ public class Cpu implements InstructionTable { break; case 0x64: // n/a break; - case 0x65: // n/a + case 0x65: // ADC - Add with Carry - Zero Page + j = bus.read(operands[0]); + if (decimalModeFlag) { + a = adcDecimal(a, j); + } else { + a = adc(a, j); + } break; - case 0x66: // n/a + case 0x66: // ROR - Rotate Right - Zero Page + j = bus.read(operands[0]); + k = ror(j); + bus.write(operands[0], k); + setArithmeticFlags(k); break; case 0x67: // n/a break; @@ -452,11 +478,17 @@ public class Cpu implements InstructionTable { break; case 0x83: // n/a break; - case 0x84: // n/a + case 0x84: // STY - Store Y Register - Zero Page + bus.write(operands[0], y); + setArithmeticFlags(y); break; - case 0x85: // n/a + case 0x85: // STA - Store Accumulator - Zero Page + bus.write(operands[0], a); + setArithmeticFlags(a); break; - case 0x86: // n/a + case 0x86: // STX - Store X Register - Zero Page + bus.write(operands[0], x); + setArithmeticFlags(x); break; case 0x87: // n/a break; @@ -529,11 +561,17 @@ public class Cpu implements InstructionTable { break; case 0xa3: // n/a break; - case 0xa4: // n/a + case 0xa4: // LDY - Load Y Register - Zero Page + y = bus.read(operands[0]); + setArithmeticFlags(y); break; - case 0xa5: // n/a + case 0xa5: // LDA - Load Accumulator - Zero Page + a = bus.read(operands[0]); + setArithmeticFlags(a); break; - case 0xa6: // n/a + case 0xa6: // LDA - Load X Register - Zero Page + x = bus.read(operands[0]); + setArithmeticFlags(x); break; case 0xa7: // n/a break; @@ -596,7 +634,7 @@ public class Cpu implements InstructionTable { case 0xbf: // n/a break; - case 0xc0: // CPY - Immediate + case 0xc0: // CPY - Compare Y Register - Immediate cmp(y, operands[0]); break; case 0xc1: // n/a @@ -605,11 +643,17 @@ public class Cpu implements InstructionTable { break; case 0xc3: // n/a break; - case 0xc4: // n/a + case 0xc4: // CPY - Compare Y Register - Zero Page + cmp(y, bus.read(operands[0])); break; - case 0xc5: // n/a + case 0xc5: // CMP - Compare Accumulator - Zero Page + cmp(a, bus.read(operands[0])); break; - case 0xc6: // n/a + case 0xc6: // DEC - Decrement Memory - Zero Page + j = bus.read(operands[0]); + k = --j & 0xff; + bus.write(operands[0], k); + setArithmeticFlags(k); break; case 0xc7: // n/a break; @@ -678,11 +722,22 @@ public class Cpu implements InstructionTable { break; case 0xe3: // n/a break; - case 0xe4: // n/a + case 0xe4: // CPX - Compare X Register - Zero Page + cmp(x, bus.read(operands[0])); break; - case 0xe5: // n/a + case 0xe5: // SBC - Subtract with Carry (Borrow) - Zero Page + j = bus.read(operands[0]); + if (decimalModeFlag) { + a = sbcDecimal(a, j); + } else { + a = sbc(a, j); + } break; - case 0xe6: // n/a + case 0xe6: // INC - Increment Memory - Zero Page + j = bus.read(operands[0]); + k = ++j & 0xff; + bus.write(operands[0], k); + setArithmeticFlags(k); break; case 0xe7: // n/a break; @@ -866,6 +921,28 @@ public class Cpu implements InstructionTable { setCarryFlag((m & 0x01) != 0); return (m >>> 1) & 0xff; } + + /** + * Rotates the given value left by one bit, setting bit 0 to the value + * of the carry flag, and setting the carry flag to the original value + * of bit 7. + */ + private int rol(int m) { + int result = ((m << 1) | getCarryBit()) & 0xff; + setCarryFlag((m & 0x80) != 0); + return result; + } + + /** + * Rotates the given value right by one bit, setting bit 7 to the value + * of the carry flag, and setting the carry flag to the original value + * of bit 1. + */ + private int ror(int m) { + int result = ((m >>> 1) | (getCarryBit() << 7)) & 0xff; + setCarryFlag((m & 0x01) != 0); + return result; + } /** * @return the negative flag diff --git a/src/test/java/com/loomcom/symon/CpuImmediateModeTest.java b/src/test/java/com/loomcom/symon/CpuImmediateModeTest.java index 2f9f1ce..19a5455 100644 --- a/src/test/java/com/loomcom/symon/CpuImmediateModeTest.java +++ b/src/test/java/com/loomcom/symon/CpuImmediateModeTest.java @@ -99,7 +99,7 @@ public class CpuImmediateModeTest extends TestCase { /* AND Immediate Mode Tests - 0x29 */ - public void test_AND_SetsAccumulator() { + public void test_AND() { bus.loadProgram(0x29, 0x00, // AND #$00 0x29, 0x11, // AND #$11 0xa9, 0xaa, // LDA #$AA @@ -152,7 +152,7 @@ public class CpuImmediateModeTest extends TestCase { /* EOR Immediate Mode Tests - 0x49 */ - public void test_EOR_SetsAccumulator() { + public void test_EOR() { bus.loadProgram(0xa9, 0x88, // LDA #$88 0x49, 0x00, // EOR #$00 0x49, 0xff, // EOR #$ff @@ -505,7 +505,7 @@ public class CpuImmediateModeTest extends TestCase { assertTrue(cpu.getNegativeFlag()); } - public void test_CPY_DoesNotSetCarryFlagIfYGreaterThanMemory() { + public void test_CPY_DoesNotSetCarryFlagIfYLessThanThanMemory() { bus.loadProgram(0xa0, 0x08, // LDY #$08 0xc0, 0x0a); // CPY #$0A cpu.step(2); diff --git a/src/test/java/com/loomcom/symon/CpuZeroPageModeTest.java b/src/test/java/com/loomcom/symon/CpuZeroPageModeTest.java index 43b2ed1..68d3976 100644 --- a/src/test/java/com/loomcom/symon/CpuZeroPageModeTest.java +++ b/src/test/java/com/loomcom/symon/CpuZeroPageModeTest.java @@ -102,6 +102,7 @@ public class CpuZeroPageModeTest extends TestCase { } /* ASL - Arithmetic Shift Left - $06 */ + public void test_ASL() { bus.write(0x0000, 0x00); bus.write(0x0001, 0x01); @@ -147,6 +148,7 @@ public class CpuZeroPageModeTest extends TestCase { } /* BIT - Bit Test - $24 */ + public void test_BIT() { bus.write(0x0000, 0xc0); @@ -200,75 +202,993 @@ public class CpuZeroPageModeTest extends TestCase { } /* AND - Logical AND - $25 */ + public void test_AND() { + bus.write(0x0000, 0x00); + bus.write(0x0001, 0x11); + bus.write(0x0002, 0xff); + bus.write(0x0003, 0x99); + bus.write(0x0004, 0x11); + bus.write(0x0005, 0x0f); + + bus.loadProgram(0x25, 0x00, // AND $00 + 0x25, 0x01, // AND $01 + 0xa9, 0xaa, // LDA #$aa + 0x25, 0x02, // AND $02 + 0x25, 0x03, // AND $03 + 0x25, 0x04, // AND $04 + 0xa9, 0xff, // LDA #$ff + 0x25, 0x05); // AND $05 + 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()); } - /* ROL - Rotate Left - $26 */ + /* ROL - Rotate Shift Left - $26 */ + public void test_ROL() { + + bus.write(0x0000, 0x00); + bus.write(0x0001, 0x01); + + bus.loadProgram(0x26, 0x00, // ROL $00 (m=%00000000, c=0) + 0x26, 0x01, // ROL $01 (m=%00000010, c=0) + 0x38, // SEC (m=%00000010, c=1) + 0x26, 0x01, // ROL $01 (m=%00000101, c=0) + 0x26, 0x01, // ROL $01 (m=%00001010, c=0) + 0x26, 0x01, // ROL $01 (m=%00010100, c=0) + 0x26, 0x01, // ROL $01 (m=%00101000, c=0) + 0x26, 0x01, // ROL $01 (m=%01010000, c=0) + 0x26, 0x01, // ROL $01 (m=%10100000, c=0) + 0x26, 0x01, // ROL $01 (m=%01000000, c=1) + 0x26, 0x01); // ROL $01 (m=%10000001, c=0) + + cpu.step(); + assertEquals(0x00, bus.read(0x0000)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x02, bus.read(0x0001)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(2); + assertEquals(0x05, bus.read(0x0001)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x0a, bus.read(0x0001)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x14, bus.read(0x0001)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x28, bus.read(0x0001)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x50, bus.read(0x0001)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0xa0, bus.read(0x0001)); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x40, bus.read(0x0001)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x81, bus.read(0x0001)); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); } /* EOR - Exclusive OR - $45 */ + public void test_EOR() { + bus.write(0x10, 0x00); + bus.write(0x11, 0xff); + bus.write(0x12, 0x33); + bus.write(0x13, 0x44); + + bus.loadProgram(0xa9, 0x88, // LDA #$88 + 0x45, 0x10, // EOR $10 + 0x45, 0x11, // EOR $11 + 0x45, 0x12, // EOR $12 + 0x45, 0x13); // EOR $13 + 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 - $46 */ + public void test_LSR() { + bus.write(0x0000, 0x00); + bus.write(0x0001, 0x01); + bus.write(0x0002, 0x02); + bus.write(0x0003, 0x44); + bus.write(0x0004, 0x80); + bus.write(0x0005, 0x02); + + bus.loadProgram(0x46, 0x00, // LSR $00 + 0x46, 0x01, // LSR $01 + 0x46, 0x02, // LSR $02 + 0x46, 0x03, // LSR $03 + 0x46, 0x04, // LSR $04 + 0x38, // SEC + 0x46, 0x05); // LSR $05 + + cpu.step(); + assertEquals(0x00, bus.read(0x0000)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x00, bus.read(0x0001)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x01, bus.read(0x0002)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x22, bus.read(0x0003)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x40, bus.read(0x0004)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + // Setting Carry should not affect the result. + cpu.step(2); + assertEquals(0x01, bus.read(0x0005)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); } /* ADC - Add with Carry - $65 */ + public void test_ADC() { - } + bus.write(0x10, 0x01); + bus.write(0x11, 0xff); + + bus.loadProgram(0xa9, 0x00, // LDA #$00 + 0x65, 0x10); // ADC $10 + 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 + 0x65, 0x10); // ADC $10 + 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 + 0x65, 0x10); // ADC $10 + 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 + 0x65, 0x10); // ADC $10 + 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 + 0x65, 0x11); // ADC $11 + 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 + 0x65, 0x11); // ADC $11 + 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 + 0x65, 0x11); // ADC $11 + 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 + 0x65, 0x11); // ADC $11 + 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(0x10, 0x01); + + bus.loadProgram(0xa9, 0x00, // LDA #$00 + 0x38, // SEC + 0x65, 0x10); // ADC $10 + 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(0x10, 0x01); + bus.write(0x11, 0x99); + + bus.loadProgram(0xf8, // SED + 0xa9, 0x01, // LDA #$01 + 0x65, 0x10); // ADC $10 + 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 + 0x65, 0x10); // ADC $10 + 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 + 0x65, 0x10); // ADC $10 + 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 + 0x65, 0x10); // ADC $10 + 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 + 0x65, 0x11); // ADC $10 + 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 + 0x65, 0x11); // ADC $11 + 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 + 0x65, 0x11); // ADC $11 + cpu.step(3); + assertEquals(0x49, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); + } /* ROR - Rotate Right - $66 */ + public void test_ROR() { + + bus.write(0x10, 0x00); + bus.write(0x11, 0x10); + + bus.loadProgram(0x66, 0x10, // ROR $00 (m=%00000000, c=0) + 0x66, 0x11, // ROR $01 (m=%00001000, c=0) + 0x66, 0x11, // ROR $01 (m=%00000100, c=0) + 0x66, 0x11, // ROR $01 (m=%00000010, c=0) + 0x66, 0x11, // ROR $01 (m=%00000001, c=0) + 0x66, 0x11, // ROR $01 (m=%00000000, c=1) + 0x66, 0x11, // ROR $01 (m=%10000000, c=0) + 0x66, 0x11, // ROR $01 (m=%01000000, c=0) + 0x66, 0x11, // ROR $01 (m=%00100000, c=0) + 0x66, 0x11); // ROR $01 (m=%00010000, c=0) + + cpu.step(); + assertEquals(0x00, bus.read(0x10)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x08, bus.read(0x11)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x04, bus.read(0x11)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x02, bus.read(0x11)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x01, bus.read(0x11)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x00, bus.read(0x11)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertTrue(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x80, bus.read(0x11)); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x40, bus.read(0x11)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x20, bus.read(0x11)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); + + cpu.step(); + assertEquals(0x10, bus.read(0x11)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getCarryFlag()); } /* STY - Store Y Register - $84 */ + public void test_STY() { - } + cpu.setYRegister(0x00); + bus.loadProgram(0x84, 0x10); + cpu.step(); + assertEquals(0x00, bus.read(0x10)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + cpu.reset(); + + cpu.setYRegister(0x0f); + bus.loadProgram(0x84, 0x10); + cpu.step(); + assertEquals(0x0f, bus.read(0x10)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.reset(); + + cpu.setYRegister(0x80); + bus.loadProgram(0x84, 0x10); + cpu.step(); + assertEquals(0x80, bus.read(0x10)); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + } + /* STA - Store Accumulator - $85 */ + public void test_STA() { - } + cpu.setAccumulator(0x00); + bus.loadProgram(0x85, 0x10); + cpu.step(); + assertEquals(0x00, bus.read(0x10)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + cpu.reset(); + + cpu.setAccumulator(0x0f); + bus.loadProgram(0x85, 0x10); + cpu.step(); + assertEquals(0x0f, bus.read(0x10)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.reset(); + + cpu.setAccumulator(0x80); + bus.loadProgram(0x85, 0x10); + cpu.step(); + assertEquals(0x80, bus.read(0x10)); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + } + /* STX - Store X Register - $86 */ + public void test_STX() { - } + cpu.setXRegister(0x00); + bus.loadProgram(0x86, 0x10); + cpu.step(); + assertEquals(0x00, bus.read(0x10)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + cpu.reset(); + + cpu.setXRegister(0x0f); + bus.loadProgram(0x86, 0x10); + cpu.step(); + assertEquals(0x0f, bus.read(0x10)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.reset(); + + cpu.setXRegister(0x80); + bus.loadProgram(0x86, 0x10); + cpu.step(); + assertEquals(0x80, bus.read(0x10)); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + } + /* LDY - Load Y Register - $a4 */ - public void test_LDY() { - } + public void test_LDY() { + bus.write(0x10, 0x00); + bus.write(0x11, 0x0f); + bus.write(0x12, 0x80); + + bus.loadProgram(0xa4, 0x10, + 0xa4, 0x11, + 0xa4, 0x12); + + 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 - $a5 */ + public void test_LDA() { + bus.write(0x10, 0x00); + bus.write(0x11, 0x0f); + bus.write(0x12, 0x80); + + bus.loadProgram(0xa5, 0x10, + 0xa5, 0x11, + 0xa5, 0x12); + + 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()); } /* LDX - Load X Register - $a6 */ - public void test_LDX() { - } + public void test_LDX() { + bus.write(0x10, 0x00); + bus.write(0x11, 0x0f); + bus.write(0x12, 0x80); + + bus.loadProgram(0xa6, 0x10, + 0xa6, 0x11, + 0xa6, 0x12); + + 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()); + } + /* CPY - Compare Y Register - $c4 */ + public void test_CPY() { + bus.write(0x10, 0x00); + bus.write(0x11, 0x80); + bus.write(0x12, 0xff); + + cpu.setYRegister(0x80); + + bus.loadProgram(0xc4, 0x10, + 0xc4, 0x11, + 0xc4, 0x12); + + 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 } /* CMP - Compare Accumulator - $c5 */ + public void test_CMP() { + bus.write(0x10, 0x00); + bus.write(0x11, 0x80); + bus.write(0x12, 0xff); + + cpu.setAccumulator(0x80); + + bus.loadProgram(0xc5, 0x10, + 0xc5, 0x11, + 0xc5, 0x12); + + 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 - $c6 */ + public void test_DEC() { + bus.write(0x10, 0x00); + bus.write(0x11, 0x01); + bus.write(0x12, 0x80); + bus.write(0x13, 0xff); + + bus.loadProgram(0xc6, 0x10, // DEC $10 + 0xc6, 0x11, // DEC $11 + 0xc6, 0x12, // DEC $12 + 0xc6, 0x13); // DEC $13 + + cpu.step(); + assertEquals(0xff, bus.read(0x10)); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x00, bus.read(0x11)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x7f, bus.read(0x12)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0xfe, bus.read(0x13)); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); } /* CPX - Compare X Register - $e4 */ + public void test_CPX() { + bus.write(0x10, 0x00); + bus.write(0x11, 0x80); + bus.write(0x12, 0xff); + + cpu.setXRegister(0x80); + + bus.loadProgram(0xe4, 0x10, + 0xe4, 0x11, + 0xe4, 0x12); + + 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 } /* SBC - Subtract with Carry - $e5 */ + public void test_SBC() { + bus.write(0x10, 0x01); + + bus.loadProgram(0xa9, 0x00, // LDA #$00 + 0xe5, 0x10); // SBC $10 + 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 + 0xe5, 0x10); // SBC $10 + 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 + 0xe5, 0x10); // SBC $10 + 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 + 0xe5, 0x10); // SBC $10 + 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 + 0xe5, 0x10); // SBC $10 + 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(0x10, 0x01); + + // Subtrace with Carry Flag cleared + bus.loadProgram(0x18, // CLC + 0xa9, 0x05, // LDA #$00 + 0xe5, 0x10); // SBC $10 + + cpu.step(3); + assertEquals(0x03, cpu.getAccumulator()); + + cpu.reset(); + + // Subtrace with Carry Flag cleared + bus.loadProgram(0x18, // CLC + 0xa9, 0x00, // LDA #$00 + 0xe5, 0x10); // SBC $10 + + cpu.step(3); + assertEquals(0xfe, cpu.getAccumulator()); + + cpu.reset(); + + // Subtract with Carry Flag set + bus.loadProgram(0x38, // SEC + 0xa9, 0x05, // LDA #$00 + 0xe5, 0x10); // SBC $10 + 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 + 0xe5, 0x10); // SBC $10 + cpu.step(3); + assertEquals(0xff, cpu.getAccumulator()); + assertFalse(cpu.getCarryFlag()); + + } + + public void test_SBC_DecimalMode() { + bus.write(0x10, 0x01); + bus.write(0x20, 0x11); + + bus.loadProgram(0xf8, + 0xa9, 0x00, + 0xe5, 0x10); + 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, + 0xe5, 0x10); + 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, + 0xe5, 0x10); + 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 + 0xe5, 0x10); // SBC $10 + 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 + 0xe5, 0x20); // SBC $20 + 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 + 0xe5, 0x10); // SBC $10 + 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 + 0xe5, 0x10); // SBC $10 + 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 - $e6 */ + public void test_INC() { + bus.write(0x10, 0x00); + bus.write(0x11, 0x7f); + bus.write(0x12, 0xff); + + bus.loadProgram(0xe6, 0x10, // INC $10 + 0xe6, 0x11, // INC $11 + 0xe6, 0x12); // INC $12 + + cpu.step(); + assertEquals(0x01, bus.read(0x10)); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x80, bus.read(0x11)); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0x00, bus.read(0x12)); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); } }