package i6502

import (
	"fmt"
	"io/ioutil"
	"testing"

	"github.com/stretchr/testify/assert"
)

// Creates a new machine, returning the different parts
func NewRamMachine() (*Cpu, *AddressBus, *Ram) {
	ram, _ := NewRam(0x100000) // Full 64kB
	bus, _ := NewAddressBus()
	bus.Attach(ram, 0x0000)
	cpu, _ := NewCpu(bus)

	cpu.Reset()

	return cpu, bus, ram
}

func loadProgram(path string) []byte {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		panic(fmt.Sprintf("Cannot open program file '%s'\n.", path))
	}

	return data
}

func TestNewCpu(t *testing.T) {
	cpu, err := NewCpu(nil)

	assert.NotNil(t, cpu)
	assert.Nil(t, err)
}

func TestStackPushPopPeek(t *testing.T) {
	assert := assert.New(t)
	cpu, _, _ := NewRamMachine()

	assert.EqualValues(0xFF, cpu.SP)

	cpu.stackPush(0x42)
	cpu.stackPush(0xA0)

	assert.EqualValues(0xFD, cpu.SP)
	assert.EqualValues(0x42, cpu.Bus.ReadByte(0x1FF))
	assert.EqualValues(0xA0, cpu.Bus.ReadByte(0x1FE))

	peekValue := cpu.stackPeek()
	assert.EqualValues(0xFD, cpu.SP)
	assert.EqualValues(0xA0, peekValue)

	popValue := cpu.stackPop()
	assert.EqualValues(0xFE, cpu.SP)
	assert.EqualValues(0xA0, popValue)
}

func TestCpuAddressBus(t *testing.T) {
	assert := assert.New(t)

	cpu, bus, _ := NewRamMachine()
	assert.EqualValues(cpu.Bus, bus)
	assert.NotNil(cpu.Bus)
}

func TestCpuReset(t *testing.T) {
	assert := assert.New(t)

	cpu, _, _ := NewRamMachine()
	cpu.Bus.Write16(0xFFFC, 0x1234)

	cpu.Reset()

	// **1101** is specified, but we are satisfied with
	// 00110100 here.
	assert.EqualValues(0x34, cpu.P)
	assert.True(cpu.getIrqDisable())
	assert.False(cpu.getDecimal())
	assert.True(cpu.getBreak())

	// Read PC from $FFFC-FFFD
	assert.EqualValues(0x1234, cpu.PC)
}

func TestCpuInterrupt(t *testing.T) {
	cpu, _, _ := NewRamMachine()

	cpu.Bus.Write16(0xFFFE, 0x1234) // Write the IRQ vector
	cpu.setIrqDisable(false)        // Enable interrupts
	cpu.SP = 0xFF                   // Set the stack pointer
	cpu.PC = 0x0380                 // Some fake point of execution

	assert.EqualValues(t, 0xFF, cpu.SP)

	status := cpu.P

	// Trigger IRQ
	cpu.Interrupt()

	assert.EqualValues(t, 0x1234, cpu.PC)
	assert.EqualValues(t, 0x03, cpu.Bus.ReadByte(0x01FF))
	assert.EqualValues(t, 0x80, cpu.Bus.ReadByte(0x01FE))
	assert.EqualValues(t, status, cpu.Bus.ReadByte(0x01FD))
	assert.True(t, cpu.getIrqDisable())
}

func TestProgramLoading(t *testing.T) {
	assert := assert.New(t)

	program := []byte{0xEA, 0xEB, 0xEC}

	cpu, bus, _ := NewRamMachine()
	cpu.LoadProgram(program, 0x0300)

	assert.EqualValues(0xEA, bus.ReadByte(0x0300))
	assert.EqualValues(0xEB, bus.ReadByte(0x0301))
	assert.EqualValues(0xEC, bus.ReadByte(0x0302))

	assert.EqualValues(0x0300, cpu.PC)
}

//// NOP

func TestNOP(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xEA}, 0x0300)
	cpu.Step()
	assert.EqualValues(t, 0x0301, cpu.PC)
}

func TestSEC(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x38}, 0x0300)

	assert.False(t, cpu.getCarry())
	cpu.Step()
	assert.True(t, cpu.getCarry())
}

func TestSED(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xF8}, 0x0300)

	assert.False(t, cpu.getDecimal())
	cpu.Step()
	assert.True(t, cpu.getDecimal())
}

func TestSEI(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x78}, 0x0300)
	cpu.setIrqDisable(false)

	assert.False(t, cpu.getIrqDisable())
	cpu.Step()
	assert.True(t, cpu.getIrqDisable())
}

func TestCLC(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x18}, 0x0300)
	cpu.setCarry(true)

	assert.True(t, cpu.getCarry())
	cpu.Step()
	assert.False(t, cpu.getCarry())
}

func TestCLD(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xD8}, 0x0300)
	cpu.setDecimal(true)

	assert.True(t, cpu.getDecimal())
	cpu.Step()
	assert.False(t, cpu.getDecimal())
}

func TestCLI(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x58}, 0x0300)
	cpu.setIrqDisable(true)

	assert.True(t, cpu.getIrqDisable())
	cpu.Step()
	assert.False(t, cpu.getIrqDisable())
}

func TestCLV(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xB8}, 0x0300)
	cpu.setOverflow(true)

	assert.True(t, cpu.getOverflow())
	cpu.Step()
	assert.False(t, cpu.getOverflow())
}

//// ADC

func TestADCImmediate(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x69, 0x53}, 0x0300)
	cpu.A = 0x42

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x95, cpu.A)
	assert.False(t, cpu.getCarry())
}

func TestADCWithCarry(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x69, 0x53}, 0x0300)
	cpu.A = 0xC0

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x13, cpu.A)
	assert.True(t, cpu.getCarry())
}

func TestADCWithCarryOver(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x69, 0x04}, 0x0300)

	cpu.setCarry(true)
	cpu.A = 0x05

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x0A, cpu.A)
	assert.False(t, cpu.getCarry())
}

func TestADCWithOverflow(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x69, 0xD0}, 0x0300)

	cpu.A = 0x90

	// 0x90 + 0xD0 = 0x160
	// 208 + 144 = 352 => unsigned carry
	// -48 + -112 = 96 => signed overflow
	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x60, cpu.A)
	assert.True(t, cpu.getCarry())
	assert.True(t, cpu.getOverflow())
}

func TestADCZero(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x69, 0x00}, 0x0300)
	cpu.A = 0x00

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x00, cpu.A)
	assert.True(t, cpu.getZero())
}

func TestADCNegative(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x69, 0xF7}, 0x0300)
	cpu.A = 0x00

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0xF7, cpu.A)
	assert.True(t, cpu.getNegative())
}

func TestADCDecimal(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x69, 0x28}, 0x0300)
	cpu.setDecimal(true)
	cpu.A = 0x19

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x47, cpu.A)
}

func TestADCZeropage(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x65, 0x53}, 0x0300)
	cpu.A = 0x42
	cpu.Bus.WriteByte(0x53, 0x12)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x54, cpu.A)
}

func TestADCZeropageX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x75, 0x53}, 0x0300)
	cpu.A = 0x42
	cpu.X = 0x01
	cpu.Bus.WriteByte(0x54, 0x12)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x54, cpu.A)
}

func TestADCAbsolute(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x6D, 0x00, 0x80}, 0x0300)
	cpu.A = 0x42
	cpu.Bus.WriteByte(0x8000, 0x12)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0x54, cpu.A)
}

func TestADCAbsoluteX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x7D, 0x00, 0x80}, 0x0300)
	cpu.A = 0x42
	cpu.X = 0x02
	cpu.Bus.WriteByte(0x8002, 0x12)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0x54, cpu.A)
}

func TestADCAbsoluteY(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x79, 0x00, 0x80}, 0x0300)
	cpu.A = 0x42
	cpu.Y = 0x02
	cpu.Bus.WriteByte(0x8002, 0x12)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0x54, cpu.A)
}

func TestADCIndirectX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x61, 0x80}, 0x0300)
	cpu.A = 0x42
	cpu.X = 0x02
	cpu.Bus.Write16(0x82, 0xC000)
	cpu.Bus.WriteByte(0xC000, 0x12)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x54, cpu.A)
}

func TestADCIndirectY(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x71, 0x80}, 0x0300)
	cpu.A = 0x42
	cpu.Y = 0x02
	cpu.Bus.Write16(0x80, 0xC000)
	cpu.Bus.WriteByte(0xC002, 0x12)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x54, cpu.A)
}

