mirror of
https://github.com/sethm/symon.git
synced 2024-06-02 14:41:33 +00:00
b5a470d3ba
When describing the CPU's reset pin, the W65C02S data sheet says: > All Registers are initialized by software except the Decimal and Interrupt > disable mode select bits of the Processor Status Register (P) are initialized > by hardware. It then has a diagram of the power-on state of the processor status register: > 7 6 5 4 3 2 1 0 > * * 1 1 0 1 * * > N V - B D I Z C > > * = software initialized Confusingly the text indicates that only the D and I flags are initialised by hardware, while the diagram indicates that the B flag is initialised too. Meanwhile, https://www.nesdev.org/wiki/CPU_power_up_state says that the power-on state of the NES CPU is $34 (exactly matching the diagram above) but https://www.nesdev.org/wiki/Status_flags#The_B_flag says that the B flag does not physically exist within P register, it's only relevant in the copy of P that gets pushed to the stack by BRK (set), PHP (set), or an interrupt signal (cleared). As a result, the most sensible power-on state for the processor status register is with the "interrupt disable" flag set and everything else cleared.
863 lines
28 KiB
Java
863 lines
28 KiB
Java
package com.loomcom.symon;
|
|
|
|
import com.loomcom.symon.devices.Memory;
|
|
import com.loomcom.symon.exceptions.*;
|
|
|
|
import junit.framework.*;
|
|
|
|
public class CpuImmediateModeTest extends TestCase {
|
|
|
|
protected Cpu cpu;
|
|
protected Bus bus;
|
|
protected Memory mem;
|
|
|
|
public void setUp() throws MemoryRangeException, MemoryAccessException {
|
|
this.cpu = new Cpu();
|
|
this.bus = new Bus(0x0000, 0xffff);
|
|
this.mem = new Memory(0x0000, 0xffff);
|
|
bus.addCpu(cpu);
|
|
bus.addDevice(mem);
|
|
|
|
// Load the reset vector.
|
|
bus.write(0xfffc, Bus.DEFAULT_LOAD_ADDRESS & 0x00ff);
|
|
bus.write(0xfffd, (Bus.DEFAULT_LOAD_ADDRESS & 0xff00) >>> 8);
|
|
|
|
cpu.reset();
|
|
// Assert initial state
|
|
assertEquals(0, cpu.getAccumulator());
|
|
assertEquals(0, cpu.getXRegister());
|
|
assertEquals(0, cpu.getYRegister());
|
|
assertEquals(0x200, cpu.getProgramCounter());
|
|
assertEquals(0xff, cpu.getStackPointer());
|
|
assertEquals(0x24, cpu.getProcessorStatus());
|
|
}
|
|
|
|
/*
|
|
* The following opcodes are tested for correctness in this file:
|
|
*
|
|
* ORA - $09
|
|
* AND - $29
|
|
* EOR - $49
|
|
* ADC - $69
|
|
* LDY - $a0
|
|
*
|
|
* LDX - $a2
|
|
* LDA - $a9
|
|
* CPY - $c0
|
|
* CMP - $c9
|
|
* CPX - $e0
|
|
*
|
|
* SBC - $e9
|
|
*/
|
|
|
|
/* ORA Immediate Mode Tests - 0x09 */
|
|
|
|
public void test_ORA() throws MemoryAccessException {
|
|
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() throws MemoryAccessException {
|
|
bus.loadProgram(0x09, 0x00); // ORA #$00
|
|
cpu.step();
|
|
assertTrue(cpu.getZeroFlag());
|
|
}
|
|
|
|
public void test_ORA_DoesNotSetZeroFlagIfResultNotZero() throws MemoryAccessException {
|
|
bus.loadProgram(0x09, 0x01); // ORA #$01
|
|
cpu.step();
|
|
assertFalse(cpu.getZeroFlag());
|
|
}
|
|
|
|
public void test_ORA_SetsNegativeFlagIfResultIsNegative() throws MemoryAccessException {
|
|
bus.loadProgram(0x09, 0x80); // ORA #$80
|
|
cpu.step();
|
|
assertTrue(cpu.getNegativeFlag());
|
|
}
|
|
|
|
public void test_ORA_DoesNotSetNegativeFlagIfResultNotNegative() throws MemoryAccessException {
|
|
bus.loadProgram(0x09, 0x7f); // ORA #$7F
|
|
cpu.step();
|
|
assertFalse(cpu.getNegativeFlag());
|
|
}
|
|
|
|
/* AND Immediate Mode Tests - 0x29 */
|
|
|
|
public void test_AND() throws MemoryAccessException {
|
|
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() throws MemoryAccessException {
|
|
bus.loadProgram(0xa9, 0x88, // LDA #$88
|
|
0x29, 0x11); // AND #$11
|
|
cpu.step(2);
|
|
assertTrue(cpu.getZeroFlag());
|
|
}
|
|
|
|
public void test_AND_DoesNotSetZeroFlagIfResultNotZero() throws MemoryAccessException {
|
|
bus.loadProgram(0xa9, 0x88, // LDA #$88
|
|
0x29, 0xf1); // AND #$F1
|
|
cpu.step(2);
|
|
assertFalse(cpu.getZeroFlag());
|
|
}
|
|
|
|
public void test_AND_SetsNegativeFlagIfResultIsNegative() throws MemoryAccessException {
|
|
bus.loadProgram(0xa9, 0x88, // LDA #$88
|
|
0x29, 0xf0); // AND #$F0
|
|
cpu.step(2);
|
|
assertTrue(cpu.getNegativeFlag());
|
|
}
|
|
|
|
public void test_AND_DoesNotSetNegativeFlagIfResultNotNegative() throws MemoryAccessException {
|
|
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() throws MemoryAccessException {
|
|
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() throws MemoryAccessException {
|
|
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() throws MemoryAccessException {
|
|
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.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.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.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() throws MemoryAccessException {
|
|
bus.loadProgram(0xa9, 0x00, // LDA #$01
|
|
0x38, // SEC
|
|
0x69, 0x01); // ADC #$01
|
|
cpu.step(3);
|
|
assertEquals(0x02, cpu.getAccumulator());
|
|
assertFalse(cpu.getNegativeFlag());
|
|
assertFalse(cpu.getOverflowFlag());
|
|
assertFalse(cpu.getZeroFlag());
|
|
assertFalse(cpu.getCarryFlag());
|
|
}
|
|
|
|
public void test_ADC_DecimalMode() throws MemoryAccessException {
|
|
bus.loadProgram(0xf8, // SED
|
|
0xa9, 0x01, // LDA #$01
|
|
0x69, 0x01); // ADC #$01
|
|
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
|
|
0x69, 0x01); // ADC #$01
|
|
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
|
|
0x69, 0x01); // ADC #$01
|
|
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
|
|
0x69, 0x01); // ADC #$01
|
|
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
|
|
0x69, 0x99); // ADC #$01
|
|
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
|
|
0x69, 0x99); // ADC #$99
|
|
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
|
|
0x69, 0x99); // ADC #$99
|
|
cpu.step(3);
|
|
assertEquals(0x49, cpu.getAccumulator());
|
|
assertFalse(cpu.getNegativeFlag());
|
|
assertFalse(cpu.getOverflowFlag());
|
|
assertFalse(cpu.getZeroFlag());
|
|
assertTrue(cpu.getCarryFlag());
|
|
}
|
|
|
|
/* LDY Immediate Mode Tests - 0xa0 */
|
|
|
|
public void test_LDY_SetsYRegister() throws MemoryAccessException {
|
|
bus.loadProgram(0xa0, 0x12); // LDY #$12
|
|
cpu.step();
|
|
assertEquals(0x12, cpu.getYRegister());
|
|
}
|
|
|
|
public void test_LDY_SetsZeroFlagIfArgIsZero() throws MemoryAccessException {
|
|
bus.loadProgram(0xa0, 0x00); // LDY #$00
|
|
cpu.step();
|
|
assertTrue(cpu.getZeroFlag());
|
|
}
|
|
|
|
public void test_LDY_DoesNotSetZeroFlagIfResultNotZero() throws MemoryAccessException {
|
|
bus.loadProgram(0xa0, 0x12); // LDY #$12
|
|
cpu.step();
|
|
assertFalse(cpu.getZeroFlag());
|
|
}
|
|
|
|
public void test_LDY_SetsNegativeFlagIfResultIsNegative() throws MemoryAccessException {
|
|
bus.loadProgram(0xa0, 0x80); // LDY #$80
|
|
cpu.step();
|
|
assertTrue(cpu.getNegativeFlag());
|
|
}
|
|
|
|
public void test_LDY_DoesNotSetNegativeFlagIfResultNotNegative() throws MemoryAccessException {
|
|
bus.loadProgram(0xa0, 0x7f); // LDY #$7F
|
|
cpu.step();
|
|
assertFalse(cpu.getNegativeFlag());
|
|
}
|
|
|
|
/* LDX Immediate Mode Tests - 0xa2 */
|
|
|
|
public void test_LDX_SetsXRegister() throws MemoryAccessException {
|
|
bus.loadProgram(0xa2, 0x12); // LDX #$12
|
|
cpu.step();
|
|
assertEquals(0x12, cpu.getXRegister());
|
|
}
|
|
|
|
public void test_LDX_SetsZeroFlagIfResultIsZero() throws MemoryAccessException {
|
|
bus.loadProgram(0xa2, 0x00); // LDX #$00
|
|
cpu.step();
|
|
assertTrue(cpu.getZeroFlag());
|
|
}
|
|
|
|
public void test_LDX_DoesNotSetZeroFlagIfResultNotZero() throws MemoryAccessException {
|
|
bus.loadProgram(0xa2, 0x12); // LDX #$12
|
|
cpu.step();
|
|
assertFalse(cpu.getZeroFlag());
|
|
}
|
|
|
|
public void test_LDX_SetsNegativeFlagIfResultIsNegative() throws MemoryAccessException {
|
|
bus.loadProgram(0xa2, 0x80); // LDX #$80
|
|
cpu.step();
|
|
assertTrue(cpu.getNegativeFlag());
|
|
}
|
|
|
|
public void test_LDX_DoesNotSetNegativeFlagIfResultNotNegative() throws MemoryAccessException {
|
|
bus.loadProgram(0xa2, 0x7f); // LDX #$7F
|
|
cpu.step();
|
|
assertFalse(cpu.getNegativeFlag());
|
|
}
|
|
|
|
/* LDA Immediate Mode Tests - 0xa9 */
|
|
|
|
public void test_LDA_SetsAccumulator() throws MemoryAccessException {
|
|
bus.loadProgram(0xa9, 0x12); // LDA #$12
|
|
cpu.step();
|
|
assertEquals(0x12, cpu.getAccumulator());
|
|
}
|
|
|
|
public void test_LDA_SetsZeroFlagIfResultIsZero() throws MemoryAccessException {
|
|
bus.loadProgram(0xa9, 0x00); // LDA #$00
|
|
cpu.step();
|
|
assertTrue(cpu.getZeroFlag());
|
|
}
|
|
|
|
public void test_LDA_DoesNotSetZeroFlagIfResultNotZero() throws MemoryAccessException {
|
|
bus.loadProgram(0xa9, 0x12); // LDA #$12
|
|
cpu.step();
|
|
assertFalse(cpu.getZeroFlag());
|
|
}
|
|
|
|
public void test_LDA_SetsNegativeFlagIfResultIsNegative() throws MemoryAccessException {
|
|
bus.loadProgram(0xa9, 0x80); // LDA #$80
|
|
cpu.step();
|
|
assertTrue(cpu.getNegativeFlag());
|
|
}
|
|
|
|
public void test_LDA_DoesNotSetNegativeFlagIfResultNotNegative() throws MemoryAccessException {
|
|
bus.loadProgram(0xa9, 0x7f); // LDA #$7F
|
|
cpu.step();
|
|
assertFalse(cpu.getNegativeFlag());
|
|
}
|
|
|
|
/* CPY Immediate Mode Tests - 0xc0 */
|
|
|
|
public void test_CPY_SetsZeroAndCarryFlagsIfNumbersSame() throws MemoryAccessException {
|
|
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() throws MemoryAccessException {
|
|
bus.loadProgram(0xa0, 0x0a, // LDY #$0A
|
|
0xc0, 0x08); // CPY #$08
|
|
cpu.step(2);
|
|
assertTrue(cpu.getCarryFlag());
|
|
assertFalse(cpu.getZeroFlag());
|
|
// $0a - $08 = positive
|
|
assertFalse(cpu.getNegativeFlag());
|
|
|
|
cpu.reset();
|
|
bus.loadProgram(0xa0, 0xfa, // LDY #$FA
|
|
0xc0, 0x80); // CPY #$80
|
|
cpu.step(2);
|
|
assertTrue(cpu.getCarryFlag());
|
|
assertFalse(cpu.getZeroFlag());
|
|
// $fa - 80 = positive
|
|
assertFalse(cpu.getNegativeFlag());
|
|
}
|
|
|
|
public void test_CPY_DoesNotSetCarryFlagIfYLessThanThanMemory() throws MemoryAccessException {
|
|
bus.loadProgram(0xa0, 0x08, // LDY #$08
|
|
0xc0, 0x0a); // CPY #$0A
|
|
cpu.step(2);
|
|
assertFalse(cpu.getCarryFlag());
|
|
assertFalse(cpu.getZeroFlag());
|
|
// 08 - 0a = negative
|
|
assertTrue(cpu.getNegativeFlag());
|
|
|
|
cpu.reset();
|
|
bus.loadProgram(0xa0, 0x70, // LDY #$70
|
|
0xc0, 0x80); // CPY #$80
|
|
cpu.step(2);
|
|
assertFalse(cpu.getCarryFlag());
|
|
assertFalse(cpu.getZeroFlag());
|
|
// $70 - $80 = negative
|
|
assertTrue(cpu.getNegativeFlag());
|
|
}
|
|
|
|
/* CMP Immediate Mode Tests - 0xc9 */
|
|
|
|
public void test_CMP_SetsZeroAndCarryFlagsIfNumbersSame() throws MemoryAccessException {
|
|
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() throws MemoryAccessException {
|
|
bus.loadProgram(0xa9, 0x0a, // LDA #$0A
|
|
0xc9, 0x08); // CMP #$08
|
|
cpu.step(2);
|
|
assertTrue(cpu.getCarryFlag());
|
|
assertFalse(cpu.getZeroFlag());
|
|
// $0a - $08 = positive
|
|
assertFalse(cpu.getNegativeFlag());
|
|
|
|
cpu.reset();
|
|
bus.loadProgram(0xa9, 0xfa, // LDA #$FA
|
|
0xc9, 0x80); // CMP #$80
|
|
cpu.step(2);
|
|
assertTrue(cpu.getCarryFlag());
|
|
assertFalse(cpu.getZeroFlag());
|
|
// $fa - $80 = positive
|
|
assertFalse(cpu.getNegativeFlag());
|
|
}
|
|
|
|
public void test_CMP_DoesNotSetCarryFlagIfYGreaterThanMemory() throws MemoryAccessException {
|
|
bus.loadProgram(0xa9, 0x08, // LDA #$08
|
|
0xc9, 0x0a); // CMP #$0A
|
|
cpu.step(2);
|
|
assertFalse(cpu.getCarryFlag());
|
|
assertFalse(cpu.getZeroFlag());
|
|
// 08 - 0a = negative
|
|
assertTrue(cpu.getNegativeFlag());
|
|
|
|
cpu.reset();
|
|
bus.loadProgram(0xa9, 0x70, // LDA #$70
|
|
0xc9, 0x80); // CMP #$80
|
|
cpu.step(2);
|
|
assertFalse(cpu.getCarryFlag());
|
|
assertFalse(cpu.getZeroFlag());
|
|
// 70 - 80 = negative
|
|
assertTrue(cpu.getNegativeFlag());
|
|
}
|
|
|
|
/* CPX Immediate Mode Tests - 0xe0 */
|
|
|
|
public void test_CPX_SetsZeroAndCarryFlagsIfNumbersSame() throws MemoryAccessException {
|
|
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() throws MemoryAccessException {
|
|
bus.loadProgram(0xa2, 0x0a, // LDX #$0A
|
|
0xe0, 0x08); // CPX #$08
|
|
cpu.step(2);
|
|
assertTrue(cpu.getCarryFlag());
|
|
assertFalse(cpu.getZeroFlag());
|
|
// $0a - $08 = positive
|
|
assertFalse(cpu.getNegativeFlag());
|
|
|
|
cpu.reset();
|
|
bus.loadProgram(0xa2, 0xfa, // LDX #$FA
|
|
0xe0, 0x80); // CPX #$80
|
|
cpu.step(2);
|
|
assertTrue(cpu.getCarryFlag());
|
|
assertFalse(cpu.getZeroFlag());
|
|
// $fa - $80 = positive
|
|
assertFalse(cpu.getNegativeFlag());
|
|
}
|
|
|
|
public void test_CPX_DoesNotSetCarryFlagIfYGreaterThanMemory() throws MemoryAccessException {
|
|
bus.loadProgram(0xa2, 0x08, // LDX #$08
|
|
0xe0, 0x0a); // CPX #$0A
|
|
cpu.step(2);
|
|
assertFalse(cpu.getCarryFlag());
|
|
assertFalse(cpu.getZeroFlag());
|
|
// $08 - $0a = negative
|
|
assertTrue(cpu.getNegativeFlag());
|
|
|
|
cpu.reset();
|
|
bus.loadProgram(0xa2, 0x70, // LDX #$70
|
|
0xe0, 0x80); // CMX #$80
|
|
cpu.step(2);
|
|
assertFalse(cpu.getCarryFlag());
|
|
assertFalse(cpu.getZeroFlag());
|
|
// $70 - $80 = negative
|
|
assertTrue(cpu.getNegativeFlag());
|
|
}
|
|
|
|
/* SBC Immediate Mode Tests - 0xe9 */
|
|
|
|
public void test_SBC() throws MemoryAccessException {
|
|
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.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() throws MemoryAccessException {
|
|
// Subtrace with Carry Flag cleared
|
|
bus.loadProgram(0x18, // CLC
|
|
0xa9, 0x05, // LDA #$00
|
|
0xe9, 0x01); // SBC #$01
|
|
|
|
cpu.step(3);
|
|
assertEquals(0x03, cpu.getAccumulator());
|
|
|
|
cpu.reset();
|
|
|
|
// Subtrace with Carry Flag cleared
|
|
bus.loadProgram(0x18, // CLC
|
|
0xa9, 0x00, // LDA #$00
|
|
0xe9, 0x01); // SBC #$01
|
|
|
|
cpu.step(3);
|
|
assertEquals(0xfe, cpu.getAccumulator());
|
|
|
|
cpu.reset();
|
|
|
|
// Subtract with Carry Flag set
|
|
bus.loadProgram(0x38, // SEC
|
|
0xa9, 0x05, // LDA #$00
|
|
0xe9, 0x01); // SBC #$01
|
|
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
|
|
0xe9, 0x01); // SBC #$01
|
|
cpu.step(3);
|
|
assertEquals(0xff, cpu.getAccumulator());
|
|
assertFalse(cpu.getCarryFlag());
|
|
|
|
}
|
|
|
|
public void test_SBC_DecimalMode() throws MemoryAccessException {
|
|
bus.loadProgram(0xf8,
|
|
0xa9, 0x00,
|
|
0xe9, 0x01);
|
|
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,
|
|
0xe9, 0x01);
|
|
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,
|
|
0xe9, 0x01);
|
|
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
|
|
0xe9, 0x01); // SBC #$01
|
|
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
|
|
0xe9, 0x11); // SBC #$11
|
|
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
|
|
0xe9, 0x01); // SBC #$01
|
|
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
|
|
0xe9, 0x01); // SBC #$01
|
|
cpu.step(4);
|
|
assertEquals(0x99, cpu.getAccumulator());
|
|
assertFalse(cpu.getCarryFlag());
|
|
assertFalse(cpu.getNegativeFlag());
|
|
assertFalse(cpu.getOverflowFlag());
|
|
assertFalse(cpu.getZeroFlag());
|
|
assertTrue(cpu.getDecimalModeFlag());
|
|
}
|
|
}
|