diff --git a/src/main/java/com/loomcom/lm6502/Cpu.java b/src/main/java/com/loomcom/lm6502/Cpu.java index f992c93..f23f5ee 100644 --- a/src/main/java/com/loomcom/lm6502/Cpu.java +++ b/src/main/java/com/loomcom/lm6502/Cpu.java @@ -27,6 +27,7 @@ public class Cpu implements InstructionTable { /* Status Flag Register bits */ private boolean carryFlag; + private boolean negativeFlag; private boolean zeroFlag; private boolean irqDisableFlag; private boolean decimalModeFlag; @@ -435,13 +436,15 @@ public class Cpu implements InstructionTable { case 0xa0: // LDY - Immediate y = operands[0]; - // TODO: Set Zero Flag, Negative Flag + setZeroFlag(y); + setNegativeFlag(y); break; case 0xa1: // n/a break; case 0xa2: // LDX - Immediate x = operands[0]; - // TODO: Set Zero Flag, Negative Flag + setZeroFlag(x); + setNegativeFlag(x); break; case 0xa3: // n/a break; @@ -457,7 +460,8 @@ public class Cpu implements InstructionTable { break; case 0xa9: // LDA - Immediate a = operands[0]; - // TODO: Set Zero Flag, Negative Flag + setZeroFlag(a); + setNegativeFlag(a); break; case 0xaa: // n/a break; @@ -643,8 +647,21 @@ public class Cpu implements InstructionTable { * @return the negative flag */ public boolean getNegativeFlag() { - // True if the most significant bit is '1' - return ((a>>>7)&0xff) == 1; + return negativeFlag; + } + + /** + * @param register the register value to test for negativity + */ + public void setNegativeFlag(int register) { + this.negativeFlag = (((register>>>7)&0xff) == 1); + } + + /** + * @param negativeFlag the negative flag to set + */ + public void setNegativeFlag(boolean negativeFlag) { + this.negativeFlag = negativeFlag; } /** @@ -668,6 +685,13 @@ public class Cpu implements InstructionTable { return zeroFlag; } + /** + * @param register the register to test for zero + */ + public void setZeroFlag(int register) { + this.zeroFlag = (register == 0); + } + /** * @param zeroFlag the zero flag to set */ @@ -731,6 +755,22 @@ public class Cpu implements InstructionTable { 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. */ @@ -751,12 +791,13 @@ public class Cpu implements InstructionTable { */ public String toString() { String opcode = CpuUtils.opcode(ir, operands[0], operands[1]); - StringBuffer sb = new StringBuffer(String.format("$%04X", addr) + " "); - sb.append(String.format("%-12s", opcode)); - sb.append("A=" + String.format("$%02X", a) + "; "); - sb.append("X=" + String.format("$%02X", x) + "; "); - sb.append("Y=" + String.format("$%02X", y) + "; "); - sb.append("PC=" + String.format("$%04X", pc)+ "; "); + StringBuffer sb = new StringBuffer(String.format("$%04X", addr) + + " "); + sb.append(String.format("%-14s", opcode)); + sb.append("A=" + String.format("$%02X", a) + " "); + sb.append("X=" + String.format("$%02X", x) + " "); + sb.append("Y=" + String.format("$%02X", y) + " "); + sb.append("PC=" + String.format("$%04X", pc)+ " "); sb.append("P=" + statusRegisterString()); return sb.toString(); } diff --git a/src/main/java/com/loomcom/lm6502/CpuUtils.java b/src/main/java/com/loomcom/lm6502/CpuUtils.java index 9f187e6..a6b4cec 100644 --- a/src/main/java/com/loomcom/lm6502/CpuUtils.java +++ b/src/main/java/com/loomcom/lm6502/CpuUtils.java @@ -20,7 +20,7 @@ public class CpuUtils { */ public static String opcode(int opcode, int op1, int op2) { String opcodeName = Cpu.opcodeNames[opcode]; - if (opcodeName == null) { return "??"; } + if (opcodeName == null) { return "???"; } StringBuffer sb = new StringBuffer(opcodeName); diff --git a/src/main/java/com/loomcom/lm6502/Simulator.java b/src/main/java/com/loomcom/lm6502/Simulator.java index adf9ce7..7bd8a83 100644 --- a/src/main/java/com/loomcom/lm6502/Simulator.java +++ b/src/main/java/com/loomcom/lm6502/Simulator.java @@ -65,23 +65,30 @@ public class Simulator { bus.write(0x0306, 0x1a); bus.write(0x0307, 0xea); // NOP bus.write(0x0308, 0xea); // NOP - bus.write(0x0309, 0xa2); // LDX #$03 - bus.write(0x030a, 0x03); + bus.write(0x0309, 0xa2); // LDX #$90 + bus.write(0x030a, 0x90); - bus.write(0x030b, 0xa9); // LDA #$00 - bus.write(0x030c, 0x00); - bus.write(0x030d, 0xa2); // LDX #$00 - bus.write(0x030e, 0x00); - bus.write(0x030f, 0xa0); // LDY #$00 - bus.write(0x0310, 0x00); + bus.write(0x030b, 0xea); // NOP + bus.write(0x030c, 0xea); // NOP + bus.write(0x030d, 0xea); // NOP + + bus.write(0x030e, 0xa2); // LDX #$02 + bus.write(0x030f, 0x02); + + bus.write(0x0310, 0xa9); // LDA #$00 + bus.write(0x0311, 0x00); + bus.write(0x0312, 0xa2); // LDX #$00 + bus.write(0x0313, 0x00); + bus.write(0x0314, 0xa0); // LDY #$00 + bus.write(0x0315, 0x00); - bus.write(0x0311, 0x4c); // JMP #$0300 - bus.write(0x0312, 0x00); - bus.write(0x0313, 0x03); + bus.write(0x0316, 0x4c); // JMP #$0300 + bus.write(0x0317, 0x00); + bus.write(0x0318, 0x03); cpu.reset(); - for (int i = 0; i <= 23; i++) { + for (int i = 0; i <= 40; i++) { cpu.step(); System.out.println(cpu.toString()); } diff --git a/src/test/java/com/loomcom/lm6502/CpuTest.java b/src/test/java/com/loomcom/lm6502/CpuTest.java index 29aab1e..580cab3 100644 --- a/src/test/java/com/loomcom/lm6502/CpuTest.java +++ b/src/test/java/com/loomcom/lm6502/CpuTest.java @@ -2,11 +2,18 @@ package com.loomcom.lm6502; import junit.framework.*; +import com.loomcom.lm6502.devices.*; +import com.loomcom.lm6502.exceptions.*; + /** * */ public class CpuTest extends TestCase { + private Cpu cpu; + private Bus bus; + private Memory mem; + public CpuTest(String testName) { super(testName); } @@ -14,10 +21,143 @@ public class CpuTest extends TestCase { public static Test suite() { return new TestSuite(CpuTest.class); } + + 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(new Memory(0x0000, 0x10000)); - public void testCpu() { - Cpu cpu = new Cpu(); - assertNotNull(cpu); + // All test programs start at 0x0200; + bus.write(0xfffc, 0x00); + bus.write(0xfffd, 0x02); + + cpu.reset(); + } + + public void testReset() { + assertEquals(0, cpu.getAccumulator()); + assertEquals(0, cpu.getXRegister()); + assertEquals(0, cpu.getYRegister()); + assertEquals(0x0200, cpu.getProgramCounter()); + assertFalse(cpu.getCarryFlag()); + assertFalse(cpu.getZeroFlag()); + assertFalse(cpu.getIrqDisableFlag()); + assertFalse(cpu.getDecimalModeFlag()); + assertFalse(cpu.getBreakFlag()); + assertFalse(cpu.getOverflowFlag()); + assertFalse(cpu.getNegativeFlag()); + } + + /* LDA Immediate Mode Tests - 0xa9 */ + + public void test_LDA_IMM_SetsAccumulator() { + bus.write(0x0200, 0xa9); + bus.write(0x0201, 0x12); + cpu.step(); + assertEquals(0x12, cpu.getAccumulator()); + } + + public void test_LDA_IMM_SetsZeroFlagIfArgIsZero() { + bus.write(0x0200, 0xa9); + bus.write(0x0201, 0x00); + cpu.step(); + assertTrue(cpu.getZeroFlag()); } + public void test_LDA_IMM_DoesNotSetZeroFlagIfArgNotZero() { + bus.write(0x0200, 0xa9); + bus.write(0x0201, 0x12); + cpu.step(); + assertFalse(cpu.getZeroFlag()); + } + + public void test_LDA_IMM_SetsNegativeFlagIfArgIsNegative() { + bus.write(0x0200, 0xa9); + bus.write(0x0201, 0x80); + cpu.step(); + assertTrue(cpu.getNegativeFlag()); + } + + public void test_LDA_IMM_DoesNotSetNegativeFlagIfArgNotNegative() { + bus.write(0x0200, 0xa9); + bus.write(0x0201, 0x7f); + cpu.step(); + assertFalse(cpu.getNegativeFlag()); + } + + /* LDX Immediate Mode Tests - 0xa2 */ + + public void test_LDX_IMM_SetsXRegister() { + bus.write(0x0200, 0xa2); + bus.write(0x0201, 0x12); + cpu.step(); + assertEquals(0x12, cpu.getXRegister()); + } + + public void test_LDX_IMM_SetsZeroFlagIfArgIsZero() { + bus.write(0x0200, 0xa2); + bus.write(0x0201, 0x00); + cpu.step(); + assertTrue(cpu.getZeroFlag()); + } + + public void test_LDX_IMM_DoesNotSetZeroFlagIfArgNotZero() { + bus.write(0x0200, 0xa2); + bus.write(0x0201, 0x12); + cpu.step(); + assertFalse(cpu.getZeroFlag()); + } + + public void test_LDX_IMM_SetsNegativeFlagIfArgIsNegative() { + bus.write(0x0200, 0xa2); + bus.write(0x0201, 0x80); + cpu.step(); + assertTrue(cpu.getNegativeFlag()); + } + + public void test_LDX_IMM_DoesNotSetNegativeFlagIfArgNotNegative() { + bus.write(0x0200, 0xa2); + bus.write(0x0201, 0x7f); + cpu.step(); + assertFalse(cpu.getNegativeFlag()); + } + + /* LDY Immediate Mode Tests - 0xa0 */ + + public void test_LDY_IMM_SetsYRegister() { + bus.write(0x0200, 0xa0); + bus.write(0x0201, 0x12); + cpu.step(); + assertEquals(0x12, cpu.getYRegister()); + } + + public void test_LDY_IMM_SetsZeroFlagIfArgIsZero() { + bus.write(0x0200, 0xa0); + bus.write(0x0201, 0x00); + cpu.step(); + assertTrue(cpu.getZeroFlag()); + } + + public void test_LDY_IMM_DoesNotSetZeroFlagIfArgNotZero() { + bus.write(0x0200, 0xa0); + bus.write(0x0201, 0x12); + cpu.step(); + assertFalse(cpu.getZeroFlag()); + } + + public void test_LDY_IMM_SetsNegativeFlagIfArgIsNegative() { + bus.write(0x0200, 0xa0); + bus.write(0x0201, 0x80); + cpu.step(); + assertTrue(cpu.getNegativeFlag()); + } + + public void test_LDY_IMM_DoesNotSetNegativeFlagIfArgNotNegative() { + bus.write(0x0200, 0xa0); + bus.write(0x0201, 0x7f); + cpu.step(); + assertFalse(cpu.getNegativeFlag()); + } } \ No newline at end of file