//// SBC

func TestSBCImmediate(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xE9, 0x01}, 0x0300)
	cpu.A = 0x42
	cpu.setCarry(true)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x41, cpu.A)
	assert.True(t, cpu.getCarry())
}

func TestSBCWithoutCarry(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xE9, 0x01}, 0x0300)
	cpu.A = 0x42
	cpu.setCarry(false)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x40, cpu.A)
	assert.True(t, cpu.getCarry())
}

func TestSBCNegativeNoCarry(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xE9, 0x43}, 0x0300)
	cpu.A = 0x42
	cpu.setCarry(true)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0xff, cpu.A)
	assert.False(t, cpu.getCarry())
	assert.True(t, cpu.getNegative())
}

func TestSBCDecimal(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xE9, 0x03}, 0x0300)
	cpu.setDecimal(true)
	cpu.A = 0x32

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x28, cpu.A)
}

func TestSBCZero(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xE9, 0x42}, 0x0300)
	cpu.A = 0x42
	cpu.setCarry(true)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x00, cpu.A)
	assert.True(t, cpu.getZero())
}

func TestSBCZeropage(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xE5, 0x53}, 0x0300)
	cpu.setCarry(true)
	cpu.A = 0x42
	cpu.Bus.WriteByte(0x53, 0x12)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x30, cpu.A)
}

func TestZeropageX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xF5, 0x53}, 0x0300)
	cpu.setCarry(true)
	cpu.A = 0x42
	cpu.X = 0x01
	cpu.Bus.WriteByte(0x54, 0x12)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x30, cpu.A)
}

func TestSBCAbsolute(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xED, 0x00, 0x80}, 0x0300)
	cpu.setCarry(true)
	cpu.A = 0x42
	cpu.Bus.WriteByte(0x8000, 0x12)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0x30, cpu.A)
}

func TestSBCAbsoluteX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xFD, 0x00, 0x80}, 0x0300)
	cpu.setCarry(true)
	cpu.A = 0x42
	cpu.X = 0x02
	cpu.Bus.WriteByte(0x8002, 0x12)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0x30, cpu.A)
}

func TestSBCAbsoluteY(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xF9, 0x00, 0x80}, 0x0300)
	cpu.setCarry(true)
	cpu.A = 0x42
	cpu.Y = 0x02
	cpu.Bus.WriteByte(0x8002, 0x12)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0x30, cpu.A)
}

func TestSBCIndirectX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xE1, 0x80}, 0x0300)
	cpu.setCarry(true)
	cpu.A = 0x42
	cpu.X = 0x02
	cpu.Bus.Write16(0x82, 0xC000)
	cpu.Bus.WriteByte(0xC000, 0x12)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x30, cpu.A)
}

func TestSBCIndirectY(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xF1, 0x80}, 0x0300)
	cpu.setCarry(true)
	cpu.A = 0x42
	cpu.Y = 0x02
	cpu.Bus.Write16(0x80, 0xC000)
	cpu.Bus.WriteByte(0xC002, 0x12)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x30, cpu.A)
}

//// INX

func TestINX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xE8}, 0x0300)
	cpu.X = 0x42

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0x43, cpu.X)
}

func TestINXRollover(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xE8}, 0x0300)
	cpu.X = 0xFF

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0x00, cpu.X)
}

//// INY

func TestINY(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xC8}, 0x0300)
	cpu.Y = 0x42

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0x43, cpu.Y)
}

func TestINYRollover(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xC8}, 0x0300)
	cpu.Y = 0xFF

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0x00, cpu.Y)
}

//// INC

func TestINCZeropage(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xE6, 0x42}, 0x0300)
	cpu.Bus.WriteByte(0x42, 0x01)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x02, cpu.Bus.ReadByte(0x42))
}

func TestINCZeropageX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xF6, 0x42}, 0x0300)
	cpu.X = 0x01
	cpu.Bus.WriteByte(0x43, 0x01)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x02, cpu.Bus.ReadByte(0x43))
}

func TestINCAbsolute(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xEE, 0x00, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x8000, 0x01)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0x02, cpu.Bus.ReadByte(0x8000))
}

func TestINCAbsoluteX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xFE, 0x00, 0x80}, 0x0300)
	cpu.X = 0x02
	cpu.Bus.WriteByte(0x8002, 0x01)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0x02, cpu.Bus.ReadByte(0x8002))
}

//// DEX

func TestDEX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xCA}, 0x0300)
	cpu.X = 0x42

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0x41, cpu.X)
}

func TestDEXRollover(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xCA}, 0x0300)
	cpu.X = 0x00

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0xFF, cpu.X)
}

//// DEY

func TestDEY(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x88}, 0x0300)
	cpu.Y = 0x42

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0x41, cpu.Y)
}

func TestDEYRollover(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x88}, 0x0300)
	cpu.Y = 0x00

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0xFF, cpu.Y)
}

//// DEC

func TestDECZeropage(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xC6, 0x42}, 0x0300)
	cpu.Bus.WriteByte(0x42, 0x01)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x00, cpu.Bus.ReadByte(0x42))
}

func TestDECZeropageX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xD6, 0x42}, 0x0300)
	cpu.X = 0x01
	cpu.Bus.WriteByte(0x43, 0x01)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x00, cpu.Bus.ReadByte(0x43))
}

func TestDECAbsolute(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xCE, 0x00, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x8000, 0x01)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0x00, cpu.Bus.ReadByte(0x8000))
}

func TestDECAbsoluteX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xDE, 0x00, 0x80}, 0x0300)
	cpu.X = 0x02
	cpu.Bus.WriteByte(0x8002, 0x01)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0x00, cpu.Bus.ReadByte(0x8002))
}

//// LDA

func TestLDAImmediate(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xA9, 0x42}, 0x0300)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x42, cpu.A)
}

func TestLDANegative(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xA9, 0xAE}, 0x0300)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0xAE, cpu.A)
	assert.True(t, cpu.getNegative())
}

func TestLDAZero(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xA9, 0x00}, 0x0300)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x00, cpu.A)
	assert.True(t, cpu.getZero())
}

func TestLDAZeropage(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xA5, 0x42}, 0x0300)
	cpu.Bus.WriteByte(0x42, 0xF8)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0xF8, cpu.A)
}

func TestLDAZeropageX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xB5, 0x41}, 0x0300)
	cpu.X = 0x01
	cpu.Bus.WriteByte(0x42, 0xF8)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0xF8, cpu.A)
}

func TestLDAAbsolute(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xAD, 0x00, 0x80}, 0x0300)
	cpu.Bus.Write16(0x8000, 0xF8)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0xF8, cpu.A)
}

func TestLDAAbsoluteX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xBD, 0x00, 0x80}, 0x0300)
	cpu.X = 0x02
	cpu.Bus.Write16(0x8002, 0xF8)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0xF8, cpu.A)
}

func TestLDAAbsoluteY(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xB9, 0x00, 0x80}, 0x0300)
	cpu.Y = 0x02
	cpu.Bus.Write16(0x8002, 0xF8)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0xF8, cpu.A)
}

func TestLDAIndirectX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xA1, 0x80}, 0x0300)
	cpu.X = 0x02
	cpu.Bus.Write16(0x82, 0xC000)
	cpu.Bus.WriteByte(0xC000, 0xF8)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0xF8, cpu.A)
}

func TestLDAIndirectY(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xB1, 0x80}, 0x0300)
	cpu.Y = 0x02
	cpu.Bus.Write16(0x80, 0xC000)
	cpu.Bus.WriteByte(0xC002, 0xF8)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0xF8, cpu.A)
}

//// LDX

func TestLDXImmediate(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xA2, 0x42}, 0x0300)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x42, cpu.X)
}

func TestLDXNegative(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xA2, 0xAE}, 0x0300)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0xAE, cpu.X)
	assert.True(t, cpu.getNegative())
}

func TestLDXZero(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xA2, 0x00}, 0x0300)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x00, cpu.X)
	assert.True(t, cpu.getZero())
}

func TestLDXZeropage(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xA6, 0x42}, 0x0300)
	cpu.Bus.WriteByte(0x42, 0xF8)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0xF8, cpu.X)
}

func TestLDXZeropageY(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xB6, 0x41}, 0x0300)
	cpu.Y = 0x01
	cpu.Bus.WriteByte(0x42, 0xF8)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0xF8, cpu.X)
}

func TestLDXAbsolute(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xAE, 0x00, 0x80}, 0x0300)
	cpu.Bus.Write16(0x8000, 0xF8)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0xF8, cpu.X)
}

