ksim65/src/test/kotlin/TestCommon6502.kt

6221 lines
174 KiB
Kotlin

import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.TestInstance
import razorvine.ksim65.*
import razorvine.ksim65.components.*
import kotlin.test.*
/*
Unit test suite adapted from Py65 https://github.com/mnaberez/py65
Copyright (c) 2008-2018, Mike Naberezny and contributors.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@TestInstance(TestInstance.Lifecycle.PER_METHOD)
abstract class TestCommon6502 {
// Tests common to 6502-based microprocessors
val mpu: Cpu6502
val memory = Ram(0, 0xffff)
val bus = Bus()
abstract fun createCpu(): Cpu6502
init {
mpu = this.createCpu()
bus.add(mpu)
bus.add(memory)
memory.fill(0xaa)
memory[Cpu6502.RESET_vector] = 0
memory[Cpu6502.RESET_vector + 1] = 0
mpu.reset()
mpu.regP.I = false // allow interrupts again
}
companion object {
// processor flags
const val fNEGATIVE = 128
const val fOVERFLOW = 64
const val fUNUSED = 32
const val fBREAK = 16
const val fDECIMAL = 8
const val fINTERRUPT = 4
const val fZERO = 2
const val fCARRY = 1
}
// test helpers
fun writeMem(memory: MemMappedComponent, startAddress: Address, data: Iterable<UByte>) {
var addr = startAddress
data.forEach { memory[addr++] = it }
}
// Reset
@Test
fun test_reset_sets_registers_to_initial_states() {
mpu.reset()
assertEquals(0xFD, mpu.regSP)
assertEquals(0, mpu.regA)
assertEquals(0, mpu.regX)
assertEquals(0, mpu.regY)
assertTrue(mpu.regP.I) // the other status flags are undefined after reset
}
// ADC Absolute
@Test
fun test_adc_bcd_off_absolute_carry_clear_in_accumulator_zeroes() {
mpu.regA = 0
// $0000 ADC $C000
writeMem(memory, 0x0000, listOf(0x6D, 0x00, 0xC0))
// assertEquals(0x10000, memory.size)
memory[0xC000] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.C)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.Z)
}
@Test
fun test_adc_bcd_off_absolute_carry_set_in_accumulator_zero() {
mpu.regA = 0
mpu.regP.C = true
// $0000 ADC $C000
writeMem(memory, 0x0000, listOf(0x6D, 0x00, 0xC0))
memory[0xC000] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x01, mpu.regA)
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.Z)
assertFalse(mpu.regP.C)
}
@Test
fun test_adc_bcd_off_absolute_carry_clear_in_no_carry_clear_out() {
mpu.regA = 0x01
// $0000 ADC $C000
writeMem(memory, 0x0000, listOf(0x6D, 0x00, 0xC0))
memory[0xC000] = 0xFE
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0xFF, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.C)
assertFalse(mpu.regP.Z)
}
@Test
fun test_adc_bcd_off_absolute_carry_clear_in_carry_set_out() {
mpu.regA = 0x02
// $0000 ADC $C000
writeMem(memory, 0x0000, listOf(0x6D, 0x00, 0xC0))
memory[0xC000] = 0xFF
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x01, mpu.regA)
assertTrue(mpu.regP.C)
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_adc_bcd_off_absolute_overflow_clr_no_carry_01_plus_01() {
mpu.regP.C = false
mpu.regA = 0x01
// $0000 ADC $C000
writeMem(memory, 0x0000, listOf(0x6D, 0x00, 0xC0))
memory[0xC000] = 0x01
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x02, mpu.regA)
assertFalse(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_absolute_overflow_clr_no_carry_01_plus_ff() {
mpu.regP.C = false
mpu.regA = 0x01
// $0000 ADC $C000
writeMem(memory, 0x0000, listOf(0x6D, 0x00, 0xC0))
memory[0xC000] = 0xff
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_absolute_overflow_set_no_carry_7f_plus_01() {
mpu.regP.C = false
mpu.regA = 0x7f
// $0000 ADC $C000
writeMem(memory, 0x0000, listOf(0x6D, 0x00, 0xC0))
memory[0xC000] = 0x01
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertTrue(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_absolute_overflow_set_no_carry_80_plus_ff() {
mpu.regP.C = false
mpu.regA = 0x80
// $0000 ADC $C000
writeMem(memory, 0x0000, listOf(0x6D, 0x00, 0xC0))
memory[0xC000] = 0xff
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x7f, mpu.regA)
assertTrue(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_absolute_overflow_set_on_40_plus_40() {
mpu.regP.V = false
mpu.regA = 0x40
// $0000 ADC $C000
writeMem(memory, 0x0000, listOf(0x6D, 0x00, 0xC0))
memory[0xC000] = 0x40
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertTrue(mpu.regP.N)
assertTrue(mpu.regP.V)
assertFalse(mpu.regP.Z)
}
// ADC Zero Page
@Test
fun test_adc_bcd_off_zp_carry_clear_in_accumulator_zeroes() {
mpu.regA = 0
// $0000 ADC $00B0
writeMem(memory, 0x0000, listOf(0x65, 0xB0))
memory[0x00B0] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.C)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.Z)
}
@Test
fun test_adc_bcd_off_zp_carry_set_in_accumulator_zero() {
mpu.regA = 0
mpu.regP.C = true
// $0000 ADC $00B0
writeMem(memory, 0x0000, listOf(0x65, 0xB0))
memory[0x00B0] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x01, mpu.regA)
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.Z)
assertFalse(mpu.regP.C)
}
@Test
fun test_adc_bcd_off_zp_carry_clear_in_no_carry_clear_out() {
mpu.regA = 0x01
// $0000 ADC $00B0
writeMem(memory, 0x0000, listOf(0x65, 0xB0))
memory[0x00B0] = 0xFE
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xFF, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.C)
assertFalse(mpu.regP.Z)
}
@Test
fun test_adc_bcd_off_zp_carry_clear_in_carry_set_out() {
mpu.regA = 0x02
// $0000 ADC $00B0
writeMem(memory, 0x0000, listOf(0x65, 0xB0))
memory[0x00B0] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x01, mpu.regA)
assertTrue(mpu.regP.C)
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_adc_bcd_off_zp_overflow_clr_no_carry_01_plus_01() {
mpu.regP.C = false
mpu.regA = 0x01
// $0000 ADC $00B0
writeMem(memory, 0x0000, listOf(0x65, 0xB0))
memory[0x00B0] = 0x01
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x02, mpu.regA)
assertFalse(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_zp_overflow_clr_no_carry_01_plus_ff() {
mpu.regP.C = false
mpu.regA = 0x01
// $0000 ADC $00B0
writeMem(memory, 0x0000, listOf(0x65, 0xB0))
memory[0x00B0] = 0xff
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_zp_overflow_set_no_carry_7f_plus_01() {
mpu.regP.C = false
mpu.regA = 0x7f
// $0000 ADC $00B0
writeMem(memory, 0x0000, listOf(0x65, 0xB0))
memory[0x00B0] = 0x01
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertTrue(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_zp_overflow_set_no_carry_80_plus_ff() {
mpu.regP.C = false
mpu.regA = 0x80
// $0000 ADC $00B0
writeMem(memory, 0x0000, listOf(0x65, 0xB0))
memory[0x00B0] = 0xff
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x7f, mpu.regA)
assertTrue(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_zp_overflow_set_on_40_plus_40() {
mpu.regA = 0x40
mpu.regP.V = false
// $0000 ADC $00B0
writeMem(memory, 0x0000, listOf(0x65, 0xB0))
memory[0x00B0] = 0x40
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertTrue(mpu.regP.N)
assertTrue(mpu.regP.V)
assertFalse(mpu.regP.Z)
}
// ADC Immediate
@Test
fun test_adc_bcd_off_immediate_carry_clear_in_accumulator_zeroes() {
mpu.regA = 0
// $0000 ADC #$00
writeMem(memory, 0x0000, listOf(0x69, 0x00))
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.C)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.Z)
}
@Test
fun test_adc_bcd_off_immediate_carry_set_in_accumulator_zero() {
mpu.regA = 0
mpu.regP.C = true
// $0000 ADC #$00
writeMem(memory, 0x0000, listOf(0x69, 0x00))
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x01, mpu.regA)
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.Z)
assertFalse(mpu.regP.C)
}
@Test
fun test_adc_bcd_off_immediate_carry_clear_in_no_carry_clear_out() {
mpu.regA = 0x01
// $0000 ADC #$FE
writeMem(memory, 0x0000, listOf(0x69, 0xFE))
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xFF, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.C)
assertFalse(mpu.regP.Z)
}
@Test
fun test_adc_bcd_off_immediate_carry_clear_in_carry_set_out() {
mpu.regA = 0x02
// $0000 ADC #$FF
writeMem(memory, 0x0000, listOf(0x69, 0xFF))
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x01, mpu.regA)
assertTrue(mpu.regP.C)
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_adc_bcd_off_immediate_overflow_clr_no_carry_01_plus_01() {
mpu.regP.C = false
mpu.regA = 0x01
// $0000 ADC #$01
writeMem(memory, 0x000, listOf(0x69, 0x01))
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x02, mpu.regA)
assertFalse(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_immediate_overflow_clr_no_carry_01_plus_ff() {
mpu.regP.C = false
mpu.regA = 0x01
// $0000 ADC #$FF
writeMem(memory, 0x000, listOf(0x69, 0xff))
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_immediate_overflow_set_no_carry_7f_plus_01() {
mpu.regP.C = false
mpu.regA = 0x7f
// $0000 ADC #$01
writeMem(memory, 0x000, listOf(0x69, 0x01))
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertTrue(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_immediate_overflow_set_no_carry_80_plus_ff() {
mpu.regP.C = false
mpu.regA = 0x80
// $0000 ADC #$FF
writeMem(memory, 0x000, listOf(0x69, 0xff))
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x7f, mpu.regA)
assertTrue(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_immediate_overflow_set_on_40_plus_40() {
mpu.regA = 0x40
// $0000 ADC #$40
writeMem(memory, 0x0000, listOf(0x69, 0x40))
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertTrue(mpu.regP.N)
assertTrue(mpu.regP.V)
assertFalse(mpu.regP.Z)
}
@Test
fun test_adc_bcd_on_immediate_79_plus_00_carry_set() {
mpu.regP.D = true
mpu.regP.C = true
mpu.regA = 0x79
// $0000 ADC #$00
writeMem(memory, 0x0000, listOf(0x69, 0x00))
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertFalse(mpu.regP.C)
assertFalse(mpu.regP.Z)
assertTrue(mpu.regP.N)
assertTrue(mpu.regP.V)
}
@Test
fun test_adc_bcd_on_immediate_6f_plus_00_carry_set() {
mpu.regP.D = true
mpu.regP.C = true
mpu.regA = 0x6f
// $0000 ADC #$00
writeMem(memory, 0x0000, listOf(0x69, 0x00))
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x76, mpu.regA)
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.V)
assertFalse(mpu.regP.Z)
assertFalse(mpu.regP.C)
}
// ADC Absolute, X-Indexed
@Test
fun test_adc_bcd_off_abs_x_carry_clear_in_accumulator_zeroes() {
mpu.regA = 0x00
mpu.regX = 0x03
// $0000 ADC $C000,X
writeMem(memory, 0x0000, listOf(0x7D, 0x00, 0xC0))
memory[0xC000 + mpu.regX] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.C)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.Z)
}
@Test
fun test_adc_bcd_off_abs_x_carry_set_in_accumulator_zero() {
mpu.regA = 0
mpu.regX = 0x03
mpu.regP.C = true
// $0000 ADC $C000,X
writeMem(memory, 0x0000, listOf(0x7D, 0x00, 0xC0))
memory[0xC000 + mpu.regX] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x01, mpu.regA)
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.Z)
assertFalse(mpu.regP.C)
}
@Test
fun test_adc_bcd_off_abs_x_carry_clear_in_no_carry_clear_out() {
mpu.regA = 0x01
mpu.regX = 0x03
// $0000 ADC $C000,X
writeMem(memory, 0x0000, listOf(0x7D, 0x00, 0xC0))
memory[0xC000 + mpu.regX] = 0xFE
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0xFF, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.C)
assertFalse(mpu.regP.Z)
}
@Test
fun test_adc_bcd_off_abs_x_carry_clear_in_carry_set_out() {
mpu.regA = 0x02
mpu.regX = 0x03
// $0000 ADC $C000,X
writeMem(memory, 0x0000, listOf(0x7D, 0x00, 0xC0))
memory[0xC000 + mpu.regX] = 0xFF
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x01, mpu.regA)
assertTrue(mpu.regP.C)
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_adc_bcd_off_abs_x_overflow_clr_no_carry_01_plus_01() {
mpu.regP.C = false
mpu.regA = 0x01
// $0000 ADC $C000,X
writeMem(memory, 0x0000, listOf(0x7D, 0x00, 0xC0))
memory[0xC000 + mpu.regX] = 0x01
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x02, mpu.regA)
assertFalse(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_abs_x_overflow_clr_no_carry_01_plus_ff() {
mpu.regP.C = false
mpu.regA = 0x01
// $0000 ADC $C000,X
writeMem(memory, 0x0000, listOf(0x7D, 0x00, 0xC0))
memory[0xC000 + mpu.regX] = 0xff
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_abs_x_overflow_set_no_carry_7f_plus_01() {
mpu.regP.C = false
mpu.regA = 0x7f
// $0000 ADC $C000,X
writeMem(memory, 0x0000, listOf(0x7D, 0x00, 0xC0))
memory[0xC000 + mpu.regX] = 0x01
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertTrue(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_abs_x_overflow_set_no_carry_80_plus_ff() {
mpu.regP.C = false
mpu.regA = 0x80
// $0000 ADC $C000,X
writeMem(memory, 0x0000, listOf(0x7D, 0x00, 0xC0))
memory[0xC000 + mpu.regX] = 0xff
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x7f, mpu.regA)
assertTrue(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_abs_x_overflow_set_on_40_plus_40() {
mpu.regP.V = false
mpu.regA = 0x40
mpu.regX = 0x03
// $0000 ADC $C000,X
writeMem(memory, 0x0000, listOf(0x7D, 0x00, 0xC0))
memory[0xC000 + mpu.regX] = 0x40
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertTrue(mpu.regP.N)
assertTrue(mpu.regP.V)
assertFalse(mpu.regP.Z)
}
// ADC Absolute, Y-Indexed
@Test
fun test_adc_bcd_off_abs_y_carry_clear_in_accumulator_zeroes() {
mpu.regA = 0x00
mpu.regY = 0x03
// $0000 ADC $C000,Y
writeMem(memory, 0x0000, listOf(0x79, 0x00, 0xC0))
memory[0xC000 + mpu.regY] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.C)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.Z)
}
@Test
fun test_adc_bcd_off_abs_y_carry_set_in_accumulator_zero() {
mpu.regA = 0
mpu.regY = 0x03
mpu.regP.C = true
// $0000 ADC $C000,Y
writeMem(memory, 0x0000, listOf(0x79, 0x00, 0xC0))
memory[0xC000 + mpu.regY] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x01, mpu.regA)
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.Z)
assertFalse(mpu.regP.C)
}
@Test
fun test_adc_bcd_off_abs_y_carry_clear_in_no_carry_clear_out() {
mpu.regA = 0x01
mpu.regY = 0x03
// $0000 ADC $C000,Y
writeMem(memory, 0x0000, listOf(0x79, 0x00, 0xC0))
memory[0xC000 + mpu.regY] = 0xFE
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0xFF, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.C)
assertFalse(mpu.regP.Z)
}
@Test
fun test_adc_bcd_off_abs_y_carry_clear_in_carry_set_out() {
mpu.regA = 0x02
mpu.regY = 0x03
// $0000 ADC $C000,Y
writeMem(memory, 0x0000, listOf(0x79, 0x00, 0xC0))
memory[0xC000 + mpu.regY] = 0xFF
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x01, mpu.regA)
assertTrue(mpu.regP.C)
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_adc_bcd_off_abs_y_overflow_clr_no_carry_01_plus_01() {
mpu.regP.C = false
mpu.regA = 0x01
// $0000 ADC $C000,Y
writeMem(memory, 0x0000, listOf(0x79, 0x00, 0xC0))
memory[0xC000 + mpu.regY] = 0x01
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x02, mpu.regA)
assertFalse(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_abs_y_overflow_clr_no_carry_01_plus_ff() {
mpu.regP.C = false
mpu.regA = 0x01
// $0000 ADC $C000,Y
writeMem(memory, 0x0000, listOf(0x79, 0x00, 0xC0))
memory[0xC000 + mpu.regY] = 0xFF
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_abs_y_overflow_set_no_carry_7f_plus_01() {
mpu.regP.C = false
mpu.regA = 0x7f
// $0000 ADC $C000,Y
writeMem(memory, 0x0000, listOf(0x79, 0x00, 0xC0))
memory[0xC000 + mpu.regY] = 0x01
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertTrue(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_abs_y_overflow_set_no_carry_80_plus_ff() {
mpu.regP.C = false
mpu.regA = 0x80
// $0000 ADC $C000,Y
writeMem(memory, 0x0000, listOf(0x79, 0x00, 0xC0))
memory[0xC000 + mpu.regY] = 0xFF
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x7f, mpu.regA)
assertTrue(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_abs_y_overflow_set_on_40_plus_40() {
mpu.regP.V = false
mpu.regA = 0x40
mpu.regY = 0x03
// $0000 ADC $C000,Y
writeMem(memory, 0x0000, listOf(0x79, 0x00, 0xC0))
memory[0xC000 + mpu.regY] = 0x40
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertTrue(mpu.regP.N)
assertTrue(mpu.regP.V)
assertFalse(mpu.regP.Z)
}
// ADC Zero Page, X-Indexed
@Test
fun test_adc_bcd_off_zp_x_carry_clear_in_accumulator_zeroes() {
mpu.regA = 0x00
mpu.regX = 0x03
// $0000 ADC $0010,X
writeMem(memory, 0x0000, listOf(0x75, 0x10))
memory[0x0010 + mpu.regX] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.C)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.Z)
}
@Test
fun test_adc_bcd_off_zp_x_carry_set_in_accumulator_zero() {
mpu.regA = 0
mpu.regX = 0x03
mpu.regP.C = true
// $0000 ADC $0010,X
writeMem(memory, 0x0000, listOf(0x75, 0x10))
memory[0x0010 + mpu.regX] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x01, mpu.regA)
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.Z)
assertFalse(mpu.regP.C)
}
@Test
fun test_adc_bcd_off_zp_x_carry_clear_in_no_carry_clear_out() {
mpu.regA = 0x01
mpu.regX = 0x03
// $0000 ADC $0010,X
writeMem(memory, 0x0000, listOf(0x75, 0x10))
memory[0x0010 + mpu.regX] = 0xFE
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xFF, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.C)
assertFalse(mpu.regP.Z)
}
@Test
fun test_adc_bcd_off_zp_x_carry_clear_in_carry_set_out() {
mpu.regA = 0x02
mpu.regX = 0x03
// $0000 ADC $0010,X
writeMem(memory, 0x0000, listOf(0x75, 0x10))
memory[0x0010 + mpu.regX] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x01, mpu.regA)
assertTrue(mpu.regP.C)
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_adc_bcd_off_zp_x_overflow_clr_no_carry_01_plus_01() {
mpu.regP.C = false
mpu.regA = 0x01
mpu.regX = 0x03
// $0000 ADC $0010,X
writeMem(memory, 0x0000, listOf(0x75, 0x10))
memory[0x0010 + mpu.regX] = 0x01
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x02, mpu.regA)
assertFalse(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_zp_x_overflow_clr_no_carry_01_plus_ff() {
mpu.regP.C = false
mpu.regA = 0x01
mpu.regX = 0x03
// $0000 ADC $0010,X
writeMem(memory, 0x0000, listOf(0x75, 0x10))
memory[0x0010 + mpu.regX] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_zp_x_overflow_set_no_carry_7f_plus_01() {
mpu.regP.C = false
mpu.regA = 0x7f
mpu.regX = 0x03
// $0000 ADC $0010,X
writeMem(memory, 0x0000, listOf(0x75, 0x10))
memory[0x0010 + mpu.regX] = 0x01
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertTrue(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_zp_x_overflow_set_no_carry_80_plus_ff() {
mpu.regP.C = false
mpu.regA = 0x80
mpu.regX = 0x03
// $0000 ADC $0010,X
writeMem(memory, 0x0000, listOf(0x75, 0x10))
memory[0x0010 + mpu.regX] = 0xff
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x7f, mpu.regA)
assertTrue(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_zp_x_overflow_set_on_40_plus_40() {
mpu.regP.V = false
mpu.regA = 0x40
mpu.regX = 0x03
// $0000 ADC $0010,X
writeMem(memory, 0x0000, listOf(0x75, 0x10))
memory[0x0010 + mpu.regX] = 0x40
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertTrue(mpu.regP.N)
assertTrue(mpu.regP.V)
assertFalse(mpu.regP.Z)
}
// ADC Indirect, Indexed (X)
@Test
fun test_adc_bcd_off_ind_indexed_carry_clear_in_accumulator_zeroes() {
mpu.regA = 0x00
mpu.regX = 0x03
// $0000 ADC ($0010,X)
// $0013 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x61, 0x10))
writeMem(memory, 0x0013, listOf(0xCD, 0xAB))
memory[0xABCD] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.C)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.Z)
}
@Test
fun test_adc_bcd_off_ind_indexed_carry_set_in_accumulator_zero() {
mpu.regA = 0
mpu.regX = 0x03
mpu.regP.C = true
// $0000 ADC ($0010,X)
// $0013 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x61, 0x10))
writeMem(memory, 0x0013, listOf(0xCD, 0xAB))
memory[0xABCD] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x01, mpu.regA)
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.Z)
assertFalse(mpu.regP.C)
}
@Test
fun test_adc_bcd_off_ind_indexed_carry_clear_in_no_carry_clear_out() {
mpu.regA = 0x01
mpu.regX = 0x03
// $0000 ADC ($0010,X)
// $0013 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x61, 0x10))
writeMem(memory, 0x0013, listOf(0xCD, 0xAB))
memory[0xABCD] = 0xFE
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xFF, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.C)
assertFalse(mpu.regP.Z)
}
@Test
fun test_adc_bcd_off_ind_indexed_carry_clear_in_carry_set_out() {
mpu.regA = 0x02
mpu.regX = 0x03
// $0000 ADC ($0010,X)
// $0013 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x61, 0x10))
writeMem(memory, 0x0013, listOf(0xCD, 0xAB))
memory[0xABCD] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x01, mpu.regA)
assertTrue(mpu.regP.C)
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_adc_bcd_off_ind_indexed_overflow_clr_no_carry_01_plus_01() {
mpu.regP.C = false
mpu.regA = 0x01
mpu.regX = 0x03
// $0000 ADC ($0010,X)
// $0013 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x61, 0x10))
writeMem(memory, 0x0013, listOf(0xCD, 0xAB))
memory[0xABCD] = 0x01
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x02, mpu.regA)
assertFalse(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_ind_indexed_overflow_clr_no_carry_01_plus_ff() {
mpu.regP.C = false
mpu.regA = 0x01
mpu.regX = 0x03
// $0000 ADC ($0010,X)
// $0013 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x61, 0x10))
writeMem(memory, 0x0013, listOf(0xCD, 0xAB))
memory[0xABCD] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_ind_indexed_overflow_set_no_carry_7f_plus_01() {
mpu.regP.C = false
mpu.regA = 0x7f
mpu.regX = 0x03
// $0000 ADC ($0010,X)
// $0013 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x61, 0x10))
writeMem(memory, 0x0013, listOf(0xCD, 0xAB))
memory[0xABCD] = 0x01
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertTrue(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_ind_indexed_overflow_set_no_carry_80_plus_ff() {
mpu.regP.C = false
mpu.regA = 0x80
mpu.regX = 0x03
// $0000 ADC ($0010,X)
// $0013 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x61, 0x10))
writeMem(memory, 0x0013, listOf(0xCD, 0xAB))
memory[0xABCD] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x7f, mpu.regA)
assertTrue(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_ind_indexed_overflow_set_on_40_plus_40() {
mpu.regP.V = false
mpu.regA = 0x40
mpu.regX = 0x03
// $0000 ADC ($0010,X)
// $0013 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x61, 0x10))
writeMem(memory, 0x0013, listOf(0xCD, 0xAB))
memory[0xABCD] = 0x40
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertTrue(mpu.regP.N)
assertTrue(mpu.regP.V)
assertFalse(mpu.regP.Z)
}
// ADC Indexed, Indirect (Y)
@Test
fun test_adc_bcd_off_indexed_ind_carry_clear_in_accumulator_zeroes() {
mpu.regA = 0x00
mpu.regY = 0x03
// $0000 ADC ($0010),Y
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x71, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD + mpu.regY] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.C)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.Z)
}
@Test
fun test_adc_bcd_off_indexed_ind_carry_set_in_accumulator_zero() {
mpu.regA = 0
mpu.regY = 0x03
mpu.regP.C = true
// $0000 ADC ($0010),Y
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x71, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD + mpu.regY] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x01, mpu.regA)
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.Z)
assertFalse(mpu.regP.C)
}
@Test
fun test_adc_bcd_off_indexed_ind_carry_clear_in_no_carry_clear_out() {
mpu.regA = 0x01
mpu.regY = 0x03
// $0000 ADC ($0010),Y
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x71, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD + mpu.regY] = 0xFE
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xFF, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.C)
assertFalse(mpu.regP.Z)
}
@Test
fun test_adc_bcd_off_indexed_ind_carry_clear_in_carry_set_out() {
mpu.regA = 0x02
mpu.regY = 0x03
// $0000 ADC ($0010),Y
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x71, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD + mpu.regY] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x01, mpu.regA)
assertTrue(mpu.regP.C)
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_adc_bcd_off_indexed_ind_overflow_clr_no_carry_01_plus_01() {
mpu.regP.C = false
mpu.regA = 0x01
mpu.regY = 0x03
// $0000 $0000 ADC ($0010),Y
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x71, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD + mpu.regY] = 0x01
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x02, mpu.regA)
assertFalse(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_indexed_ind_overflow_clr_no_carry_01_plus_ff() {
mpu.regP.C = false
mpu.regA = 0x01
mpu.regY = 0x03
// $0000 ADC ($0010),Y
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x71, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD + mpu.regY] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_indexed_ind_overflow_set_no_carry_7f_plus_01() {
mpu.regP.C = false
mpu.regA = 0x7f
mpu.regY = 0x03
// $0000 ADC ($0010),Y
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x71, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD + mpu.regY] = 0x01
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertTrue(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_indexed_ind_overflow_set_no_carry_80_plus_ff() {
mpu.regP.C = false
mpu.regA = 0x80
mpu.regY = 0x03
// $0000 $0000 ADC ($0010),Y
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x71, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD + mpu.regY] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x7f, mpu.regA)
assertTrue(mpu.regP.V)
}
@Test
fun test_adc_bcd_off_indexed_ind_overflow_set_on_40_plus_40() {
mpu.regP.V = false
mpu.regA = 0x40
mpu.regY = 0x03
// $0000 ADC ($0010),Y
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x71, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD + mpu.regY] = 0x40
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertTrue(mpu.regP.N)
assertTrue(mpu.regP.V)
assertFalse(mpu.regP.Z)
}
// AND (Absolute)
@Test
fun test_and_absolute_all_zeros_setting_zero_flag() {
mpu.regA = 0xFF
// $0000 AND $ABCD
writeMem(memory, 0x0000, listOf(0x2D, 0xCD, 0xAB))
memory[0xABCD] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_and_absolute_zeros_and_ones_setting_negative_flag() {
mpu.regA = 0xFF
// $0000 AND $ABCD
writeMem(memory, 0x0000, listOf(0x2D, 0xCD, 0xAB))
memory[0xABCD] = 0xAA
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0xAA, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
// AND (Absolute)
@Test
fun test_and_zp_all_zeros_setting_zero_flag() {
mpu.regA = 0xFF
// $0000 AND $0010
writeMem(memory, 0x0000, listOf(0x25, 0x10))
memory[0x0010] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_and_zp_zeros_and_ones_setting_negative_flag() {
mpu.regA = 0xFF
// $0000 AND $0010
writeMem(memory, 0x0000, listOf(0x25, 0x10))
memory[0x0010] = 0xAA
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xAA, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
// AND (Immediate)
@Test
fun test_and_immediate_all_zeros_setting_zero_flag() {
mpu.regA = 0xFF
// $0000 AND #$00
writeMem(memory, 0x0000, listOf(0x29, 0x00))
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_and_immediate_zeros_and_ones_setting_negative_flag() {
mpu.regA = 0xFF
// $0000 AND #$AA
writeMem(memory, 0x0000, listOf(0x29, 0xAA))
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xAA, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
// AND (Absolute, X-Indexed)
@Test
fun test_and_abs_x_all_zeros_setting_zero_flag() {
mpu.regA = 0xFF
mpu.regX = 0x03
// $0000 AND $ABCD,X
writeMem(memory, 0x0000, listOf(0x3d, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_and_abs_x_zeros_and_ones_setting_negative_flag() {
mpu.regA = 0xFF
mpu.regX = 0x03
// $0000 AND $ABCD,X
writeMem(memory, 0x0000, listOf(0x3d, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0xAA
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0xAA, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
// AND (Absolute, Y-Indexed)
@Test
fun test_and_abs_y_all_zeros_setting_zero_flag() {
mpu.regA = 0xFF
mpu.regY = 0x03
// $0000 AND $ABCD,X
writeMem(memory, 0x0000, listOf(0x39, 0xCD, 0xAB))
memory[0xABCD + mpu.regY] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_and_abs_y_zeros_and_ones_setting_negative_flag() {
mpu.regA = 0xFF
mpu.regY = 0x03
// $0000 AND $ABCD,X
writeMem(memory, 0x0000, listOf(0x39, 0xCD, 0xAB))
memory[0xABCD + mpu.regY] = 0xAA
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0xAA, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
// AND Indirect, Indexed (X)
@Test
fun test_and_ind_indexed_x_all_zeros_setting_zero_flag() {
mpu.regA = 0xFF
mpu.regX = 0x03
// $0000 AND ($0010,X)
// $0013 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x21, 0x10))
writeMem(memory, 0x0013, listOf(0xCD, 0xAB))
memory[0xABCD] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_and_ind_indexed_x_zeros_and_ones_setting_negative_flag() {
mpu.regA = 0xFF
mpu.regX = 0x03
// $0000 AND ($0010,X)
// $0013 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x21, 0x10))
writeMem(memory, 0x0013, listOf(0xCD, 0xAB))
memory[0xABCD] = 0xAA
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xAA, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
// AND Indexed, Indirect (Y)
@Test
fun test_and_indexed_ind_y_all_zeros_setting_zero_flag() {
mpu.regA = 0xFF
mpu.regY = 0x03
// $0000 AND ($0010),Y
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x31, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD + mpu.regY] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_and_indexed_ind_y_zeros_and_ones_setting_negative_flag() {
mpu.regA = 0xFF
mpu.regY = 0x03
// $0000 AND ($0010),Y
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x31, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD + mpu.regY] = 0xAA
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xAA, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
// AND Zero Page, X-Indexed
@Test
fun test_and_zp_x_all_zeros_setting_zero_flag() {
mpu.regA = 0xFF
mpu.regX = 0x03
// $0000 AND $0010,X
writeMem(memory, 0x0000, listOf(0x35, 0x10))
memory[0x0010 + mpu.regX] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_and_zp_x_all_zeros_and_ones_setting_negative_flag() {
mpu.regA = 0xFF
mpu.regX = 0x03
// $0000 AND $0010,X
writeMem(memory, 0x0000, listOf(0x35, 0x10))
memory[0x0010 + mpu.regX] = 0xAA
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xAA, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
// ASL Accumulator
@Test
fun test_asl_accumulator_sets_z_flag() {
mpu.regA = 0x00
// $0000 ASL A
memory[0x0000] = 0x0A
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_asl_accumulator_sets_n_flag() {
mpu.regA = 0x40
// $0000 ASL A
memory[0x0000] = 0x0A
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_asl_accumulator_shifts_out_zero() {
mpu.regA = 0x7F
// $0000 ASL A
memory[0x0000] = 0x0A
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0xFE, mpu.regA)
assertFalse(mpu.regP.C)
}
@Test
fun test_asl_accumulator_shifts_out_one() {
mpu.regA = 0xFF
// $0000 ASL A
memory[0x0000] = 0x0A
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0xFE, mpu.regA)
assertTrue(mpu.regP.C)
}
@Test
fun test_asl_accumulator_80_sets_z_flag() {
mpu.regA = 0x80
mpu.regP.Z = false
// $0000 ASL A
memory[0x0000] = 0x0A
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
}
// ASL Absolute
@Test
fun test_asl_absolute_sets_z_flag() {
// $0000 ASL $ABCD
writeMem(memory, 0x0000, listOf(0x0E, 0xCD, 0xAB))
memory[0xABCD] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, memory[0xABCD])
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_asl_absolute_sets_n_flag() {
// $0000 ASL $ABCD
writeMem(memory, 0x0000, listOf(0x0E, 0xCD, 0xAB))
memory[0xABCD] = 0x40
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x80, memory[0xABCD])
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_asl_absolute_shifts_out_zero() {
mpu.regA = 0xAA
// $0000 ASL $ABCD
writeMem(memory, 0x0000, listOf(0x0E, 0xCD, 0xAB))
memory[0xABCD] = 0x7F
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0xAA, mpu.regA)
assertEquals(0xFE, memory[0xABCD])
assertFalse(mpu.regP.C)
}
@Test
fun test_asl_absolute_shifts_out_one() {
mpu.regA = 0xAA
// $0000 ASL $ABCD
writeMem(memory, 0x0000, listOf(0x0E, 0xCD, 0xAB))
memory[0xABCD] = 0xFF
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0xAA, mpu.regA)
assertEquals(0xFE, memory[0xABCD])
assertTrue(mpu.regP.C)
}
// ASL Zero Page
@Test
fun test_asl_zp_sets_z_flag() {
// $0000 ASL $0010
writeMem(memory, 0x0000, listOf(0x06, 0x10))
memory[0x0010] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, memory[0x0010])
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_asl_zp_sets_n_flag() {
// $0000 ASL $0010
writeMem(memory, 0x0000, listOf(0x06, 0x10))
memory[0x0010] = 0x40
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x80, memory[0x0010])
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_asl_zp_shifts_out_zero() {
mpu.regA = 0xAA
// $0000 ASL $0010
writeMem(memory, 0x0000, listOf(0x06, 0x10))
memory[0x0010] = 0x7F
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xAA, mpu.regA)
assertEquals(0xFE, memory[0x0010])
assertFalse(mpu.regP.C)
}
@Test
fun test_asl_zp_shifts_out_one() {
mpu.regA = 0xAA
// $0000 ASL $0010
writeMem(memory, 0x0000, listOf(0x06, 0x10))
memory[0x0010] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xAA, mpu.regA)
assertEquals(0xFE, memory[0x0010])
assertTrue(mpu.regP.C)
}
// ASL Absolute, X-Indexed
@Test
fun test_asl_abs_x_indexed_sets_z_flag() {
mpu.regX = 0x03
// $0000 ASL $ABCD,X
writeMem(memory, 0x0000, listOf(0x1E, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, memory[0xABCD + mpu.regX])
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_asl_abs_x_indexed_sets_n_flag() {
mpu.regX = 0x03
// $0000 ASL $ABCD,X
writeMem(memory, 0x0000, listOf(0x1E, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0x40
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x80, memory[0xABCD + mpu.regX])
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_asl_abs_x_indexed_shifts_out_zero() {
mpu.regA = 0xAA
mpu.regX = 0x03
// $0000 ASL $ABCD,X
writeMem(memory, 0x0000, listOf(0x1E, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0x7F
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0xAA, mpu.regA)
assertEquals(0xFE, memory[0xABCD + mpu.regX])
assertFalse(mpu.regP.C)
}
@Test
fun test_asl_abs_x_indexed_shifts_out_one() {
mpu.regA = 0xAA
mpu.regX = 0x03
// $0000 ASL $ABCD,X
writeMem(memory, 0x0000, listOf(0x1E, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0xFF
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0xAA, mpu.regA)
assertEquals(0xFE, memory[0xABCD + mpu.regX])
assertTrue(mpu.regP.C)
}
// ASL Zero Page, X-Indexed
@Test
fun test_asl_zp_x_indexed_sets_z_flag() {
mpu.regX = 0x03
// $0000 ASL $0010,X
writeMem(memory, 0x0000, listOf(0x16, 0x10))
memory[0x0010 + mpu.regX] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, memory[0x0010 + mpu.regX])
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_asl_zp_x_indexed_sets_n_flag() {
mpu.regX = 0x03
// $0000 ASL $0010,X
writeMem(memory, 0x0000, listOf(0x16, 0x10))
memory[0x0010 + mpu.regX] = 0x40
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x80, memory[0x0010 + mpu.regX])
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_asl_zp_x_indexed_shifts_out_zero() {
mpu.regX = 0x03
mpu.regA = 0xAA
// $0000 ASL $0010,X
writeMem(memory, 0x0000, listOf(0x16, 0x10))
memory[0x0010 + mpu.regX] = 0x7F
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xAA, mpu.regA)
assertEquals(0xFE, memory[0x0010 + mpu.regX])
assertFalse(mpu.regP.C)
}
@Test
fun test_asl_zp_x_indexed_shifts_out_one() {
mpu.regX = 0x03
mpu.regA = 0xAA
// $0000 ASL $0010,X
writeMem(memory, 0x0000, listOf(0x16, 0x10))
memory[0x0010 + mpu.regX] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xAA, mpu.regA)
assertEquals(0xFE, memory[0x0010 + mpu.regX])
assertTrue(mpu.regP.C)
}
// BCC
@Test
fun test_bcc_carry_clear_branches_relative_forward() {
mpu.regP.C = false
// $0000 BCC +6
writeMem(memory, 0x0000, listOf(0x90, 0x06))
mpu.step()
assertEquals(0x0002 + 0x06, mpu.regPC)
}
@Test
fun test_bcc_carry_clear_branches_relative_backward() {
mpu.regP.C = false
mpu.regPC = 0x0050
val rel = 256 + (-6) // two's complement of 6
// $0000 BCC -6
writeMem(memory, 0x0050, listOf(0x90, rel.toShort()))
mpu.step()
assertEquals(0x0052 - 6, mpu.regPC)
}
@Test
fun test_bcc_carry_set_does_not_branch() {
mpu.regP.C = true
// $0000 BCC +6
writeMem(memory, 0x0000, listOf(0x90, 0x06))
mpu.step()
assertEquals(0x0002, mpu.regPC)
}
// BCS
@Test
fun test_bcs_carry_set_branches_relative_forward() {
mpu.regP.C = true
// $0000 BCS +6
writeMem(memory, 0x0000, listOf(0xB0, 0x06))
mpu.step()
assertEquals(0x0002 + 0x06, mpu.regPC)
}
@Test
fun test_bcs_carry_set_branches_relative_backward() {
mpu.regP.C = true
mpu.regPC = 0x0050
val rel = 256 + (-6) // two's complement of 6
// $0000 BCS -6
writeMem(memory, 0x0050, listOf(0xB0, rel.toShort()))
mpu.step()
assertEquals(0x0052 - 6, mpu.regPC)
}
@Test
fun test_bcs_carry_clear_does_not_branch() {
mpu.regP.C = false
// $0000 BCS +6
writeMem(memory, 0x0000, listOf(0xB0, 0x06))
mpu.step()
assertEquals(0x0002, mpu.regPC)
}
// BEQ
@Test
fun test_beq_zero_set_branches_relative_forward() {
mpu.regP.Z = true
// $0000 BEQ +6
writeMem(memory, 0x0000, listOf(0xF0, 0x06))
mpu.step()
assertEquals(0x0002 + 0x06, mpu.regPC)
}
@Test
fun test_beq_zero_set_branches_relative_backward() {
mpu.regP.Z = true
mpu.regPC = 0x0050
val rel = 256 + (-6) // two's complement of 6
// $0000 BEQ -6
writeMem(memory, 0x0050, listOf(0xF0, rel.toShort()))
mpu.step()
assertEquals(0x0052 - 6, mpu.regPC)
}
@Test
fun test_beq_zero_clear_does_not_branch() {
mpu.regP.Z = false
// $0000 BEQ +6
writeMem(memory, 0x0000, listOf(0xF0, 0x06))
mpu.step()
assertEquals(0x0002, mpu.regPC)
}
// BIT (Absolute)
@Test
fun test_bit_abs_copies_bit_7_of_memory_to_n_flag_when_0() {
mpu.regP.N = false
// $0000 BIT $FEED
writeMem(memory, 0x0000, listOf(0x2C, 0xED, 0xFE))
memory[0xFEED] = 0xFF
mpu.regA = 0xFF
mpu.step()
assertTrue(mpu.regP.N)
}
@Test
fun test_bit_abs_copies_bit_7_of_memory_to_n_flag_when_1() {
mpu.regP.N = true
// $0000 BIT $FEED
writeMem(memory, 0x0000, listOf(0x2C, 0xED, 0xFE))
memory[0xFEED] = 0x00
mpu.regA = 0xFF
mpu.step()
assertFalse(mpu.regP.N)
}
@Test
fun test_bit_abs_copies_bit_6_of_memory_to_v_flag_when_0() {
mpu.regP.V = false
// $0000 BIT $FEED
writeMem(memory, 0x0000, listOf(0x2C, 0xED, 0xFE))
memory[0xFEED] = 0xFF
mpu.regA = 0xFF
mpu.step()
assertTrue(mpu.regP.V)
}
@Test
fun test_bit_abs_copies_bit_6_of_memory_to_v_flag_when_1() {
mpu.regP.V = true
// $0000 BIT $FEED
writeMem(memory, 0x0000, listOf(0x2C, 0xED, 0xFE))
memory[0xFEED] = 0x00
mpu.regA = 0xFF
mpu.step()
assertFalse(mpu.regP.V)
}
@Test
fun test_bit_abs_stores_result_of_and_in_z_preserves_a_when_1() {
mpu.regP.Z = false
// $0000 BIT $FEED
writeMem(memory, 0x0000, listOf(0x2C, 0xED, 0xFE))
memory[0xFEED] = 0x00
mpu.regA = 0x01
mpu.step()
assertTrue(mpu.regP.Z)
assertEquals(0x01, mpu.regA)
assertEquals(0x00, memory[0xFEED])
}
@Test
fun test_bit_abs_stores_result_of_and_when_nonzero_in_z_preserves_a() {
mpu.regP.Z = true
// $0000 BIT $FEED
writeMem(memory, 0x0000, listOf(0x2C, 0xED, 0xFE))
memory[0xFEED] = 0x01
mpu.regA = 0x01
mpu.step()
assertFalse(mpu.regP.Z) // result of AND is non-zero
assertEquals(0x01, mpu.regA)
assertEquals(0x01, memory[0xFEED])
}
@Test
fun test_bit_abs_stores_result_of_and_when_zero_in_z_preserves_a() {
mpu.regP.Z = false
// $0000 BIT $FEED
writeMem(memory, 0x0000, listOf(0x2C, 0xED, 0xFE))
memory[0xFEED] = 0x00
mpu.regA = 0x01
mpu.step()
assertTrue(mpu.regP.Z) // result of AND is zero
assertEquals(0x01, mpu.regA)
assertEquals(0x00, memory[0xFEED])
}
// BIT (Zero Page)
@Test
fun test_bit_zp_copies_bit_7_of_memory_to_n_flag_when_0() {
mpu.regP.N = false
// $0000 BIT $0010
writeMem(memory, 0x0000, listOf(0x24, 0x10))
memory[0x0010] = 0xFF
mpu.regA = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(11L, mpu.totalCycles)
assertTrue(mpu.regP.N)
}
@Test
fun test_bit_zp_copies_bit_7_of_memory_to_n_flag_when_1() {
mpu.regP.N = true
// $0000 BIT $0010
writeMem(memory, 0x0000, listOf(0x24, 0x10))
memory[0x0010] = 0x00
mpu.regA = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(11L, mpu.totalCycles)
assertFalse(mpu.regP.N)
}
@Test
fun test_bit_zp_copies_bit_6_of_memory_to_v_flag_when_0() {
mpu.regP.V = false
// $0000 BIT $0010
writeMem(memory, 0x0000, listOf(0x24, 0x10))
memory[0x0010] = 0xFF
mpu.regA = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(11L, mpu.totalCycles)
assertTrue(mpu.regP.V)
}
@Test
fun test_bit_zp_copies_bit_6_of_memory_to_v_flag_when_1() {
mpu.regP.V = true
// $0000 BIT $0010
writeMem(memory, 0x0000, listOf(0x24, 0x10))
memory[0x0010] = 0x00
mpu.regA = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(11L, mpu.totalCycles)
assertFalse(mpu.regP.V)
}
@Test
fun test_bit_zp_stores_result_of_and_in_z_preserves_a_when_1() {
mpu.regP.Z = false
// $0000 BIT $0010
writeMem(memory, 0x0000, listOf(0x24, 0x10))
memory[0x0010] = 0x00
mpu.regA = 0x01
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(11L, mpu.totalCycles)
assertTrue(mpu.regP.Z)
assertEquals(0x01, mpu.regA)
assertEquals(0x00, memory[0x0010])
}
@Test
fun test_bit_zp_stores_result_of_and_when_nonzero_in_z_preserves_a() {
mpu.regP.Z = true
// $0000 BIT $0010
writeMem(memory, 0x0000, listOf(0x24, 0x10))
memory[0x0010] = 0x01
mpu.regA = 0x01
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(11L, mpu.totalCycles)
assertFalse(mpu.regP.Z) // result of AND is non-zero
assertEquals(0x01, mpu.regA)
assertEquals(0x01, memory[0x0010])
}
@Test
fun test_bit_zp_stores_result_of_and_when_zero_in_z_preserves_a() {
mpu.regP.Z = false
// $0000 BIT $0010
writeMem(memory, 0x0000, listOf(0x24, 0x10))
memory[0x0010] = 0x00
mpu.regA = 0x01
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(11L, mpu.totalCycles)
assertTrue(mpu.regP.Z) // result of AND is zero
assertEquals(0x01, mpu.regA)
assertEquals(0x00, memory[0x0010])
}
// BMI
@Test
fun test_bmi_negative_set_branches_relative_forward() {
mpu.regP.N = true
// $0000 BMI +06
writeMem(memory, 0x0000, listOf(0x30, 0x06))
mpu.step()
assertEquals(0x0002 + 0x06, mpu.regPC)
}
@Test
fun test_bmi_negative_set_branches_relative_backward() {
mpu.regP.N = true
mpu.regPC = 0x0050
// $0000 BMI -6
val rel = 256 + (-6) // two's complement of 6
writeMem(memory, 0x0050, listOf(0x30, rel.toShort()))
mpu.step()
assertEquals(0x0052 - 6, mpu.regPC)
}
@Test
fun test_bmi_negative_clear_does_not_branch() {
mpu.regP.N = false
// $0000 BEQ +6
writeMem(memory, 0x0000, listOf(0x30, 0x06))
mpu.step()
assertEquals(0x0002, mpu.regPC)
}
// BNE
@Test
fun test_bne_zero_clear_branches_relative_forward() {
mpu.regP.Z = false
// $0000 BNE +6
writeMem(memory, 0x0000, listOf(0xD0, 0x06))
mpu.step()
assertEquals(0x0002 + 0x06, mpu.regPC)
}
@Test
fun test_bne_zero_clear_branches_relative_backward() {
mpu.regP.Z = false
mpu.regPC = 0x0050
// $0050 BNE -6
val rel = 256 + (-6) // two's complement of 6
writeMem(memory, 0x0050, listOf(0xD0, rel.toShort()))
mpu.step()
assertEquals(0x0052 - 6, mpu.regPC)
}
@Test
fun test_bne_zero_set_does_not_branch() {
mpu.regP.Z = true
// $0000 BNE +6
writeMem(memory, 0x0000, listOf(0xD0, 0x06))
mpu.step()
assertEquals(0x0002, mpu.regPC)
}
// BPL
@Test
fun test_bpl_negative_clear_branches_relative_forward() {
mpu.regP.N = false
// $0000 BPL +06
writeMem(memory, 0x0000, listOf(0x10, 0x06))
mpu.step()
assertEquals(0x0002 + 0x06, mpu.regPC)
}
@Test
fun test_bpl_negative_clear_branches_relative_backward() {
mpu.regP.N = false
mpu.regPC = 0x0050
// $0050 BPL -6
val rel = 256 + (-6) // two's complement of 6
writeMem(memory, 0x0050, listOf(0x10, rel.toShort()))
mpu.step()
assertEquals(0x0052 - 6, mpu.regPC)
}
@Test
fun test_bpl_negative_set_does_not_branch() {
mpu.regP.N = true
// $0000 BPL +6
writeMem(memory, 0x0000, listOf(0x10, 0x06))
mpu.step()
assertEquals(0x0002, mpu.regPC)
}
// BRK
@Test
fun test_brk_pushes_pc_plus_2_and_status_then_sets_pc_to_irq_vector() {
writeMem(memory, 0xFFFE, listOf(0xCD, 0xAB))
mpu.regSP = 0xff
mpu.regP.I = false
// $C000 BRK
memory[0xC000] = 0x00
mpu.regPC = 0xC000
mpu.step()
assertEquals(0xABCD, mpu.regPC)
assertEquals(0xFC, mpu.regSP)
assertEquals(0xC0, memory[0x1FF]) // PCH
assertEquals(0x02, memory[0x1FE]) // PCL
assertEquals(fBREAK or fUNUSED, memory[0x1FD].toInt(), "Status on stack should have no I flag")
assertEquals(fBREAK or fUNUSED or fINTERRUPT, mpu.regP.asInt())
}
// BVC
@Test
fun test_bvc_overflow_clear_branches_relative_forward() {
mpu.regP.V = false
// $0000 BVC +6
writeMem(memory, 0x0000, listOf(0x50, 0x06))
mpu.step()
assertEquals(0x0002 + 0x06, mpu.regPC)
}
@Test
fun test_bvc_overflow_clear_branches_relative_backward() {
mpu.regP.V = false
mpu.regPC = 0x0050
val rel = 256 + (-6) // two's complement of 6
// $0050 BVC -6
writeMem(memory, 0x0050, listOf(0x50, rel.toShort()))
mpu.step()
assertEquals(0x0052 - 6, mpu.regPC)
}
@Test
fun test_bvc_overflow_set_does_not_branch() {
mpu.regP.V = true
// $0000 BVC +6
writeMem(memory, 0x0000, listOf(0x50, 0x06))
mpu.step()
assertEquals(0x0002, mpu.regPC)
}
// BVS
@Test
fun test_bvs_overflow_set_branches_relative_forward() {
mpu.regP.V = true
// $0000 BVS +6
writeMem(memory, 0x0000, listOf(0x70, 0x06))
mpu.step()
assertEquals(0x0002 + 0x06, mpu.regPC)
}
@Test
fun test_bvs_overflow_set_branches_relative_backward() {
mpu.regP.V = true
mpu.regPC = 0x0050
val rel = 256 + (-6) // two's complement of 6
// $0050 BVS -6
writeMem(memory, 0x0050, listOf(0x70, rel.toShort()))
mpu.step()
assertEquals(0x0052 - 6, mpu.regPC)
}
@Test
fun test_bvs_overflow_clear_does_not_branch() {
mpu.regP.V = false
// $0000 BVS +6
writeMem(memory, 0x0000, listOf(0x70, 0x06))
mpu.step()
assertEquals(0x0002, mpu.regPC)
}
// CLC
@Test
fun test_clc_clears_carry_flag() {
mpu.regP.C = true
// $0000 CLC
memory[0x0000] = 0x18
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertFalse(mpu.regP.C)
}
// CLD
@Test
fun test_cld_clears_decimal_flag() {
mpu.regP.D = true
// $0000 CLD
memory[0x0000] = 0xD8
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertFalse(mpu.regP.D)
}
// CLI
@Test
fun test_cli_clears_interrupt_mask_flag() {
mpu.regP.I = true
// $0000 CLI
memory[0x0000] = 0x58
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertFalse(mpu.regP.I)
}
// CLV
@Test
fun test_clv_clears_overflow_flag() {
mpu.regP.V = true
// $0000 CLV
memory[0x0000] = 0xB8
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertFalse(mpu.regP.V)
}
// Compare instructions
// See http://6502.org/tutorials/compare_instructions.html
// and http://www.6502.org/tutorials/compare_beyond.html
// Cheat sheet:
// - Comparison is actually subtraction "register - memory"
// - Z contains equality result (1 equal, 0 not equal)
// - C contains result of unsigned comparison (0 if A<m, 1 if A>=m)
// - N holds MSB of subtraction result (*NOT* of signed subtraction)
// - V is not affected by comparison
// - D has no effect on comparison
// CMP Immediate
@Test
fun test_cmp_imm_sets_zero_carry_clears_neg_flags_if_equal() {
// Comparison: A == m
// $0000 CMP #10 , A will be 10
writeMem(memory, 0x0000, listOf(0xC9, 10))
mpu.regA = 10
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.Z)
assertTrue(mpu.regP.C)
}
@Test
fun test_cmp_imm_clears_zero_carry_takes_neg_if_less_unsigned() {
// Comparison: A < m (unsigned)
// $0000 CMP #10 , A will be 1
writeMem(memory, 0x0000, listOf(0xC9, 10))
mpu.regA = 1
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertTrue(mpu.regP.N) // 0x01-0x0A=0xF7
assertFalse(mpu.regP.Z)
assertFalse(mpu.regP.C)
}
@Test
fun test_cmp_imm_clears_zero_sets_carry_takes_neg_if_less_signed() {
// Comparison: A < #nn (signed), A negative
// $0000 CMP #1, A will be -1 (0xFF)
writeMem(memory, 0x0000, listOf(0xC9, 1))
mpu.regA = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertTrue(mpu.regP.N) // 0xFF-0x01=0xFE
assertFalse(mpu.regP.Z)
assertTrue(mpu.regP.C) // A>m unsigned
}
@Test
fun test_cmp_imm_clears_zero_carry_takes_neg_if_less_signed_nega() {
// Comparison: A < m (signed), A and m both negative
// $0000 CMP #0xFF (-1), A will be -2 (0xFE)
writeMem(memory, 0x0000, listOf(0xC9, 0xFF))
mpu.regA = 0xFE
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertTrue(mpu.regP.N) // 0xFE-0xFF=0xFF
assertFalse(mpu.regP.Z)
assertFalse(mpu.regP.C) // A<m unsigned
}
@Test
fun test_cmp_imm_clears_zero_sets_carry_takes_neg_if_more_unsigned() {
// Comparison: A > m (unsigned)
// $0000 CMP #1 , A will be 10
writeMem(memory, 0x0000, listOf(0xC9, 1))
mpu.regA = 10
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertFalse(mpu.regP.N) // 0x0A-0x01 = 0x09
assertFalse(mpu.regP.Z)
assertTrue(mpu.regP.C) // A>m unsigned
}
@Test
fun test_cmp_imm_clears_zero_carry_takes_neg_if_more_signed() {
// Comparison: A > m (signed), memory negative
// $0000 CMP #$FF (-1), A will be 2
writeMem(memory, 0x0000, listOf(0xC9, 0xFF))
mpu.regA = 2
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertFalse(mpu.regP.N) // 0x02-0xFF=0x01
assertFalse(mpu.regP.Z)
assertFalse(mpu.regP.C) // A<m unsigned
}
@Test
fun test_cmp_imm_clears_zero_carry_takes_neg_if_more_signed_nega() {
// Comparison: A > m (signed), A and m both negative
// $0000 CMP #$FE (-2), A will be -1 (0xFF)
writeMem(memory, 0x0000, listOf(0xC9, 0xFE))
mpu.regA = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertFalse(mpu.regP.N) // 0xFF-0xFE=0x01
assertFalse(mpu.regP.Z)
assertTrue(mpu.regP.C) // A>m unsigned
}
// CPX Immediate
@Test
fun test_cpx_imm_sets_zero_carry_clears_neg_flags_if_equal() {
// Comparison: X == m
// $0000 CPX #$20
writeMem(memory, 0x0000, listOf(0xE0, 0x20))
mpu.regX = 0x20
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertTrue(mpu.regP.Z)
assertTrue(mpu.regP.C)
assertFalse(mpu.regP.N)
}
// CPY Immediate
@Test
fun test_cpy_imm_sets_zero_carry_clears_neg_flags_if_equal() {
// Comparison: Y == m
// $0000 CPY #$30
writeMem(memory, 0x0000, listOf(0xC0, 0x30))
mpu.regY = 0x30
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertTrue(mpu.regP.Z)
assertTrue(mpu.regP.C)
assertFalse(mpu.regP.N)
}
// DEC Absolute
@Test
fun test_dec_abs_decrements_memory() {
// $0000 DEC 0xABCD
writeMem(memory, 0x0000, listOf(0xCE, 0xCD, 0xAB))
memory[0xABCD] = 0x10
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x0F, memory[0xABCD])
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_dec_abs_below_00_rolls_over_and_sets_negative_flag() {
// $0000 DEC 0xABCD
writeMem(memory, 0x0000, listOf(0xCE, 0xCD, 0xAB))
memory[0xABCD] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0xFF, memory[0xABCD])
assertFalse(mpu.regP.Z)
assertTrue(mpu.regP.N)
}
@Test
fun test_dec_abs_sets_zero_flag_when_decrementing_to_zero() {
// $0000 DEC 0xABCD
writeMem(memory, 0x0000, listOf(0xCE, 0xCD, 0xAB))
memory[0xABCD] = 0x01
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, memory[0xABCD])
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
// DEC Zero Page
@Test
fun test_dec_zp_decrements_memory() {
// $0000 DEC 0x0010
writeMem(memory, 0x0000, listOf(0xC6, 0x10))
memory[0x0010] = 0x10
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x0F, memory[0x0010])
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_dec_zp_below_00_rolls_over_and_sets_negative_flag() {
// $0000 DEC 0x0010
writeMem(memory, 0x0000, listOf(0xC6, 0x10))
memory[0x0010] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xFF, memory[0x0010])
assertFalse(mpu.regP.Z)
assertTrue(mpu.regP.N)
}
@Test
fun test_dec_zp_sets_zero_flag_when_decrementing_to_zero() {
// $0000 DEC 0x0010
writeMem(memory, 0x0000, listOf(0xC6, 0x10))
memory[0x0010] = 0x01
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, memory[0x0010])
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
// DEC Absolute, X-Indexed
@Test
fun test_dec_abs_x_decrements_memory() {
// $0000 DEC 0xABCD,X
writeMem(memory, 0x0000, listOf(0xDE, 0xCD, 0xAB))
mpu.regX = 0x03
memory[0xABCD + mpu.regX] = 0x10
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x0F, memory[0xABCD + mpu.regX])
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_dec_abs_x_below_00_rolls_over_and_sets_negative_flag() {
// $0000 DEC 0xABCD,X
writeMem(memory, 0x0000, listOf(0xDE, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0xFF, memory[0xABCD + mpu.regX])
assertFalse(mpu.regP.Z)
assertTrue(mpu.regP.N)
}
@Test
fun test_dec_abs_x_sets_zero_flag_when_decrementing_to_zero() {
// $0000 DEC 0xABCD,X
writeMem(memory, 0x0000, listOf(0xDE, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0x01
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, memory[0xABCD + mpu.regX])
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
// DEC Zero Page, X-Indexed
@Test
fun test_dec_zp_x_decrements_memory() {
// $0000 DEC 0x0010,X
writeMem(memory, 0x0000, listOf(0xD6, 0x10))
mpu.regX = 0x03
memory[0x0010 + mpu.regX] = 0x10
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x0F, memory[0x0010 + mpu.regX])
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_dec_zp_x_below_00_rolls_over_and_sets_negative_flag() {
// $0000 DEC 0x0010,X
writeMem(memory, 0x0000, listOf(0xD6, 0x10))
mpu.regX = 0x03
memory[0x0010 + mpu.regX] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xFF, memory[0x0010 + mpu.regX])
assertFalse(mpu.regP.Z)
assertTrue(mpu.regP.N)
}
@Test
fun test_dec_zp_x_sets_zero_flag_when_decrementing_to_zero() {
// $0000 DEC 0x0010,X
writeMem(memory, 0x0000, listOf(0xD6, 0x10))
mpu.regX = 0x03
memory[0x0010 + mpu.regX] = 0x01
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, memory[0x0010 + mpu.regX])
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
// DEX
@Test
fun test_dex_decrements_x() {
mpu.regX = 0x10
// $0000 DEX
memory[0x0000] = 0xCA
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x0F, mpu.regX)
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_dex_below_00_rolls_over_and_sets_negative_flag() {
mpu.regX = 0x00
// $0000 DEX
memory[0x0000] = 0xCA
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0xFF, mpu.regX)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_dex_sets_zero_flag_when_decrementing_to_zero() {
mpu.regX = 0x01
// $0000 DEX
memory[0x0000] = 0xCA
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x00, mpu.regX)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
// DEY
@Test
fun test_dey_decrements_y() {
mpu.regY = 0x10
// $0000 DEY
memory[0x0000] = 0x88
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x0F, mpu.regY)
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_dey_below_00_rolls_over_and_sets_negative_flag() {
mpu.regY = 0x00
// $0000 DEY
memory[0x0000] = 0x88
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0xFF, mpu.regY)
assertTrue(mpu.regP.N)
}
@Test
fun test_dey_sets_zero_flag_when_decrementing_to_zero() {
mpu.regY = 0x01
// $0000 DEY
memory[0x0000] = 0x88
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x00, mpu.regY)
assertTrue(mpu.regP.Z)
}
// EOR Absolute
@Test
fun test_eor_absolute_flips_bits_over_setting_z_flag() {
mpu.regA = 0xFF
writeMem(memory, 0x0000, listOf(0x4D, 0xCD, 0xAB))
memory[0xABCD] = 0xFF
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertEquals(0xFF, memory[0xABCD])
assertTrue(mpu.regP.Z)
}
@Test
fun test_eor_absolute_flips_bits_over_setting_n_flag() {
mpu.regA = 0x00
writeMem(memory, 0x0000, listOf(0x4D, 0xCD, 0xAB))
memory[0xABCD] = 0xFF
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0xFF, mpu.regA)
assertEquals(0xFF, memory[0xABCD])
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
// EOR Zero Page
@Test
fun test_eor_zp_flips_bits_over_setting_z_flag() {
mpu.regA = 0xFF
writeMem(memory, 0x0000, listOf(0x45, 0x10))
memory[0x0010] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertEquals(0xFF, memory[0x0010])
assertTrue(mpu.regP.Z)
}
@Test
fun test_eor_zp_flips_bits_over_setting_n_flag() {
mpu.regA = 0x00
writeMem(memory, 0x0000, listOf(0x45, 0x10))
memory[0x0010] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xFF, mpu.regA)
assertEquals(0xFF, memory[0x0010])
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
// EOR Immediate
@Test
fun test_eor_immediate_flips_bits_over_setting_z_flag() {
mpu.regA = 0xFF
writeMem(memory, 0x0000, listOf(0x49, 0xFF))
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
}
@Test
fun test_eor_immediate_flips_bits_over_setting_n_flag() {
mpu.regA = 0x00
writeMem(memory, 0x0000, listOf(0x49, 0xFF))
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xFF, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
// EOR Absolute, X-Indexed
@Test
fun test_eor_abs_x_indexed_flips_bits_over_setting_z_flag() {
mpu.regA = 0xFF
mpu.regX = 0x03
writeMem(memory, 0x0000, listOf(0x5D, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0xFF
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertEquals(0xFF, memory[0xABCD + mpu.regX])
assertTrue(mpu.regP.Z)
}
@Test
fun test_eor_abs_x_indexed_flips_bits_over_setting_n_flag() {
mpu.regA = 0x00
mpu.regX = 0x03
writeMem(memory, 0x0000, listOf(0x5D, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0xFF
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0xFF, mpu.regA)
assertEquals(0xFF, memory[0xABCD + mpu.regX])
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
// EOR Absolute, Y-Indexed
@Test
fun test_eor_abs_y_indexed_flips_bits_over_setting_z_flag() {
mpu.regA = 0xFF
mpu.regY = 0x03
writeMem(memory, 0x0000, listOf(0x59, 0xCD, 0xAB))
memory[0xABCD + mpu.regY] = 0xFF
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertEquals(0xFF, memory[0xABCD + mpu.regY])
assertTrue(mpu.regP.Z)
}
@Test
fun test_eor_abs_y_indexed_flips_bits_over_setting_n_flag() {
mpu.regA = 0x00
mpu.regY = 0x03
writeMem(memory, 0x0000, listOf(0x59, 0xCD, 0xAB))
memory[0xABCD + mpu.regY] = 0xFF
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0xFF, mpu.regA)
assertEquals(0xFF, memory[0xABCD + mpu.regY])
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
// EOR Indirect, Indexed (X)
@Test
fun test_eor_ind_indexed_x_flips_bits_over_setting_z_flag() {
mpu.regA = 0xFF
mpu.regX = 0x03
writeMem(memory, 0x0000, listOf(0x41, 0x10)) // => EOR listOf($0010,X)
writeMem(memory, 0x0013, listOf(0xCD, 0xAB)) // => Vector to $ABCD
memory[0xABCD] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertEquals(0xFF, memory[0xABCD])
assertTrue(mpu.regP.Z)
}
@Test
fun test_eor_ind_indexed_x_flips_bits_over_setting_n_flag() {
mpu.regA = 0x00
mpu.regX = 0x03
writeMem(memory, 0x0000, listOf(0x41, 0x10)) // => EOR listOf($0010,X)
writeMem(memory, 0x0013, listOf(0xCD, 0xAB)) // => Vector to $ABCD
memory[0xABCD] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xFF, mpu.regA)
assertEquals(0xFF, memory[0xABCD])
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
// EOR Indexed, Indirect (Y)
@Test
fun test_eor_indexed_ind_y_flips_bits_over_setting_z_flag() {
mpu.regA = 0xFF
mpu.regY = 0x03
writeMem(memory, 0x0000, listOf(0x51, 0x10)) // => EOR listOf($0010),Y
writeMem(memory, 0x0010, listOf(0xCD, 0xAB)) // => Vector to $ABCD
memory[0xABCD + mpu.regY] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertEquals(0xFF, memory[0xABCD + mpu.regY])
assertTrue(mpu.regP.Z)
}
@Test
fun test_eor_indexed_ind_y_flips_bits_over_setting_n_flag() {
mpu.regA = 0x00
mpu.regY = 0x03
writeMem(memory, 0x0000, listOf(0x51, 0x10)) // => EOR listOf($0010),Y
writeMem(memory, 0x0010, listOf(0xCD, 0xAB)) // => Vector to $ABCD
memory[0xABCD + mpu.regY] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xFF, mpu.regA)
assertEquals(0xFF, memory[0xABCD + mpu.regY])
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
// EOR Zero Page, X-Indexed
@Test
fun test_eor_zp_x_indexed_flips_bits_over_setting_z_flag() {
mpu.regA = 0xFF
mpu.regX = 0x03
writeMem(memory, 0x0000, listOf(0x55, 0x10))
memory[0x0010 + mpu.regX] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertEquals(0xFF, memory[0x0010 + mpu.regX])
assertTrue(mpu.regP.Z)
}
@Test
fun test_eor_zp_x_indexed_flips_bits_over_setting_n_flag() {
mpu.regA = 0x00
mpu.regX = 0x03
writeMem(memory, 0x0000, listOf(0x55, 0x10))
memory[0x0010 + mpu.regX] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xFF, mpu.regA)
assertEquals(0xFF, memory[0x0010 + mpu.regX])
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
// INC Absolute
@Test
fun test_inc_abs_increments_memory() {
writeMem(memory, 0x0000, listOf(0xEE, 0xCD, 0xAB))
memory[0xABCD] = 0x09
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x0A, memory[0xABCD])
assertFalse(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_inc_abs_increments_memory_rolls_over_and_sets_zero_flag() {
writeMem(memory, 0x0000, listOf(0xEE, 0xCD, 0xAB))
memory[0xABCD] = 0xFF
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, memory[0xABCD])
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_inc_abs_sets_negative_flag_when_incrementing_above_7F() {
writeMem(memory, 0x0000, listOf(0xEE, 0xCD, 0xAB))
memory[0xABCD] = 0x7F
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x80, memory[0xABCD])
assertFalse(mpu.regP.Z)
assertTrue(mpu.regP.N)
}
// INC Zero Page
@Test
fun test_inc_zp_increments_memory() {
writeMem(memory, 0x0000, listOf(0xE6, 0x10))
memory[0x0010] = 0x09
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x0A, memory[0x0010])
assertFalse(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_inc_zp_increments_memory_rolls_over_and_sets_zero_flag() {
writeMem(memory, 0x0000, listOf(0xE6, 0x10))
memory[0x0010] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, memory[0x0010])
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_inc_zp_sets_negative_flag_when_incrementing_above_7F() {
writeMem(memory, 0x0000, listOf(0xE6, 0x10))
memory[0x0010] = 0x7F
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x80, memory[0x0010])
assertFalse(mpu.regP.Z)
assertTrue(mpu.regP.N)
}
// INC Absolute, X-Indexed
@Test
fun test_inc_abs_x_increments_memory() {
writeMem(memory, 0x0000, listOf(0xFE, 0xCD, 0xAB))
mpu.regX = 0x03
memory[0xABCD + mpu.regX] = 0x09
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x0A, memory[0xABCD + mpu.regX])
assertFalse(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_inc_abs_x_increments_memory_rolls_over_and_sets_zero_flag() {
writeMem(memory, 0x0000, listOf(0xFE, 0xCD, 0xAB))
mpu.regX = 0x03
memory[0xABCD + mpu.regX] = 0xFF
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, memory[0xABCD + mpu.regX])
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_inc_abs_x_sets_negative_flag_when_incrementing_above_7F() {
writeMem(memory, 0x0000, listOf(0xFE, 0xCD, 0xAB))
mpu.regX = 0x03
memory[0xABCD + mpu.regX] = 0x7F
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x80, memory[0xABCD + mpu.regX])
assertFalse(mpu.regP.Z)
assertTrue(mpu.regP.N)
}
// INC Zero Page, X-Indexed
@Test
fun test_inc_zp_x_increments_memory() {
writeMem(memory, 0x0000, listOf(0xF6, 0x10))
mpu.regX = 0x03
memory[0x0010 + mpu.regX] = 0x09
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x0A, memory[0x0010 + mpu.regX])
assertFalse(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_inc_zp_x_increments_memory_rolls_over_and_sets_zero_flag() {
writeMem(memory, 0x0000, listOf(0xF6, 0x10))
memory[0x0010 + mpu.regX] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, memory[0x0010 + mpu.regX])
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_inc_zp_x_sets_negative_flag_when_incrementing_above_7F() {
writeMem(memory, 0x0000, listOf(0xF6, 0x10))
memory[0x0010 + mpu.regX] = 0x7F
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x80, memory[0x0010 + mpu.regX])
assertFalse(mpu.regP.Z)
assertTrue(mpu.regP.N)
}
// INX
@Test
fun test_inx_increments_x() {
mpu.regX = 0x09
memory[0x0000] = 0xE8 // => INX
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x0A, mpu.regX)
assertFalse(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_inx_above_FF_rolls_over_and_sets_zero_flag() {
mpu.regX = 0xFF
memory[0x0000] = 0xE8 // => INX
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x00, mpu.regX)
assertTrue(mpu.regP.Z)
}
@Test
fun test_inx_sets_negative_flag_when_incrementing_above_7F() {
mpu.regX = 0x7f
memory[0x0000] = 0xE8 // => INX
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x80, mpu.regX)
assertTrue(mpu.regP.N)
}
// INY
@Test
fun test_iny_increments_y() {
mpu.regY = 0x09
memory[0x0000] = 0xC8 // => INY
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x0A, mpu.regY)
assertFalse(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_iny_above_FF_rolls_over_and_sets_zero_flag() {
mpu.regY = 0xFF
memory[0x0000] = 0xC8 // => INY
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x00, mpu.regY)
assertTrue(mpu.regP.Z)
}
@Test
fun test_iny_sets_negative_flag_when_incrementing_above_7F() {
mpu.regY = 0x7f
memory[0x0000] = 0xC8 // => INY
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x80, mpu.regY)
assertTrue(mpu.regP.N)
}
// JMP Absolute
@Test
fun test_jmp_abs_jumps_to_absolute_address() {
// $0000 JMP $ABCD
writeMem(memory, 0x0000, listOf(0x4C, 0xCD, 0xAB))
mpu.step()
assertEquals(0xABCD, mpu.regPC)
}
// JMP Indirect
@Test
fun test_jmp_ind_jumps_to_indirect_address() {
// $0000 JMP ($ABCD)
writeMem(memory, 0x0000, listOf(0x6C, 0x00, 0x02))
writeMem(memory, 0x0200, listOf(0xCD, 0xAB))
mpu.step()
assertEquals(0xABCD, mpu.regPC)
}
// JSR
@Test
fun test_jsr_pushes_pc_plus_2_and_sets_pc() {
// $C000 JSR $FFD2
mpu.regSP = 0xFF
writeMem(memory, 0xC000, listOf(0x20, 0xD2, 0xFF))
mpu.regPC = 0xC000
mpu.step()
assertEquals(0xFFD2, mpu.regPC)
assertEquals(0xFD, mpu.regSP)
assertEquals(0xC0, memory[0x01FF]) // PCH
assertEquals(0x02, memory[0x01FE]) // PCL+2
}
// LDA Absolute
@Test
fun test_lda_absolute_loads_a_sets_n_flag() {
mpu.regA = 0x00
// $0000 LDA $ABCD
writeMem(memory, 0x0000, listOf(0xAD, 0xCD, 0xAB))
memory[0xABCD] = 0x80
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_lda_absolute_loads_a_sets_z_flag() {
mpu.regA = 0xFF
// $0000 LDA $ABCD
writeMem(memory, 0x0000, listOf(0xAD, 0xCD, 0xAB))
memory[0xABCD] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
// LDA Zero Page
@Test
fun test_lda_zp_loads_a_sets_n_flag() {
mpu.regA = 0x00
// $0000 LDA $0010
writeMem(memory, 0x0000, listOf(0xA5, 0x10))
memory[0x0010] = 0x80
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_lda_zp_loads_a_sets_z_flag() {
mpu.regA = 0xFF
// $0000 LDA $0010
writeMem(memory, 0x0000, listOf(0xA5, 0x10))
memory[0x0010] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
// LDA Immediate
@Test
fun test_lda_immediate_loads_a_sets_n_flag() {
mpu.regA = 0x00
// $0000 LDA #$80
writeMem(memory, 0x0000, listOf(0xA9, 0x80))
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_lda_immediate_loads_a_sets_z_flag() {
mpu.regA = 0xFF
// $0000 LDA #$00
writeMem(memory, 0x0000, listOf(0xA9, 0x00))
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
// LDA Absolute, X-Indexed
@Test
fun test_lda_abs_x_indexed_loads_a_sets_n_flag() {
mpu.regA = 0x00
mpu.regX = 0x03
// $0000 LDA $ABCD,X
writeMem(memory, 0x0000, listOf(0xBD, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0x80
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_lda_abs_x_indexed_loads_a_sets_z_flag() {
mpu.regA = 0xFF
mpu.regX = 0x03
// $0000 LDA $ABCD,X
writeMem(memory, 0x0000, listOf(0xBD, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_lda_abs_x_indexed_does_not_page_wrap() {
mpu.regA = 0
mpu.regX = 0xFF
// $0000 LDA $0080,X
writeMem(memory, 0x0000, listOf(0xBD, 0x80, 0x00))
memory[0x0080 + mpu.regX] = 0x42
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x42, mpu.regA)
}
// LDA Absolute, Y-Indexed
@Test
fun test_lda_abs_y_indexed_loads_a_sets_n_flag() {
mpu.regA = 0x00
mpu.regY = 0x03
// $0000 LDA $ABCD,Y
writeMem(memory, 0x0000, listOf(0xB9, 0xCD, 0xAB))
memory[0xABCD + mpu.regY] = 0x80
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_lda_abs_y_indexed_loads_a_sets_z_flag() {
mpu.regA = 0xFF
mpu.regY = 0x03
// $0000 LDA $ABCD,Y
writeMem(memory, 0x0000, listOf(0xB9, 0xCD, 0xAB))
memory[0xABCD + mpu.regY] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_lda_abs_y_indexed_does_not_page_wrap() {
mpu.regA = 0
mpu.regY = 0xFF
// $0000 LDA $0080,X
writeMem(memory, 0x0000, listOf(0xB9, 0x80, 0x00))
memory[0x0080 + mpu.regY] = 0x42
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x42, mpu.regA)
}
// LDA Indirect, Indexed (X)
@Test
fun test_lda_ind_indexed_x_loads_a_sets_n_flag() {
mpu.regA = 0x00
mpu.regX = 0x03
// $0000 LDA ($0010,X)
// $0013 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0xA1, 0x10))
writeMem(memory, 0x0013, listOf(0xCD, 0xAB))
memory[0xABCD] = 0x80
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_lda_ind_indexed_x_loads_a_sets_z_flag() {
mpu.regA = 0x00
mpu.regX = 0x03
// $0000 LDA ($0010,X)
// $0013 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0xA1, 0x10))
writeMem(memory, 0x0013, listOf(0xCD, 0xAB))
memory[0xABCD] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
// LDA Indexed, Indirect (Y)
@Test
fun test_lda_indexed_ind_y_loads_a_sets_n_flag() {
mpu.regA = 0x00
mpu.regY = 0x03
// $0000 LDA ($0010),Y
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0xB1, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD + mpu.regY] = 0x80
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_lda_indexed_ind_y_correct_index() {
mpu.regA = 0x00
mpu.regY = 0xf3
// $0000 LDA ($0010),Y
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0xB1, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD + mpu.regY] = 0x80
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x80, mpu.regA)
}
@Test
fun test_lda_indexed_ind_y_loads_a_sets_z_flag() {
mpu.regA = 0x00
mpu.regY = 0x03
// $0000 LDA ($0010),Y
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0xB1, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD + mpu.regY] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
// LDA Zero Page, X-Indexed
@Test
fun test_lda_zp_x_indexed_loads_a_sets_n_flag() {
mpu.regA = 0x00
mpu.regX = 0x03
// $0000 LDA $10,X
writeMem(memory, 0x0000, listOf(0xB5, 0x10))
memory[0x0010 + mpu.regX] = 0x80
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_lda_zp_x_indexed_correct_index() {
mpu.regA = 0x00
mpu.regX = 0xf3
// $0000 LDA $10,X
writeMem(memory, 0x0000, listOf(0xB5, 0x10))
memory[(0x0010 + mpu.regX) and 255] = 0x80
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x80, mpu.regA)
}
@Test
fun test_lda_zp_x_indexed_loads_a_sets_z_flag() {
mpu.regA = 0xFF
mpu.regX = 0x03
// $0000 LDA $10,X
writeMem(memory, 0x0000, listOf(0xB5, 0x10))
memory[0x0010 + mpu.regX] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
// LDX Absolute
@Test
fun test_ldx_absolute_loads_x_sets_n_flag() {
mpu.regX = 0x00
// $0000 LDX $ABCD
writeMem(memory, 0x0000, listOf(0xAE, 0xCD, 0xAB))
memory[0xABCD] = 0x80
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x80, mpu.regX)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_ldx_absolute_loads_x_sets_z_flag() {
mpu.regX = 0xFF
// $0000 LDX $ABCD
writeMem(memory, 0x0000, listOf(0xAE, 0xCD, 0xAB))
memory[0xABCD] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, mpu.regX)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
// LDX Zero Page
@Test
fun test_ldx_zp_loads_x_sets_n_flag() {
mpu.regX = 0x00
// $0000 LDX $0010
writeMem(memory, 0x0000, listOf(0xA6, 0x10))
memory[0x0010] = 0x80
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x80, mpu.regX)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_ldx_zp_loads_x_sets_z_flag() {
mpu.regX = 0xFF
// $0000 LDX $0010
writeMem(memory, 0x0000, listOf(0xA6, 0x10))
memory[0x0010] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regX)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
// LDX Immediate
@Test
fun test_ldx_immediate_loads_x_sets_n_flag() {
mpu.regX = 0x00
// $0000 LDX #$80
writeMem(memory, 0x0000, listOf(0xA2, 0x80))
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x80, mpu.regX)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_ldx_immediate_loads_x_sets_z_flag() {
mpu.regX = 0xFF
// $0000 LDX #$00
writeMem(memory, 0x0000, listOf(0xA2, 0x00))
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regX)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
// LDX Absolute, Y-Indexed
@Test
fun test_ldx_abs_y_indexed_loads_x_sets_n_flag() {
mpu.regX = 0x00
mpu.regY = 0x03
// $0000 LDX $ABCD,Y
writeMem(memory, 0x0000, listOf(0xBE, 0xCD, 0xAB))
memory[0xABCD + mpu.regY] = 0x80
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x80, mpu.regX)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_ldx_abs_y_indexed_loads_x_sets_z_flag() {
mpu.regX = 0xFF
mpu.regY = 0x03
// $0000 LDX $ABCD,Y
writeMem(memory, 0x0000, listOf(0xBE, 0xCD, 0xAB))
memory[0xABCD + mpu.regY] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, mpu.regX)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
// LDX Zero Page, Y-Indexed
@Test
fun test_ldx_zp_y_indexed_loads_x_sets_n_flag() {
mpu.regX = 0x00
mpu.regY = 0x03
// $0000 LDX $0010,Y
writeMem(memory, 0x0000, listOf(0xB6, 0x10))
memory[0x0010 + mpu.regY] = 0x80
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x80, mpu.regX)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_ldx_zp_y_indexed_loads_x_sets_z_flag() {
mpu.regX = 0xFF
mpu.regY = 0x03
// $0000 LDX $0010,Y
writeMem(memory, 0x0000, listOf(0xB6, 0x10))
memory[0x0010 + mpu.regY] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regX)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
// LDY Absolute
@Test
fun test_ldy_absolute_loads_y_sets_n_flag() {
mpu.regY = 0x00
// $0000 LDY $ABCD
writeMem(memory, 0x0000, listOf(0xAC, 0xCD, 0xAB))
memory[0xABCD] = 0x80
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x80, mpu.regY)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_ldy_absolute_loads_y_sets_z_flag() {
mpu.regY = 0xFF
// $0000 LDY $ABCD
writeMem(memory, 0x0000, listOf(0xAC, 0xCD, 0xAB))
memory[0xABCD] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, mpu.regY)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
// LDY Zero Page
@Test
fun test_ldy_zp_loads_y_sets_n_flag() {
mpu.regY = 0x00
// $0000 LDY $0010
writeMem(memory, 0x0000, listOf(0xA4, 0x10))
memory[0x0010] = 0x80
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x80, mpu.regY)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_ldy_zp_loads_y_sets_z_flag() {
mpu.regY = 0xFF
// $0000 LDY $0010
writeMem(memory, 0x0000, listOf(0xA4, 0x10))
memory[0x0010] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regY)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
// LDY Immediate
@Test
fun test_ldy_immediate_loads_y_sets_n_flag() {
mpu.regY = 0x00
// $0000 LDY #$80
writeMem(memory, 0x0000, listOf(0xA0, 0x80))
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x80, mpu.regY)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_ldy_immediate_loads_y_sets_z_flag() {
mpu.regY = 0xFF
// $0000 LDY #$00
writeMem(memory, 0x0000, listOf(0xA0, 0x00))
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regY)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
// LDY Absolute, X-Indexed
@Test
fun test_ldy_abs_x_indexed_loads_x_sets_n_flag() {
mpu.regY = 0x00
mpu.regX = 0x03
// $0000 LDY $ABCD,X
writeMem(memory, 0x0000, listOf(0xBC, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0x80
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x80, mpu.regY)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_ldy_abs_x_indexed_loads_x_sets_z_flag() {
mpu.regY = 0xFF
mpu.regX = 0x03
// $0000 LDY $ABCD,X
writeMem(memory, 0x0000, listOf(0xBC, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, mpu.regY)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
// LDY Zero Page, X-Indexed
@Test
fun test_ldy_zp_x_indexed_loads_x_sets_n_flag() {
mpu.regY = 0x00
mpu.regX = 0x03
// $0000 LDY $0010,X
writeMem(memory, 0x0000, listOf(0xB4, 0x10))
memory[0x0010 + mpu.regX] = 0x80
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x80, mpu.regY)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_ldy_zp_x_indexed_loads_x_sets_z_flag() {
mpu.regY = 0xFF
mpu.regX = 0x03
// $0000 LDY $0010,X
writeMem(memory, 0x0000, listOf(0xB4, 0x10))
memory[0x0010 + mpu.regX] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regY)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
// LSR Accumulator
@Test
fun test_lsr_accumulator_rotates_in_zero_not_carry() {
mpu.regP.C = true
// $0000 LSR A
memory[0x0000] = (0x4A)
mpu.regA = 0x00
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.C)
assertFalse(mpu.regP.N)
}
@Test
fun test_lsr_accumulator_sets_carry_and_zero_flags_after_rotation() {
mpu.regP.C = false
// $0000 LSR A
memory[0x0000] = (0x4A)
mpu.regA = 0x01
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
assertTrue(mpu.regP.C)
assertFalse(mpu.regP.N)
}
@Test
fun test_lsr_accumulator_rotates_bits_right() {
mpu.regP.C = true
// $0000 LSR A
memory[0x0000] = (0x4A)
mpu.regA = 0x04
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x02, mpu.regA)
assertFalse(mpu.regP.Z)
assertFalse(mpu.regP.C)
assertFalse(mpu.regP.N)
}
// LSR Absolute
@Test
fun test_lsr_absolute_rotates_in_zero_not_carry() {
mpu.regP.C = true
// $0000 LSR $ABCD
writeMem(memory, 0x0000, listOf(0x4E, 0xCD, 0xAB))
memory[0xABCD] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, memory[0xABCD])
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.C)
assertFalse(mpu.regP.N)
}
@Test
fun test_lsr_absolute_sets_carry_and_zero_flags_after_rotation() {
mpu.regP.C = false
// $0000 LSR $ABCD
writeMem(memory, 0x0000, listOf(0x4E, 0xCD, 0xAB))
memory[0xABCD] = 0x01
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, memory[0xABCD])
assertTrue(mpu.regP.Z)
assertTrue(mpu.regP.C)
assertFalse(mpu.regP.N)
}
@Test
fun test_lsr_absolute_rotates_bits_right() {
mpu.regP.C = true
// $0000 LSR $ABCD
writeMem(memory, 0x0000, listOf(0x4E, 0xCD, 0xAB))
memory[0xABCD] = 0x04
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x02, memory[0xABCD])
assertFalse(mpu.regP.Z)
assertFalse(mpu.regP.C)
assertFalse(mpu.regP.N)
}
// LSR Zero Page
@Test
fun test_lsr_zp_rotates_in_zero_not_carry() {
mpu.regP.C = true
// $0000 LSR $0010
writeMem(memory, 0x0000, listOf(0x46, 0x10))
memory[0x0010] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, memory[0x0010])
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.C)
assertFalse(mpu.regP.N)
}
@Test
fun test_lsr_zp_sets_carry_and_zero_flags_after_rotation() {
mpu.regP.C = false
// $0000 LSR $0010
writeMem(memory, 0x0000, listOf(0x46, 0x10))
memory[0x0010] = 0x01
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, memory[0x0010])
assertTrue(mpu.regP.Z)
assertTrue(mpu.regP.C)
assertFalse(mpu.regP.N)
}
@Test
fun test_lsr_zp_rotates_bits_right() {
mpu.regP.C = true
// $0000 LSR $0010
writeMem(memory, 0x0000, listOf(0x46, 0x10))
memory[0x0010] = 0x04
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x02, memory[0x0010])
assertFalse(mpu.regP.Z)
assertFalse(mpu.regP.C)
assertFalse(mpu.regP.N)
}
// LSR Absolute, X-Indexed
@Test
fun test_lsr_abs_x_indexed_rotates_in_zero_not_carry() {
mpu.regP.C = true
mpu.regX = 0x03
// $0000 LSR $ABCD,X
writeMem(memory, 0x0000, listOf(0x5E, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, memory[0xABCD + mpu.regX])
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.C)
assertFalse(mpu.regP.N)
}
@Test
fun test_lsr_abs_x_indexed_sets_c_and_z_flags_after_rotation() {
mpu.regP.C = false
mpu.regX = 0x03
// $0000 LSR $ABCD,X
writeMem(memory, 0x0000, listOf(0x5E, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0x01
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, memory[0xABCD + mpu.regX])
assertTrue(mpu.regP.Z)
assertTrue(mpu.regP.C)
assertFalse(mpu.regP.N)
}
@Test
fun test_lsr_abs_x_indexed_rotates_bits_right() {
mpu.regP.C = true
// $0000 LSR $ABCD,X
writeMem(memory, 0x0000, listOf(0x5E, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0x04
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x02, memory[0xABCD + mpu.regX])
assertFalse(mpu.regP.Z)
assertFalse(mpu.regP.C)
assertFalse(mpu.regP.N)
}
// LSR Zero Page, X-Indexed
@Test
fun test_lsr_zp_x_indexed_rotates_in_zero_not_carry() {
mpu.regP.C = true
mpu.regX = 0x03
// $0000 LSR $0010,X
writeMem(memory, 0x0000, listOf(0x56, 0x10))
memory[0x0010 + mpu.regX] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, memory[0x0010 + mpu.regX])
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.C)
assertFalse(mpu.regP.N)
}
@Test
fun test_lsr_zp_x_indexed_sets_carry_and_zero_flags_after_rotation() {
mpu.regP.C = false
mpu.regX = 0x03
// $0000 LSR $0010,X
writeMem(memory, 0x0000, listOf(0x56, 0x10))
memory[0x0010 + mpu.regX] = 0x01
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, memory[0x0010 + mpu.regX])
assertTrue(mpu.regP.Z)
assertTrue(mpu.regP.C)
assertFalse(mpu.regP.N)
}
@Test
fun test_lsr_zp_x_indexed_rotates_bits_right() {
mpu.regP.C = true
mpu.regX = 0x03
// $0000 LSR $0010,X
writeMem(memory, 0x0000, listOf(0x56, 0x10))
memory[0x0010 + mpu.regX] = 0x04
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x02, memory[0x0010 + mpu.regX])
assertFalse(mpu.regP.Z)
assertFalse(mpu.regP.C)
assertFalse(mpu.regP.N)
}
// NOP
@Test
fun test_nop_does_nothing() {
// $0000 NOP
memory[0x0000] = 0xEA
mpu.step()
assertEquals(0x0001, mpu.regPC)
}
// ORA Absolute
@Test
fun test_ora_absolute_zeroes_or_zeros_sets_z_flag() {
mpu.regP.Z = false
mpu.regA = 0x00
// $0000 ORA $ABCD
writeMem(memory, 0x0000, listOf(0x0D, 0xCD, 0xAB))
memory[0xABCD] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
}
@Test
fun test_ora_absolute_turns_bits_on_sets_n_flag() {
mpu.regP.N = false
mpu.regA = 0x03
// $0000 ORA $ABCD
writeMem(memory, 0x0000, listOf(0x0D, 0xCD, 0xAB))
memory[0xABCD] = 0x82
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x83, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
// ORA Zero Page
@Test
fun test_ora_zp_zeroes_or_zeros_sets_z_flag() {
mpu.regP.Z = false
mpu.regA = 0x00
// $0000 ORA $0010
writeMem(memory, 0x0000, listOf(0x05, 0x10))
memory[0x0010] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
}
@Test
fun test_ora_zp_turns_bits_on_sets_n_flag() {
mpu.regP.N = false
mpu.regA = 0x03
// $0000 ORA $0010
writeMem(memory, 0x0000, listOf(0x05, 0x10))
memory[0x0010] = 0x82
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x83, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
// ORA Immediate
@Test
fun test_ora_immediate_zeroes_or_zeros_sets_z_flag() {
mpu.regP.Z = false
mpu.regA = 0x00
// $0000 ORA #$00
writeMem(memory, 0x0000, listOf(0x09, 0x00))
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
}
@Test
fun test_ora_immediate_turns_bits_on_sets_n_flag() {
mpu.regP.N = false
mpu.regA = 0x03
// $0000 ORA #$82
writeMem(memory, 0x0000, listOf(0x09, 0x82))
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x83, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
// ORA Absolute, X
@Test
fun test_ora_abs_x_indexed_zeroes_or_zeros_sets_z_flag() {
mpu.regP.Z = false
mpu.regA = 0x00
mpu.regX = 0x03
// $0000 ORA $ABCD,X
writeMem(memory, 0x0000, listOf(0x1D, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
}
@Test
fun test_ora_abs_x_indexed_turns_bits_on_sets_n_flag() {
mpu.regP.N = false
mpu.regA = 0x03
mpu.regX = 0x03
// $0000 ORA $ABCD,X
writeMem(memory, 0x0000, listOf(0x1D, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0x82
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x83, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
// ORA Absolute, Y
@Test
fun test_ora_abs_y_indexed_zeroes_or_zeros_sets_z_flag() {
mpu.regP.Z = false
mpu.regA = 0x00
mpu.regY = 0x03
// $0000 ORA $ABCD,Y
writeMem(memory, 0x0000, listOf(0x19, 0xCD, 0xAB))
memory[0xABCD + mpu.regY] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
}
@Test
fun test_ora_abs_y_indexed_turns_bits_on_sets_n_flag() {
mpu.regP.N = false
mpu.regA = 0x03
mpu.regY = 0x03
// $0000 ORA $ABCD,Y
writeMem(memory, 0x0000, listOf(0x19, 0xCD, 0xAB))
memory[0xABCD + mpu.regY] = 0x82
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x83, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
// ORA Indirect, Indexed (X)
@Test
fun test_ora_ind_indexed_x_zeroes_or_zeros_sets_z_flag() {
mpu.regP.Z = false
mpu.regA = 0x00
mpu.regX = 0x03
// $0000 ORA ($0010,X)
// $0013 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x01, 0x10))
writeMem(memory, 0x0013, listOf(0xCD, 0xAB))
memory[0xABCD] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
}
@Test
fun test_ora_ind_indexed_x_turns_bits_on_sets_n_flag() {
mpu.regP.N = false
mpu.regA = 0x03
mpu.regX = 0x03
// $0000 ORA ($0010,X)
// $0013 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x01, 0x10))
writeMem(memory, 0x0013, listOf(0xCD, 0xAB))
memory[0xABCD] = 0x82
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x83, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
// ORA Indexed, Indirect (Y)
@Test
fun test_ora_indexed_ind_y_zeroes_or_zeros_sets_z_flag() {
mpu.regP.Z = false
mpu.regA = 0x00
mpu.regY = 0x03
// $0000 ORA ($0010),Y
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x11, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD + mpu.regY] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
}
@Test
fun test_ora_indexed_ind_y_turns_bits_on_sets_n_flag() {
mpu.regP.N = false
mpu.regA = 0x03
mpu.regY = 0x03
// $0000 ORA ($0010),Y
// $0010 Vector to $ABCD
writeMem(memory, 0x0000, listOf(0x11, 0x10))
writeMem(memory, 0x0010, listOf(0xCD, 0xAB))
memory[0xABCD + mpu.regY] = 0x82
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x83, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
// ORA Zero Page, X
@Test
fun test_ora_zp_x_indexed_zeroes_or_zeros_sets_z_flag() {
mpu.regP.Z = false
mpu.regA = 0x00
mpu.regX = 0x03
// $0000 ORA $0010,X
writeMem(memory, 0x0000, listOf(0x15, 0x10))
memory[0x0010 + mpu.regX] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
}
@Test
fun test_ora_zp_x_indexed_turns_bits_on_sets_n_flag() {
mpu.regP.N = false
mpu.regA = 0x03
mpu.regX = 0x03
// $0000 ORA $0010,X
writeMem(memory, 0x0000, listOf(0x15, 0x10))
memory[0x0010 + mpu.regX] = 0x82
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x83, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
// PHA
@Test
fun test_pha_pushes_a_and_updates_sp() {
mpu.regA = 0xAB
// $0000 PHA
memory[0x0000] = 0x48
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0xAB, mpu.regA)
assertEquals(0xFC, mpu.regSP)
assertEquals(0xAB, memory[0x01FD])
}
// PHP
@Test
fun test_php_pushes_processor_status_and_updates_sp() {
for (flags in 0 until 0x100) {
mpu.reset()
mpu.regP.fromInt(flags or fBREAK or fUNUSED)
// $0000 PHP
memory[0x0000] = 0x08
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0xFC, mpu.regSP)
assertEquals((flags or fBREAK or fUNUSED), memory[0x1FD].toInt())
}
}
// PLA
@Test
fun test_pla_pulls_top_byte_from_stack_into_a_and_updates_sp() {
// $0000 PLA
memory[0x0000] = 0x68
memory[0x01FF] = 0xAB
mpu.regSP = 0xFE
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0xAB, mpu.regA)
assertEquals(0xFF, mpu.regSP)
}
// PLP
@Test
fun test_plp_pulls_top_byte_from_stack_into_flags_and_updates_sp() {
mpu.regP.fromInt(0)
memory[0x01FF] = 0xBA // must have BREAK and UNUSED set
memory[0x0000] = 0x28 // PLP
mpu.regSP = 0xFE
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0xAA, mpu.regP.asInt()) // BREAK cleared
assertEquals(0xFF, mpu.regSP)
}
// ROL Accumulator
@Test
fun test_rol_accumulator_zero_and_carry_zero_sets_z_flag() {
mpu.regA = 0x00
mpu.regP.C = false
memory[0x0000] = 0x2A // ROL A
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_rol_accumulator_80_and_carry_zero_sets_z_flag() {
mpu.regA = 0x80
mpu.regP.C = false
mpu.regP.Z = false
// $0000 ROL A
memory[0x0000] = 0x2A
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_rol_accumulator_zero_and_carry_one_clears_z_flag() {
mpu.regA = 0x00
mpu.regP.C = true
// $0000 ROL A
memory[0x0000] = 0x2A
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x01, mpu.regA)
assertFalse(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_rol_accumulator_sets_n_flag() {
mpu.regA = 0x40
mpu.regP.C = true
// $0000 ROL A
memory[0x0000] = 0x2A
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x81, mpu.regA)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_rol_accumulator_shifts_out_zero() {
mpu.regA = 0x7F
mpu.regP.C = false
// $0000 ROL A
memory[0x0000] = 0x2A
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0xFE, mpu.regA)
assertFalse(mpu.regP.C)
}
@Test
fun test_rol_accumulator_shifts_out_one() {
mpu.regA = 0xFF
mpu.regP.C = false
// $0000 ROL A
memory[0x0000] = 0x2A
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0xFE, mpu.regA)
assertTrue(mpu.regP.C)
}
// ROL Absolute
@Test
fun test_rol_absolute_zero_and_carry_zero_sets_z_flag() {
mpu.regP.C = false
// $0000 ROL $ABCD
writeMem(memory, 0x0000, listOf(0x2E, 0xCD, 0xAB))
memory[0xABCD] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, memory[0xABCD])
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_rol_absolute_80_and_carry_zero_sets_z_flag() {
mpu.regP.C = false
mpu.regP.Z = false
// $0000 ROL $ABCD
writeMem(memory, 0x0000, listOf(0x2E, 0xCD, 0xAB))
memory[0xABCD] = 0x80
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, memory[0xABCD])
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_rol_absolute_zero_and_carry_one_clears_z_flag() {
mpu.regA = 0x00
mpu.regP.C = true
// $0000 ROL $ABCD
writeMem(memory, 0x0000, listOf(0x2E, 0xCD, 0xAB))
memory[0xABCD] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x01, memory[0xABCD])
assertFalse(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_rol_absolute_sets_n_flag() {
mpu.regP.C = true
// $0000 ROL $ABCD
writeMem(memory, 0x0000, listOf(0x2E, 0xCD, 0xAB))
memory[0xABCD] = 0x40
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x81, memory[0xABCD])
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_rol_absolute_shifts_out_zero() {
mpu.regP.C = false
// $0000 ROL $ABCD
writeMem(memory, 0x0000, listOf(0x2E, 0xCD, 0xAB))
memory[0xABCD] = 0x7F
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0xFE, memory[0xABCD])
assertFalse(mpu.regP.C)
}
@Test
fun test_rol_absolute_shifts_out_one() {
mpu.regP.C = false
// $0000 ROL $ABCD
writeMem(memory, 0x0000, listOf(0x2E, 0xCD, 0xAB))
memory[0xABCD] = 0xFF
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0xFE, memory[0xABCD])
assertTrue(mpu.regP.C)
}
// ROL Zero Page
@Test
fun test_rol_zp_zero_and_carry_zero_sets_z_flag() {
mpu.regP.C = false
// $0000 ROL $0010
writeMem(memory, 0x0000, listOf(0x26, 0x10))
memory[0x0010] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, memory[0x0010])
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_rol_zp_80_and_carry_zero_sets_z_flag() {
mpu.regP.C = false
mpu.regP.Z = false
// $0000 ROL $0010
writeMem(memory, 0x0000, listOf(0x26, 0x10))
memory[0x0010] = 0x80
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, memory[0x0010])
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_rol_zp_zero_and_carry_one_clears_z_flag() {
mpu.regA = 0x00
mpu.regP.C = true
// $0000 ROL $0010
writeMem(memory, 0x0000, listOf(0x26, 0x10))
memory[0x0010] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x01, memory[0x0010])
assertFalse(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_rol_zp_sets_n_flag() {
mpu.regP.C = true
// $0000 ROL $0010
writeMem(memory, 0x0000, listOf(0x26, 0x10))
memory[0x0010] = 0x40
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x81, memory[0x0010])
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_rol_zp_shifts_out_zero() {
mpu.regP.C = false
// $0000 ROL $0010
writeMem(memory, 0x0000, listOf(0x26, 0x10))
memory[0x0010] = 0x7F
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xFE, memory[0x0010])
assertFalse(mpu.regP.C)
}
@Test
fun test_rol_zp_shifts_out_one() {
mpu.regP.C = false
// $0000 ROL $0010
writeMem(memory, 0x0000, listOf(0x26, 0x10))
memory[0x0010] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xFE, memory[0x0010])
assertTrue(mpu.regP.C)
}
// ROL Absolute, X-Indexed
@Test
fun test_rol_abs_x_indexed_zero_and_carry_zero_sets_z_flag() {
mpu.regP.C = false
mpu.regX = 0x03
// $0000 ROL $ABCD,X
writeMem(memory, 0x0000, listOf(0x3E, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, memory[0xABCD + mpu.regX])
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_rol_abs_x_indexed_80_and_carry_zero_sets_z_flag() {
mpu.regP.C = false
mpu.regP.Z = false
mpu.regX = 0x03
// $0000 ROL $ABCD,X
writeMem(memory, 0x0000, listOf(0x3E, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0x80
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, memory[0xABCD + mpu.regX])
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_rol_abs_x_indexed_zero_and_carry_one_clears_z_flag() {
mpu.regX = 0x03
mpu.regP.C = true
// $0000 ROL $ABCD,X
writeMem(memory, 0x0000, listOf(0x3E, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x01, memory[0xABCD + mpu.regX])
assertFalse(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_rol_abs_x_indexed_sets_n_flag() {
mpu.regX = 0x03
mpu.regP.C = true
// $0000 ROL $ABCD,X
writeMem(memory, 0x0000, listOf(0x3E, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0x40
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x81, memory[0xABCD + mpu.regX])
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_rol_abs_x_indexed_shifts_out_zero() {
mpu.regX = 0x03
mpu.regP.C = false
// $0000 ROL $ABCD,X
writeMem(memory, 0x0000, listOf(0x3E, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0x7F
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0xFE, memory[0xABCD + mpu.regX])
assertFalse(mpu.regP.C)
}
@Test
fun test_rol_abs_x_indexed_shifts_out_one() {
mpu.regX = 0x03
mpu.regP.C = false
// $0000 ROL $ABCD,X
writeMem(memory, 0x0000, listOf(0x3E, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0xFF
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0xFE, memory[0xABCD + mpu.regX])
assertTrue(mpu.regP.C)
}
// ROL Zero Page, X-Indexed
@Test
fun test_rol_zp_x_indexed_zero_and_carry_zero_sets_z_flag() {
mpu.regP.C = false
mpu.regX = 0x03
writeMem(memory, 0x0000, listOf(0x36, 0x10))
// $0000 ROL $0010,X
memory[0x0010 + mpu.regX] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, memory[0x0010 + mpu.regX])
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_rol_zp_x_indexed_80_and_carry_zero_sets_z_flag() {
mpu.regP.C = false
mpu.regP.Z = false
mpu.regX = 0x03
writeMem(memory, 0x0000, listOf(0x36, 0x10))
// $0000 ROL $0010,X
memory[0x0010 + mpu.regX] = 0x80
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, memory[0x0010 + mpu.regX])
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_rol_zp_x_indexed_zero_and_carry_one_clears_z_flag() {
mpu.regX = 0x03
mpu.regP.C = true
writeMem(memory, 0x0000, listOf(0x36, 0x10))
// $0000 ROL $0010,X
memory[0x0010 + mpu.regX] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x01, memory[0x0010 + mpu.regX])
assertFalse(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_rol_zp_x_indexed_sets_n_flag() {
mpu.regX = 0x03
mpu.regP.C = true
// $0000 ROL $0010,X
writeMem(memory, 0x0000, listOf(0x36, 0x10))
memory[0x0010 + mpu.regX] = 0x40
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x81, memory[0x0010 + mpu.regX])
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.Z)
}
@Test
fun test_rol_zp_x_indexed_shifts_out_zero() {
mpu.regX = 0x03
mpu.regP.C = false
// $0000 ROL $0010,X
writeMem(memory, 0x0000, listOf(0x36, 0x10))
memory[0x0010 + mpu.regX] = 0x7F
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xFE, memory[0x0010 + mpu.regX])
assertFalse(mpu.regP.C)
}
@Test
fun test_rol_zp_x_indexed_shifts_out_one() {
mpu.regX = 0x03
mpu.regP.C = false
// $0000 ROL $0010,X
writeMem(memory, 0x0000, listOf(0x36, 0x10))
memory[0x0010 + mpu.regX] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xFE, memory[0x0010 + mpu.regX])
assertTrue(mpu.regP.C)
}
// ROR Accumulator
@Test
fun test_ror_accumulator_zero_and_carry_zero_sets_z_flag() {
mpu.regA = 0x00
mpu.regP.C = false
// $0000 ROR A
memory[0x0000] = 0x6A
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_ror_accumulator_zero_and_carry_one_rotates_in_sets_n_flags() {
mpu.regA = 0x00
mpu.regP.C = true
// $0000 ROR A
memory[0x0000] = 0x6A
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertFalse(mpu.regP.Z)
assertTrue(mpu.regP.N)
}
@Test
fun test_ror_accumulator_shifts_out_zero() {
mpu.regA = 0x02
mpu.regP.C = true
// $0000 ROR A
memory[0x0000] = 0x6A
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x81, mpu.regA)
assertFalse(mpu.regP.C)
}
@Test
fun test_ror_accumulator_shifts_out_one() {
mpu.regA = 0x03
mpu.regP.C = true
// $0000 ROR A
memory[0x0000] = 0x6A
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x81, mpu.regA)
assertTrue(mpu.regP.C)
}
// ROR Absolute
@Test
fun test_ror_absolute_zero_and_carry_zero_sets_z_flag() {
mpu.regP.C = false
// $0000 ROR $ABCD
writeMem(memory, 0x0000, listOf(0x6E, 0xCD, 0xAB))
memory[0xABCD] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, memory[0xABCD])
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_ror_absolute_zero_and_carry_one_rotates_in_sets_n_flags() {
mpu.regP.C = true
// $0000 ROR $ABCD
writeMem(memory, 0x0000, listOf(0x6E, 0xCD, 0xAB))
memory[0xABCD] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x80, memory[0xABCD])
assertFalse(mpu.regP.Z)
assertTrue(mpu.regP.N)
}
@Test
fun test_ror_absolute_shifts_out_zero() {
mpu.regP.C = true
// $0000 ROR $ABCD
writeMem(memory, 0x0000, listOf(0x6E, 0xCD, 0xAB))
memory[0xABCD] = 0x02
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x81, memory[0xABCD])
assertFalse(mpu.regP.C)
}
@Test
fun test_ror_absolute_shifts_out_one() {
mpu.regP.C = true
// $0000 ROR $ABCD
writeMem(memory, 0x0000, listOf(0x6E, 0xCD, 0xAB))
memory[0xABCD] = 0x03
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x81, memory[0xABCD])
assertTrue(mpu.regP.C)
}
// ROR Zero Page
@Test
fun test_ror_zp_zero_and_carry_zero_sets_z_flag() {
mpu.regP.C = false
// $0000 ROR $0010
writeMem(memory, 0x0000, listOf(0x66, 0x10))
memory[0x0010] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, memory[0x0010])
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_ror_zp_zero_and_carry_one_rotates_in_sets_n_flags() {
mpu.regP.C = true
// $0000 ROR $0010
writeMem(memory, 0x0000, listOf(0x66, 0x10))
memory[0x0010] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x80, memory[0x0010])
assertFalse(mpu.regP.Z)
assertTrue(mpu.regP.N)
}
@Test
fun test_ror_zp_zero_absolute_shifts_out_zero() {
mpu.regP.C = true
// $0000 ROR $0010
writeMem(memory, 0x0000, listOf(0x66, 0x10))
memory[0x0010] = 0x02
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x81, memory[0x0010])
assertFalse(mpu.regP.C)
}
@Test
fun test_ror_zp_shifts_out_one() {
mpu.regP.C = true
// $0000 ROR $0010
writeMem(memory, 0x0000, listOf(0x66, 0x10))
memory[0x0010] = 0x03
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x81, memory[0x0010])
assertTrue(mpu.regP.C)
}
// ROR Absolute, X-Indexed
@Test
fun test_ror_abs_x_indexed_zero_and_carry_zero_sets_z_flag() {
mpu.regX = 0x03
mpu.regP.C = false
// $0000 ROR $ABCD,X
writeMem(memory, 0x0000, listOf(0x7E, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, memory[0xABCD + mpu.regX])
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_ror_abs_x_indexed_z_and_c_1_rotates_in_sets_n_flags() {
mpu.regX = 0x03
mpu.regP.C = true
// $0000 ROR $ABCD,X
writeMem(memory, 0x0000, listOf(0x7E, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x80, memory[0xABCD + mpu.regX])
assertFalse(mpu.regP.Z)
assertTrue(mpu.regP.N)
}
@Test
fun test_ror_abs_x_indexed_shifts_out_zero() {
mpu.regX = 0x03
mpu.regP.C = true
// $0000 ROR $ABCD,X
writeMem(memory, 0x0000, listOf(0x7E, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0x02
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x81, memory[0xABCD + mpu.regX])
assertFalse(mpu.regP.C)
}
@Test
fun test_ror_abs_x_indexed_shifts_out_one() {
mpu.regX = 0x03
mpu.regP.C = true
// $0000 ROR $ABCD,X
writeMem(memory, 0x0000, listOf(0x7E, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0x03
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x81, memory[0xABCD + mpu.regX])
assertTrue(mpu.regP.C)
}
// ROR Zero Page, X-Indexed
@Test
fun test_ror_zp_x_indexed_zero_and_carry_zero_sets_z_flag() {
mpu.regX = 0x03
mpu.regP.C = false
// $0000 ROR $0010,X
writeMem(memory, 0x0000, listOf(0x76, 0x10))
memory[0x0010 + mpu.regX] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, memory[0x0010 + mpu.regX])
assertTrue(mpu.regP.Z)
assertFalse(mpu.regP.N)
}
@Test
fun test_ror_zp_x_indexed_zero_and_carry_one_rotates_in_sets_n_flags() {
mpu.regX = 0x03
mpu.regP.C = true
// $0000 ROR $0010,X
writeMem(memory, 0x0000, listOf(0x76, 0x10))
memory[0x0010 + mpu.regX] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x80, memory[0x0010 + mpu.regX])
assertFalse(mpu.regP.Z)
assertTrue(mpu.regP.N)
}
@Test
fun test_ror_zp_x_indexed_zero_absolute_shifts_out_zero() {
mpu.regX = 0x03
mpu.regP.C = true
// $0000 ROR $0010,X
writeMem(memory, 0x0000, listOf(0x76, 0x10))
memory[0x0010 + mpu.regX] = 0x02
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x81, memory[0x0010 + mpu.regX])
assertFalse(mpu.regP.C)
}
@Test
fun test_ror_zp_x_indexed_shifts_out_one() {
mpu.regX = 0x03
mpu.regP.C = true
// $0000 ROR $0010,X
writeMem(memory, 0x0000, listOf(0x76, 0x10))
memory[0x0010 + mpu.regX] = 0x03
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x81, memory[0x0010 + mpu.regX])
assertTrue(mpu.regP.C)
}
// RTI
@Test
fun test_rti_restores_status_and_pc_and_updates_sp() {
// $0000 RTI
memory[0x0000] = 0x40
writeMem(memory, 0x01FD, listOf(0xFC, 0x03, 0xC0)) // Status, PCL, PCH
mpu.regSP = 0xFC
mpu.step()
assertEquals(0xFF, mpu.regSP)
assertEquals(0xEC, mpu.regP.asInt()) // BREAK flag cleared
assertEquals(0xC003, mpu.regPC)
}
@Test
@Disabled("this test is invalid")
fun test_rti_forces_break_and_unused_flags_high() {
assertEquals(0b00100000, mpu.regP.asInt())
memory[0x0000] = 0x40 // RTI
writeMem(memory, 0x01FD, listOf(0x00, 0x03, 0xC0)) // Status, PCL, PCH
mpu.regSP = 0xFC
mpu.step()
assertEquals(0b00110000, mpu.regP.asInt())
}
// RTS
@Test
fun test_rts_restores_pc_and_increments_then_updates_sp() {
// $0000 RTS
memory[0x0000] = 0x60
writeMem(memory, 0x01FE, listOf(0x03, 0xC0)) // PCL, PCH
mpu.regPC = 0x0000
mpu.regSP = 0xFD
mpu.step()
assertEquals(0xC004, mpu.regPC)
assertEquals(0xFF, mpu.regSP)
}
@Test
fun test_rts_wraps_around_top_of_memory() {
// $1000 RTS
memory[0x1000] = 0x60
writeMem(memory, 0x01FE, listOf(0xFF, 0xFF)) // PCL, PCH
mpu.regPC = 0x1000
mpu.regSP = 0xFD
mpu.step()
assertEquals(0x0000, mpu.regPC)
assertEquals(0xFF, mpu.regSP)
}
// SBC Absolute
@Test
fun test_sbc_abs_all_zeros_and_no_borrow_is_zero() {
mpu.regP.D = false
mpu.regP.C = true // borrow = 0
mpu.regA = 0x00
// $0000 SBC $ABCD
writeMem(memory, 0x0000, listOf(0xED, 0xCD, 0xAB))
memory[0xABCD] = 0x00
mpu.step()
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.C)
assertTrue(mpu.regP.Z)
}
@Test
fun test_sbc_abs_downto_zero_no_borrow_sets_z_clears_n() {
mpu.regP.D = false
mpu.regP.C = true // borrow = 0
mpu.regA = 0x01
// $0000 SBC $ABCD
writeMem(memory, 0x0000, listOf(0xED, 0xCD, 0xAB))
memory[0xABCD] = 0x01
mpu.step()
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.C)
assertTrue(mpu.regP.Z)
}
@Test
fun test_sbc_abs_downto_zero_with_borrow_sets_z_clears_n() {
mpu.regP.D = false
mpu.regP.C = false // borrow = 1
mpu.regA = 0x01
// $0000 SBC $ABCD
writeMem(memory, 0x0000, listOf(0xED, 0xCD, 0xAB))
memory[0xABCD] = 0x00
mpu.step()
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.C)
assertTrue(mpu.regP.Z)
}
@Test
fun test_sbc_abs_downto_four_with_borrow_clears_z_n() {
mpu.regP.D = false
mpu.regP.C = false // borrow = 1
mpu.regA = 0x07
// $0000 SBC $ABCD
writeMem(memory, 0x0000, listOf(0xED, 0xCD, 0xAB))
memory[0xABCD] = 0x02
mpu.step()
assertEquals(0x04, mpu.regA)
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.Z)
assertTrue(mpu.regP.C)
}
// SBC Zero Page
@Test
fun test_sbc_zp_all_zeros_and_no_borrow_is_zero() {
mpu.regP.D = false
mpu.regP.C = true // borrow = 0
mpu.regA = 0x00
// $0000 SBC $10
writeMem(memory, 0x0000, listOf(0xE5, 0x10))
memory[0x0010] = 0x00
mpu.step()
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.C)
assertTrue(mpu.regP.Z)
}
@Test
fun test_sbc_zp_downto_zero_no_borrow_sets_z_clears_n() {
mpu.regP.D = false
mpu.regP.C = true // borrow = 0
mpu.regA = 0x01
// $0000 SBC $10
writeMem(memory, 0x0000, listOf(0xE5, 0x10))
memory[0x0010] = 0x01
mpu.step()
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.C)
assertTrue(mpu.regP.Z)
}
@Test
fun test_sbc_zp_downto_zero_with_borrow_sets_z_clears_n() {
mpu.regP.D = false
mpu.regP.C = false // borrow = 1
mpu.regA = 0x01
// => SBC $10
writeMem(memory, 0x0000, listOf(0xE5, 0x10))
memory[0x0010] = 0x00
mpu.step()
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.C)
assertTrue(mpu.regP.Z)
}
@Test
fun test_sbc_zp_downto_four_with_borrow_clears_z_n() {
mpu.regP.D = false
mpu.regP.C = false // borrow = 1
mpu.regA = 0x07
// => SBC $10
writeMem(memory, 0x0000, listOf(0xE5, 0x10))
memory[0x0010] = 0x02
mpu.step()
assertEquals(0x04, mpu.regA)
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.Z)
assertTrue(mpu.regP.C)
}
// SBC Immediate
@Test
fun test_sbc_imm_all_zeros_and_no_borrow_is_zero() {
mpu.regP.D = false
mpu.regP.C = true // borrow = 0
mpu.regA = 0x00
// $0000 SBC #$00
writeMem(memory, 0x0000, listOf(0xE9, 0x00))
mpu.step()
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.C)
assertTrue(mpu.regP.Z)
}
@Test
fun test_sbc_imm_downto_zero_no_borrow_sets_z_clears_n() {
mpu.regP.D = false
mpu.regP.C = true // borrow = 0
mpu.regA = 0x01
// $0000 SBC #$01
writeMem(memory, 0x0000, listOf(0xE9, 0x01))
mpu.step()
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.C)
assertTrue(mpu.regP.Z)
}
@Test
fun test_sbc_imm_downto_zero_with_borrow_sets_z_clears_n() {
mpu.regP.D = false
mpu.regP.C = false // borrow = 1
mpu.regA = 0x01
// $0000 SBC #$00
writeMem(memory, 0x0000, listOf(0xE9, 0x00))
mpu.step()
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.C)
assertTrue(mpu.regP.Z)
}
@Test
fun test_sbc_imm_downto_four_with_borrow_clears_z_n() {
mpu.regP.D = false
mpu.regP.C = false // borrow = 1
mpu.regA = 0x07
// $0000 SBC #$02
writeMem(memory, 0x0000, listOf(0xE9, 0x02))
mpu.step()
assertEquals(0x04, mpu.regA)
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.Z)
assertTrue(mpu.regP.C)
}
@Test
fun test_sbc_bcd_on_immediate_0a_minus_00_carry_set() {
mpu.regP.D = true
mpu.regP.C = true
mpu.regA = 0x0a
// $0000 SBC #$00
writeMem(memory, 0x0000, listOf(0xe9, 0x00))
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x0a, mpu.regA)
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.V)
assertFalse(mpu.regP.Z)
assertTrue(mpu.regP.C)
}
@Test
fun test_sbc_bcd_on_immediate_9a_minus_00_carry_set() {
mpu.regP.D = true
mpu.regP.C = true
mpu.regA = 0x9a
// $0000 SBC #$00
writeMem(memory, 0x0000, listOf(0xe9, 0x00))
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x9a, mpu.regA)
assertFalse(mpu.regP.Z)
assertTrue(mpu.regP.C)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.V)
}
@Test
fun test_sbc_bcd_on_immediate_00_minus_01_carry_set() {
mpu.regP.D = true
mpu.regP.V = true
mpu.regP.Z = true
mpu.regP.C = true
mpu.regP.N = false
mpu.regA = 0x00
// => $0000 SBC #$00
writeMem(memory, 0x0000, listOf(0xe9, 0x01))
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x99, mpu.regA)
assertFalse(mpu.regP.Z)
assertTrue(mpu.regP.N)
assertFalse(mpu.regP.V)
assertFalse(mpu.regP.C)
}
// SBC Absolute, X-Indexed
@Test
fun test_sbc_abs_x_all_zeros_and_no_borrow_is_zero() {
mpu.regP.D = false
mpu.regP.C = true // borrow = 0
mpu.regA = 0x00
// $0000 SBC $FEE0,X
writeMem(memory, 0x0000, listOf(0xFD, 0xE0, 0xFE))
mpu.regX = 0x0D
memory[0xFEED] = 0x00
mpu.step()
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.C)
assertTrue(mpu.regP.Z)
}
@Test
fun test_sbc_abs_x_downto_zero_no_borrow_sets_z_clears_n() {
mpu.regP.D = false
mpu.regP.C = true // borrow = 0
mpu.regA = 0x01
// $0000 SBC $FEE0,X
writeMem(memory, 0x0000, listOf(0xFD, 0xE0, 0xFE))
mpu.regX = 0x0D
memory[0xFEED] = 0x01
mpu.step()
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.C)
assertTrue(mpu.regP.Z)
}
@Test
fun test_sbc_abs_x_downto_zero_with_borrow_sets_z_clears_n() {
mpu.regP.D = false
mpu.regP.C = false // borrow = 1
mpu.regA = 0x01
// $0000 SBC $FEE0,X
writeMem(memory, 0x0000, listOf(0xFD, 0xE0, 0xFE))
mpu.regX = 0x0D
memory[0xFEED] = 0x00
mpu.step()
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.C)
assertTrue(mpu.regP.Z)
}
@Test
fun test_sbc_abs_x_downto_four_with_borrow_clears_z_n() {
mpu.regP.D = false
mpu.regP.C = false // borrow = 1
mpu.regA = 0x07
// $0000 SBC $FEE0,X
writeMem(memory, 0x0000, listOf(0xFD, 0xE0, 0xFE))
mpu.regX = 0x0D
memory[0xFEED] = 0x02
mpu.step()
assertEquals(0x04, mpu.regA)
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.Z)
assertTrue(mpu.regP.C)
}
// SBC Absolute, Y-Indexed
@Test
fun test_sbc_abs_y_all_zeros_and_no_borrow_is_zero() {
mpu.regP.D = false
mpu.regP.C = true // borrow = 0
mpu.regA = 0x00
// $0000 SBC $FEE0,Y
writeMem(memory, 0x0000, listOf(0xF9, 0xE0, 0xFE))
mpu.regY = 0x0D
memory[0xFEED] = 0x00
mpu.step()
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.C)
assertTrue(mpu.regP.Z)
}
@Test
fun test_sbc_abs_y_downto_zero_no_borrow_sets_z_clears_n() {
mpu.regP.D = false
mpu.regP.C = true // borrow = 0
mpu.regA = 0x01
// $0000 SBC $FEE0,Y
writeMem(memory, 0x0000, listOf(0xF9, 0xE0, 0xFE))
mpu.regY = 0x0D
memory[0xFEED] = 0x01
mpu.step()
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.C)
assertTrue(mpu.regP.Z)
}
@Test
fun test_sbc_abs_y_downto_zero_with_borrow_sets_z_clears_n() {
mpu.regP.D = false
mpu.regP.C = false // borrow = 1
mpu.regA = 0x01
// $0000 SBC $FEE0,Y
writeMem(memory, 0x0000, listOf(0xF9, 0xE0, 0xFE))
mpu.regY = 0x0D
memory[0xFEED] = 0x00
mpu.step()
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.C)
assertTrue(mpu.regP.Z)
}
@Test
fun test_sbc_abs_y_downto_four_with_borrow_clears_z_n() {
mpu.regP.D = false
mpu.regP.C = false // borrow = 1
mpu.regA = 0x07
// $0000 SBC $FEE0,Y
writeMem(memory, 0x0000, listOf(0xF9, 0xE0, 0xFE))
mpu.regY = 0x0D
memory[0xFEED] = 0x02
mpu.step()
assertEquals(0x04, mpu.regA)
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.Z)
assertTrue(mpu.regP.C)
}
// SBC Indirect, Indexed (X)
@Test
fun test_sbc_ind_x_all_zeros_and_no_borrow_is_zero() {
mpu.regP.D = false
mpu.regP.C = true // borrow = 0
mpu.regA = 0x00
// $0000 SBC ($10,X)
// $0013 Vector to $FEED
writeMem(memory, 0x0000, listOf(0xE1, 0x10))
writeMem(memory, 0x0013, listOf(0xED, 0xFE))
mpu.regX = 0x03
memory[0xFEED] = 0x00
mpu.step()
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.C)
assertTrue(mpu.regP.Z)
}
@Test
fun test_sbc_ind_x_downto_zero_no_borrow_sets_z_clears_n() {
mpu.regP.D = false
mpu.regP.C = true // borrow = 0
mpu.regA = 0x01
// $0000 SBC ($10,X)
// $0013 Vector to $FEED
writeMem(memory, 0x0000, listOf(0xE1, 0x10))
writeMem(memory, 0x0013, listOf(0xED, 0xFE))
mpu.regX = 0x03
memory[0xFEED] = 0x01
mpu.step()
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.C)
assertTrue(mpu.regP.Z)
}
@Test
fun test_sbc_ind_x_downto_zero_with_borrow_sets_z_clears_n() {
mpu.regP.D = false
mpu.regP.C = false // borrow = 1
mpu.regA = 0x01
// $0000 SBC ($10,X)
// $0013 Vector to $FEED
writeMem(memory, 0x0000, listOf(0xE1, 0x10))
writeMem(memory, 0x0013, listOf(0xED, 0xFE))
mpu.regX = 0x03
memory[0xFEED] = 0x00
mpu.step()
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.C)
assertTrue(mpu.regP.Z)
}
@Test
fun test_sbc_ind_x_downto_four_with_borrow_clears_z_n() {
mpu.regP.D = false
mpu.regP.C = false // borrow = 1
mpu.regA = 0x07
// $0000 SBC ($10,X)
// $0013 Vector to $FEED
writeMem(memory, 0x0000, listOf(0xE1, 0x10))
writeMem(memory, 0x0013, listOf(0xED, 0xFE))
mpu.regX = 0x03
memory[0xFEED] = 0x02
mpu.step()
assertEquals(0x04, mpu.regA)
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.Z)
assertTrue(mpu.regP.C)
}
// SBC Indexed, Indirect (Y)
@Test
fun test_sbc_ind_y_all_zeros_and_no_borrow_is_zero() {
mpu.regP.D = false
mpu.regP.C = true // borrow = 0
mpu.regA = 0x00
mpu.regY = 0x03
// $0000 SBC ($10),Y
// $0010 Vector to $FEED
writeMem(memory, 0x0000, listOf(0xF1, 0x10))
writeMem(memory, 0x0010, listOf(0xED, 0xFE))
memory[0xFEED + mpu.regY] = 0x00
mpu.step()
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.C)
assertTrue(mpu.regP.Z)
}
@Test
fun test_sbc_ind_y_downto_zero_no_borrow_sets_z_clears_n() {
mpu.regP.D = false
mpu.regP.C = true // borrow = 0
mpu.regA = 0x01
// $0000 SBC ($10),Y
// $0010 Vector to $FEED
writeMem(memory, 0x0000, listOf(0xF1, 0x10))
writeMem(memory, 0x0010, listOf(0xED, 0xFE))
memory[0xFEED + mpu.regY] = 0x01
mpu.step()
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.C)
assertTrue(mpu.regP.Z)
}
@Test
fun test_sbc_ind_y_downto_zero_with_borrow_sets_z_clears_n() {
mpu.regP.D = false
mpu.regP.C = false // borrow = 1
mpu.regA = 0x01
// $0000 SBC ($10),Y
// $0010 Vector to $FEED
writeMem(memory, 0x0000, listOf(0xF1, 0x10))
writeMem(memory, 0x0010, listOf(0xED, 0xFE))
memory[0xFEED + mpu.regY] = 0x00
mpu.step()
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.C)
assertTrue(mpu.regP.Z)
}
@Test
fun test_sbc_ind_y_downto_four_with_borrow_clears_z_n() {
mpu.regP.D = false
mpu.regP.C = false // borrow = 1
mpu.regA = 0x07
// $0000 SBC ($10),Y
// $0010 Vector to $FEED
writeMem(memory, 0x0000, listOf(0xF1, 0x10))
writeMem(memory, 0x0010, listOf(0xED, 0xFE))
memory[0xFEED + mpu.regY] = 0x02
mpu.step()
assertEquals(0x04, mpu.regA)
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.Z)
assertTrue(mpu.regP.C)
}
// SBC Zero Page, X-Indexed
@Test
fun test_sbc_zp_x_all_zeros_and_no_borrow_is_zero() {
mpu.regP.D = false
mpu.regP.C = true // borrow = 0
mpu.regA = 0x00
// $0000 SBC $10,X
writeMem(memory, 0x0000, listOf(0xF5, 0x10))
mpu.regX = 0x0D
memory[0x001D] = 0x00
mpu.step()
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.C)
assertTrue(mpu.regP.Z)
}
@Test
fun test_sbc_zp_x_downto_zero_no_borrow_sets_z_clears_n() {
mpu.regP.D = false
mpu.regP.C = true // borrow = 0
mpu.regA = 0x01
// $0000 SBC $10,X
writeMem(memory, 0x0000, listOf(0xF5, 0x10))
mpu.regX = 0x0D
memory[0x001D] = 0x01
mpu.step()
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.C)
assertTrue(mpu.regP.Z)
}
@Test
fun test_sbc_zp_x_downto_zero_with_borrow_sets_z_clears_n() {
mpu.regP.D = false
mpu.regP.C = false // borrow = 1
mpu.regA = 0x01
// $0000 SBC $10,X
writeMem(memory, 0x0000, listOf(0xF5, 0x10))
mpu.regX = 0x0D
memory[0x001D] = 0x00
mpu.step()
assertEquals(0x00, mpu.regA)
assertFalse(mpu.regP.N)
assertTrue(mpu.regP.C)
assertTrue(mpu.regP.Z)
}
@Test
fun test_sbc_zp_x_downto_four_with_borrow_clears_z_n() {
mpu.regP.D = false
mpu.regP.C = false // borrow = 1
mpu.regA = 0x07
// $0000 SBC $10,X
writeMem(memory, 0x0000, listOf(0xF5, 0x10))
mpu.regX = 0x0D
memory[0x001D] = 0x02
mpu.step()
assertEquals(0x04, mpu.regA)
assertFalse(mpu.regP.N)
assertFalse(mpu.regP.Z)
assertTrue(mpu.regP.C)
}
// SEC
@Test
fun test_sec_sets_carry_flag() {
mpu.regP.C = false
// $0000 SEC
memory[0x0000] = 0x038
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertTrue(mpu.regP.C)
}
// SED
@Test
fun test_sed_sets_decimal_mode_flag() {
mpu.regP.D = false
// $0000 SED
memory[0x0000] = 0xF8
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertTrue(mpu.regP.D)
}
// SEI
@Test
fun test_sei_sets_interrupt_disable_flag() {
mpu.regP.I = false
// $0000 SEI
memory[0x0000] = 0x78
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertTrue(mpu.regP.I)
}
// STA Absolute
@Test
fun test_sta_absolute_stores_a_leaves_a_and_n_flag_unchanged() {
val flags = 0xFF and fNEGATIVE.inv()
mpu.regP.fromInt(flags)
mpu.regA = 0xFF
// $0000 STA $ABCD
writeMem(memory, 0x0000, listOf(0x8D, 0xCD, 0xAB))
memory[0xABCD] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0xFF, memory[0xABCD])
assertEquals(0xFF, mpu.regA)
assertEquals(flags, mpu.regP.asInt())
}
@Test
fun test_sta_absolute_stores_a_leaves_a_and_z_flag_unchanged() {
val flags = 0xFF and fZERO.inv()
mpu.regP.fromInt(flags)
mpu.regA = 0x00
// $0000 STA $ABCD
writeMem(memory, 0x0000, listOf(0x8D, 0xCD, 0xAB))
memory[0xABCD] = 0xFF
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, memory[0xABCD])
assertEquals(0x00, mpu.regA)
assertEquals(flags, mpu.regP.asInt())
}
// STA Zero Page
@Test
fun test_sta_zp_stores_a_leaves_a_and_n_flag_unchanged() {
val flags = 0xFF and fNEGATIVE.inv()
mpu.regP.fromInt(flags)
mpu.regA = 0xFF
// $0000 STA $0010
writeMem(memory, 0x0000, listOf(0x85, 0x10))
memory[0x0010] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xFF, memory[0x0010])
assertEquals(0xFF, mpu.regA)
assertEquals(flags, mpu.regP.asInt())
}
@Test
fun test_sta_zp_stores_a_leaves_a_and_z_flag_unchanged() {
val flags = 0xFF and fZERO.inv()
mpu.regP.fromInt(flags)
mpu.regA = 0x00
// $0000 STA $0010
writeMem(memory, 0x0000, listOf(0x85, 0x10))
memory[0x0010] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, memory[0x0010])
assertEquals(0x00, mpu.regA)
assertEquals(flags, mpu.regP.asInt())
}
// STA Absolute, X-Indexed
@Test
fun test_sta_abs_x_indexed_stores_a_leaves_a_and_n_flag_unchanged() {
val flags = 0xFF and fNEGATIVE.inv()
mpu.regP.fromInt(flags)
mpu.regA = 0xFF
mpu.regX = 0x03
// $0000 STA $ABCD,X
writeMem(memory, 0x0000, listOf(0x9D, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0xFF, memory[0xABCD + mpu.regX])
assertEquals(0xFF, mpu.regA)
assertEquals(flags, mpu.regP.asInt())
}
@Test
fun test_sta_abs_x_indexed_stores_a_leaves_a_and_z_flag_unchanged() {
val flags = 0xFF and fZERO.inv()
mpu.regP.fromInt(flags)
mpu.regA = 0x00
mpu.regX = 0x03
// $0000 STA $ABCD,X
writeMem(memory, 0x0000, listOf(0x9D, 0xCD, 0xAB))
memory[0xABCD + mpu.regX] = 0xFF
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, memory[0xABCD + mpu.regX])
assertEquals(0x00, mpu.regA)
assertEquals(flags, mpu.regP.asInt())
}
// STA Absolute, Y-Indexed
@Test
fun test_sta_abs_y_indexed_stores_a_leaves_a_and_n_flag_unchanged() {
val flags = 0xFF and fNEGATIVE.inv()
mpu.regP.fromInt(flags)
mpu.regA = 0xFF
mpu.regY = 0x03
// $0000 STA $ABCD,Y
writeMem(memory, 0x0000, listOf(0x99, 0xCD, 0xAB))
memory[0xABCD + mpu.regY] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0xFF, memory[0xABCD + mpu.regY])
assertEquals(0xFF, mpu.regA)
assertEquals(flags, mpu.regP.asInt())
}
@Test
fun test_sta_abs_y_indexed_stores_a_leaves_a_and_z_flag_unchanged() {
val flags = 0xFF and fZERO.inv()
mpu.regP.fromInt(flags)
mpu.regA = 0x00
mpu.regY = 0x03
// $0000 STA $ABCD,Y
writeMem(memory, 0x0000, listOf(0x99, 0xCD, 0xAB))
memory[0xABCD + mpu.regY] = 0xFF
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, memory[0xABCD + mpu.regY])
assertEquals(0x00, mpu.regA)
assertEquals(flags, mpu.regP.asInt())
}
// STA Indirect, Indexed (X)
@Test
fun test_sta_ind_indexed_x_stores_a_leaves_a_and_n_flag_unchanged() {
val flags = 0xFF and fNEGATIVE.inv()
mpu.regP.fromInt(flags)
mpu.regA = 0xFF
mpu.regX = 0x03
// $0000 STA ($0010,X)
// $0013 Vector to $FEED
writeMem(memory, 0x0000, listOf(0x81, 0x10))
writeMem(memory, 0x0013, listOf(0xED, 0xFE))
memory[0xFEED] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xFF, memory[0xFEED])
assertEquals(0xFF, mpu.regA)
assertEquals(flags, mpu.regP.asInt())
}
@Test
fun test_sta_ind_indexed_x_stores_a_leaves_a_and_z_flag_unchanged() {
val flags = 0xFF and fZERO.inv()
mpu.regP.fromInt(flags)
mpu.regA = 0x00
mpu.regX = 0x03
// $0000 STA ($0010,X)
// $0013 Vector to $FEED
writeMem(memory, 0x0000, listOf(0x81, 0x10))
writeMem(memory, 0x0013, listOf(0xED, 0xFE))
memory[0xFEED] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, memory[0xFEED])
assertEquals(0x00, mpu.regA)
assertEquals(flags, mpu.regP.asInt())
}
// STA Indexed, Indirect (Y)
@Test
fun test_sta_indexed_ind_y_stores_a_leaves_a_and_n_flag_unchanged() {
val flags = 0xFF and fNEGATIVE.inv()
mpu.regP.fromInt(flags)
mpu.regA = 0xFF
mpu.regY = 0x03
// $0000 STA ($0010),Y
// $0010 Vector to $FEED
writeMem(memory, 0x0000, listOf(0x91, 0x10))
writeMem(memory, 0x0010, listOf(0xED, 0xFE))
memory[0xFEED + mpu.regY] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xFF, memory[0xFEED + mpu.regY])
assertEquals(0xFF, mpu.regA)
assertEquals(flags, mpu.regP.asInt())
}
@Test
fun test_sta_indexed_ind_y_stores_a_leaves_a_and_z_flag_unchanged() {
val flags = 0xFF and fZERO.inv()
mpu.regP.fromInt(flags)
mpu.regA = 0x00
mpu.regY = 0x03
// $0000 STA ($0010),Y
// $0010 Vector to $FEED
writeMem(memory, 0x0000, listOf(0x91, 0x10))
writeMem(memory, 0x0010, listOf(0xED, 0xFE))
memory[0xFEED + mpu.regY] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, memory[0xFEED + mpu.regY])
assertEquals(0x00, mpu.regA)
assertEquals(flags, mpu.regP.asInt())
}
// STA Zero Page, X-Indexed
@Test
fun test_sta_zp_x_indexed_stores_a_leaves_a_and_n_flag_unchanged() {
val flags = 0xFF and fNEGATIVE.inv()
mpu.regP.fromInt(flags)
mpu.regA = 0xFF
mpu.regX = 0x03
// $0000 STA $0010,X
writeMem(memory, 0x0000, listOf(0x95, 0x10))
memory[0x0010 + mpu.regX] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xFF, memory[0x0010 + mpu.regX])
assertEquals(0xFF, mpu.regA)
assertEquals(flags, mpu.regP.asInt())
}
@Test
fun test_sta_zp_x_indexed_stores_a_leaves_a_and_z_flag_unchanged() {
val flags = 0xFF and fZERO.inv()
mpu.regP.fromInt(flags)
mpu.regA = 0x00
mpu.regX = 0x03
// $0000 STA $0010,X
writeMem(memory, 0x0000, listOf(0x95, 0x10))
memory[0x0010 + mpu.regX] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, memory[0x0010 + mpu.regX])
assertEquals(0x00, mpu.regA)
assertEquals(flags, mpu.regP.asInt())
}
// STX Absolute
@Test
fun test_stx_absolute_stores_x_leaves_x_and_n_flag_unchanged() {
val flags = 0xFF and fNEGATIVE.inv()
mpu.regP.fromInt(flags)
mpu.regX = 0xFF
// $0000 STX $ABCD
writeMem(memory, 0x0000, listOf(0x8E, 0xCD, 0xAB))
memory[0xABCD] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0xFF, memory[0xABCD])
assertEquals(0xFF, mpu.regX)
assertEquals(flags, mpu.regP.asInt())
}
@Test
fun test_stx_absolute_stores_x_leaves_x_and_z_flag_unchanged() {
val flags = 0xFF and fZERO.inv()
mpu.regP.fromInt(flags)
mpu.regX = 0x00
// $0000 STX $ABCD
writeMem(memory, 0x0000, listOf(0x8E, 0xCD, 0xAB))
memory[0xABCD] = 0xFF
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, memory[0xABCD])
assertEquals(0x00, mpu.regX)
assertEquals(flags, mpu.regP.asInt())
}
// STX Zero Page
@Test
fun test_stx_zp_stores_x_leaves_x_and_n_flag_unchanged() {
val flags = 0xFF and fNEGATIVE.inv()
mpu.regP.fromInt(flags)
mpu.regX = 0xFF
// $0000 STX $0010
writeMem(memory, 0x0000, listOf(0x86, 0x10))
memory[0x0010] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xFF, memory[0x0010])
assertEquals(0xFF, mpu.regX)
assertEquals(flags, mpu.regP.asInt())
}
@Test
fun test_stx_zp_stores_x_leaves_x_and_z_flag_unchanged() {
val flags = 0xFF and fZERO.inv()
mpu.regP.fromInt(flags)
mpu.regX = 0x00
// $0000 STX $0010
writeMem(memory, 0x0000, listOf(0x86, 0x10))
memory[0x0010] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, memory[0x0010])
assertEquals(0x00, mpu.regX)
assertEquals(flags, mpu.regP.asInt())
}
// STX Zero Page, Y-Indexed
@Test
fun test_stx_zp_y_indexed_stores_x_leaves_x_and_n_flag_unchanged() {
val flags = 0xFF and fNEGATIVE.inv()
mpu.regP.fromInt(flags)
mpu.regX = 0xFF
mpu.regY = 0x03
// $0000 STX $0010,Y
writeMem(memory, 0x0000, listOf(0x96, 0x10))
memory[0x0010 + mpu.regY] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xFF, memory[0x0010 + mpu.regY])
assertEquals(0xFF, mpu.regX)
assertEquals(flags, mpu.regP.asInt())
}
@Test
fun test_stx_zp_y_indexed_stores_x_leaves_x_and_z_flag_unchanged() {
val flags = 0xFF and fZERO.inv()
mpu.regP.fromInt(flags)
mpu.regX = 0x00
mpu.regY = 0x03
// $0000 STX $0010,Y
writeMem(memory, 0x0000, listOf(0x96, 0x10))
memory[0x0010 + mpu.regY] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, memory[0x0010 + mpu.regY])
assertEquals(0x00, mpu.regX)
assertEquals(flags, mpu.regP.asInt())
}
// STY Absolute
@Test
fun test_sty_absolute_stores_y_leaves_y_and_n_flag_unchanged() {
val flags = 0xFF and fNEGATIVE.inv()
mpu.regP.fromInt(flags)
mpu.regY = 0xFF
// $0000 STY $ABCD
writeMem(memory, 0x0000, listOf(0x8C, 0xCD, 0xAB))
memory[0xABCD] = 0x00
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0xFF, memory[0xABCD])
assertEquals(0xFF, mpu.regY)
assertEquals(flags, mpu.regP.asInt())
}
@Test
fun test_sty_absolute_stores_y_leaves_y_and_z_flag_unchanged() {
val flags = 0xFF and fZERO.inv()
mpu.regP.fromInt(flags)
mpu.regY = 0x00
// $0000 STY $ABCD
writeMem(memory, 0x0000, listOf(0x8C, 0xCD, 0xAB))
memory[0xABCD] = 0xFF
mpu.step()
assertEquals(0x0003, mpu.regPC)
assertEquals(0x00, memory[0xABCD])
assertEquals(0x00, mpu.regY)
assertEquals(flags, mpu.regP.asInt())
}
// STY Zero Page
@Test
fun test_sty_zp_stores_y_leaves_y_and_n_flag_unchanged() {
val flags = 0xFF and fNEGATIVE.inv()
mpu.regP.fromInt(flags)
mpu.regY = 0xFF
// $0000 STY $0010
writeMem(memory, 0x0000, listOf(0x84, 0x10))
memory[0x0010] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xFF, memory[0x0010])
assertEquals(0xFF, mpu.regY)
assertEquals(flags, mpu.regP.asInt())
}
@Test
fun test_sty_zp_stores_y_leaves_y_and_z_flag_unchanged() {
val flags = 0xFF and fZERO.inv()
mpu.regP.fromInt(flags)
mpu.regY = 0x00
// $0000 STY $0010
writeMem(memory, 0x0000, listOf(0x84, 0x10))
memory[0x0010] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, memory[0x0010])
assertEquals(0x00, mpu.regY)
assertEquals(flags, mpu.regP.asInt())
}
// STY Zero Page, X-Indexed
@Test
fun test_sty_zp_x_indexed_stores_y_leaves_y_and_n_flag_unchanged() {
val flags = 0xFF and fNEGATIVE.inv()
mpu.regP.fromInt(flags)
mpu.regY = 0xFF
mpu.regX = 0x03
// $0000 STY $0010,X
writeMem(memory, 0x0000, listOf(0x94, 0x10))
memory[0x0010 + mpu.regX] = 0x00
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0xFF, memory[0x0010 + mpu.regX])
assertEquals(0xFF, mpu.regY)
assertEquals(flags, mpu.regP.asInt())
}
@Test
fun test_sty_zp_x_indexed_stores_y_leaves_y_and_z_flag_unchanged() {
val flags = 0xFF and fZERO.inv()
mpu.regP.fromInt(flags)
mpu.regY = 0x00
mpu.regX = 0x03
// $0000 STY $0010,X
writeMem(memory, 0x0000, listOf(0x94, 0x10))
memory[0x0010 + mpu.regX] = 0xFF
mpu.step()
assertEquals(0x0002, mpu.regPC)
assertEquals(0x00, memory[0x0010 + mpu.regX])
assertEquals(0x00, mpu.regY)
assertEquals(flags, mpu.regP.asInt())
}
// TAX
@Test
fun test_tax_transfers_accumulator_into_x() {
mpu.regA = 0xAB
mpu.regX = 0x00
// $0000 TAX
memory[0x0000] = 0xAA
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0xAB, mpu.regA)
assertEquals(0xAB, mpu.regX)
}
@Test
fun test_tax_sets_negative_flag() {
mpu.regP.N = false
mpu.regA = 0x80
mpu.regX = 0x00
// $0000 TAX
memory[0x0000] = 0xAA
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertEquals(0x80, mpu.regX)
assertTrue(mpu.regP.N)
}
@Test
fun test_tax_sets_zero_flag() {
mpu.regP.Z = false
mpu.regA = 0x00
mpu.regX = 0xFF
// $0000 TAX
memory[0x0000] = 0xAA
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertEquals(0x00, mpu.regX)
assertTrue(mpu.regP.Z)
}
// TAY
@Test
fun test_tay_transfers_accumulator_into_y() {
mpu.regA = 0xAB
mpu.regY = 0x00
// $0000 TAY
memory[0x0000] = 0xA8
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0xAB, mpu.regA)
assertEquals(0xAB, mpu.regY)
}
@Test
fun test_tay_sets_negative_flag() {
mpu.regP.N = false
mpu.regA = 0x80
mpu.regY = 0x00
// $0000 TAY
memory[0x0000] = 0xA8
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertEquals(0x80, mpu.regY)
assertTrue(mpu.regP.N)
}
@Test
fun test_tay_sets_zero_flag() {
mpu.regP.Z = false
mpu.regA = 0x00
mpu.regY = 0xFF
// $0000 TAY
memory[0x0000] = 0xA8
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertEquals(0x00, mpu.regY)
assertTrue(mpu.regP.Z)
}
// TSX
@Test
fun test_tsx_transfers_stack_pointer_into_x() {
mpu.regSP = 0xAB
mpu.regX = 0x00
// $0000 TSX
memory[0x0000] = 0xBA
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0xAB, mpu.regSP)
assertEquals(0xAB, mpu.regX)
}
@Test
fun test_tsx_sets_negative_flag() {
mpu.regP.N = false
mpu.regSP = 0x80
mpu.regX = 0x00
// $0000 TSX
memory[0x0000] = 0xBA
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x80, mpu.regSP)
assertEquals(0x80, mpu.regX)
assertTrue(mpu.regP.N)
}
@Test
fun test_tsx_sets_zero_flag() {
mpu.regP.Z = false
mpu.regSP = 0x00
mpu.regY = 0xFF
// $0000 TSX
memory[0x0000] = 0xBA
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x00, mpu.regSP)
assertEquals(0x00, mpu.regX)
assertTrue(mpu.regP.Z)
}
// TXA
@Test
fun test_txa_transfers_x_into_a() {
mpu.regX = 0xAB
mpu.regA = 0x00
// $0000 TXA
memory[0x0000] = 0x8A
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0xAB, mpu.regA)
assertEquals(0xAB, mpu.regX)
}
@Test
fun test_txa_sets_negative_flag() {
mpu.regP.N = false
mpu.regX = 0x80
mpu.regA = 0x00
// $0000 TXA
memory[0x0000] = 0x8A
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertEquals(0x80, mpu.regX)
assertTrue(mpu.regP.N)
}
@Test
fun test_txa_sets_zero_flag() {
mpu.regP.Z = false
mpu.regX = 0x00
mpu.regA = 0xFF
// $0000 TXA
memory[0x0000] = 0x8A
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x00, mpu.regA)
assertEquals(0x00, mpu.regX)
assertTrue(mpu.regP.Z)
}
// TXS
@Test
fun test_txs_transfers_x_into_stack_pointer() {
mpu.regX = 0xAB
// $0000 TXS
memory[0x0000] = 0x9A
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0xAB, mpu.regSP)
assertEquals(0xAB, mpu.regX)
}
@Test
fun test_txs_does_not_set_negative_flag() {
mpu.regP.N = false
mpu.regX = 0x80
// $0000 TXS
memory[0x0000] = 0x9A
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x80, mpu.regSP)
assertEquals(0x80, mpu.regX)
assertFalse(mpu.regP.N)
}
@Test
fun test_txs_does_not_set_zero_flag() {
mpu.regP.Z = false
mpu.regX = 0x00
// $0000 TXS
memory[0x0000] = 0x9A
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x00, mpu.regSP)
assertEquals(0x00, mpu.regX)
assertFalse(mpu.regP.Z)
}
// TYA
@Test
fun test_tya_transfers_y_into_a() {
mpu.regY = 0xAB
mpu.regA = 0x00
// $0000 TYA
memory[0x0000] = 0x98
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0xAB, mpu.regA)
assertEquals(0xAB, mpu.regY)
}
@Test
fun test_tya_sets_negative_flag() {
mpu.regP.N = false
mpu.regY = 0x80
mpu.regA = 0x00
// $0000 TYA
memory[0x0000] = 0x98
mpu.step()
assertEquals(0x0001, mpu.regPC)
assertEquals(0x80, mpu.regA)
assertEquals(0x80, mpu.regY)
assertTrue(mpu.regP.N)
}
@Test
fun test_tya_sets_zero_flag() {
mpu.regP.Z = false
mpu.regY = 0x00
mpu.regA = 0xFF
// $0000 TYA
memory[0x0000] = 0x98
mpu.step()
assertEquals(0x00, mpu.regA)
assertEquals(0x00, mpu.regY)
assertTrue(mpu.regP.Z)
assertEquals(0x0001, mpu.regPC)
}
@Test
fun test_brk_interrupt() {
writeMem(memory, 0xFFFE, listOf(0x00, 0x04))
writeMem(memory, 0x0000, listOf(0xA9, 0x01, // LDA #$01
0x00, 0xEA, // BRK + skipped byte
0xEA, 0xEA, // NOP, NOP
0xA9, 0x03)) // LDA #$03
writeMem(memory, 0x0400, listOf(0xA9, 0x02, // LDA #$02
0x40)) // RTI
mpu.step() // LDA #$01
assertEquals(0x01, mpu.regA)
assertEquals(0x0002, mpu.regPC)
mpu.step() // BRK
assertEquals(0x0400, mpu.regPC)
mpu.step() // LDA #$02
assertEquals(0x02, mpu.regA)
assertEquals(0x0402, mpu.regPC)
mpu.step() // RTI
assertEquals(0x0004, mpu.regPC)
mpu.step() // A NOP
mpu.step() // The second NOP
mpu.step() // LDA #$03
assertEquals(0x03, mpu.regA)
assertEquals(0x0008, mpu.regPC)
}
}