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: Cpu6502Core
    val memory = Ram(0, 0xffff)
    val bus = Bus()

    abstract fun createCpu(): Cpu6502Core

    init {
        mpu = this.createCpu()
        bus.add(mpu)
        bus.add(memory)
        memory.fill(0xaa)
        memory[Cpu6502Core.RESET_VECTOR] = 0
        memory[Cpu6502Core.RESET_VECTOR+1] = 0
        mpu.reset()
        mpu.regP.I = false        // allow interrupts again
    }

    companion object {
        // processor flags
        const val F_NEGATIVE = 128
        const val F_OVERFLOW = 64
        const val F_UNUSED = 32
        const val F_BREAK = 16
        const val F_DECIMAL = 8
        const val F_INTERRUPT = 4
        const val F_ZERO = 2
        const val F_CARRY = 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(F_BREAK or F_UNUSED, memory[0x1FD].toInt(), "Status on stack should have no I flag")
        assertEquals(F_BREAK or F_UNUSED or F_INTERRUPT, 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 F_BREAK or F_UNUSED)
            // $0000 PHP
            memory[0x0000] = 0x08
            mpu.step()
            assertEquals(0x0001, mpu.regPC)
            assertEquals(0xFC, mpu.regSP)
            assertEquals((flags or F_BREAK or F_UNUSED), 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 F_NEGATIVE.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 F_ZERO.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 F_NEGATIVE.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 F_ZERO.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 F_NEGATIVE.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 F_ZERO.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 F_NEGATIVE.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 F_ZERO.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 F_NEGATIVE.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 F_ZERO.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 F_NEGATIVE.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 F_ZERO.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 F_NEGATIVE.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 F_ZERO.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 F_NEGATIVE.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 F_ZERO.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 F_NEGATIVE.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 F_ZERO.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 F_NEGATIVE.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 F_ZERO.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 F_NEGATIVE.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 F_ZERO.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 F_NEGATIVE.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 F_ZERO.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 F_NEGATIVE.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 F_ZERO.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)
    }
}