func TestLDXAbsoluteY(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xBE, 0x00, 0x80}, 0x0300)
	cpu.Y = 0x02
	cpu.Bus.Write16(0x8002, 0xF8)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0xF8, cpu.X)
}

//// LDY

func TestLDYImmediate(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xA0, 0x42}, 0x0300)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x42, cpu.Y)
}

func TestLDYNegative(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xA0, 0xAE}, 0x0300)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0xAE, cpu.Y)
	assert.True(t, cpu.getNegative())
}

func TestLDYZero(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xA0, 0x00}, 0x0300)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x00, cpu.Y)
	assert.True(t, cpu.getZero())
}

func TestLDYZeropage(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xA4, 0x42}, 0x0300)
	cpu.Bus.WriteByte(0x42, 0xF8)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0xF8, cpu.Y)
}

func TestLDYZeropageX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xB4, 0x41}, 0x0300)
	cpu.X = 0x01
	cpu.Bus.WriteByte(0x42, 0xF8)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0xF8, cpu.Y)
}

func TestLDYAbsolute(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xAC, 0x00, 0x80}, 0x0300)
	cpu.Bus.Write16(0x8000, 0xF8)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0xF8, cpu.Y)
}

func TestLDYAbsoluteX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xBC, 0x00, 0x80}, 0x0300)
	cpu.X = 0x02
	cpu.Bus.Write16(0x8002, 0xF8)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0xF8, cpu.Y)
}

//// ORA

func TestORAImmediate(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x09, 0x02}, 0x0300)
	cpu.A = 0x70

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x72, cpu.A)
}

func TestORANegative(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x09, 0x02}, 0x0300)
	cpu.A = 0xF0

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0xF2, cpu.A)
	assert.True(t, cpu.getNegative())
}

func TestORAZero(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x09, 0x00}, 0x0300)
	cpu.A = 0x00

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x00, cpu.A)
	assert.True(t, cpu.getZero())
}

func TestORAZeropage(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x05, 0x42}, 0x0300)
	cpu.A = 0xF0
	cpu.Bus.WriteByte(0x0042, 0x02)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0xF2, cpu.A)
}

func TestORAZeropageX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x15, 0x40}, 0x0300)
	cpu.A = 0xF0
	cpu.X = 0x02
	cpu.Bus.WriteByte(0x0042, 0x02)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0xF2, cpu.A)
}

func TestORAAbsolute(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x0D, 0x00, 0x80}, 0x0300)
	cpu.A = 0xF0
	cpu.Bus.WriteByte(0x8000, 0x02)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0xF2, cpu.A)
}

func TestORAAbsoluteX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x1D, 0x00, 0x80}, 0x0300)
	cpu.A = 0xF0
	cpu.X = 0x02
	cpu.Bus.WriteByte(0x8002, 0x02)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0xF2, cpu.A)
}

func TestORAAbsoluteY(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x19, 0x00, 0x80}, 0x0300)
	cpu.A = 0xF0
	cpu.Y = 0x02
	cpu.Bus.WriteByte(0x8002, 0x02)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0xF2, cpu.A)
}

func TestORAIndirectX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x01, 0x40}, 0x0300)
	cpu.A = 0xF0
	cpu.X = 0x02
	cpu.Bus.Write16(0x42, 0xC000)
	cpu.Bus.WriteByte(0xC000, 0x02)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0xF2, cpu.A)
}

func TestORAIndirectY(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x11, 0x40}, 0x0300)
	cpu.A = 0xF0
	cpu.Y = 0x02
	cpu.Bus.Write16(0x40, 0xC000)
	cpu.Bus.WriteByte(0xC002, 0x02)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0xF2, cpu.A)
}

//// AND

func TestANDImmediate(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x29, 0x0f}, 0x0300)
	cpu.A = 0x42

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x02, cpu.A)
}

func TestANDNegative(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x29, 0xF0}, 0x0300)
	cpu.A = 0xA3

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0xA0, cpu.A)
	assert.True(t, cpu.getNegative())
}

func TestANDZero(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x29, 0xf0}, 0x0300)
	cpu.A = 0x0f

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x00, cpu.A)
	assert.True(t, cpu.getZero())
}

func TestANDZeropage(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x25, 0x42}, 0x0300)
	cpu.A = 0xE9
	cpu.Bus.WriteByte(0x0042, 0x0f)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x09, cpu.A)
}

func TestANDZeropageX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x35, 0x40}, 0x0300)
	cpu.A = 0x42
	cpu.X = 0x02
	cpu.Bus.WriteByte(0x0042, 0x0F)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x02, cpu.A)
}

func TestANDAbsolute(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x2D, 0x00, 0x80}, 0x0300)
	cpu.A = 0x42
	cpu.Bus.WriteByte(0x8000, 0x0F)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0x02, cpu.A)
}

func TestANDAbsoluteX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x3D, 0x00, 0x80}, 0x0300)
	cpu.A = 0x42
	cpu.X = 0x02
	cpu.Bus.WriteByte(0x8002, 0x0F)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0x02, cpu.A)
}

func TestANDAbsoluteY(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x39, 0x00, 0x80}, 0x0300)
	cpu.A = 0x42
	cpu.Y = 0x02
	cpu.Bus.WriteByte(0x8002, 0x0F)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0x02, cpu.A)
}

func TestANDIndirectX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x21, 0x80}, 0x0300)
	cpu.A = 0x42
	cpu.X = 0x02
	cpu.Bus.Write16(0x82, 0xC000)
	cpu.Bus.WriteByte(0xC000, 0x0F)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x02, cpu.A)
}

func TestANDIndirectY(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x31, 0x80}, 0x0300)
	cpu.A = 0x42
	cpu.Y = 0x02
	cpu.Bus.Write16(0x80, 0xC000)
	cpu.Bus.WriteByte(0xC002, 0x0F)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x02, cpu.A)
}

//// EOR

func TestEORImmediate(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x49, 0x7f}, 0x0300)
	cpu.A = 0x42

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x3D, cpu.A)
}

func TestEORNegative(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x49, 0xf7}, 0x0300)
	cpu.A = 0x24

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0xD3, cpu.A)
	assert.True(t, cpu.getNegative())
}

func TestEORZero(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x49, 0xff}, 0x0300)
	cpu.A = 0xff

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x00, cpu.A)
	assert.True(t, cpu.getZero())
}

func TestEORZeropage(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x45, 0x80}, 0x0300)
	cpu.A = 0x42
	cpu.Bus.WriteByte(0x0080, 0x7f)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x3D, cpu.A)
}

func TestEORZeropageX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x55, 0x80}, 0x0300)
	cpu.A = 0x42
	cpu.X = 0x02
	cpu.Bus.WriteByte(0x0082, 0x7F)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x3D, cpu.A)
}

func TestEORAbsolute(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x4D, 0x00, 0x80}, 0x0300)
	cpu.A = 0x42
	cpu.Bus.WriteByte(0x8000, 0x7F)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0x3D, cpu.A)
}

func TestEORAbsoluteX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x5D, 0x00, 0x80}, 0x0300)
	cpu.A = 0x42
	cpu.X = 0x02
	cpu.Bus.WriteByte(0x8002, 0x7F)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0x3D, cpu.A)
}

func TestEORAbsoluteY(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x59, 0x00, 0x80}, 0x0300)
	cpu.A = 0x42
	cpu.Y = 0x02
	cpu.Bus.WriteByte(0x8002, 0x7F)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0x3D, cpu.A)
}

func TestEORIndirectX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x41, 0x80}, 0x0300)
	cpu.A = 0x42
	cpu.X = 0x02
	cpu.Bus.Write16(0x82, 0xC000)
	cpu.Bus.WriteByte(0xC000, 0x7F)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x3D, cpu.A)
}

func TestEORIndirectY(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x51, 0x80}, 0x0300)
	cpu.A = 0x42
	cpu.Y = 0x02
	cpu.Bus.Write16(0x80, 0xC000)
	cpu.Bus.WriteByte(0xC002, 0x7F)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x3D, cpu.A)
}

//// STA

func TestSTAZeropage(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x85, 0x80}, 0x0300)
	cpu.A = 0x42

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x42, cpu.Bus.ReadByte(0x0080))
}

func TestSTAZeropageX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x95, 0x80}, 0x0300)
	cpu.A = 0x42
	cpu.X = 0x02

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x42, cpu.Bus.ReadByte(0x0082))
}

