Bug Fixes and Copyright Date Change

The simulator now passes Klaus Dormann's 6502 Functional Test suite for
the first time.

Bug Fixes:

- PHP was not correctly setting the Break bit on the stack copy of the
  processor status, so subsequent PLA's would not set the Break status
  flag.

- The CPU had swapped NMI and IRQ reset vectors, so RTI was failing.

- BRK was pushing PC + 2 onto the stack, instead of PC + 1

- (Zero Page,X) addressing mode did not correctly wrap on zero page
  boundaries.

- The instruction table used for disassembly had addressing modes
  of LDA $B9 and $BD reversed. This did not affect behavior, only
  disassembly of these instructions.

Other:

- Updated copyright date for 2013.

- Started migrating old JUnit 3 style tests to JUnit 4 annotations.
This commit is contained in:
Seth Morabito committed 2013-01-01 17:03:16 -08:00
1 parent 92b61e4839
commit da8250778e
25 files changed
+323 -130

No files matched your search

@@ -3,14 +3,17 @@ package com.loomcom.symon;
import com.loomcom.symon.devices.Memory;
import com.loomcom.symon.exceptions.MemoryAccessException;
import com.loomcom.symon.exceptions.MemoryRangeException;
import junit.framework.*;
import org.junit.*;
public class CpuImpliedModeTest extends TestCase {
import static org.junit.Assert.*;
protected Cpu cpu;
protected Bus bus;
public class CpuImpliedModeTest {
protected Cpu cpu;
protected Bus bus;
protected Memory mem;
@Before
public void setUp() throws MemoryRangeException, MemoryAccessException {
this.cpu = new Cpu();
this.bus = new Bus(0x0000, 0xffff);
@@ -33,42 +36,43 @@ public class CpuImpliedModeTest extends TestCase {
assertEquals(0x20, cpu.getProcessorStatus());
}
/*
* The following opcodes are tested for correctness in this file:
*
* BRK - $00
* CLC - $18
* CLD - $d8
* CLI - $58
* CLV - $B8
*
* DEX - $ca
* DEY - $88
* INX - $e8
* INY - $c8
* NOP - $ea
*
* PHA - $48
* PHP - $08
* PLA - $68
* PLP - $28
* RTI - $40
*
* RTS - $60
* SEC - $38
* SED - $f8
* SEI - $78
* TAX - $aa
*
* TAY - $a8
* TSX - $ba
* TXA - $8a
* TXS - $9a
* TYA - $98
*/
/*
* The following opcodes are tested for correctness in this file:
*
* BRK - $00
* CLC - $18
* CLD - $d8
* CLI - $58
* CLV - $B8
*
* DEX - $ca
* DEY - $88
* INX - $e8
* INY - $c8
* NOP - $ea
*
* PHA - $48
* PHP - $08
* PLA - $68
* PLP - $28
* RTI - $40
*
* RTS - $60
* SEC - $38
* SED - $f8
* SEI - $78
* TAX - $aa
*
* TAY - $a8
* TSX - $ba
* TXA - $8a
* TXS - $9a
* TYA - $98
*/
/* BRK Tests - 0x00 */
/* BRK Tests - 0x00 */
@Test
public void test_BRK() throws MemoryAccessException {
cpu.setCarryFlag();
cpu.setOverflowFlag();
@@ -80,15 +84,15 @@ public class CpuImpliedModeTest extends TestCase {
assertEquals(0xff, cpu.getStackPointer());
// Set the IRQ vector
bus.write(Cpu.IRQ_VECTOR_H, 0x12);
bus.write(Cpu.IRQ_VECTOR_L, 0x34);
bus.write(0xffff, 0x12);
bus.write(0xfffe, 0x34);
bus.loadProgram(0xea,
0xea,
0xea,
0x00,
0xea,
0xea);
bus.loadProgram(0xea, // NOP
0xea, // NOP
0xea, // NOP
0x00, // BRK
0xea, // NOP
0xea); // NOP
cpu.step(3); // Three NOP instructions
@@ -96,9 +100,9 @@ public class CpuImpliedModeTest extends TestCase {
cpu.step(); // Triggers the BRK
// Was at PC = 0x204. PC+2 should now be on the stack
// Was at PC = 0x204. PC+1 should now be on the stack
assertEquals(0x02, bus.read(0x1ff)); // PC high byte
assertEquals(0x06, bus.read(0x1fe)); // PC low byte
assertEquals(0x05, bus.read(0x1fe)); // PC low byte
assertEquals(0x20 | Cpu.P_CARRY | Cpu.P_OVERFLOW | Cpu.P_BREAK,
bus.read(0x1fd)); // Processor Status, with B set
@@ -108,10 +112,11 @@ public class CpuImpliedModeTest extends TestCase {
// B and I flags should have been set on P
assertEquals(0x20 | Cpu.P_CARRY | Cpu.P_OVERFLOW | Cpu.P_BREAK |
Cpu.P_IRQ_DISABLE,
Cpu.P_IRQ_DISABLE,
cpu.getProcessorStatus());
}
@Test
public void test_BRK_HonorsIrqDisableFlag() throws MemoryAccessException {
cpu.setIrqDisableFlag();
@@ -144,6 +149,7 @@ public class CpuImpliedModeTest extends TestCase {
}
/* CLC - Clear Carry Flag - $18 */
@Test
public void test_CLC() throws MemoryAccessException {
cpu.setCarryFlag();
assertTrue(cpu.getCarryFlag());
@@ -155,6 +161,7 @@ public class CpuImpliedModeTest extends TestCase {
}
/* CLD - Clear Decimal Mode Flag - $d8 */
@Test
public void test_CLD() throws MemoryAccessException {
cpu.setDecimalModeFlag();
assertTrue(cpu.getDecimalModeFlag());
@@ -166,6 +173,7 @@ public class CpuImpliedModeTest extends TestCase {
}
/* CLI - Clear Interrupt Disabled Flag - $58 */
@Test
public void test_CLI() throws MemoryAccessException {
cpu.setIrqDisableFlag();
assertTrue(cpu.getIrqDisableFlag());
@@ -177,6 +185,7 @@ public class CpuImpliedModeTest extends TestCase {
}
/* CLV - Clear Overflow Flag - $b8 */
@Test
public void test_CLV() throws MemoryAccessException {
cpu.setOverflowFlag();
assertTrue(cpu.getOverflowFlag());
@@ -187,8 +196,8 @@ public class CpuImpliedModeTest extends TestCase {
assertFalse(cpu.getOverflowFlag());
}
/* DEX - Decrement the X register - $ca */
/* DEX - Decrement the X register - $ca */
@Test
public void test_DEX() throws MemoryAccessException {
bus.loadProgram(0xca);
cpu.setXRegister(0x02);
@@ -198,6 +207,7 @@ public class CpuImpliedModeTest extends TestCase {
assertFalse(cpu.getNegativeFlag());
}
@Test
public void test_DEX_SetsZeroFlagWhenZero() throws MemoryAccessException {
bus.loadProgram(0xca);
cpu.setXRegister(0x01);
@@ -207,6 +217,7 @@ public class CpuImpliedModeTest extends TestCase {
assertFalse(cpu.getNegativeFlag());
}
@Test
public void test_DEX_SetsNegativeFlagWhen() throws MemoryAccessException {
bus.loadProgram(0xca);
cpu.step();
@@ -215,8 +226,8 @@ public class CpuImpliedModeTest extends TestCase {
assertTrue(cpu.getNegativeFlag());
}
/* DEY - Decrement the Y register - $88 */
/* DEY - Decrement the Y register - $88 */
@Test
public void test_DEY() throws MemoryAccessException {
bus.loadProgram(0x88);
cpu.setYRegister(0x02);
@@ -226,6 +237,7 @@ public class CpuImpliedModeTest extends TestCase {
assertFalse(cpu.getNegativeFlag());
}
@Test
public void test_DEY_SetsZeroFlagWhenZero() throws MemoryAccessException {
bus.loadProgram(0x88);
cpu.setYRegister(0x01);
@@ -235,6 +247,7 @@ public class CpuImpliedModeTest extends TestCase {
assertFalse(cpu.getNegativeFlag());
}
@Test
public void test_DEY_SetsNegativeFlagWhen() throws MemoryAccessException {
bus.loadProgram(0x88);
cpu.step();
@@ -243,8 +256,8 @@ public class CpuImpliedModeTest extends TestCase {
assertTrue(cpu.getNegativeFlag());
}
/* INX - Increment the X register - $e8 */
/* INX - Increment the X register - $e8 */
@Test
public void test_INX() throws MemoryAccessException {
bus.loadProgram(0xe8);
cpu.step();
@@ -253,6 +266,7 @@ public class CpuImpliedModeTest extends TestCase {
assertFalse(cpu.getNegativeFlag());
}
@Test
public void test_INX_SetsNegativeFlagWhenNegative() throws MemoryAccessException {
bus.loadProgram(0xe8);
cpu.setXRegister(0x7f);
@@ -262,6 +276,7 @@ public class CpuImpliedModeTest extends TestCase {
assertTrue(cpu.getNegativeFlag());
}
@Test
public void test_INX_SetsZeroFlagWhenZero() throws MemoryAccessException {
bus.loadProgram(0xe8);
cpu.setXRegister(0xff);
@@ -271,8 +286,8 @@ public class CpuImpliedModeTest extends TestCase {
assertFalse(cpu.getNegativeFlag());
}
/* INY - Increment the Y register - $c8 */
/* INY - Increment the Y register - $c8 */
@Test
public void test_INY() throws MemoryAccessException {
bus.loadProgram(0xc8);
cpu.step();
@@ -281,6 +296,7 @@ public class CpuImpliedModeTest extends TestCase {
assertFalse(cpu.getNegativeFlag());
}
@Test
public void test_INY_SetsNegativeFlagWhenNegative() throws MemoryAccessException {
bus.loadProgram(0xc8);
cpu.setYRegister(0x7f);
@@ -290,6 +306,7 @@ public class CpuImpliedModeTest extends TestCase {
assertTrue(cpu.getNegativeFlag());
}
@Test
public void test_INY_SetsZeroFlagWhenZero() throws MemoryAccessException {
bus.loadProgram(0xc8);
cpu.setYRegister(0xff);
@@ -299,8 +316,8 @@ public class CpuImpliedModeTest extends TestCase {
assertFalse(cpu.getNegativeFlag());
}
/* NOP - No Operation - $ea */
/* NOP - No Operation - $ea */
@Test
public void test_NOP() throws MemoryAccessException {
bus.loadProgram(0xea);
cpu.step();
@@ -313,8 +330,8 @@ public class CpuImpliedModeTest extends TestCase {
assertEquals(0x20, cpu.getProcessorStatus());
}
/* PHA - Push Accumulator - $48 */
/* PHA - Push Accumulator - $48 */
@Test
public void test_PHA() throws MemoryAccessException {
bus.loadProgram(0x48);
cpu.setAccumulator(0x3a);
@@ -323,18 +340,20 @@ public class CpuImpliedModeTest extends TestCase {
assertEquals(0x3a, cpu.stackPeek());
}
/* PHP - Push Processor Status - $08 */
/* PHP - Push Processor Status - $08 */
@Test
public void test_PHP() throws MemoryAccessException {
bus.loadProgram(0x08);
cpu.setProcessorStatus(0x27);
cpu.step();
assertEquals(0xfe, cpu.getStackPointer());
assertEquals(0x27, cpu.stackPeek());
// PHP should have set the BREAK flag _on the stack_ (but not in the CPU)
assertEquals(0x37, cpu.stackPeek());
assertEquals(0x27, cpu.getProcessorStatus());
}
/* PLA - Pul Accumulator - $68 */
/* PLA - Pul Accumulator - $68 */
@Test
public void test_PLA() throws MemoryAccessException {
cpu.stackPush(0x32);
bus.loadProgram(0x68);
@@ -344,6 +363,7 @@ public class CpuImpliedModeTest extends TestCase {
assertFalse(cpu.getZeroFlag());
}
@Test
public void test_PLA_SetsZeroIfAccumulatorIsZero() throws MemoryAccessException {
cpu.stackPush(0x00);
bus.loadProgram(0x68);
@@ -353,6 +373,7 @@ public class CpuImpliedModeTest extends TestCase {
assertTrue(cpu.getZeroFlag());
}
@Test
public void test_PLA_SetsNegativeIfAccumulatorIsNegative() throws MemoryAccessException {
cpu.stackPush(0xff);
bus.loadProgram(0x68);
@@ -362,8 +383,8 @@ public class CpuImpliedModeTest extends TestCase {
assertFalse(cpu.getZeroFlag());
}
/* PLP - Pull Processor Status - $28 */
/* PLP - Pull Processor Status - $28 */
@Test
public void test_PLP() throws MemoryAccessException {
cpu.stackPush(0x2f);
bus.loadProgram(0x28);
@@ -371,8 +392,8 @@ public class CpuImpliedModeTest extends TestCase {
assertEquals(0x2f, cpu.getProcessorStatus());
}
/* RTI - Return from Interrupt - $40 */
/* RTI - Return from Interrupt - $40 */
@Test
public void test_RTI() throws MemoryAccessException {
cpu.stackPush(0x0f); // PC hi
cpu.stackPush(0x11); // PC lo
@@ -385,8 +406,8 @@ public class CpuImpliedModeTest extends TestCase {
assertEquals(0x29, cpu.getProcessorStatus());
}
/* RTS - Return from Subroutine - $60 */
/* RTS - Return from Subroutine - $60 */
@Test
public void test_RTS() throws MemoryAccessException {
cpu.stackPush(0x0f); // PC hi
cpu.stackPush(0x11); // PC lo
@@ -398,32 +419,32 @@ public class CpuImpliedModeTest extends TestCase {
assertEquals(0x20, cpu.getProcessorStatus());
}
/* SEC - Set Carry Flag - $38 */
/* SEC - Set Carry Flag - $38 */
@Test
public void test_SEC() throws MemoryAccessException {
bus.loadProgram(0x38);
cpu.step();
assertTrue(cpu.getCarryFlag());
}
/* SED - Set Decimal Mode Flag - $f8 */
/* SED - Set Decimal Mode Flag - $f8 */
@Test
public void test_SED() throws MemoryAccessException {
bus.loadProgram(0xf8);
cpu.step();
assertTrue(cpu.getDecimalModeFlag());
}
/* SEI - Set Interrupt Disable Flag - $78 */
/* SEI - Set Interrupt Disable Flag - $78 */
@Test
public void test_SEI() throws MemoryAccessException {
bus.loadProgram(0x78);
cpu.step();
assertTrue(cpu.getIrqDisableFlag());
}
/* TAX - Transfer Accumulator to X Register - $aa */
/* TAX - Transfer Accumulator to X Register - $aa */
@Test
public void test_TAX() throws MemoryAccessException {
cpu.setAccumulator(0x32);
bus.loadProgram(0xaa);
@@ -433,6 +454,7 @@ public class CpuImpliedModeTest extends TestCase {
assertFalse(cpu.getNegativeFlag());
}
@Test
public void test_TAX_SetsZeroFlagIfXIsZero() throws MemoryAccessException {
cpu.setAccumulator(0x00);
bus.loadProgram(0xaa);
@@ -442,6 +464,7 @@ public class CpuImpliedModeTest extends TestCase {
assertFalse(cpu.getNegativeFlag());
}
@Test
public void test_TAX_SetsNegativeFlagIfXIsNegative() throws MemoryAccessException {
cpu.setAccumulator(0xff);
bus.loadProgram(0xaa);
@@ -451,8 +474,8 @@ public class CpuImpliedModeTest extends TestCase {
assertTrue(cpu.getNegativeFlag());
}
/* TAY - Transfer Accumulator to Y Register - $a8 */
/* TAY - Transfer Accumulator to Y Register - $a8 */
@Test
public void test_TAY() throws MemoryAccessException {
cpu.setAccumulator(0x32);
bus.loadProgram(0xa8);
@@ -462,6 +485,7 @@ public class CpuImpliedModeTest extends TestCase {
assertFalse(cpu.getNegativeFlag());
}
@Test
public void test_TAY_SetsZeroFlagIfYIsZero() throws MemoryAccessException {
cpu.setAccumulator(0x00);
bus.loadProgram(0xa8);
@@ -471,6 +495,7 @@ public class CpuImpliedModeTest extends TestCase {
assertFalse(cpu.getNegativeFlag());
}
@Test
public void test_TAY_SetsNegativeFlagIfYIsNegative() throws MemoryAccessException {
cpu.setAccumulator(0xff);
bus.loadProgram(0xa8);
@@ -480,8 +505,8 @@ public class CpuImpliedModeTest extends TestCase {
assertTrue(cpu.getNegativeFlag());
}
/* TSX - Transfer Stack Pointer to X Register - $ba */
/* TSX - Transfer Stack Pointer to X Register - $ba */
@Test
public void test_TSX() throws MemoryAccessException {
cpu.setStackPointer(0x32);
bus.loadProgram(0xba);
@@ -491,6 +516,7 @@ public class CpuImpliedModeTest extends TestCase {
assertFalse(cpu.getNegativeFlag());
}
@Test
public void test_TSX_SetsZeroFlagIfXIsZero() throws MemoryAccessException {
cpu.setStackPointer(0x00);
bus.loadProgram(0xba);
@@ -500,6 +526,7 @@ public class CpuImpliedModeTest extends TestCase {
assertFalse(cpu.getNegativeFlag());
}
@Test
public void test_TSX_SetsNegativeFlagIfXIsNegative() throws MemoryAccessException {
cpu.setStackPointer(0xff);
bus.loadProgram(0xba);
@@ -509,8 +536,8 @@ public class CpuImpliedModeTest extends TestCase {
assertTrue(cpu.getNegativeFlag());
}
/* TXA - Transfer X Register to Accumulator - $8a */
/* TXA - Transfer X Register to Accumulator - $8a */
@Test
public void test_TXA() throws MemoryAccessException {
cpu.setXRegister(0x32);
bus.loadProgram(0x8a);
@@ -520,6 +547,7 @@ public class CpuImpliedModeTest extends TestCase {
assertFalse(cpu.getNegativeFlag());
}
@Test
public void test_TXA_SetsZeroFlagIfAccumulatorIsZero() throws MemoryAccessException {
cpu.setXRegister(0x00);
bus.loadProgram(0x8a);
@@ -529,6 +557,7 @@ public class CpuImpliedModeTest extends TestCase {
assertFalse(cpu.getNegativeFlag());
}
@Test
public void test_TXA_SetsNegativeFlagIfAccumulatorIsNegative() throws MemoryAccessException {
cpu.setXRegister(0xff);
bus.loadProgram(0x8a);
@@ -538,8 +567,8 @@ public class CpuImpliedModeTest extends TestCase {
assertTrue(cpu.getNegativeFlag());
}
/* TXS - Transfer X Register to Stack Pointer - $9a */
/* TXS - Transfer X Register to Stack Pointer - $9a */
@Test
public void test_TXS() throws MemoryAccessException {
cpu.setXRegister(0x32);
bus.loadProgram(0x9a);
@@ -549,6 +578,7 @@ public class CpuImpliedModeTest extends TestCase {
assertFalse(cpu.getNegativeFlag());
}
@Test
public void test_TXS_DoesNotAffectProcessorStatus() throws MemoryAccessException {
cpu.setXRegister(0x00);
bus.loadProgram(0x9a);
@@ -565,8 +595,8 @@ public class CpuImpliedModeTest extends TestCase {
assertFalse(cpu.getNegativeFlag());
}
/* TYA - Transfer Y Register to Accumulator - $98 */
/* TYA - Transfer Y Register to Accumulator - $98 */
@Test
public void test_TYA() throws MemoryAccessException {
cpu.setYRegister(0x32);
bus.loadProgram(0x98);
@@ -576,6 +606,7 @@ public class CpuImpliedModeTest extends TestCase {
assertFalse(cpu.getNegativeFlag());
}
@Test
public void test_TYA_SetsZeroFlagIfAccumulatorIsZero() throws MemoryAccessException {
cpu.setYRegister(0x00);
bus.loadProgram(0x98);
@@ -585,6 +616,7 @@ public class CpuImpliedModeTest extends TestCase {
assertFalse(cpu.getNegativeFlag());
}
@Test
public void test_TYA_SetsNegativeFlagIfAccumulatorIsNegative() throws MemoryAccessException {
cpu.setYRegister(0xff);
bus.loadProgram(0x98);
@@ -593,5 +625,4 @@ public class CpuImpliedModeTest extends TestCase {
assertFalse(cpu.getZeroFlag());
assertTrue(cpu.getNegativeFlag());
}
}
@@ -48,6 +48,32 @@ public class CpuIndexedIndirectModeTest {
assertEquals(0x45, cpu.getAccumulator());
}
@Test
public void testZeroPageWrap() throws Exception {
bus.write(0x0020, 0x01);
bus.write(0x0021, 0x07); // ($0701)
bus.write(0x0701, 0xaa);
bus.write(0x000f, 0x02);
bus.write(0x0010, 0x08); // ($0802)
bus.write(0x0802, 0xbb);
bus.write(0x010f, 0x03);
bus.write(0x0110, 0x09); // ($0903)
bus.write(0x0903, 0xcc);
cpu.setXRegister(0x10);
// No wrap needed
bus.loadProgram(0xa1, 0x10, // LDA ($10,X) = ($10 + $10) & $ff = $20
0xa1, 0xff); // LDA ($ff,X) = ($ff + $10) & $ff = $0f, NOT $10f!
cpu.step(1);
assertEquals(0xaa, cpu.getAccumulator());
cpu.step(1);
assertEquals(0xbb, cpu.getAccumulator());
}
@Test
public void test_ORA() throws Exception {
bus.write(0x0012, 0x1f);