diff --git a/src/main/java/com/loomcom/symon/Cpu.java b/src/main/java/com/loomcom/symon/Cpu.java index e997dfb..4697144 100644 --- a/src/main/java/com/loomcom/symon/Cpu.java +++ b/src/main/java/com/loomcom/symon/Cpu.java @@ -162,7 +162,8 @@ public class Cpu implements InstructionTable { break; case 0x17: // n/a break; - case 0x18: // n/a + case 0x18: // CLC - Clear Carry Flag, Implied + clearCarryFlag(); break; case 0x19: // n/a break; @@ -230,7 +231,8 @@ public class Cpu implements InstructionTable { break; case 0x37: // n/a break; - case 0x38: // n/a + case 0x38: // SEC - Set Carry Flag, Implied + setCarryFlag(); break; case 0x39: // n/a break; @@ -299,7 +301,8 @@ public class Cpu implements InstructionTable { break; case 0x57: // n/a break; - case 0x58: // n/a + case 0x58: // CLI - Clear Interrupt Disable, Implied + clearIrqDisableFlag(); break; case 0x59: // n/a break; @@ -367,7 +370,8 @@ public class Cpu implements InstructionTable { break; case 0x77: // n/a break; - case 0x78: // n/a + case 0x78: // SEI - Set Interrupt Disable, Implied + setIrqDisableFlag(); break; case 0x79: // n/a break; @@ -505,7 +509,8 @@ public class Cpu implements InstructionTable { break; case 0xb7: // n/a break; - case 0xb8: // n/a + case 0xb8: // CLV - Clear Overflow Flag, Implied + clearOverflowFlag(); break; case 0xb9: // n/a break; @@ -573,7 +578,8 @@ public class Cpu implements InstructionTable { break; case 0xd7: // n/a break; - case 0xd8: // n/a + case 0xd8: // CLD - Clear Decimal Mode, Implied + clearDecimalModeFlag(); break; case 0xd9: // n/a break; @@ -642,7 +648,8 @@ public class Cpu implements InstructionTable { break; case 0xf7: // n/a break; - case 0xf8: // n/a + case 0xf8: // SED - Set Decimal Flag, Implied + setDecimalModeFlag(); break; case 0xf9: // n/a break; @@ -679,8 +686,8 @@ public class Cpu implements InstructionTable { } public int sbc(int acc, int operand) { - // Equivalent to ADC of the 2's complement of the operand - return adc(acc, (--operand) ^ 0xff); + // Equivalent to ADC of the 2's complement of the operand, minus the /carry + return adc(acc, (--operand ^ 0xff)); } public void cmp(int reg, int operand) { @@ -720,119 +727,214 @@ public class Cpu implements InstructionTable { } /** - * @return the carry flag - */ - public boolean getCarryFlag() { - return carryFlag; - } + * @return the carry flag + */ + public boolean getCarryFlag() { + return carryFlag; + } /** - * @param carryFlag the carry flag to set - */ - public void setCarryFlag(boolean carryFlag) { - this.carryFlag = carryFlag; - } - - /** - * @return the zero flag - */ - public boolean getZeroFlag() { - return zeroFlag; - } - - /** - * @param zeroFlag the zero flag to set - */ - public void setZeroFlag(boolean zeroFlag) { - this.zeroFlag = zeroFlag; - } + * @param carryFlag the carry flag to set + */ + public void setCarryFlag(boolean carryFlag) { + this.carryFlag = carryFlag; + } /** - * @return the irq disable flag - */ - public boolean getIrqDisableFlag() { - return irqDisableFlag; - } + * Sets the Carry Flag + */ + public void setCarryFlag() { + this.carryFlag = true; + } /** - * @param irqDisableFlag the irq disable flag to set - */ - public void setIrqDisableFlag(boolean irqDisableFlag) { - this.irqDisableFlag = irqDisableFlag; - } + * Clears the Carry Flag + */ + public void clearCarryFlag() { + this.carryFlag = false; + } /** - * @return the decimal mode flag - */ - public boolean getDecimalModeFlag() { - return decimalModeFlag; - } + * @return the zero flag + */ + public boolean getZeroFlag() { + return zeroFlag; + } /** - * @param decimalModeFlag the decimal mde flag to set - */ - public void setDecimalModeFlag(boolean decimalModeFlag) { - this.decimalModeFlag = decimalModeFlag; - } + * @param zeroFlag the zero flag to set + */ + public void setZeroFlag(boolean zeroFlag) { + this.zeroFlag = zeroFlag; + } /** - * @return the break flag - */ - public boolean getBreakFlag() { - return breakFlag; - } + * Sets the Zero Flag + */ + public void setZeroFlag() { + this.zeroFlag = true; + } /** - * @param breakFlag the break flag to set - */ - public void setBreakFlag(boolean breakFlag) { - this.breakFlag = breakFlag; - } + * Clears the Zero Flag + */ + public void clearZeroFlag() { + this.zeroFlag = false; + } /** - * @return the overflow flag - */ - public boolean getOverflowFlag() { - return overflowFlag; - } + * @return the irq disable flag + */ + public boolean getIrqDisableFlag() { + return irqDisableFlag; + } /** - * @param overflowFlag the overflow flag to set - */ - public void setOverflowFlag(boolean overflowFlag) { - this.overflowFlag = overflowFlag; - } + * @param irqDisableFlag the irq disable flag to set + */ + public void setIrqDisableFlag(boolean irqDisableFlag) { + this.irqDisableFlag = irqDisableFlag; + } - public int getAccumulator() { - return a; - } + public void setIrqDisableFlag() { + this.irqDisableFlag = true; + } - public int getXRegister() { - return x; - } + public void clearIrqDisableFlag() { + this.irqDisableFlag = false; + } - public int getYRegister() { - return y; - } - public int getProgramCounter() { - return pc; - } + /** + * @return the decimal mode flag + */ + public boolean getDecimalModeFlag() { + return decimalModeFlag; + } - /** - * @return A string representing the current status register state. - */ - public String statusRegisterString() { - StringBuffer sb = new StringBuffer(); - sb.append("(N:" + (getNegativeFlag() ? '1' : '0') + ", "); - sb.append("V:" + (getOverflowFlag() ? '1' : '0') + ", "); - sb.append("B:" + (getBreakFlag() ? '1' : '0') + ", "); - sb.append("D:" + (getDecimalModeFlag() ? '1' : '0') + ", "); - sb.append("I:" + (getIrqDisableFlag() ? '1' : '0') + ", "); - sb.append("Z:" + (getZeroFlag() ? '1' : '0') + ", "); - sb.append("C:" + (getCarryFlag() ? '1' : '0') + ")"); - return sb.toString(); - } + /** + * @param decimalModeFlag the decimal mode flag to set + */ + public void setDecimalModeFlag(boolean decimalModeFlag) { + this.decimalModeFlag = decimalModeFlag; + } + + /** + * Sets the Decimal Mode Flag to true. + */ + public void setDecimalModeFlag() { + this.decimalModeFlag = true; + } + + /** + * Clears the Decimal Mode Flag. + */ + public void clearDecimalModeFlag() { + this.decimalModeFlag = false; + } + + /** + * @return the break flag + */ + public boolean getBreakFlag() { + return breakFlag; + } + + /** + * @param breakFlag the break flag to set + */ + public void setBreakFlag(boolean breakFlag) { + this.breakFlag = breakFlag; + } + + /** + * Sets the Break Flag + */ + public void setBreakFlag() { + this.breakFlag = true; + } + + /** + * Clears the Break Flag + */ + public void clearBreakFlag() { + this.breakFlag = false; + } + + /** + * @return the overflow flag + */ + public boolean getOverflowFlag() { + return overflowFlag; + } + + /** + * @param overflowFlag the overflow flag to set + */ + public void setOverflowFlag(boolean overflowFlag) { + this.overflowFlag = overflowFlag; + } + + /** + * Sets the Overflow Flag + */ + public void setOverflowFlag() { + this.overflowFlag = true; + } + + /** + * Clears the Overflow Flag + */ + public void clearOverflowFlag() { + this.overflowFlag = false; + } + + public int getAccumulator() { + return a; + } + + public void setAccumulator(int val) { + this.a = val; + } + + public int getXRegister() { + return x; + } + + public void setXRegister(int val) { + this.x = val; + } + + public int getYRegister() { + return y; + } + + public void setYRegister(int val) { + this.y = val; + } + + public int getProgramCounter() { + return pc; + } + + public void setProgramCounter(int addr) { + this.pc = addr; + } + + /** + * @return A string representing the current status register state. + */ + public String statusRegisterString() { + StringBuffer sb = new StringBuffer(); + sb.append("(N:" + (getNegativeFlag() ? '1' : '0') + ", "); + sb.append("V:" + (getOverflowFlag() ? '1' : '0') + ", "); + sb.append("B:" + (getBreakFlag() ? '1' : '0') + ", "); + sb.append("D:" + (getDecimalModeFlag() ? '1' : '0') + ", "); + sb.append("I:" + (getIrqDisableFlag() ? '1' : '0') + ", "); + sb.append("Z:" + (getZeroFlag() ? '1' : '0') + ", "); + sb.append("C:" + (getCarryFlag() ? '1' : '0') + ")"); + return sb.toString(); + } /** * Returns a string representing the CPU state. diff --git a/src/test/java/com/loomcom/symon/CpuImmediateModeTest.java b/src/test/java/com/loomcom/symon/CpuImmediateModeTest.java index 799fe6e..2247099 100644 --- a/src/test/java/com/loomcom/symon/CpuImmediateModeTest.java +++ b/src/test/java/com/loomcom/symon/CpuImmediateModeTest.java @@ -159,147 +159,99 @@ public class CpuImmediateModeTest extends TestCase { /* ADC Immediate Mode Tests - 0x69 */ - public void test_ADC_SetsAccumulator() { - bus.loadProgram(0x69, 0x01, // ADC #$01 - 0x69, 0xa0, // ADC #$a0 - 0x69, 0x02, // ADC #$02 - 0x69, 0x06); // ADC #$06 - - cpu.step(); + public void test_ADC() { + bus.loadProgram(0xa9, 0x00, // LDA #$00 + 0x69, 0x01); // ADC #$01 + cpu.step(2); assertEquals(0x01, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); - cpu.step(); - assertEquals(0xa1, cpu.getAccumulator()); + cpu.reset(); + bus.loadProgram(0xa9, 0x7f, // LDA #$7f + 0x69, 0x01); // ADC #$01 + cpu.step(2); + assertEquals(0x80, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertTrue(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); - cpu.step(); - assertEquals(0xa3, cpu.getAccumulator()); + cpu.reset(); + bus.loadProgram(0xa9, 0x80, // LDA #$80 + 0x69, 0x01); // ADC #$01 + cpu.step(2); + assertEquals(0x81, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getCarryFlag()); - cpu.step(); - assertEquals(0xa9, cpu.getAccumulator()); + cpu.reset(); + bus.loadProgram(0xa9, 0xff, // LDA #$ff + 0x69, 0x01); // ADC #$01 + 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 + 0x69, 0xff); // ADC #$ff + 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 + 0x69, 0xff); // ADC #$ff + 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 + 0x69, 0xff); // ADC #$ff + 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 + 0x69, 0xff); // ADC #$ff + cpu.step(2); + assertEquals(0xfe, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getCarryFlag()); } public void test_ADC_IncludesCarry() { - cpu.setCarryFlag(true); - - bus.loadProgram(0x69, 0x01); // ADC #$01 - - cpu.step(); + bus.loadProgram(0xa9, 0x00, // LDA #$01 + 0x38, // SEC + 0x69, 0x01); // ADC #$01 + cpu.step(3); assertEquals(0x02, cpu.getAccumulator()); - } - - public void test_ADC_SetsCarryIfResultCarries() { - bus.loadProgram(0xa9, 0xff, // LDA #$FE - 0x69, 0x02); - - cpu.step(2); - - assertEquals(0x01, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); + assertFalse(cpu.getNegativeFlag()); assertFalse(cpu.getOverflowFlag()); - } - - public void test_ADC_SetsOverflowIfResultChangesSign() { - bus.loadProgram(0xa9, 0x7f, // LDA #$7f - 0x69, 0x01); // ADC #$01 - - cpu.step(2); - - assertEquals(0x80, cpu.getAccumulator()); assertFalse(cpu.getZeroFlag()); assertFalse(cpu.getCarryFlag()); - assertTrue(cpu.getOverflowFlag()); - - cpu.reset(); - - bus.loadProgram(0xa9, 0x80, // LDA #$80 - 0x69, 0xff); // ADC #$ff - - cpu.step(2); - - assertEquals(0x7f, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - assertFalse(cpu.getNegativeFlag()); - assertTrue(cpu.getOverflowFlag()); } - public void test_ADC_DoesNotSetOverflowIfNotNeeded() { - bus.loadProgram(0xa9, 0xff, // LDA #$ff - 0x69, 0x01); // ADC #$01 - - cpu.step(2); - - assertEquals(0x00, cpu.getAccumulator()); - assertTrue(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - - cpu.reset(); - - bus.loadProgram(0xa9, 0x01, // LDA #$01 - 0x69, 0x01); // ADC #$01 - - cpu.step(2); - assertEquals(0x02, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - } - - public void test_ADC_SetsNegativeFlagIfResultIsNegative() { - bus.loadProgram(0xa9, 0x7f, // LDA #$7F - 0x69, 0x01); // ADC #$01 - - cpu.step(2); - - assertEquals(0x80, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - assertTrue(cpu.getNegativeFlag()); - assertTrue(cpu.getOverflowFlag()); - } - - public void test_ADC_SetsZeroFlagIfResultIsZero() { - bus.loadProgram(0xa9, 0xff, // LDA #$FF - 0x69, 0x01); // ADC #$01 - - cpu.step(2); - - assertEquals(0x00, cpu.getAccumulator()); - assertTrue(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - } - - public void test_ADC_DoesNotSetNegativeFlagIfResultNotNegative() { - bus.loadProgram(0xa9, 0x7e, // LDA #$7E - 0x69, 0x01); // ADC #$01 - - cpu.step(2); - - assertEquals(0x7f, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - } - - public void test_ADC_DoesNotSetZeroFlagIfResultNotZero() { - bus.loadProgram(0xa9, 0xff, // LDA #$ff - 0x69, 0x03); // ADC #$03 - - cpu.step(2); - - assertEquals(0x2, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - } /* LDY Immediate Mode Tests - 0xa0 */ @@ -612,29 +564,63 @@ public class CpuImmediateModeTest extends TestCase { /* SBC Immediate Mode Tests - 0xe9 */ - public void test_SBC_SetsAccumulator() { - bus.loadProgram(0xa9, 0xff, // LDA #$FF - 0xe9, 0x01, // SBC #$01 - 0xe9, 0x01, // SBC #$a0 - 0xe9, 0x01, // SBC #$02 - 0xe9, 0x01); // SBC #$06 - + public void test_SBC() { + bus.loadProgram(0xa9, 0x00, // LDA #$00 + 0xe9, 0x01); // SBC #$01 + 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 + 0xe9, 0x01); // SBC #$01 + 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 + 0xe9, 0x01); // SBC #$01 + 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 + 0xe9, 0x01); // SBC #$01 cpu.step(2); assertEquals(0xfd, cpu.getAccumulator()); + assertTrue(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getZeroFlag()); assertTrue(cpu.getCarryFlag()); - cpu.step(); - assertEquals(0xfc, cpu.getAccumulator()); - assertTrue(cpu.getCarryFlag()); - - cpu.step(); - assertEquals(0xfb, cpu.getAccumulator()); - assertTrue(cpu.getCarryFlag()); - - cpu.step(); - assertEquals(0xfa, cpu.getAccumulator()); + cpu.reset(); + bus.loadProgram(0xa9, 0x02, // LDA #$02 + 0xe9, 0x01); // SBC #$01 + cpu.step(2); + assertEquals(0x00, cpu.getAccumulator()); + assertFalse(cpu.getNegativeFlag()); + assertFalse(cpu.getOverflowFlag()); + assertTrue(cpu.getZeroFlag()); assertTrue(cpu.getCarryFlag()); } -} + public void test_SBC_IncludesNotOfCarry() { + cpu.reset(); + bus.loadProgram(0x38, // SEC + 0xa9, 0x00, // LDA #$00 + 0xe9, 0x01); // SBC #$01 + cpu.step(3); + assertEquals(0xff, cpu.getAccumulator()); + } +} \ No newline at end of file