func TestSTAAbsolute(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x8D, 0x00, 0x80}, 0x0300)
	cpu.A = 0x42

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0x42, cpu.Bus.ReadByte(0x8000))
}

func TestSTAAbsoluteX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x9D, 0x00, 0x80}, 0x0300)
	cpu.A = 0x42
	cpu.X = 0x02

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0x42, cpu.Bus.ReadByte(0x8002))
}

func TestSTAAbsoluteY(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x99, 0x00, 0x80}, 0x0300)
	cpu.A = 0x42
	cpu.Y = 0x02
	cpu.Bus.WriteByte(0x8002, 0x7F)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0x42, cpu.Bus.ReadByte(0x8002))
}

func TestSTAIndirectX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x81, 0x80}, 0x0300)
	cpu.A = 0x42
	cpu.X = 0x02
	cpu.Bus.Write16(0x82, 0xC000)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x42, cpu.Bus.ReadByte(0xC000))
}

func TestSTAIndirectY(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x91, 0x80}, 0x0300)
	cpu.A = 0x42
	cpu.Y = 0x02
	cpu.Bus.Write16(0x80, 0xC000)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x42, cpu.Bus.ReadByte(0xC002))
}

//// STX

func TestSTXZeropage(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x86, 0x80}, 0x0300)
	cpu.X = 0x42

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x42, cpu.Bus.ReadByte(0x0080))
}

func TestSTXZeropageY(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x96, 0x80}, 0x0300)
	cpu.X = 0x42
	cpu.Y = 0x02

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x42, cpu.Bus.ReadByte(0x0082))
}

func TestSTXAbsolute(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x8E, 0x00, 0x80}, 0x0300)
	cpu.X = 0x42

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0x42, cpu.Bus.ReadByte(0x8000))
}

//// STY

func TestSTYZeropage(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x84, 0x80}, 0x0300)
	cpu.Y = 0x42

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x42, cpu.Bus.ReadByte(0x0080))
}

func TestSTYZeropageX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x94, 0x80}, 0x0300)
	cpu.X = 0x02
	cpu.Y = 0x42

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x42, cpu.Bus.ReadByte(0x0082))
}

func TestSTYAbsolute(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x8C, 0x00, 0x80}, 0x0300)
	cpu.Y = 0x42

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0x42, cpu.Bus.ReadByte(0x8000))
}

//// TAX

func TestTAX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xAA}, 0x0300)
	cpu.A = 0x42

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0x42, cpu.X)
}

func TestTAXNegative(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xAA}, 0x0300)
	cpu.A = 0xE0

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0xE0, cpu.X)
	assert.True(t, cpu.getNegative())
}

func TestTAXZero(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xAA}, 0x0300)
	cpu.A = 0x00

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0x00, cpu.X)
	assert.True(t, cpu.getZero())
}

//// TAY

func TestTAY(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xA8}, 0x0300)
	cpu.A = 0x42

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0x42, cpu.Y)
}

func TestTAYNegative(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xA8}, 0x0300)
	cpu.A = 0xE0

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0xE0, cpu.Y)
	assert.True(t, cpu.getNegative())
}

func TestTAYZero(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xA8}, 0x0300)
	cpu.A = 0x00

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0x00, cpu.Y)
	assert.True(t, cpu.getZero())
}

//// TXA

func TestTXA(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x8A}, 0x0300)
	cpu.X = 0x42

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0x42, cpu.A)
}

func TestTXANegative(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x8A}, 0x0300)
	cpu.X = 0xE0

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0xE0, cpu.A)
	assert.True(t, cpu.getNegative())
}

func TestTXAZero(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x8A}, 0x0300)
	cpu.X = 0x00

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0x00, cpu.A)
	assert.True(t, cpu.getZero())
}

//// TYA

func TestTYA(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x98}, 0x0300)
	cpu.Y = 0x42

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0x42, cpu.A)
}

func TestTYANegative(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x98}, 0x0300)
	cpu.Y = 0xE0

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0xE0, cpu.A)
	assert.True(t, cpu.getNegative())
}

func TestTYAZero(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x98}, 0x0300)
	cpu.Y = 0x00

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0x00, cpu.A)
	assert.True(t, cpu.getZero())
}

//// TSX

func TestTSX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xBA}, 0x0300)
	cpu.SP = 0x42

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0x42, cpu.X)
}

func TestTSXNegative(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xBA}, 0x0300)
	cpu.SP = 0xE0

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0xE0, cpu.X)
	assert.True(t, cpu.getNegative())
}

func TestTSXZero(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0xBA}, 0x0300)
	cpu.SP = 0x00

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0x00, cpu.X)
	assert.True(t, cpu.getZero())
}

//// TXS

func TestTXS(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x9A}, 0x0300)
	cpu.X = 0x42

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0x42, cpu.SP)
}

//// ASL

func TestASLaccumulator(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x0A}, 0x0300)
	cpu.A = 0x01

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0x02, cpu.A)
}

func TestASLAccumulatorNegative(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x0A}, 0x0300)
	cpu.A = 0x40 // 0100 0000

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0x80, cpu.A)
	assert.True(t, cpu.getNegative())
}

func TestASLAccumulatorZero(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x0A}, 0x0300)
	cpu.A = 0x80 // 1000 0000

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0x00, cpu.A)
	assert.True(t, cpu.getZero())
}

func TestASLAccumulatorCarry(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x0A}, 0x0300)
	cpu.A = 0xAA // 1010 1010

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0x54, cpu.A)
	assert.True(t, cpu.getCarry())
}

func TestASLzeropage(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x06, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x0080, 0x01)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x02, cpu.Bus.ReadByte(0x0080))
}

func TestASLzeropageNegative(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x06, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x0080, 0x40)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x80, cpu.Bus.ReadByte(0x0080))
	assert.True(t, cpu.getNegative())
}

func TestASLzeropageZero(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x06, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x0080, 0x80)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x00, cpu.Bus.ReadByte(0x0080))
	assert.True(t, cpu.getZero())
}

func TestASLzeropageCarry(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x06, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x0080, 0xAA)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x54, cpu.Bus.ReadByte(0x0080))
	assert.True(t, cpu.getCarry())
}

func TestASLzeropageX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x16, 0x80}, 0x0300)
	cpu.X = 0x02
	cpu.Bus.WriteByte(0x0082, 0x01)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x02, cpu.Bus.ReadByte(0x0082))
}

func TestASLabsolute(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x0E, 0x00, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x8000, 0x01)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0x02, cpu.Bus.ReadByte(0x8000))
}

func TestASLabsoluteX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x1E, 0x00, 0x80}, 0x0300)
	cpu.X = 0x02
	cpu.Bus.WriteByte(0x8002, 0x01)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0x02, cpu.Bus.ReadByte(0x8002))
}

//// LSR

func TestLSRaccumulator(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x4A}, 0x0300)
	cpu.A = 0x02

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0x01, cpu.A)
}

func TestLSRAccumulatorZero(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x4A}, 0x0300)
	cpu.A = 0x01

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0x00, cpu.A)
	assert.True(t, cpu.getZero())
}

func TestLSRAccumulatorCarry(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x4A}, 0x0300)
	cpu.A = 0x01

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0x00, cpu.A)
	assert.True(t, cpu.getCarry())
}

func TestLSRzeropage(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x46, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x0080, 0x02)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x01, cpu.Bus.ReadByte(0x0080))
}

func TestLSRzeropageZero(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x46, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x0080, 0x01)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x00, cpu.Bus.ReadByte(0x0080))
	assert.True(t, cpu.getZero())
}

func TestLSRzeropageCarry(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x46, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x0080, 0x01)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x00, cpu.Bus.ReadByte(0x0080))
	assert.True(t, cpu.getCarry())
}

func TestLSRzeropageX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x56, 0x80}, 0x0300)
	cpu.X = 0x02
	cpu.Bus.WriteByte(0x0082, 0x04)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x02, cpu.Bus.ReadByte(0x0082))
}

func TestLSRabsolute(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x4E, 0x00, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x8000, 0x04)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0x02, cpu.Bus.ReadByte(0x8000))
}

func TestLSRabsoluteX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x5E, 0x00, 0x80}, 0x0300)
	cpu.X = 0x02
	cpu.Bus.WriteByte(0x8002, 0x04)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0x02, cpu.Bus.ReadByte(0x8002))
}

//// ROL

func TestROLAccumulator(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x2A}, 0x0300)
	cpu.A = 0x01

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0x02, cpu.A)
}

