From 088b0823e12943596a9e6dd4275306833364334b Mon Sep 17 00:00:00 2001 From: "Seth J. Morabito" Date: Mon, 15 Dec 2008 02:26:13 -0800 Subject: [PATCH] More unit tests. SBC partially working, but I need to figure out what's going wrong. --- src/main/java/com/loomcom/symon/Cpu.java | 82 ++- .../loomcom/symon/CpuImmediateModeTest.java | 640 ++++++++++++++++++ .../loomcom/symon/CpuImmediateModeTests.java | 457 ------------- 3 files changed, 689 insertions(+), 490 deletions(-) create mode 100644 src/test/java/com/loomcom/symon/CpuImmediateModeTest.java delete mode 100644 src/test/java/com/loomcom/symon/CpuImmediateModeTests.java diff --git a/src/main/java/com/loomcom/symon/Cpu.java b/src/main/java/com/loomcom/symon/Cpu.java index 73d28fc..e997dfb 100644 --- a/src/main/java/com/loomcom/symon/Cpu.java +++ b/src/main/java/com/loomcom/symon/Cpu.java @@ -6,7 +6,7 @@ import java.util.Arrays; * Main 6502 CPU Simulation. */ public class Cpu implements InstructionTable { - + public static final int DEFAULT_BASE_ADDRESS = 0x200; /* The Bus */ @@ -24,9 +24,9 @@ public class Cpu implements InstructionTable { /* Operands for the current instruction */ private int[] operands = new int[2]; - private int addr; // The address the most recent instruction + private int addr; // The address the most recent instruction // was fetched from - + /* Status Flag Register bits */ private boolean carryFlag; private boolean negativeFlag; @@ -62,13 +62,13 @@ public class Cpu implements InstructionTable { public void reset() { // Registers sp = 0x01ff; - + // Set the PC to the address stored in 0xfffc pc = CpuUtils.address(bus.read(0xfffc), bus.read(0xfffd)); - + // Clear instruction register. ir = 0; - + // Clear status register bits. carryFlag = false; irqDisableFlag = false; @@ -95,7 +95,7 @@ public class Cpu implements InstructionTable { // TODO: The way we increment the PC may need // to change when interrupts are implemented - + // Increment PC incProgramCounter(); @@ -109,7 +109,7 @@ public class Cpu implements InstructionTable { // Execute switch(ir) { - + case 0x00: // HLT // TODO: Halt! break; @@ -522,7 +522,8 @@ public class Cpu implements InstructionTable { case 0xbf: // n/a break; - case 0xc0: // n/a + case 0xc0: // CPY - Immediate + cmp(y, operands[0]); break; case 0xc1: // n/a break; @@ -540,7 +541,8 @@ public class Cpu implements InstructionTable { break; case 0xc8: // n/a break; - case 0xc9: // n/a + case 0xc9: // CMP - Immediate + cmp(a, operands[0]); break; case 0xca: // n/a break; @@ -588,7 +590,8 @@ public class Cpu implements InstructionTable { case 0xdf: // n/a break; - case 0xe0: // n/a + case 0xe0: // CPX - Immediate + cmp(x, operands[0]); break; case 0xe1: // n/a break; @@ -607,6 +610,8 @@ public class Cpu implements InstructionTable { case 0xe8: // n/a break; case 0xe9: // n/a + a = sbc(a, operands[0]); + setArithmeticFlags(a); break; case 0xea: // NOP break; @@ -658,25 +663,36 @@ public class Cpu implements InstructionTable { /** * Add with Carry, used by all addressing mode implementations of ADC. - * As a side effect, this will set the - * + * As a side effect, this will set the + * * @param acc The current value of the accumulator * @param operand The operand * @return */ public int adc(int acc, int operand) { - int result = operand + a + (carryFlag ? 1 : 0); - int carry = (operand & 0x7f) + (a & 0x7f) + (carryFlag ? 1 : 0); - if (result > 0xff) { setCarryFlag(true); } + int result = operand + acc + (carryFlag ? 1 : 0); + int carry = (operand & 0x7f) + (acc & 0x7f) + (carryFlag ? 1 : 0); + setCarryFlag(result > 0xff); result = result & 0xff; setOverflowFlag(carryFlag ^ ((carry & 0x80) != 0)); return result; } - + + public int sbc(int acc, int operand) { + // Equivalent to ADC of the 2's complement of the operand + return adc(acc, (--operand) ^ 0xff); + } + + public void cmp(int reg, int operand) { + setCarryFlag(reg >= operand); + setZeroFlag(reg == operand); + setNegativeFlag((reg - operand) > 0); + } + /** * Set the Negative and Zero flags based on the current value of the * register operand. - * + * * @param reg The register. */ public void setArithmeticFlags(int reg) { @@ -689,7 +705,7 @@ public class Cpu implements InstructionTable { public boolean getNegativeFlag() { return negativeFlag; } - + /** * @param register the register value to test for negativity */ @@ -702,7 +718,7 @@ public class Cpu implements InstructionTable { public void setNegativeFlag(boolean negativeFlag) { this.negativeFlag = negativeFlag; } - + /** * @return the carry flag */ @@ -716,14 +732,14 @@ public class Cpu implements InstructionTable { public void setCarryFlag(boolean carryFlag) { this.carryFlag = carryFlag; } - + /** * @return the zero flag */ public boolean getZeroFlag() { return zeroFlag; } - + /** * @param zeroFlag the zero flag to set */ @@ -786,23 +802,23 @@ public class Cpu implements InstructionTable { public void setOverflowFlag(boolean overflowFlag) { this.overflowFlag = overflowFlag; } - + public int getAccumulator() { return a; } - + public int getXRegister() { return x; } - + public int getYRegister() { return y; } - + public int getProgramCounter() { return pc; } - + /** * @return A string representing the current status register state. */ @@ -819,7 +835,7 @@ public class Cpu implements InstructionTable { } /** - * Returns a string representing the CPU state. + * Returns a string representing the CPU state. */ public String toString() { String opcode = CpuUtils.opcode(ir, operands[0], operands[1]); @@ -833,20 +849,20 @@ public class Cpu implements InstructionTable { sb.append("P=" + statusRegisterString()); return sb.toString(); } - + /** * Push an item onto the stack, and decrement the stack counter. * Silently fails to push onto the stack if SP is - * TODO: Unit tests. + * TODO: Unit tests. */ protected void push(int data) { bus.write(sp, data); if (sp > 0x100) { sp--; } } - + /** - * Pop a byte off the user stack, and increment the stack counter. + * Pop a byte off the user stack, and increment the stack counter. * TODO: Unit tests. */ protected int pop() { @@ -865,5 +881,5 @@ public class Cpu implements InstructionTable { ++pc; } } - + } \ No newline at end of file diff --git a/src/test/java/com/loomcom/symon/CpuImmediateModeTest.java b/src/test/java/com/loomcom/symon/CpuImmediateModeTest.java new file mode 100644 index 0000000..799fe6e --- /dev/null +++ b/src/test/java/com/loomcom/symon/CpuImmediateModeTest.java @@ -0,0 +1,640 @@ +package com.loomcom.symon; + +import com.loomcom.symon.devices.Memory; +import com.loomcom.symon.exceptions.MemoryRangeException; +import junit.framework.*; + +public class CpuImmediateModeTest extends TestCase { + + protected Cpu cpu; + protected Bus bus; + protected Memory mem; + + public void setUp() throws MemoryRangeException { + 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(); + } + + /* ORA Immediate Mode Tests - 0x09 */ + + public void test_ORA_SetsAccumulator() { + bus.loadProgram(0x09, 0x00, // ORA #$00 + 0x09, 0x11, // ORA #$11 + 0x09, 0x22, // ORA #$22 + 0x09, 0x44, // ORA #$44 + 0x09, 0x88); // ORA #$88 + cpu.step(); + assertEquals(0x00, cpu.getAccumulator()); + + cpu.step(); + assertEquals(0x11, cpu.getAccumulator()); + + cpu.step(); + assertEquals(0x33, cpu.getAccumulator()); + + cpu.step(); + assertEquals(0x77, cpu.getAccumulator()); + + cpu.step(); + assertEquals(0xff, cpu.getAccumulator()); + } + + public void test_ORA_SetsZeroFlagIfResultIsZero() { + bus.loadProgram(0x09, 0x00); // ORA #$00 + cpu.step(); + assertTrue(cpu.getZeroFlag()); + } + + public void test_ORA_DoesNotSetZeroFlagIfResultNotZero() { + bus.loadProgram(0x09, 0x01); // ORA #$01 + cpu.step(); + assertFalse(cpu.getZeroFlag()); + } + + public void test_ORA_SetsNegativeFlagIfResultIsNegative() { + bus.loadProgram(0x09, 0x80); // ORA #$80 + cpu.step(); + assertTrue(cpu.getNegativeFlag()); + } + + public void test_ORA_DoesNotSetNegativeFlagIfResultNotNegative() { + bus.loadProgram(0x09, 0x7f); // ORA #$7F + cpu.step(); + assertFalse(cpu.getNegativeFlag()); + } + + /* AND Immediate Mode Tests - 0x29 */ + + public void test_AND_SetsAccumulator() { + bus.loadProgram(0x29, 0x00, // AND #$00 + 0x29, 0x11, // AND #$11 + 0xa9, 0xaa, // LDA #$AA + 0x29, 0xff, // AND #$FF + 0x29, 0x99, // AND #$99 + 0x29, 0x11); // AND #$11 + cpu.step(); + assertEquals(0x00, cpu.getAccumulator()); + + cpu.step(); + assertEquals(0x00, cpu.getAccumulator()); + + cpu.step(2); + assertEquals(0xaa, cpu.getAccumulator()); + + cpu.step(); + assertEquals(0x88, cpu.getAccumulator()); + + cpu.step(); + assertEquals(0x00, cpu.getAccumulator()); + } + + public void test_AND_SetsZeroFlagIfResultIsZero() { + bus.loadProgram(0xa9, 0x88, // LDA #$88 + 0x29, 0x11); // AND #$11 + cpu.step(2); + assertTrue(cpu.getZeroFlag()); + } + + public void test_AND_DoesNotSetZeroFlagIfResultNotZero() { + bus.loadProgram(0xa9, 0x88, // LDA #$88 + 0x29, 0xf1); // AND #$F1 + cpu.step(2); + assertFalse(cpu.getZeroFlag()); + } + + public void test_AND_SetsNegativeFlagIfResultIsNegative() { + bus.loadProgram(0xa9, 0x88, // LDA #$88 + 0x29, 0xf0); // AND #$F0 + cpu.step(2); + assertTrue(cpu.getNegativeFlag()); + } + + public void test_AND_DoesNotSetNegativeFlagIfResultNotNegative() { + bus.loadProgram(0xa9, 0x88, // LDA #$88 + 0x29, 0x0f); // AND #$0F + cpu.step(2); + assertFalse(cpu.getNegativeFlag()); + } + + /* EOR Immediate Mode Tests - 0x49 */ + + public void test_EOR_SetsAccumulator() { + bus.loadProgram(0xa9, 0x88, // LDA #$88 + 0x49, 0x00, // EOR #$00 + 0x49, 0xff, // EOR #$ff + 0x49, 0x33); // EOR #$33 + cpu.step(2); + assertEquals(0x88, cpu.getAccumulator()); + + cpu.step(); + assertEquals(0x77, cpu.getAccumulator()); + + cpu.step(); + assertEquals(0x44, cpu.getAccumulator()); + } + + public void test_EOR_SetsArithmeticFlags() { + bus.loadProgram(0xa9, 0x77, // LDA #$77 + 0x49, 0x77, // EOR #$77 + 0x49, 0xff); // EOR #$ff + cpu.step(2); + assertEquals(0x00, cpu.getAccumulator()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.step(); + assertEquals(0xff, cpu.getAccumulator()); + assertFalse(cpu.getZeroFlag()); + assertTrue(cpu.getNegativeFlag()); + } + + /* 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(); + assertEquals(0x01, cpu.getAccumulator()); + + cpu.step(); + assertEquals(0xa1, cpu.getAccumulator()); + + cpu.step(); + assertEquals(0xa3, cpu.getAccumulator()); + + cpu.step(); + assertEquals(0xa9, cpu.getAccumulator()); + } + + public void test_ADC_IncludesCarry() { + cpu.setCarryFlag(true); + + bus.loadProgram(0x69, 0x01); // ADC #$01 + + cpu.step(); + 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.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 */ + + public void test_LDY_SetsYRegister() { + bus.loadProgram(0xa0, 0x12); // LDY #$12 + cpu.step(); + assertEquals(0x12, cpu.getYRegister()); + } + + public void test_LDY_SetsZeroFlagIfArgIsZero() { + bus.loadProgram(0xa0, 0x00); // LDY #$00 + cpu.step(); + assertTrue(cpu.getZeroFlag()); + } + + public void test_LDY_DoesNotSetZeroFlagIfResultNotZero() { + bus.loadProgram(0xa0, 0x12); // LDY #$12 + cpu.step(); + assertFalse(cpu.getZeroFlag()); + } + + public void test_LDY_SetsNegativeFlagIfResultIsNegative() { + bus.loadProgram(0xa0, 0x80); // LDY #$80 + cpu.step(); + assertTrue(cpu.getNegativeFlag()); + } + + public void test_LDY_DoesNotSetNegativeFlagIfResultNotNegative() { + bus.loadProgram(0xa0, 0x7f); // LDY #$7F + cpu.step(); + assertFalse(cpu.getNegativeFlag()); + } + + /* LDX Immediate Mode Tests - 0xa2 */ + + public void test_LDX_SetsXRegister() { + bus.loadProgram(0xa2, 0x12); // LDX #$12 + cpu.step(); + assertEquals(0x12, cpu.getXRegister()); + } + + public void test_LDX_SetsZeroFlagIfResultIsZero() { + bus.loadProgram(0xa2, 0x00); // LDX #$00 + cpu.step(); + assertTrue(cpu.getZeroFlag()); + } + + public void test_LDX_DoesNotSetZeroFlagIfResultNotZero() { + bus.loadProgram(0xa2, 0x12); // LDX #$12 + cpu.step(); + assertFalse(cpu.getZeroFlag()); + } + + public void test_LDX_SetsNegativeFlagIfResultIsNegative() { + bus.loadProgram(0xa2, 0x80); // LDX #$80 + cpu.step(); + assertTrue(cpu.getNegativeFlag()); + } + + public void test_LDX_DoesNotSetNegativeFlagIfResultNotNegative() { + bus.loadProgram(0xa2, 0x7f); // LDX #$7F + cpu.step(); + assertFalse(cpu.getNegativeFlag()); + } + + /* LDA Immediate Mode Tests - 0xa9 */ + + public void test_LDA_SetsAccumulator() { + bus.loadProgram(0xa9, 0x12); // LDA #$12 + cpu.step(); + assertEquals(0x12, cpu.getAccumulator()); + } + + public void test_LDA_SetsZeroFlagIfResultIsZero() { + bus.loadProgram(0xa9, 0x00); // LDA #$00 + cpu.step(); + assertTrue(cpu.getZeroFlag()); + } + + public void test_LDA_DoesNotSetZeroFlagIfResultNotZero() { + bus.loadProgram(0xa9, 0x12); // LDA #$12 + cpu.step(); + assertFalse(cpu.getZeroFlag()); + } + + public void test_LDA_SetsNegativeFlagIfResultIsNegative() { + bus.loadProgram(0xa9, 0x80); // LDA #$80 + cpu.step(); + assertTrue(cpu.getNegativeFlag()); + } + + public void test_LDA_DoesNotSetNegativeFlagIfResultNotNegative() { + bus.loadProgram(0xa9, 0x7f); // LDA #$7F + cpu.step(); + assertFalse(cpu.getNegativeFlag()); + } + + /* CPY Immediate Mode Tests - 0xc0 */ + + public void test_CPY_SetsZeroAndCarryFlagsIfNumbersSame() { + bus.loadProgram(0xa0, 0x00, // LDY #$00 + 0xc0, 0x00); // CPY #$00 + cpu.step(2); + assertTrue(cpu.getCarryFlag()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.reset(); + bus.loadProgram(0xa0, 0x01, // LDY #$01 + 0xc0, 0x01); // CPY #$01 + cpu.step(2); + assertTrue(cpu.getCarryFlag()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.reset(); + bus.loadProgram(0xa0, 0x7f, // LDY #$7F + 0xc0, 0x7f); // CPY #$7F + cpu.step(2); + assertTrue(cpu.getCarryFlag()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.reset(); + bus.loadProgram(0xa0, 0xFF, // LDY #$FF + 0xc0, 0xFF); // CPY #$FF + cpu.step(2); + assertTrue(cpu.getCarryFlag()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + } + + public void test_CPY_SetsCarryFlagIfYGreaterThanMemory() { + bus.loadProgram(0xa0, 0x0a, // LDY #$0A + 0xc0, 0x08); // CPY #$08 + cpu.step(2); + assertTrue(cpu.getCarryFlag()); + assertFalse(cpu.getZeroFlag()); + // $08 - $0a = negative + assertTrue(cpu.getNegativeFlag()); + + cpu.reset(); + bus.loadProgram(0xa0, 0xfa, // LDY #$FA + 0xc0, 0x80); // CPY #$80 + cpu.step(2); + assertTrue(cpu.getCarryFlag()); + assertFalse(cpu.getZeroFlag()); + // $80 - $FA = negative + assertTrue(cpu.getNegativeFlag()); + } + + public void test_CPY_DoesNotSetCarryFlagIfYGreaterThanMemory() { + bus.loadProgram(0xa0, 0x08, // LDY #$08 + 0xc0, 0x0a); // CPY #$0A + cpu.step(2); + assertFalse(cpu.getCarryFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.reset(); + bus.loadProgram(0xa0, 0x70, // LDY #$70 + 0xc0, 0x80); // CPY #$80 + cpu.step(2); + assertFalse(cpu.getCarryFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + } + + /* CMP Immediate Mode Tests - 0xc9 */ + + public void test_CMP_SetsZeroAndCarryFlagsIfNumbersSame() { + bus.loadProgram(0xa9, 0x00, // LDA #$00 + 0xc9, 0x00); // CMP #$00 + cpu.step(2); + assertTrue(cpu.getCarryFlag()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.reset(); + bus.loadProgram(0xa9, 0x01, // LDA #$01 + 0xc9, 0x01); // CMP #$01 + cpu.step(2); + assertTrue(cpu.getCarryFlag()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.reset(); + bus.loadProgram(0xa9, 0x7f, // LDA #$7F + 0xc9, 0x7f); // CMP #$7F + cpu.step(2); + assertTrue(cpu.getCarryFlag()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.reset(); + bus.loadProgram(0xa9, 0xFF, // LDA #$FF + 0xc9, 0xFF); // CMP #$FF + cpu.step(2); + assertTrue(cpu.getCarryFlag()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + } + + public void test_CMP_SetsCarryFlagIfYGreaterThanMemory() { + bus.loadProgram(0xa9, 0x0a, // LDA #$0A + 0xc9, 0x08); // CMP #$08 + cpu.step(2); + assertTrue(cpu.getCarryFlag()); + assertFalse(cpu.getZeroFlag()); + // $08 - $0a = negative + assertTrue(cpu.getNegativeFlag()); + + cpu.reset(); + bus.loadProgram(0xa9, 0xfa, // LDA #$FA + 0xc9, 0x80); // CMP #$80 + cpu.step(2); + assertTrue(cpu.getCarryFlag()); + assertFalse(cpu.getZeroFlag()); + // $80 - $FA = negative + assertTrue(cpu.getNegativeFlag()); + } + + public void test_CMP_DoesNotSetCarryFlagIfYGreaterThanMemory() { + bus.loadProgram(0xa9, 0x08, // LDA #$08 + 0xc9, 0x0a); // CMP #$0A + cpu.step(2); + assertFalse(cpu.getCarryFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.reset(); + bus.loadProgram(0xa9, 0x70, // LDA #$70 + 0xc9, 0x80); // CMP #$80 + cpu.step(2); + assertFalse(cpu.getCarryFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + } + + /* CPX Immediate Mode Tests - 0xe0 */ + + public void test_CPX_SetsZeroAndCarryFlagsIfNumbersSame() { + bus.loadProgram(0xa2, 0x00, // LDX #$00 + 0xe0, 0x00); // CPX #$00 + cpu.step(2); + assertTrue(cpu.getCarryFlag()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.reset(); + bus.loadProgram(0xa2, 0x01, // LDX #$01 + 0xe0, 0x01); // CPX #$01 + cpu.step(2); + assertTrue(cpu.getCarryFlag()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.reset(); + bus.loadProgram(0xa2, 0x7f, // LDX #$7F + 0xe0, 0x7f); // CPX #$7F + cpu.step(2); + assertTrue(cpu.getCarryFlag()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.reset(); + bus.loadProgram(0xa2, 0xFF, // LDX #$FF + 0xe0, 0xFF); // CPX #$FF + cpu.step(2); + assertTrue(cpu.getCarryFlag()); + assertTrue(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + } + + public void test_CPX_SetsCarryFlagIfYGreaterThanMemory() { + bus.loadProgram(0xa2, 0x0a, // LDX #$0A + 0xe0, 0x08); // CPX #$08 + cpu.step(2); + assertTrue(cpu.getCarryFlag()); + assertFalse(cpu.getZeroFlag()); + // $08 - $0a = negative + assertTrue(cpu.getNegativeFlag()); + + cpu.reset(); + bus.loadProgram(0xa2, 0xfa, // LDX #$FA + 0xe0, 0x80); // CPX #$80 + cpu.step(2); + assertTrue(cpu.getCarryFlag()); + assertFalse(cpu.getZeroFlag()); + // $80 - $FA = negative + assertTrue(cpu.getNegativeFlag()); + } + + public void test_CPX_DoesNotSetCarryFlagIfYGreaterThanMemory() { + bus.loadProgram(0xa2, 0x08, // LDX #$08 + 0xe0, 0x0a); // CPX #$0A + cpu.step(2); + assertFalse(cpu.getCarryFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + + cpu.reset(); + bus.loadProgram(0xa2, 0x70, // LDX #$70 + 0xe0, 0x80); // CMX #$80 + cpu.step(2); + assertFalse(cpu.getCarryFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getNegativeFlag()); + } + + /* 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 + + assertFalse(cpu.getCarryFlag()); + cpu.step(2); + assertEquals(0xfd, cpu.getAccumulator()); + 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()); + assertTrue(cpu.getCarryFlag()); + } + +} diff --git a/src/test/java/com/loomcom/symon/CpuImmediateModeTests.java b/src/test/java/com/loomcom/symon/CpuImmediateModeTests.java deleted file mode 100644 index ca179f4..0000000 --- a/src/test/java/com/loomcom/symon/CpuImmediateModeTests.java +++ /dev/null @@ -1,457 +0,0 @@ -package com.loomcom.symon; - -import com.loomcom.symon.devices.Memory; -import com.loomcom.symon.exceptions.MemoryRangeException; -import junit.framework.*; - -public class CpuImmediateModeTests extends TestCase { - - protected Cpu cpu; - protected Bus bus; - protected Memory mem; - - public void setUp() throws MemoryRangeException { - 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(); - } - - /* ORA Immediate Mode Tests - 0x09 */ - - public void test_ORA_SetsAccumulator() { - bus.loadProgram(0x09, 0x00, // ORA #$00 - 0x09, 0x11, // ORA #$11 - 0x09, 0x22, // ORA #$22 - 0x09, 0x44, // ORA #$44 - 0x09, 0x88); // ORA #$88 - cpu.step(); - // 0x00 | 0x00 == 0x00 - assertEquals(0x00, cpu.getAccumulator()); - - cpu.step(); - // 0x00 | 0x11 == 0x11 - assertEquals(0x11, cpu.getAccumulator()); - - cpu.step(); - // 0x11 | 0x22 == 0x33 - assertEquals(0x33, cpu.getAccumulator()); - - cpu.step(); - // 0x33 | 0x44 == 0x77 - assertEquals(0x77, cpu.getAccumulator()); - - cpu.step(); - // 0x77 | 0x88 == 0xFF - assertEquals(0xff, cpu.getAccumulator()); - } - - public void test_ORA_SetsZeroFlagIfResultIsZero() { - bus.loadProgram(0x09, 0x00); // ORA #$00 - cpu.step(); - assertTrue(cpu.getZeroFlag()); - } - - public void test_ORA_DoesNotSetZeroFlagIfResultNotZero() { - bus.loadProgram(0x09, 0x01); // ORA #$01 - cpu.step(); - assertFalse(cpu.getZeroFlag()); - } - - public void test_ORA_SetsNegativeFlagIfResultIsNegative() { - bus.loadProgram(0x09, 0x80); // ORA #$80 - cpu.step(); - assertTrue(cpu.getNegativeFlag()); - } - - public void test_ORA_DoesNotSetNegativeFlagIfResultNotNegative() { - bus.loadProgram(0x09, 0x7f); // ORA #$7F - cpu.step(); - assertFalse(cpu.getNegativeFlag()); - } - - /* AND Immediate Mode Tests - 0x29 */ - - public void test_AND_SetsAccumulator() { - bus.write(0x0200, 0x29); // AND #$00 - bus.write(0x0201, 0x00); - cpu.step(); - // 0x00 & 0x00 == 0x00 - assertEquals(0x00, cpu.getAccumulator()); - - bus.write(0x0202, 0x29); // AND #$FF - bus.write(0x0203, 0x11); - cpu.step(); - // 0x00 & 0xff == 0x00 - assertEquals(0x00, cpu.getAccumulator()); - - // Load Accumulator with AA - %10101010 - - bus.write(0x0204, 0xa9); // LDA #$AA - bus.write(0x0205, 0xaa); - cpu.step(); - - bus.write(0x0206, 0x29); // AND #$FF - bus.write(0x0207, 0xff); - cpu.step(); - // 0xaa & 0xff == 0xaa - assertEquals(0xaa, cpu.getAccumulator()); - - bus.write(0x0208, 0x29); // AND #$99 - bus.write(0x0209, 0x99); - cpu.step(); - // 0xaa & 0x99 == 0x88 - - assertEquals(0x88, cpu.getAccumulator()); - bus.write(0x020a, 0x29); // AND #$99 - bus.write(0x020b, 0x11); - cpu.step(); - // 0x88 & 0x11 == 0x00 - assertEquals(0x00, cpu.getAccumulator()); - } - - public void test_AND_SetsZeroFlagIfResultIsZero() { - bus.write(0x0200, 0xa9); // LDA #$88 - bus.write(0x0201, 0x88); - cpu.step(); - bus.write(0x0202, 0x29); // AND #$11 - bus.write(0x0203, 0x11); - cpu.step(); - assertTrue(cpu.getZeroFlag()); - } - - public void test_AND_DoesNotSetZeroFlagIfResultNotZero() { - bus.loadProgram(0xa9, 0x88, // LDA #$88 - 0x29, 0xf1); // AND #$F1 - cpu.step(2); - assertFalse(cpu.getZeroFlag()); - } - - public void test_AND_SetsNegativeFlagIfResultIsNegative() { - bus.loadProgram(0xa9, 0x88, // LDA #$88 - 0x29, 0xf0); // AND #$F0 - cpu.step(2); - assertTrue(cpu.getNegativeFlag()); - } - - public void test_AND_DoesNotSetNegativeFlagIfResultNotNegative() { - bus.loadProgram(0xa9, 0x88, // LDA #$88 - 0x29, 0x0f); // AND #$0F - cpu.step(2); - assertFalse(cpu.getNegativeFlag()); - } - - /* EOR Immediate Mode Tests - 0x49 */ - - public void test_EOR_SetsAccumulator() { - bus.loadProgram(0xa9, 0x88, // LDA #$88 - 0x49, 0x00, // EOR #$00 - 0x49, 0xff, // EOR #$ff - 0x49, 0x33); // EOR #$33 - cpu.step(); - cpu.step(); - assertEquals(0x88, cpu.getAccumulator()); - cpu.step(); - assertEquals(0x77, cpu.getAccumulator()); - cpu.step(); - assertEquals(0x44, cpu.getAccumulator()); - } - - public void test_EOR_SetsArithmeticFlags() { - bus.loadProgram(0xa9, 0x77, // LDA #$77 - 0x49, 0x77, // EOR #$77 - 0x49, 0xff); // EOR #$ff - cpu.step(); - cpu.step(); - assertEquals(0x00, cpu.getAccumulator()); - assertTrue(cpu.getZeroFlag()); - assertFalse(cpu.getNegativeFlag()); - cpu.step(); - assertEquals(0xff, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getNegativeFlag()); - } - - /* ADC Immediate Mode Tests - 0x69 */ - - public void test_ADC_SetsAccumulator() { - bus.write(0x200, 0x69); - bus.write(0x201, 0x01); - cpu.step(); - assertEquals(0x01, cpu.getAccumulator()); - - bus.write(0x202, 0x69); - bus.write(0x203, 0xa0); - cpu.step(); - assertEquals(0xa1, cpu.getAccumulator()); - - bus.write(0x204, 0x69); - bus.write(0x205, 0x02); - cpu.step(); - assertEquals(0xa3, cpu.getAccumulator()); - - bus.write(0x206, 0x69); - bus.write(0x207, 0x06); - cpu.step(); - assertEquals(0xa9, cpu.getAccumulator()); - } - - public void test_ADC_IncludesCarry() { - cpu.setCarryFlag(true); - bus.write(0x200, 0x69); - bus.write(0x201, 0x01); - cpu.step(); - assertEquals(0x02, cpu.getAccumulator()); - } - - public void test_ADC_SetsCarryIfResultCarries() { - bus.write(0x200, 0xa9); // LDA #$fe - bus.write(0x201, 0xff); - cpu.step(); - bus.write(0x202, 0x69); // ADC #$02 - bus.write(0x203, 0x02); - cpu.step(); - // $ff + $02 = $101 = [c] + $01 - assertEquals(0x01, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - assertFalse(cpu.getOverflowFlag()); - } - - public void test_ADC_SetsOverflowIfResultChangesSign() { - bus.write(0x200, 0xa9); // LDA #$7f - bus.write(0x201, 0x7f); - cpu.step(); - bus.write(0x202, 0x69); // ADC #$01 - bus.write(0x203, 0x01); - cpu.step(); - assertEquals(0x80, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - assertTrue(cpu.getOverflowFlag()); - - cpu.reset(); - - bus.write(0x200, 0xa9); // LDA #$80 - bus.write(0x201, 0x80); - cpu.step(); - bus.write(0x202, 0x69); // ADC #$ff - bus.write(0x203, 0xff); - cpu.step(); - assertEquals(0x7f, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - assertFalse(cpu.getNegativeFlag()); - assertTrue(cpu.getOverflowFlag()); - } - - public void test_ADC_DoesNotSetOverflowIfNotNeeded() { - bus.write(0x200, 0xa9); // LDA #$ff - bus.write(0x201, 0xff); - cpu.step(); - bus.write(0x202, 0x69); // ADC #$01 - bus.write(0x203, 0x01); - cpu.step(); - assertEquals(0x00, cpu.getAccumulator()); - assertTrue(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - - cpu.reset(); - - bus.write(0x200, 0xa9); // LDA #$01 - bus.write(0x201, 0x01); - cpu.step(); - bus.write(0x202, 0x69); // ADC #$01 - bus.write(0x203, 0x01); - cpu.step(); - assertEquals(0x02, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - } - - public void test_ADC_SetsNegativeFlagIfResultIsNegative() { - bus.write(0x200, 0xa9); // LDA #$7f - bus.write(0x201, 0x7f); - cpu.step(); - bus.write(0x202, 0x69); // ADC #$01 - bus.write(0x203, 0x01); - cpu.step(); - assertEquals(0x80, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - assertTrue(cpu.getNegativeFlag()); - assertTrue(cpu.getOverflowFlag()); - } - - public void test_ADC_SetsZeroFlagIfResultIsZero() { - bus.write(0x200, 0xa9); // LDA #$ff - bus.write(0x201, 0xff); - cpu.step(); - bus.write(0x202, 0x69); // ADC #$01 - bus.write(0x203, 0x01); - cpu.step(); - assertEquals(0x00, cpu.getAccumulator()); - assertTrue(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - } - - public void test_ADC_DoesNotSetNegativeFlagIfResultNotNegative() { - bus.write(0x200, 0xa9); // LDA #$7f - bus.write(0x201, 0x7e); - cpu.step(); - bus.write(0x202, 0x69); // ADC #$01 - bus.write(0x203, 0x01); - cpu.step(); - assertEquals(0x7f, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertFalse(cpu.getCarryFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - } - - public void test_ADC_DoesNotSetZeroFlagIfResultNotZero() { - bus.write(0x200, 0xa9); // LDA #$ff - bus.write(0x201, 0xff); - cpu.step(); - bus.write(0x202, 0x69); // ADC #$01 - bus.write(0x203, 0x03); - cpu.step(); - assertEquals(0x2, cpu.getAccumulator()); - assertFalse(cpu.getZeroFlag()); - assertTrue(cpu.getCarryFlag()); - assertFalse(cpu.getNegativeFlag()); - assertFalse(cpu.getOverflowFlag()); - } - - /* LDY Immediate Mode Tests - 0xa0 */ - - public void test_LDY_SetsYRegister() { - bus.write(0x0200, 0xa0); - bus.write(0x0201, 0x12); - cpu.step(); - assertEquals(0x12, cpu.getYRegister()); - } - - public void test_LDY_SetsZeroFlagIfArgIsZero() { - bus.write(0x0200, 0xa0); - bus.write(0x0201, 0x00); - cpu.step(); - assertTrue(cpu.getZeroFlag()); - } - - public void test_LDY_DoesNotSetZeroFlagIfResultNotZero() { - bus.write(0x0200, 0xa0); - bus.write(0x0201, 0x12); - cpu.step(); - assertFalse(cpu.getZeroFlag()); - } - - public void test_LDY_SetsNegativeFlagIfResultIsNegative() { - bus.write(0x0200, 0xa0); - bus.write(0x0201, 0x80); - cpu.step(); - assertTrue(cpu.getNegativeFlag()); - } - - public void test_LDY_DoesNotSetNegativeFlagIfResultNotNegative() { - bus.write(0x0200, 0xa0); - bus.write(0x0201, 0x7f); - cpu.step(); - assertFalse(cpu.getNegativeFlag()); - } - - /* LDX Immediate Mode Tests - 0xa2 */ - - public void test_LDX_SetsXRegister() { - bus.write(0x0200, 0xa2); - bus.write(0x0201, 0x12); - cpu.step(); - assertEquals(0x12, cpu.getXRegister()); - } - - public void test_LDX_SetsZeroFlagIfResultIsZero() { - bus.write(0x0200, 0xa2); - bus.write(0x0201, 0x00); - cpu.step(); - assertTrue(cpu.getZeroFlag()); - } - - public void test_LDX_DoesNotSetZeroFlagIfResultNotZero() { - bus.write(0x0200, 0xa2); - bus.write(0x0201, 0x12); - cpu.step(); - assertFalse(cpu.getZeroFlag()); - } - - public void test_LDX_SetsNegativeFlagIfResultIsNegative() { - bus.write(0x0200, 0xa2); - bus.write(0x0201, 0x80); - cpu.step(); - assertTrue(cpu.getNegativeFlag()); - } - - public void test_LDX_DoesNotSetNegativeFlagIfResultNotNegative() { - bus.write(0x0200, 0xa2); - bus.write(0x0201, 0x7f); - cpu.step(); - assertFalse(cpu.getNegativeFlag()); - } - - /* LDA Immediate Mode Tests - 0xa9 */ - - public void test_LDA_SetsAccumulator() { - bus.write(0x0200, 0xa9); - bus.write(0x0201, 0x12); - cpu.step(); - assertEquals(0x12, cpu.getAccumulator()); - } - - public void test_LDA_SetsZeroFlagIfResultIsZero() { - bus.write(0x0200, 0xa9); - bus.write(0x0201, 0x00); - cpu.step(); - assertTrue(cpu.getZeroFlag()); - } - - public void test_LDA_DoesNotSetZeroFlagIfResultNotZero() { - bus.write(0x0200, 0xa9); - bus.write(0x0201, 0x12); - cpu.step(); - assertFalse(cpu.getZeroFlag()); - } - - public void test_LDA_SetsNegativeFlagIfResultIsNegative() { - bus.write(0x0200, 0xa9); - bus.write(0x0201, 0x80); - cpu.step(); - assertTrue(cpu.getNegativeFlag()); - } - - public void test_LDA_DoesNotSetNegativeFlagIfResultNotNegative() { - bus.write(0x0200, 0xa9); - bus.write(0x0201, 0x7f); - cpu.step(); - assertFalse(cpu.getNegativeFlag()); - } - - /* CPY Immediate Mode Tests - 0xc0 */ - - /* CMP Immediate Mode Tests - 0xc9 */ - - /* CPX Immediate Mode Tests - 0xe0 */ - - /* SBC Immediate Mode Tests - 0xe9 */ -}