func TestROLAccumulatorZeroAndCarry(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x2A}, 0x0300)

	cpu.setCarry(false)
	cpu.A = 0x80

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0x00, cpu.A)
	assert.True(t, cpu.getZero())
	assert.True(t, cpu.getCarry())
}

func TestROLAccumulatorNegative(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x2A}, 0x0300)

	cpu.setCarry(false)
	cpu.A = 0x40

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0x80, cpu.A)
	assert.True(t, cpu.getNegative())
}

func TestROLZeropage(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x26, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x0080, 0x01)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x02, cpu.Bus.ReadByte(0x0080))
}

func TestROLZeropageX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x36, 0x80}, 0x0300)
	cpu.X = 0x02
	cpu.Bus.WriteByte(0x0082, 0x01)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x02, cpu.Bus.ReadByte(0x0082))
}

func TestROLAbsolute(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x2E, 0x00, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x8000, 0x01)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0x02, cpu.Bus.ReadByte(0x8000))
}

func TestROLAbsoluteX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x3E, 0x00, 0x80}, 0x0300)
	cpu.X = 0x02
	cpu.Bus.WriteByte(0x8002, 0x01)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0x02, cpu.Bus.ReadByte(0x8002))
}

//// ROR

func TestRORAccumulator(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x6A}, 0x0300)
	cpu.A = 0x02

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0x01, cpu.A)
}

func TestRORAccumulatorZeroAndCarry(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x6A}, 0x0300)

	cpu.setCarry(false)
	cpu.A = 0x01

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0x00, cpu.A)
	assert.True(t, cpu.getZero())
	assert.True(t, cpu.getCarry())
}

func TestRORAccumulatorNegative(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x6A}, 0x0300)

	cpu.setCarry(true)
	cpu.A = 0x01

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0x80, cpu.A)
	assert.True(t, cpu.getNegative())
}

func TestRORZeropage(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x66, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x0080, 0x02)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x01, cpu.Bus.ReadByte(0x0080))
}

func TestRORZeropageX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x76, 0x80}, 0x0300)
	cpu.X = 0x02
	cpu.Bus.WriteByte(0x0082, 0x02)

	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0x01, cpu.Bus.ReadByte(0x0082))
}

func TestRORAbsolute(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x6E, 0x00, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x8000, 0x02)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0x01, cpu.Bus.ReadByte(0x8000))
}

func TestRORAbsoluteX(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x7E, 0x00, 0x80}, 0x0300)
	cpu.X = 0x02
	cpu.Bus.WriteByte(0x8002, 0x02)

	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0x01, cpu.Bus.ReadByte(0x8002))
}

/// CMP

func TestCMPImmediate(t *testing.T) {
	cpu, _, _ := NewRamMachine()

	// Equality
	cpu.LoadProgram([]byte{0xC9, 0x42}, 0x0300)
	cpu.A = 0x42
	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.True(t, cpu.getCarry())
	assert.True(t, cpu.getZero())
	assert.False(t, cpu.getNegative())

	// Greater Than
	cpu.LoadProgram([]byte{0xC9, 0x42}, 0x0300)
	cpu.A = 0x43
	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.True(t, cpu.getCarry())
	assert.False(t, cpu.getZero())
	assert.False(t, cpu.getNegative())

	// Less Than
	cpu.LoadProgram([]byte{0xC9, 0x0A}, 0x0300)
	cpu.A = 0x08
	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.False(t, cpu.getCarry())
	assert.False(t, cpu.getZero())
	assert.True(t, cpu.getNegative())
}

func TestCMPZeropage(t *testing.T) {
	cpu, _, _ := NewRamMachine()

	// Equality
	cpu.LoadProgram([]byte{0xC5, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x0080, 0x42)
	cpu.A = 0x42
	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.True(t, cpu.getCarry())
	assert.True(t, cpu.getZero())
	assert.False(t, cpu.getNegative())

	// Greater Than
	cpu.LoadProgram([]byte{0xC5, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x0080, 0x42)
	cpu.A = 0x43
	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.True(t, cpu.getCarry())
	assert.False(t, cpu.getZero())
	assert.False(t, cpu.getNegative())

	// Less Than
	cpu.LoadProgram([]byte{0xC5, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x0080, 0x0A)
	cpu.A = 0x08
	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.False(t, cpu.getCarry())
	assert.False(t, cpu.getZero())
	assert.True(t, cpu.getNegative())
}

func TestCMPZeropageX(t *testing.T) {
	cpu, _, _ := NewRamMachine()

	// Equality
	cpu.LoadProgram([]byte{0xD5, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x0082, 0x42)
	cpu.X = 0x02
	cpu.A = 0x42
	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.True(t, cpu.getCarry())
	assert.True(t, cpu.getZero())
	assert.False(t, cpu.getNegative())

	// Greater Than
	cpu.LoadProgram([]byte{0xD5, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x0082, 0x42)
	cpu.X = 0x02
	cpu.A = 0x43
	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.True(t, cpu.getCarry())
	assert.False(t, cpu.getZero())
	assert.False(t, cpu.getNegative())

	// Less Than
	cpu.LoadProgram([]byte{0xD5, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x0082, 0x0A)
	cpu.X = 0x02
	cpu.A = 0x08
	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.False(t, cpu.getCarry())
	assert.False(t, cpu.getZero())
	assert.True(t, cpu.getNegative())
}

func TestCMPAbsolute(t *testing.T) {
	cpu, _, _ := NewRamMachine()

	// Equality
	cpu.LoadProgram([]byte{0xCD, 0x00, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x8000, 0x42)
	cpu.A = 0x42
	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.True(t, cpu.getCarry())
	assert.True(t, cpu.getZero())
	assert.False(t, cpu.getNegative())

	// Greater Than
	cpu.LoadProgram([]byte{0xCD, 0x00, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x8000, 0x42)
	cpu.A = 0x43
	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.True(t, cpu.getCarry())
	assert.False(t, cpu.getZero())
	assert.False(t, cpu.getNegative())

	// Less Than
	cpu.LoadProgram([]byte{0xCD, 0x00, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x8000, 0x0A)
	cpu.A = 0x08
	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.False(t, cpu.getCarry())
	assert.False(t, cpu.getZero())
	assert.True(t, cpu.getNegative())
}

func TestCMPAbsoluteX(t *testing.T) {
	cpu, _, _ := NewRamMachine()

	// Equality
	cpu.LoadProgram([]byte{0xDD, 0x00, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x8002, 0x42)
	cpu.X = 0x02
	cpu.A = 0x42
	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.True(t, cpu.getCarry())
	assert.True(t, cpu.getZero())
	assert.False(t, cpu.getNegative())

	// Greater Than
	cpu.LoadProgram([]byte{0xDD, 0x00, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x8002, 0x42)
	cpu.X = 0x02
	cpu.A = 0x43
	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.True(t, cpu.getCarry())
	assert.False(t, cpu.getZero())
	assert.False(t, cpu.getNegative())

	// Less Than
	cpu.LoadProgram([]byte{0xDD, 0x00, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x8002, 0x0A)
	cpu.X = 0x02
	cpu.A = 0x08
	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.False(t, cpu.getCarry())
	assert.False(t, cpu.getZero())
	assert.True(t, cpu.getNegative())
}

func TestCMPAbsoluteY(t *testing.T) {
	cpu, _, _ := NewRamMachine()

	// Equality
	cpu.LoadProgram([]byte{0xD9, 0x00, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x8002, 0x42)
	cpu.Y = 0x02
	cpu.A = 0x42
	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.True(t, cpu.getCarry())
	assert.True(t, cpu.getZero())
	assert.False(t, cpu.getNegative())

	// Greater Than
	cpu.LoadProgram([]byte{0xD9, 0x00, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x8002, 0x42)
	cpu.Y = 0x02
	cpu.A = 0x43
	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.True(t, cpu.getCarry())
	assert.False(t, cpu.getZero())
	assert.False(t, cpu.getNegative())

	// Less Than
	cpu.LoadProgram([]byte{0xD9, 0x00, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x8002, 0x0A)
	cpu.Y = 0x02
	cpu.A = 0x08
	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.False(t, cpu.getCarry())
	assert.False(t, cpu.getZero())
	assert.True(t, cpu.getNegative())
}

func TestCMPIndirectX(t *testing.T) {
	cpu, _, _ := NewRamMachine()

	// Equality
	cpu.LoadProgram([]byte{0xC1, 0x80}, 0x0300)
	cpu.Bus.Write16(0x0082, 0xC000)
	cpu.Bus.WriteByte(0xC000, 0x42)
	cpu.X = 0x02
	cpu.A = 0x42
	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.True(t, cpu.getCarry())
	assert.True(t, cpu.getZero())
	assert.False(t, cpu.getNegative())

	// Greater Than
	cpu.LoadProgram([]byte{0xC1, 0x80}, 0x0300)
	cpu.Bus.Write16(0x0082, 0xC000)
	cpu.Bus.WriteByte(0xC000, 0x42)
	cpu.X = 0x02
	cpu.A = 0x43
	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.True(t, cpu.getCarry())
	assert.False(t, cpu.getZero())
	assert.False(t, cpu.getNegative())

	// Less Than
	cpu.LoadProgram([]byte{0xC1, 0x80}, 0x0300)
	cpu.Bus.Write16(0x0082, 0xC000)
	cpu.Bus.WriteByte(0xC000, 0x0A)
	cpu.X = 0x02
	cpu.A = 0x08
	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.False(t, cpu.getCarry())
	assert.False(t, cpu.getZero())
	assert.True(t, cpu.getNegative())
}

func TestCMPIndirectY(t *testing.T) {
	cpu, _, _ := NewRamMachine()

	// Equality
	cpu.LoadProgram([]byte{0xD1, 0x80}, 0x0300)
	cpu.Bus.Write16(0x0080, 0xC000)
	cpu.Bus.WriteByte(0xC002, 0x42)
	cpu.Y = 0x02
	cpu.A = 0x42
	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.True(t, cpu.getCarry())
	assert.True(t, cpu.getZero())
	assert.False(t, cpu.getNegative())

	// Greater Than
	cpu.LoadProgram([]byte{0xD1, 0x80}, 0x0300)
	cpu.Bus.Write16(0x0080, 0xC000)
	cpu.Bus.WriteByte(0xC002, 0x42)
	cpu.X = 0x02
	cpu.A = 0x43
	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.True(t, cpu.getCarry())
	assert.False(t, cpu.getZero())
	assert.False(t, cpu.getNegative())

	// Less Than
	cpu.LoadProgram([]byte{0xD1, 0x80}, 0x0300)
	cpu.Bus.Write16(0x0080, 0xC000)
	cpu.Bus.WriteByte(0xC002, 0x0A)
	cpu.X = 0x02
	cpu.A = 0x08
	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.False(t, cpu.getCarry())
	assert.False(t, cpu.getZero())
	assert.True(t, cpu.getNegative())
}

//// CPX

func TestCPXImmediate(t *testing.T) {
	cpu, _, _ := NewRamMachine()

	// Equality
	cpu.LoadProgram([]byte{0xE0, 0x42}, 0x0300)
	cpu.X = 0x42
	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.True(t, cpu.getCarry())
	assert.True(t, cpu.getZero())
	assert.False(t, cpu.getNegative())

	// Greater Than
	cpu.LoadProgram([]byte{0xE0, 0x42}, 0x0300)
	cpu.X = 0x43
	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.True(t, cpu.getCarry())
	assert.False(t, cpu.getZero())
	assert.False(t, cpu.getNegative())

	// Less Than
	cpu.LoadProgram([]byte{0xE0, 0x0A}, 0x0300)
	cpu.X = 0x08
	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.False(t, cpu.getCarry())
	assert.False(t, cpu.getZero())
	assert.True(t, cpu.getNegative())
}

func TestCPXZeropage(t *testing.T) {
	cpu, _, _ := NewRamMachine()

	// Equality
	cpu.LoadProgram([]byte{0xE4, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x0080, 0x42)
	cpu.X = 0x42
	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.True(t, cpu.getCarry())
	assert.True(t, cpu.getZero())
	assert.False(t, cpu.getNegative())

	// Greater Than
	cpu.LoadProgram([]byte{0xE4, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x0080, 0x42)
	cpu.X = 0x43
	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.True(t, cpu.getCarry())
	assert.False(t, cpu.getZero())
	assert.False(t, cpu.getNegative())

	// Less Than
	cpu.LoadProgram([]byte{0xE4, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x0080, 0x0A)
	cpu.X = 0x08
	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.False(t, cpu.getCarry())
	assert.False(t, cpu.getZero())
	assert.True(t, cpu.getNegative())
}

func TestCPXAbsolute(t *testing.T) {
	cpu, _, _ := NewRamMachine()

	// Equality
	cpu.LoadProgram([]byte{0xEC, 0x00, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x8000, 0x42)
	cpu.X = 0x42
	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.True(t, cpu.getCarry())
	assert.True(t, cpu.getZero())
	assert.False(t, cpu.getNegative())

	// Greater Than
	cpu.LoadProgram([]byte{0xEC, 0x00, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x8000, 0x42)
	cpu.X = 0x43
	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.True(t, cpu.getCarry())
	assert.False(t, cpu.getZero())
	assert.False(t, cpu.getNegative())

	// Less Than
	cpu.LoadProgram([]byte{0xEC, 0x00, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x8000, 0x0A)
	cpu.X = 0x08
	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.False(t, cpu.getCarry())
	assert.False(t, cpu.getZero())
	assert.True(t, cpu.getNegative())
}

//// CPY

func TestCPYImmediate(t *testing.T) {
	cpu, _, _ := NewRamMachine()

	// Equality
	cpu.LoadProgram([]byte{0xC0, 0x42}, 0x0300)
	cpu.Y = 0x42
	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.True(t, cpu.getCarry())
	assert.True(t, cpu.getZero())
	assert.False(t, cpu.getNegative())

	// Greater Than
	cpu.LoadProgram([]byte{0xC0, 0x42}, 0x0300)
	cpu.Y = 0x43
	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.True(t, cpu.getCarry())
	assert.False(t, cpu.getZero())
	assert.False(t, cpu.getNegative())

	// Less Than
	cpu.LoadProgram([]byte{0xC0, 0x0A}, 0x0300)
	cpu.Y = 0x08
	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.False(t, cpu.getCarry())
	assert.False(t, cpu.getZero())
	assert.True(t, cpu.getNegative())
}

func TestCPYZeropage(t *testing.T) {
	cpu, _, _ := NewRamMachine()

	// Equality
	cpu.LoadProgram([]byte{0xC4, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x0080, 0x42)
	cpu.Y = 0x42
	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.True(t, cpu.getCarry())
	assert.True(t, cpu.getZero())
	assert.False(t, cpu.getNegative())

	// Greater Than
	cpu.LoadProgram([]byte{0xC4, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x0080, 0x42)
	cpu.Y = 0x43
	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.True(t, cpu.getCarry())
	assert.False(t, cpu.getZero())
	assert.False(t, cpu.getNegative())

	// Less Than
	cpu.LoadProgram([]byte{0xC4, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x0080, 0x0A)
	cpu.Y = 0x08
	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.False(t, cpu.getCarry())
	assert.False(t, cpu.getZero())
	assert.True(t, cpu.getNegative())
}

func TestCPYAbsolute(t *testing.T) {
	cpu, _, _ := NewRamMachine()

	// Equality
	cpu.LoadProgram([]byte{0xCC, 0x00, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x8000, 0x42)
	cpu.Y = 0x42
	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.True(t, cpu.getCarry())
	assert.True(t, cpu.getZero())
	assert.False(t, cpu.getNegative())

	// Greater Than
	cpu.LoadProgram([]byte{0xCC, 0x00, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x8000, 0x42)
	cpu.Y = 0x43
	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.True(t, cpu.getCarry())
	assert.False(t, cpu.getZero())
	assert.False(t, cpu.getNegative())

	// Less Than
	cpu.LoadProgram([]byte{0xCC, 0x00, 0x80}, 0x0300)
	cpu.Bus.WriteByte(0x8000, 0x0A)
	cpu.Y = 0x08
	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.False(t, cpu.getCarry())
	assert.False(t, cpu.getZero())
	assert.True(t, cpu.getNegative())
}

//// BRK

func TestBRK(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x00}, 0x0300)
	cpu.Bus.Write16(IrqVector, 0x1234)
	cpu.SP = 0xFF
	status := cpu.P

	cpu.Step()

	assert.EqualValues(t, 0x1234, cpu.PC)
	assert.EqualValues(t, 0x03, cpu.Bus.ReadByte(0x01FF))
	assert.EqualValues(t, 0x02, cpu.Bus.ReadByte(0x01FE))
	assert.EqualValues(t, status, cpu.Bus.ReadByte(0x01FD))
	assert.True(t, cpu.getBreak())

}

//// BCC

func TestBCC(t *testing.T) {
	cpu, _, _ := NewRamMachine()

	/// Positive offset
	// Carry set
	cpu.LoadProgram([]byte{0x90, 0x05}, 0x0300)
	cpu.setCarry(true)
	cpu.Step()
	assert.EqualValues(t, 0x0302, cpu.PC)

	// Carry not set
	cpu.LoadProgram([]byte{0x90, 0x05}, 0x0300)
	cpu.setCarry(false)
	cpu.Step()
	// 0x0302 + 0x05 = 0x0307
	assert.EqualValues(t, 0x0307, cpu.PC)

	/// Negative offset
	// Carry set
	cpu.LoadProgram([]byte{0x90, 0xfb}, 0x0300)
	cpu.setCarry(true)
	cpu.Step()
	assert.EqualValues(t, 0x0302, cpu.PC)

	// Carry not set
	cpu.LoadProgram([]byte{0x90, 0xFB}, 0x0300)
	cpu.setCarry(false)
	cpu.Step()
	// 0x0302 + 0xFB => 0x0302 - 0x05 => 0x02FD
	assert.EqualValues(t, 0x02FD, cpu.PC)
}

//// BCS

func TestBCS(t *testing.T) {
	cpu, _, _ := NewRamMachine()

	/// Positive offset
	// Carry set
	cpu.LoadProgram([]byte{0xB0, 0x05}, 0x0300)
	cpu.setCarry(true)
	cpu.Step()
	// 0x0302 + 0x05 = 0x0307
	assert.EqualValues(t, 0x0307, cpu.PC)

	// Carry not set
	cpu.LoadProgram([]byte{0xB0, 0x05}, 0x0300)
	cpu.setCarry(false)
	cpu.Step()
	assert.EqualValues(t, 0x0302, cpu.PC)

	/// Negative offset
	// Carry set
	cpu.LoadProgram([]byte{0xB0, 0xfb}, 0x0300)
	cpu.setCarry(true)
	cpu.Step()
	// 0x0302 + 0xFB => 0x0302 - 0x05 => 0x02FD
	assert.EqualValues(t, 0x02FD, cpu.PC)

	// Carry not set
	cpu.LoadProgram([]byte{0xB0, 0xFB}, 0x0300)
	cpu.setCarry(false)
	cpu.Step()
	assert.EqualValues(t, 0x0302, cpu.PC)
}

//// BNE

func TestBNE(t *testing.T) {
	cpu, _, _ := NewRamMachine()

	/// Positive offset
	// Carry set
	cpu.LoadProgram([]byte{0xD0, 0x05}, 0x0300)
	cpu.setZero(true)
	cpu.Step()
	assert.EqualValues(t, 0x0302, cpu.PC)

	// Carry not set
	cpu.LoadProgram([]byte{0xD0, 0x05}, 0x0300)
	cpu.setZero(false)
	cpu.Step()
	// 0x0302 + 0x05 = 0x0307
	assert.EqualValues(t, 0x0307, cpu.PC)

	/// Negative offset
	// Carry set
	cpu.LoadProgram([]byte{0xD0, 0xfb}, 0x0300)
	cpu.setZero(true)
	cpu.Step()
	assert.EqualValues(t, 0x0302, cpu.PC)

	// Carry not set
	cpu.LoadProgram([]byte{0xD0, 0xFB}, 0x0300)
	cpu.setZero(false)
	cpu.Step()
	// 0x0302 + 0xFB => 0x0302 - 0x05 => 0x02FD
	assert.EqualValues(t, 0x02FD, cpu.PC)
}

//// BEQ

func TestBEQ(t *testing.T) {
	cpu, _, _ := NewRamMachine()

	/// Positive offset
	// Carry set
	cpu.LoadProgram([]byte{0xF0, 0x05}, 0x0300)
	cpu.setZero(true)
	cpu.Step()
	// 0x0302 + 0x05 = 0x0307
	assert.EqualValues(t, 0x0307, cpu.PC)

	// Carry not set
	cpu.LoadProgram([]byte{0xF0, 0x05}, 0x0300)
	cpu.setZero(false)
	cpu.Step()
	assert.EqualValues(t, 0x0302, cpu.PC)

	/// Negative offset
	// Carry set
	cpu.LoadProgram([]byte{0xF0, 0xfb}, 0x0300)
	cpu.setZero(true)
	cpu.Step()
	// 0x0302 + 0xFB => 0x0302 - 0x05 => 0x02FD
	assert.EqualValues(t, 0x02FD, cpu.PC)

	// Carry not set
	cpu.LoadProgram([]byte{0xF0, 0xFB}, 0x0300)
	cpu.setZero(false)
	cpu.Step()
	assert.EqualValues(t, 0x0302, cpu.PC)
}

//// BPL

func TestBPL(t *testing.T) {
	cpu, _, _ := NewRamMachine()

	/// Positive offset
	// Carry set
	cpu.LoadProgram([]byte{0x10, 0x05}, 0x0300)
	cpu.setNegative(true)
	cpu.Step()
	assert.EqualValues(t, 0x0302, cpu.PC)

	// Carry not set
	cpu.LoadProgram([]byte{0x10, 0x05}, 0x0300)
	cpu.setNegative(false)
	cpu.Step()
	// 0x0302 + 0x05 = 0x0307
	assert.EqualValues(t, 0x0307, cpu.PC)

	/// Negative offset
	// Carry set
	cpu.LoadProgram([]byte{0x10, 0xfb}, 0x0300)
	cpu.setNegative(true)
	cpu.Step()
	assert.EqualValues(t, 0x0302, cpu.PC)

	// Carry not set
	cpu.LoadProgram([]byte{0x10, 0xFB}, 0x0300)
	cpu.setNegative(false)
	cpu.Step()
	// 0x0302 + 0xFB => 0x0302 - 0x05 => 0x02FD
	assert.EqualValues(t, 0x02FD, cpu.PC)
}

//// BMI

func TestBMI(t *testing.T) {
	cpu, _, _ := NewRamMachine()

	/// Positive offset
	// Carry set
	cpu.LoadProgram([]byte{0x30, 0x05}, 0x0300)
	cpu.setNegative(true)
	cpu.Step()
	// 0x0302 + 0x05 = 0x0307
	assert.EqualValues(t, 0x0307, cpu.PC)

	// Carry not set
	cpu.LoadProgram([]byte{0x30, 0x05}, 0x0300)
	cpu.setNegative(false)
	cpu.Step()
	assert.EqualValues(t, 0x0302, cpu.PC)

	/// Negative offset
	// Carry set
	cpu.LoadProgram([]byte{0x30, 0xfb}, 0x0300)
	cpu.setNegative(true)
	cpu.Step()
	// 0x0302 + 0xFB => 0x0302 - 0x05 => 0x02FD
	assert.EqualValues(t, 0x02FD, cpu.PC)

	// Carry not set
	cpu.LoadProgram([]byte{0x30, 0xFB}, 0x0300)
	cpu.setNegative(false)
	cpu.Step()
	assert.EqualValues(t, 0x0302, cpu.PC)
}

//// BVC

func TestBVC(t *testing.T) {
	cpu, _, _ := NewRamMachine()

	/// Positive offset
	// Carry set
	cpu.LoadProgram([]byte{0x50, 0x05}, 0x0300)
	cpu.setOverflow(true)
	cpu.Step()
	assert.EqualValues(t, 0x0302, cpu.PC)

	// Carry not set
	cpu.LoadProgram([]byte{0x50, 0x05}, 0x0300)
	cpu.setOverflow(false)
	cpu.Step()
	// 0x0302 + 0x05 = 0x0307
	assert.EqualValues(t, 0x0307, cpu.PC)

	/// Negative offset
	// Carry set
	cpu.LoadProgram([]byte{0x50, 0xfb}, 0x0300)
	cpu.setOverflow(true)
	cpu.Step()
	assert.EqualValues(t, 0x0302, cpu.PC)

	// Carry not set
	cpu.LoadProgram([]byte{0x50, 0xFB}, 0x0300)
	cpu.setOverflow(false)
	cpu.Step()
	// 0x0302 + 0xFB => 0x0302 - 0x05 => 0x02FD
	assert.EqualValues(t, 0x02FD, cpu.PC)
}

//// BVS

func TestBVS(t *testing.T) {
	cpu, _, _ := NewRamMachine()

	/// Positive offset
	// Carry set
	cpu.LoadProgram([]byte{0x70, 0x05}, 0x0300)
	cpu.setOverflow(true)
	cpu.Step()
	// 0x0302 + 0x05 = 0x0307
	assert.EqualValues(t, 0x0307, cpu.PC)

	// Carry not set
	cpu.LoadProgram([]byte{0x70, 0x05}, 0x0300)
	cpu.setOverflow(false)
	cpu.Step()
	assert.EqualValues(t, 0x0302, cpu.PC)

	/// Negative offset
	// Carry set
	cpu.LoadProgram([]byte{0x70, 0xfb}, 0x0300)
	cpu.setOverflow(true)
	cpu.Step()
	// 0x0302 + 0xFB => 0x0302 - 0x05 => 0x02FD
	assert.EqualValues(t, 0x02FD, cpu.PC)

	// Carry not set
	cpu.LoadProgram([]byte{0x70, 0xFB}, 0x0300)
	cpu.setOverflow(false)
	cpu.Step()
	assert.EqualValues(t, 0x0302, cpu.PC)
}

//// BIT

func TestBITZeropage(t *testing.T) {
	cpu, _, _ := NewRamMachine()

	cpu.Bus.WriteByte(0x0000, 0xC0)
	cpu.Bus.WriteByte(0x0010, 0x40)
	cpu.Bus.WriteByte(0x0020, 0x80)

	cpu.LoadProgram([]byte{0x24, 0x00}, 0x0300)
	cpu.A = 0x01
	cpu.Step()
	assert.True(t, cpu.getZero())
	assert.True(t, cpu.getNegative())
	assert.True(t, cpu.getOverflow())

	cpu.LoadProgram([]byte{0x24, 0x20}, 0x0300)
	cpu.A = 0x40
	cpu.Step()
	assert.True(t, cpu.getZero())
	assert.True(t, cpu.getNegative())
	assert.False(t, cpu.getOverflow())

	cpu.LoadProgram([]byte{0x24, 0x10}, 0x0300)
	cpu.A = 0x80
	cpu.Step()
	assert.True(t, cpu.getZero())
	assert.False(t, cpu.getNegative())
	assert.True(t, cpu.getOverflow())

	cpu.LoadProgram([]byte{0x24, 0x00}, 0x0300)
	cpu.A = 0xC0
	cpu.Step()
	assert.False(t, cpu.getZero())
	assert.True(t, cpu.getNegative())
	assert.True(t, cpu.getOverflow())

	cpu.LoadProgram([]byte{0x24, 0x00}, 0x0300)
	cpu.A = 0xFF
	cpu.Step()
	assert.False(t, cpu.getZero())
	assert.True(t, cpu.getNegative())
	assert.True(t, cpu.getOverflow())
}

func TestBITAbsolute(t *testing.T) {
	cpu, _, _ := NewRamMachine()

	cpu.Bus.WriteByte(0xC000, 0xC0)
	cpu.Bus.WriteByte(0xC010, 0x40)
	cpu.Bus.WriteByte(0xC020, 0x80)

	cpu.LoadProgram([]byte{0x2C, 0x00, 0xC0}, 0x0300)
	cpu.A = 0x01
	cpu.Step()
	assert.True(t, cpu.getZero())
	assert.True(t, cpu.getNegative())
	assert.True(t, cpu.getOverflow())

	cpu.LoadProgram([]byte{0x2C, 0x20, 0xC0}, 0x0300)
	cpu.A = 0x40
	cpu.Step()
	assert.True(t, cpu.getZero())
	assert.True(t, cpu.getNegative())
	assert.False(t, cpu.getOverflow())

	cpu.LoadProgram([]byte{0x2C, 0x10, 0xC0}, 0x0300)
	cpu.A = 0x80
	cpu.Step()
	assert.True(t, cpu.getZero())
	assert.False(t, cpu.getNegative())
	assert.True(t, cpu.getOverflow())

	cpu.LoadProgram([]byte{0x2C, 0x00, 0xC0}, 0x0300)
	cpu.A = 0xC0
	cpu.Step()
	assert.False(t, cpu.getZero())
	assert.True(t, cpu.getNegative())
	assert.True(t, cpu.getOverflow())

	cpu.LoadProgram([]byte{0x2C, 0x00, 0xC0}, 0x0300)
	cpu.A = 0xFF
	cpu.Step()
	assert.False(t, cpu.getZero())
	assert.True(t, cpu.getNegative())
	assert.True(t, cpu.getOverflow())
}

//// PHP

func TestPHP(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x08}, 0x0300)
	cpu.SP = 0xFF
	cpu.P = 0xB5

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0xFE, cpu.SP)
	assert.EqualValues(t, 0xB5, cpu.Bus.ReadByte(0x01FF))
}

//// PLP

func TestPLP(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x28}, 0x0300)
	cpu.stackPush(0xB5)
	cpu.P = 0x34

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0xFF, cpu.SP)
	assert.EqualValues(t, 0xB5, cpu.P)
}

//// PHA

func TestPHA(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x48}, 0x0300)
	cpu.SP = 0xFF
	cpu.A = 0xB5

	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0xFE, cpu.SP)
	assert.EqualValues(t, 0xB5, cpu.Bus.ReadByte(0x01FF))
}

//// PLP

func TestPLA(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x68, 0x68, 0x68}, 0x0300)

	cpu.stackPush(0x42)
	cpu.Step()

	assert.EqualValues(t, 0x0301, cpu.PC)
	assert.EqualValues(t, 0xFF, cpu.SP)
	assert.EqualValues(t, 0x42, cpu.A)

	cpu.stackPush(0xB5)
	cpu.Step()

	assert.EqualValues(t, 0x0302, cpu.PC)
	assert.EqualValues(t, 0xFF, cpu.SP)
	assert.EqualValues(t, 0xB5, cpu.A)
	assert.True(t, cpu.getNegative())

	cpu.stackPush(0x00)
	cpu.Step()

	assert.EqualValues(t, 0x0303, cpu.PC)
	assert.EqualValues(t, 0xFF, cpu.SP)
	assert.EqualValues(t, 0x00, cpu.A)
	assert.True(t, cpu.getZero())
}

//// JMP

func TestJMPAbsolute(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x4C, 0x34, 0x12}, 0x0300)

	cpu.Step()

	assert.EqualValues(t, 0x1234, cpu.PC)
}

func TestJMPIndirect(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x6C, 0x00, 0xC0}, 0x0300)
	cpu.Bus.Write16(0xC000, 0x1234)

	cpu.Step()

	assert.EqualValues(t, 0x1234, cpu.PC)
}

//// JSR

func TestJSR(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x20, 0x34, 0x12}, 0x0300)
	cpu.SP = 0xFF

	cpu.Step()

	assert.EqualValues(t, 0x1234, cpu.PC)
	assert.EqualValues(t, 0xFD, cpu.SP)

	// We expect PC - 1 (e.g. 3rd byte of JSR) to be on the stack
	assert.EqualValues(t, 0x03, cpu.Bus.ReadByte(0x1FF))
	assert.EqualValues(t, 0x02, cpu.Bus.ReadByte(0x1FE))
}

//// RTS

func TestRTS(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x60}, 0x0300)
	cpu.P = 0x34

	cpu.stackPush(0x12) // PC HI
	cpu.stackPush(0x34) // PC LO

	cpu.Step()

	assert.EqualValues(t, 0x1234+1, cpu.PC)
	assert.EqualValues(t, 0x34, cpu.P)
}

//// RTI

func TestRTI(t *testing.T) {
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram([]byte{0x40}, 0x0300)

	cpu.stackPush(0x12) // PC HI
	cpu.stackPush(0x34) // PC LO
	cpu.stackPush(0x5B) // P

	cpu.Step()

	assert.EqualValues(t, 0x1234, cpu.PC)
	assert.EqualValues(t, 0x5B|0x20, cpu.P)
}

// Run this last, as the full suite takes ±10 seconds to run at
// maximum speed
func TestKlausDormann6502(t *testing.T) {
	fmt.Println("Running Klaus Dormann' 6502 functional tests. This may take some time...")
	cpu, _, _ := NewRamMachine()
	cpu.LoadProgram(loadProgram("test/6502_functional_test.bin"), 0x0000)
	cpu.PC = 0x0400
	prevPC := uint16(0x0400)

	for {
		cpu.Step()

		if cpu.PC == prevPC {
			if cpu.PC != 0x3399 {
				str := "Looping PC detected at PC 0x%04X. We've hit a failing Klaus Dormann test."
				panic(fmt.Sprintf(str, cpu.PC))
			} else {
				fmt.Println("Klaus Dormann's 6502 functional tests passed.")
				break
			}
		}

		prevPC = cpu.PC
	}
}
