#include "Constants.h"
#include "Cpu.h"
#include "Memory.h"
#include "Io.h"
#include "CpuUtilities.h"
#include "CpuDDAndFDPrefix.h"
#include "CpuNoPrefix.h" // because DD and FD opcodes can "fall through" to unprefixed opcodes, through the many "holes"


// a marker function for the "holes" in the DD and FD prefixed instructions, in which cases the instruction is
// treated as if it had no prefix
void FALL_THROUGH_TO_UNPREFIXED(struct instruction* instruction) {
	cpu_run_no_prefix(instruction);
}

void cpu_instruction__add_indexreg16_reg16(struct instruction* instruction, Uint16 reg16, const char* disassembledName) {
	Uint16* indexReg = cpu_get_indexreg16_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg16_name(instruction);

	cpu_finalize_instruction_decode(instruction, 7);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, disassembledName, UNUSED, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	cpu_save_flags();
	cpu_addc_binary16(indexReg, reg16, 0);
	cpu_restore_flags(CPU_FLAG_S_SIGN | CPU_FLAG_Z_ZERO | CPU_FLAG_PV_PARITY_OVERFLOW);	// restore unaffected flags
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__ld_indexreg16_imm16(struct instruction* instruction, const char* disassembledName) {
	cpu_read_imm16(instruction);

	Uint16* indexReg = cpu_get_indexreg16_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg16_name(instruction);

	cpu_finalize_instruction_decode(instruction, 6);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, disassembledName, instruction->immediate.value.sixteenBit, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	*indexReg = instruction->immediate.value.sixteenBit;
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__ld_mem16_indexreg16(struct instruction* instruction) {
	cpu_read_imm16(instruction);

	Uint16* indexReg = cpu_get_indexreg16_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg16_name(instruction);

	cpu_finalize_instruction_decode(instruction, 12);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, "ld (/n0), /s0", instruction->immediate.value.sixteenBit, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	memory_write16(instruction->immediate.value.sixteenBit, *indexReg);
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__inc_indexreg16(struct instruction* instruction) {
	Uint16* indexReg = cpu_get_indexreg16_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg16_name(instruction);

	cpu_finalize_instruction_decode(instruction, 2);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, "inc /s0", UNUSED, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	(*indexReg)++;
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__inc_indexreg8h(struct instruction* instruction) {
	Uint8* indexReg = cpu_get_indexreg8h_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg8h_name(instruction);

	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, "inc /s0", UNUSED, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	cpu_save_flags();
	cpu_addc_binary8(indexReg, 1, 0);
	cpu_restore_flags(CPU_FLAG_C_CARRY);			// some flags are unaffected, so preserve them
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__inc_indexreg8l(struct instruction* instruction) {
	Uint8* indexReg = cpu_get_indexreg8l_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg8l_name(instruction);

	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, "inc /s0", UNUSED, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	cpu_save_flags();
	cpu_addc_binary8(indexReg, 1, 0);
	cpu_restore_flags(CPU_FLAG_C_CARRY);			// some flags are unaffected, so preserve them
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__dec_indexreg8h(struct instruction* instruction) {
	Uint8* indexReg = cpu_get_indexreg8h_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg8h_name(instruction);

	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, "dec /s0", UNUSED, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	cpu_save_flags();
	cpu_subc_binary8(indexReg, 1, 0);
	cpu_restore_flags(CPU_FLAG_C_CARRY);			// some flags are unaffected, so preserve them
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__dec_indexreg8l(struct instruction* instruction) {
	Uint8* indexReg = cpu_get_indexreg8l_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg8l_name(instruction);

	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, "dec /s0", UNUSED, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	cpu_save_flags();
	cpu_subc_binary8(indexReg, 1, 0);
	cpu_restore_flags(CPU_FLAG_C_CARRY);			// some flags are unaffected, so preserve them
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__ld_indexreg8h_imm8(struct instruction* instruction) {
	cpu_read_imm8(instruction);

	Uint8* indexReg = cpu_get_indexreg8h_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg8h_name(instruction);

	cpu_finalize_instruction_decode(instruction, 3);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, "ld /s0, /n0", instruction->immediate.value.eightBit, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	*indexReg = instruction->immediate.value.eightBit;
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__ld_indexreg8l_imm8(struct instruction* instruction) {
	cpu_read_imm8(instruction);

	Uint8* indexReg = cpu_get_indexreg8l_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg8l_name(instruction);

	cpu_finalize_instruction_decode(instruction, 3);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, "ld /s0, /n0", instruction->immediate.value.eightBit, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	*indexReg = instruction->immediate.value.eightBit;
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__ld_indexreg16_mem16(struct instruction* instruction) {
	cpu_read_imm16(instruction);

	Uint16* indexReg = cpu_get_indexreg16_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg16_name(instruction);

	cpu_finalize_instruction_decode(instruction, 12);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, "ld /s0, (/n0)", instruction->immediate.value.sixteenBit, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	*indexReg = memory_read16(instruction->immediate.value.sixteenBit);
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__dec_indexreg16(struct instruction* instruction) {
	Uint16* indexReg = cpu_get_indexreg16_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg16_name(instruction);

	cpu_finalize_instruction_decode(instruction, 2);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, "dec /s0", UNUSED, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	(*indexReg)--;
	cpu_mark_instruction_executed(instruction);
}

// reads the imm8
Uint16 cpu_get_absolute_address_indexreg16_plus_imm8(struct instruction* instruction) {
	cpu_read_imm8(instruction);
	Uint16* indexReg = cpu_get_indexreg16_ptr(instruction);
	Uint16 address = cpu_compute_absolute_address(*indexReg, instruction->immediate.value.eightBit);
	return address;
}

void cpu_instruction__inc_indexreg16Ptr(struct instruction* instruction) {
	Uint16 absoluteAddress = cpu_get_absolute_address_indexreg16_plus_imm8(instruction);	// reads imm8
	const char* indexRegName = cpu_get_indexreg16_name(instruction);

	cpu_finalize_instruction_decode(instruction, 15);
	cpu_set_instruction_disassembled_name_formatted_indexreg16_plus_imm8(instruction, "inc (/s0+/n0)", "inc (/s0-/n0)", indexRegName);
	
	if (!cpu_must_execute()) return;
	//execution

	Uint8 temp8 = memory_read8(absoluteAddress);
	cpu_save_flags();
	cpu_addc_binary8(&temp8, 1, 0);
	memory_write8(absoluteAddress, temp8);
	cpu_restore_flags(CPU_FLAG_C_CARRY);			// some flags are unaffected, so preserve them
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__dec_indexreg16Ptr(struct instruction* instruction) {
	Uint16 absoluteAddress = cpu_get_absolute_address_indexreg16_plus_imm8(instruction);	// reads imm8
	const char* indexRegName = cpu_get_indexreg16_name(instruction);

	cpu_finalize_instruction_decode(instruction, 15);
	cpu_set_instruction_disassembled_name_formatted_indexreg16_plus_imm8(instruction, "dec (/s0+/n0)", "dec (/s0-/n0)", indexRegName);

	if (!cpu_must_execute()) return;
	//execution

	Uint8 temp8 = memory_read8(absoluteAddress);
	cpu_save_flags();
	cpu_subc_binary8(&temp8, 1, 0);
	memory_write8(absoluteAddress, temp8);
	cpu_restore_flags(CPU_FLAG_C_CARRY);			// some flags are unaffected, so preserve them
	cpu_mark_instruction_executed(instruction);
}


void cpu_instruction__ld_indexreg16Ptr_imm8(struct instruction* instruction) {
	Uint16 absoluteAddress = cpu_get_absolute_address_indexreg16_plus_imm8(instruction);	// reads imm8
	const char* indexRegName = cpu_get_indexreg16_name(instruction);

	// read n
	Uint8 n = memory_read8(cpu_regs()->PC);
	cpu_regs()->PC += 1;

	cpu_finalize_instruction_decode(instruction, 11);
	if ((Sint8)instruction->immediate.value.eightBit < 0) {
		cpu_set_instruction_disassembled_name_formatted_str(instruction, "ld (/s0-/n0), /n1", cpu_neg8(instruction->immediate.value.eightBit), (Uint16)n, indexRegName, UNUSEDSTR);
	}
	else {
		cpu_set_instruction_disassembled_name_formatted_str(instruction, "ld (/s0+/n0), /n1", instruction->immediate.value.eightBit, (Uint16)n, indexRegName, UNUSEDSTR);
	}

	if (!cpu_must_execute()) return;
	//execution

	memory_write8(absoluteAddress, n);
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__ld_reg8_indexreg8h(struct instruction* instruction, Uint8* reg8, const char* disassembledName) {
	Uint8* indexReg = cpu_get_indexreg8h_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg8h_name(instruction);

	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, disassembledName, UNUSED, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	*reg8 = *indexReg;
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__ld_reg8_indexreg8l(struct instruction* instruction, Uint8* reg8, const char* disassembledName) {
	Uint8* indexReg = cpu_get_indexreg8l_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg8l_name(instruction);

	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, disassembledName, UNUSED, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	*reg8 = *indexReg;
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__ld_reg8_indexreg16Ptr(struct instruction* instruction, Uint8* reg8, const char* nonNegativeSource, const char* negativeSource) {
	Uint16 absoluteAddress = cpu_get_absolute_address_indexreg16_plus_imm8(instruction);	// reads imm8
	const char* indexRegName = cpu_get_indexreg16_name(instruction);

	cpu_finalize_instruction_decode(instruction, 11);
	cpu_set_instruction_disassembled_name_formatted_indexreg16_plus_imm8(instruction, nonNegativeSource, negativeSource, indexRegName);

	if (!cpu_must_execute()) return;
	//execution

	Uint8 value8 = memory_read8(absoluteAddress);
	*reg8 = value8;
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__ld_indexreg16Ptr_reg8(struct instruction* instruction, Uint8 reg8, const char* nonNegativeSource, const char* negativeSource) {
	Uint16 absoluteAddress = cpu_get_absolute_address_indexreg16_plus_imm8(instruction);	// reads imm8
	const char* indexRegName = cpu_get_indexreg16_name(instruction);

	cpu_finalize_instruction_decode(instruction, 11);
	cpu_set_instruction_disassembled_name_formatted_indexreg16_plus_imm8(instruction, nonNegativeSource, negativeSource, indexRegName);

	if (!cpu_must_execute()) return;
	//execution

	memory_write8(absoluteAddress, reg8);
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__ld_indexreg8h_reg8(struct instruction* instruction, Uint8 reg8, const char* disassembledName) {
	Uint8* indexReg = cpu_get_indexreg8h_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg8h_name(instruction);

	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, disassembledName, UNUSED, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	*indexReg = reg8;
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__ld_indexreg8l_reg8(struct instruction* instruction, Uint8 reg8, const char* disassembledName) {
	Uint8* indexReg = cpu_get_indexreg8l_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg8l_name(instruction);

	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, disassembledName, UNUSED, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	*indexReg = reg8;
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__ld_indexreg8h_indexreg8l(struct instruction* instruction) {
	Uint8* indexRegH = cpu_get_indexreg8h_ptr(instruction);
	Uint8* indexRegL = cpu_get_indexreg8l_ptr(instruction);
	const char* indexRegNameH = cpu_get_indexreg8h_name(instruction);
	const char* indexRegNameL = cpu_get_indexreg8l_name(instruction);

	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, "ld /s0, /s1", UNUSED, UNUSED, indexRegNameH, indexRegNameL);

	if (!cpu_must_execute()) return;
	//execution

	*indexRegH = *indexRegL;
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__ld_indexreg8l_indexreg8h(struct instruction* instruction) {
	Uint8* indexRegH = cpu_get_indexreg8h_ptr(instruction);
	Uint8* indexRegL = cpu_get_indexreg8l_ptr(instruction);
	const char* indexRegNameH = cpu_get_indexreg8h_name(instruction);
	const char* indexRegNameL = cpu_get_indexreg8l_name(instruction);

	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, "ld /s0, /s1", UNUSED, UNUSED, indexRegNameL, indexRegNameH);

	if (!cpu_must_execute()) return;
	//execution

	*indexRegL = *indexRegH;
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__add_A_indexreg8h(struct instruction* instruction) {
	Uint8* indexReg = cpu_get_indexreg8h_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg8h_name(instruction);

	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, "add A, /s0", UNUSED, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	cpu_addc_binary8(&(cpu_regs()->A), *indexReg, 0);
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__add_A_indexreg8l(struct instruction* instruction) {
	Uint8* indexReg = cpu_get_indexreg8l_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg8l_name(instruction);

	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, "add A, /s0", UNUSED, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	cpu_addc_binary8(&(cpu_regs()->A), *indexReg, 0);
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__add_A_indexreg16Ptr(struct instruction* instruction) {
	Uint16 absoluteAddress = cpu_get_absolute_address_indexreg16_plus_imm8(instruction);	// reads imm8
	const char* indexRegName = cpu_get_indexreg16_name(instruction);

	cpu_finalize_instruction_decode(instruction, 11);
	cpu_set_instruction_disassembled_name_formatted_indexreg16_plus_imm8(instruction, "add A, (/s0+/n0)", "add A, (/s0-/n0)", indexRegName);

	if (!cpu_must_execute()) return;
	//execution

	Uint8 temp8 = memory_read8(absoluteAddress);
	cpu_addc_binary8(&(cpu_regs()->A), temp8, 0);
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__adc_A_indexreg8h(struct instruction* instruction) {
	Uint8* indexReg = cpu_get_indexreg8h_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg8h_name(instruction);

	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, "adc A, /s0", UNUSED, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	Uint8 carry = cpu_regs()->F & CPU_FLAG_C_CARRY ? 1 : 0;
	cpu_addc_binary8(&(cpu_regs()->A), *indexReg, carry);
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__adc_A_indexreg8l(struct instruction* instruction) {
	Uint8* indexReg = cpu_get_indexreg8l_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg8l_name(instruction);

	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, "adc A, /s0", UNUSED, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	Uint8 carry = cpu_regs()->F & CPU_FLAG_C_CARRY ? 1 : 0;
	cpu_addc_binary8(&(cpu_regs()->A), *indexReg, carry);
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__adc_A_indexreg16Ptr(struct instruction* instruction) {
	Uint16 absoluteAddress = cpu_get_absolute_address_indexreg16_plus_imm8(instruction);	// reads imm8
	const char* indexRegName = cpu_get_indexreg16_name(instruction);

	cpu_finalize_instruction_decode(instruction, 11);
	cpu_set_instruction_disassembled_name_formatted_indexreg16_plus_imm8(instruction, "adc A, (/s0+/n0)", "adc A, (/s0-/n0)", indexRegName);

	if (!cpu_must_execute()) return;
	//execution
	
	Uint8 carry = cpu_regs()->F & CPU_FLAG_C_CARRY ? 1 : 0;
	Uint8 value8 = memory_read8(absoluteAddress);
	cpu_addc_binary8(&(cpu_regs()->A), value8, carry);
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__sub_indexreg8h_with_disassembled_string(struct instruction* instruction, const char* source) {
	Uint8* indexReg = cpu_get_indexreg8h_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg8h_name(instruction);

	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, source, UNUSED, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	cpu_subc_binary8(&(cpu_regs()->A), *indexReg, 0);
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__sub_indexreg8h(struct instruction* instruction) {
	cpu_instruction__sub_indexreg8h_with_disassembled_string(instruction, "sub /s0");
}

void cpu_instruction__sub_indexreg8l_with_disassembled_string(struct instruction* instruction, const char* source) {
	Uint8* indexReg = cpu_get_indexreg8l_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg8l_name(instruction);

	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, source, UNUSED, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	cpu_subc_binary8(&(cpu_regs()->A), *indexReg, 0);
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__sub_indexreg8l(struct instruction* instruction) {
	cpu_instruction__sub_indexreg8l_with_disassembled_string(instruction, "sub /s0");
}

void cpu_instruction__sub_indexreg16Ptr_with_disassembled_string(struct instruction* instruction, const char* sourceNonNegative, const char* sourceNegative) {
	Uint16 absoluteAddress = cpu_get_absolute_address_indexreg16_plus_imm8(instruction);	// reads imm8
	const char* indexRegName = cpu_get_indexreg16_name(instruction);

	cpu_finalize_instruction_decode(instruction, 11);
	cpu_set_instruction_disassembled_name_formatted_indexreg16_plus_imm8(instruction, sourceNonNegative, sourceNegative, indexRegName);

	if (!cpu_must_execute()) return;
	//execution

	Uint8 temp8 = memory_read8(absoluteAddress);
	cpu_subc_binary8(&(cpu_regs()->A), temp8, 0);
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__sub_indexreg16Ptr(struct instruction* instruction) {
	cpu_instruction__sub_indexreg16Ptr_with_disassembled_string(instruction, "sub (/s0+/n0)", "sub (/s0-/n0)");
}

void cpu_instruction__sbc_A_indexreg8h(struct instruction* instruction) {
	Uint8* indexReg = cpu_get_indexreg8h_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg8h_name(instruction);

	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, "sbc A, /s0", UNUSED, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	Uint8 carry = cpu_regs()->F & CPU_FLAG_C_CARRY ? 1 : 0;
	cpu_subc_binary8(&(cpu_regs()->A), *indexReg, carry);
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__sbc_A_indexreg8l(struct instruction* instruction) {
	Uint8* indexReg = cpu_get_indexreg8l_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg8l_name(instruction);

	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, "sbc A, /s0", UNUSED, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	Uint8 carry = cpu_regs()->F & CPU_FLAG_C_CARRY ? 1 : 0;
	cpu_subc_binary8(&(cpu_regs()->A), *indexReg, carry);
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__sbc_A_indexreg16Ptr(struct instruction* instruction) {
	Uint16 absoluteAddress = cpu_get_absolute_address_indexreg16_plus_imm8(instruction);	// reads imm8
	const char* indexRegName = cpu_get_indexreg16_name(instruction);

	cpu_finalize_instruction_decode(instruction, 11);
	cpu_set_instruction_disassembled_name_formatted_indexreg16_plus_imm8(instruction, "sbc A, (/s0+/n0)", "sbc A, (/s0-/n0)", indexRegName);

	if (!cpu_must_execute()) return;
	//execution

	Uint8 temp8 = memory_read8(absoluteAddress);
	Uint8 carry = cpu_regs()->F & CPU_FLAG_C_CARRY ? 1 : 0;
	cpu_subc_binary8(&(cpu_regs()->A), temp8, carry);
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__and_indexreg8h(struct instruction* instruction) {
	Uint8* indexReg = cpu_get_indexreg8h_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg8h_name(instruction);

	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, "and /s0", UNUSED, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	cpu_regs()->A &= *indexReg;
	if (cpu_regs()->A & (1 << 7)) cpu_regs()->F |= CPU_FLAG_S_SIGN; else cpu_regs()->F &= ~CPU_FLAG_S_SIGN;
	if (!cpu_regs()->A) cpu_regs()->F |= CPU_FLAG_Z_ZERO; else cpu_regs()->F &= ~CPU_FLAG_Z_ZERO;
	if (cpu_parity(cpu_regs()->A)) cpu_regs()->F |= CPU_FLAG_PV_PARITY_OVERFLOW; else cpu_regs()->F &= ~CPU_FLAG_PV_PARITY_OVERFLOW;

	cpu_regs()->F |= CPU_FLAG_H_HALF_CARRY;
	cpu_regs()->F &= ~CPU_FLAG_N_SUBTRACT;
	cpu_regs()->F &= ~CPU_FLAG_C_CARRY;

	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__and_indexreg8l(struct instruction* instruction) {
	Uint8* indexReg = cpu_get_indexreg8l_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg8l_name(instruction);

	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, "and /s0", UNUSED, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	cpu_regs()->A &= *indexReg;
	if (cpu_regs()->A & (1 << 7)) cpu_regs()->F |= CPU_FLAG_S_SIGN; else cpu_regs()->F &= ~CPU_FLAG_S_SIGN;
	if (!cpu_regs()->A) cpu_regs()->F |= CPU_FLAG_Z_ZERO; else cpu_regs()->F &= ~CPU_FLAG_Z_ZERO;
	if (cpu_parity(cpu_regs()->A)) cpu_regs()->F |= CPU_FLAG_PV_PARITY_OVERFLOW; else cpu_regs()->F &= ~CPU_FLAG_PV_PARITY_OVERFLOW;

	cpu_regs()->F |= CPU_FLAG_H_HALF_CARRY;
	cpu_regs()->F &= ~CPU_FLAG_N_SUBTRACT;
	cpu_regs()->F &= ~CPU_FLAG_C_CARRY;

	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__and_indexreg16Ptr(struct instruction* instruction) {
	Uint16 absoluteAddress = cpu_get_absolute_address_indexreg16_plus_imm8(instruction);	// reads imm8
	const char* indexRegName = cpu_get_indexreg16_name(instruction);

	cpu_finalize_instruction_decode(instruction, 11);
	cpu_set_instruction_disassembled_name_formatted_indexreg16_plus_imm8(instruction, "and (/s0+/n0)", "and (/s0-/n0)", indexRegName);

	if (!cpu_must_execute()) return;
	//execution

	Uint8 temp8 = memory_read8(absoluteAddress);
	cpu_regs()->A &= temp8;
	if (cpu_regs()->A & (1 << 7)) cpu_regs()->F |= CPU_FLAG_S_SIGN; else cpu_regs()->F &= ~CPU_FLAG_S_SIGN;
	if (!cpu_regs()->A) cpu_regs()->F |= CPU_FLAG_Z_ZERO; else cpu_regs()->F &= ~CPU_FLAG_Z_ZERO;
	if (cpu_parity(cpu_regs()->A)) cpu_regs()->F |= CPU_FLAG_PV_PARITY_OVERFLOW; else cpu_regs()->F &= ~CPU_FLAG_PV_PARITY_OVERFLOW;

	cpu_regs()->F |= CPU_FLAG_H_HALF_CARRY;
	cpu_regs()->F &= ~CPU_FLAG_N_SUBTRACT;
	cpu_regs()->F &= ~CPU_FLAG_C_CARRY;

	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__xor_indexreg8h(struct instruction* instruction) {
	Uint8* indexReg = cpu_get_indexreg8h_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg8h_name(instruction);

	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, "xor /s0", UNUSED, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	cpu_regs()->A ^= *indexReg;
	if (cpu_regs()->A & (1 << 7)) cpu_regs()->F |= CPU_FLAG_S_SIGN; else cpu_regs()->F &= ~CPU_FLAG_S_SIGN;
	if (!cpu_regs()->A) cpu_regs()->F |= CPU_FLAG_Z_ZERO; else cpu_regs()->F &= ~CPU_FLAG_Z_ZERO;
	if (cpu_parity(cpu_regs()->A)) cpu_regs()->F |= CPU_FLAG_PV_PARITY_OVERFLOW; else cpu_regs()->F &= ~CPU_FLAG_PV_PARITY_OVERFLOW;

	cpu_regs()->F &= ~CPU_FLAG_H_HALF_CARRY;
	cpu_regs()->F &= ~CPU_FLAG_N_SUBTRACT;
	cpu_regs()->F &= ~CPU_FLAG_C_CARRY;

	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__xor_indexreg8l(struct instruction* instruction) {
	Uint8* indexReg = cpu_get_indexreg8l_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg8l_name(instruction);

	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, "xor /s0", UNUSED, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	cpu_regs()->A ^= *indexReg;
	if (cpu_regs()->A & (1 << 7)) cpu_regs()->F |= CPU_FLAG_S_SIGN; else cpu_regs()->F &= ~CPU_FLAG_S_SIGN;
	if (!cpu_regs()->A) cpu_regs()->F |= CPU_FLAG_Z_ZERO; else cpu_regs()->F &= ~CPU_FLAG_Z_ZERO;
	if (cpu_parity(cpu_regs()->A)) cpu_regs()->F |= CPU_FLAG_PV_PARITY_OVERFLOW; else cpu_regs()->F &= ~CPU_FLAG_PV_PARITY_OVERFLOW;

	cpu_regs()->F &= ~CPU_FLAG_H_HALF_CARRY;
	cpu_regs()->F &= ~CPU_FLAG_N_SUBTRACT;
	cpu_regs()->F &= ~CPU_FLAG_C_CARRY;

	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__xor_indexreg16Ptr(struct instruction* instruction) {
	Uint16 absoluteAddress = cpu_get_absolute_address_indexreg16_plus_imm8(instruction);	// reads imm8
	const char* indexRegName = cpu_get_indexreg16_name(instruction);

	cpu_finalize_instruction_decode(instruction, 11);
	cpu_set_instruction_disassembled_name_formatted_indexreg16_plus_imm8(instruction, "xor (/s0+/n0)", "xor (/s0-/n0)", indexRegName);

	if (!cpu_must_execute()) return;
	//execution

	Uint8 temp8 = memory_read8(absoluteAddress);
	cpu_regs()->A ^= temp8;
	if (cpu_regs()->A & (1 << 7)) cpu_regs()->F |= CPU_FLAG_S_SIGN; else cpu_regs()->F &= ~CPU_FLAG_S_SIGN;
	if (!cpu_regs()->A) cpu_regs()->F |= CPU_FLAG_Z_ZERO; else cpu_regs()->F &= ~CPU_FLAG_Z_ZERO;
	if (cpu_parity(cpu_regs()->A)) cpu_regs()->F |= CPU_FLAG_PV_PARITY_OVERFLOW; else cpu_regs()->F &= ~CPU_FLAG_PV_PARITY_OVERFLOW;

	cpu_regs()->F &= ~CPU_FLAG_H_HALF_CARRY;
	cpu_regs()->F &= ~CPU_FLAG_N_SUBTRACT;
	cpu_regs()->F &= ~CPU_FLAG_C_CARRY;

	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__or_indexreg8h(struct instruction* instruction) {
	Uint8* indexReg = cpu_get_indexreg8h_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg8h_name(instruction);

	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, "or /s0", UNUSED, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	cpu_regs()->A |= *indexReg;
	if (cpu_regs()->A & (1 << 7)) cpu_regs()->F |= CPU_FLAG_S_SIGN; else cpu_regs()->F &= ~CPU_FLAG_S_SIGN;
	if (!cpu_regs()->A) cpu_regs()->F |= CPU_FLAG_Z_ZERO; else cpu_regs()->F &= ~CPU_FLAG_Z_ZERO;
	if (cpu_parity(cpu_regs()->A)) cpu_regs()->F |= CPU_FLAG_PV_PARITY_OVERFLOW; else cpu_regs()->F &= ~CPU_FLAG_PV_PARITY_OVERFLOW;

	cpu_regs()->F &= ~CPU_FLAG_H_HALF_CARRY;
	cpu_regs()->F &= ~CPU_FLAG_N_SUBTRACT;
	cpu_regs()->F &= ~CPU_FLAG_C_CARRY;

	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__or_indexreg8l(struct instruction* instruction) {
	Uint8* indexReg = cpu_get_indexreg8l_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg8l_name(instruction);

	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, "or /s0", UNUSED, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	cpu_regs()->A |= *indexReg;
	if (cpu_regs()->A & (1 << 7)) cpu_regs()->F |= CPU_FLAG_S_SIGN; else cpu_regs()->F &= ~CPU_FLAG_S_SIGN;
	if (!cpu_regs()->A) cpu_regs()->F |= CPU_FLAG_Z_ZERO; else cpu_regs()->F &= ~CPU_FLAG_Z_ZERO;
	if (cpu_parity(cpu_regs()->A)) cpu_regs()->F |= CPU_FLAG_PV_PARITY_OVERFLOW; else cpu_regs()->F &= ~CPU_FLAG_PV_PARITY_OVERFLOW;

	cpu_regs()->F &= ~CPU_FLAG_H_HALF_CARRY;
	cpu_regs()->F &= ~CPU_FLAG_N_SUBTRACT;
	cpu_regs()->F &= ~CPU_FLAG_C_CARRY;

	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__or_indexreg16Ptr(struct instruction* instruction) {
	Uint16 absoluteAddress = cpu_get_absolute_address_indexreg16_plus_imm8(instruction);	// reads imm8
	const char* indexRegName = cpu_get_indexreg16_name(instruction);

	cpu_finalize_instruction_decode(instruction, 11);
	cpu_set_instruction_disassembled_name_formatted_indexreg16_plus_imm8(instruction, "or (/s0+/n0)", "or (/s0-/n0)", indexRegName);

	if (!cpu_must_execute()) return;
	//execution

	Uint8 temp8 = memory_read8(absoluteAddress);
	cpu_regs()->A |= temp8;
	if (cpu_regs()->A & (1 << 7)) cpu_regs()->F |= CPU_FLAG_S_SIGN; else cpu_regs()->F &= ~CPU_FLAG_S_SIGN;
	if (!cpu_regs()->A) cpu_regs()->F |= CPU_FLAG_Z_ZERO; else cpu_regs()->F &= ~CPU_FLAG_Z_ZERO;
	if (cpu_parity(cpu_regs()->A)) cpu_regs()->F |= CPU_FLAG_PV_PARITY_OVERFLOW; else cpu_regs()->F &= ~CPU_FLAG_PV_PARITY_OVERFLOW;

	cpu_regs()->F &= ~CPU_FLAG_H_HALF_CARRY;
	cpu_regs()->F &= ~CPU_FLAG_N_SUBTRACT;
	cpu_regs()->F &= ~CPU_FLAG_C_CARRY;

	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__cp_indexreg8h(struct instruction* instruction) {
	Uint8 oldAcc = cpu_regs()->A;	// save A
	cpu_instruction__sub_indexreg8h_with_disassembled_string(instruction, "cp /s0");
	cpu_regs()->A = oldAcc;			// restore A
}

void cpu_instruction__cp_indexreg8l(struct instruction* instruction) {
	Uint8 oldAcc = cpu_regs()->A;	// save A
	cpu_instruction__sub_indexreg8l_with_disassembled_string(instruction, "cp /s0");
	cpu_regs()->A = oldAcc;			// restore A
}

void cpu_instruction__cp_indexreg16Ptr(struct instruction* instruction) {
	Uint8 oldAcc = cpu_regs()->A;	// save A
	cpu_instruction__sub_indexreg16Ptr_with_disassembled_string(instruction, "cp (/s0+/n0)", "cp (/s0-/n0)");
	cpu_regs()->A = oldAcc;			// restore A
}

void cpu_instruction__pop_indexreg16(struct instruction* instruction) {
	Uint16* indexReg = cpu_get_indexreg16_ptr(instruction);

	if (instruction->prefix.type == DD) {
		cpu_instruction__pop_reg16(instruction, indexReg, "pop IX");
	}
	else {
		cpu_instruction__pop_reg16(instruction, indexReg, "pop IY");
	}
}

void cpu_instruction__ex_spPtr_indexreg16(struct instruction* instruction) {
	Uint16* indexReg = cpu_get_indexreg16_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg16_name(instruction);

	cpu_finalize_instruction_decode(instruction, 15);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, "ex (SP), /s0", UNUSED, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	Uint16 temp16 = memory_read16(cpu_regs()->SP);
	memory_write16(cpu_regs()->SP, *indexReg);
	*indexReg = temp16;
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__push_indexreg16(struct instruction* instruction) {
	Uint16* indexReg = cpu_get_indexreg16_ptr(instruction);

	if (instruction->prefix.type == DD) {
		cpu_instruction__push_reg16(instruction, *indexReg, "push IX");
	}
	else {
		cpu_instruction__push_reg16(instruction, *indexReg, "push IY");
	}
}

void cpu_instruction__jp_indexreg16Ptr(struct instruction* instruction) {
	Uint16* indexReg = cpu_get_indexreg16_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg16_name(instruction);

	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, "jp (/s0)", UNUSED, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	cpu_regs()->PC = *indexReg;
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__ld_sp_indexreg16(struct instruction* instruction) {
	Uint16* indexReg = cpu_get_indexreg16_ptr(instruction);
	const char* indexRegName = cpu_get_indexreg16_name(instruction);

	cpu_finalize_instruction_decode(instruction, 2);
	cpu_set_instruction_disassembled_name_formatted_str(instruction, "ld SP, /s0", UNUSED, UNUSED, indexRegName, UNUSEDSTR);

	if (!cpu_must_execute()) return;
	//execution

	cpu_regs()->SP = *indexReg;
	cpu_mark_instruction_executed(instruction);
}




void cpu_run_DD_and_FD_prefix(struct instruction* instruction) {
	const char* indexRegName;

	switch (instruction->opcodeValue) {
	// 0x00 no instruction
	// 0x01 no instruction
	// 0x02 no instruction
	// 0x03 no instruction
	// 0x04 no instruction
	// 0x05 no instruction
	// 0x06 no instruction
	// 0x07 no instruction
	// 0x08 no instruction
	case 0x00:
	case 0x01:
	case 0x02:
	case 0x03:
	case 0x04:
	case 0x05:
	case 0x06:
	case 0x07:
	case 0x08:
		FALL_THROUGH_TO_UNPREFIXED(instruction);
		break;

	case 0x09:	// add indexreg16, bc
		cpu_instruction__add_indexreg16_reg16(instruction, *cpu_regs()->BC, "add /s0, BC");
		break;
	// 0x0A no instruction
	// 0x0B no instruction
	// 0x0C no instruction
	// 0x0D no instruction
	// 0x0E no instruction
	// 0x0F no instruction
	case 0x0A:
	case 0x0B:
	case 0x0C:
	case 0x0D:
	case 0x0E:
	case 0x0F:
		FALL_THROUGH_TO_UNPREFIXED(instruction);
		break;
	 
	// 0x10 no instruction
	// 0x11 no instruction
	// 0x12 no instruction
	// 0x13 no instruction
	// 0x14 no instruction
	// 0x15 no instruction
	// 0x16 no instruction
	// 0x17 no instruction
	// 0x18 no instruction
	case 0x10:
	case 0x11:
	case 0x12:
	case 0x13:
	case 0x14:
	case 0x15:
	case 0x16:
	case 0x17:
	case 0x18:
		FALL_THROUGH_TO_UNPREFIXED(instruction);
		break;

	case 0x19:	// add indexreg16, de
		cpu_instruction__add_indexreg16_reg16(instruction, *cpu_regs()->DE, "add /s0, DE");
		break;
	// 0x1A no instruction
	// 0x1B no instruction
	// 0x1C no instruction
	// 0x1D no instruction
	// 0x1E no instruction
	// 0x1F no instruction
	// 0x20 no instruction
	case 0x1A:
	case 0x1B:
	case 0x1C:
	case 0x1D:
	case 0x1E:
	case 0x1F:
	case 0x20:
		FALL_THROUGH_TO_UNPREFIXED(instruction);
		break;

	case 0x21:	// ld indexreg16, imm16
		cpu_instruction__ld_indexreg16_imm16(instruction, "ld /s0, /n0");
		break;
	case 0x22:	// ld (mem16), indexreg16
		cpu_instruction__ld_mem16_indexreg16(instruction);
		break;
	case 0x23:	// inc indexreg16
		cpu_instruction__inc_indexreg16(instruction);
		break;
	case 0x24:	// inc indexreg8h
		cpu_instruction__inc_indexreg8h(instruction);
		break;
	case 0x25:	// dec indexreg8h
		cpu_instruction__dec_indexreg8h(instruction);
		break;
	case 0x26:	// ld indexreg8h, imm8
		cpu_instruction__ld_indexreg8h_imm8(instruction);
		break;
	// 0x27 no instruction
	// 0x28 no instruction
	case 0x27:
	case 0x28:
		FALL_THROUGH_TO_UNPREFIXED(instruction);
		break;

	case 0x29:	// add indexreg16, indexreg16(self)
		if (instruction->prefix.type == DD) {
			cpu_instruction__add_indexreg16_reg16(instruction, *cpu_regs()->IX, "add /s0, IX");
		}
		else {
			cpu_instruction__add_indexreg16_reg16(instruction, *cpu_regs()->IY, "add /s0, IY");
		}
		break;
	case 0x2A:	// ld indexreg16, (mem16)
		cpu_instruction__ld_indexreg16_mem16(instruction);
		break;
	case 0x2B:	// dec indexreg16
		cpu_instruction__dec_indexreg16(instruction);
		break;
	case 0x2C:	// inc indexreg8l
		cpu_instruction__inc_indexreg8l(instruction);
		break;
	case 0x2D:	// dec indexreg8l
		cpu_instruction__dec_indexreg8l(instruction);
		break;
	case 0x2E:	// ld indexreg8l, imm8
		cpu_instruction__ld_indexreg8l_imm8(instruction);
		break;
	// 0x2F no instruction
	// 0x30 no instruction
	// 0x31 no instruction
	// 0x32 no instruction
	// 0x33 no instruction
	case 0x2F:
	case 0x30:
	case 0x31:
	case 0x32:
	case 0x33:
		FALL_THROUGH_TO_UNPREFIXED(instruction);
		break;

	case 0x34:	// inc (indexreg16 + imm8)
		cpu_instruction__inc_indexreg16Ptr(instruction);
		break;
	case 0x35:	// dec (indexreg16 + imm8)
		cpu_instruction__dec_indexreg16Ptr(instruction);
		break;
	case 0x36:	// ld (indexreg16 + imm8), imm8
		cpu_instruction__ld_indexreg16Ptr_imm8(instruction);
		break;
	// 0x37 no instruction
	// 0x38 no instruction
	case 0x37:
	case 0x38:
		FALL_THROUGH_TO_UNPREFIXED(instruction);
		break;

	case 0x39:	// add indexreg16, sp
		cpu_instruction__add_indexreg16_reg16(instruction, cpu_regs()->SP, "add /s0, SP");
		break;
	// 0x3A no instruction
	// 0x3B no instruction
	// 0x3C no instruction
	// 0x3D no instruction
	// 0x3E no instruction
	// 0x3F no instruction
	// 0x40 no instruction
	// 0x41 no instruction
	// 0x42 no instruction
	// 0x43 no instruction
	case 0x3A:
	case 0x3B:
	case 0x3C:
	case 0x3D:
	case 0x3E:
	case 0x3F:
	case 0x40:
	case 0x41:
	case 0x42:
	case 0x43:
		FALL_THROUGH_TO_UNPREFIXED(instruction);
		break;

	case 0x44:	// ld b, indexreg8h
		cpu_instruction__ld_reg8_indexreg8h(instruction, &(cpu_regs()->B), "ld B, /s0");
		break;
	case 0x45:	// ld b, indexreg8l
		cpu_instruction__ld_reg8_indexreg8l(instruction, &(cpu_regs()->B), "ld B, /s0");
		break;
	case 0x46:	// ld b, (indexreg16+imm8)
		cpu_instruction__ld_reg8_indexreg16Ptr(instruction, &(cpu_regs()->B), "ld B, (/s0+/n0)", "ld B, (/s0-/n0)");
		break;
	// 0x47 no instruction
	// 0x48 no instruction
	// 0x49 no instruction
	// 0x4A no instruction
	// 0x4B no instruction
	case 0x47:
	case 0x48:
	case 0x49:
	case 0x4A:
	case 0x4B:
		FALL_THROUGH_TO_UNPREFIXED(instruction);
		break;

	case 0x4C:	// ld c, indexreg8h
		cpu_instruction__ld_reg8_indexreg8h(instruction, &(cpu_regs()->C), "ld C, /s0");
		break;
	case 0x4D:	// ld c, indexreg8l
		cpu_instruction__ld_reg8_indexreg8l(instruction, &(cpu_regs()->C), "ld C, /s0");
		break;
	case 0x4E:	// ld c, (indexreg16+imm8)
		cpu_instruction__ld_reg8_indexreg16Ptr(instruction, &(cpu_regs()->C), "ld C, (/s0+/n0)", "ld C, (/s0-/n0)");
		break;
	// 0x4F no instruction
	// 0x50 no instruction
	// 0x51 no instruction
	// 0x52 no instruction
	// 0x53 no instruction
	case 0x4F:
	case 0x50:
	case 0x51:
	case 0x52:
	case 0x53:
		FALL_THROUGH_TO_UNPREFIXED(instruction);
		break;

	case 0x54:	// ld d, indexreg8h
		cpu_instruction__ld_reg8_indexreg8h(instruction, &(cpu_regs()->D), "ld D, /s0");
		break;
	case 0x55:	// ld d, indexreg8l
		cpu_instruction__ld_reg8_indexreg8l(instruction, &(cpu_regs()->D), "ld D, /s0");
		break;
	case 0x56:	// ld d, (indexreg16+imm8)
		cpu_instruction__ld_reg8_indexreg16Ptr(instruction, &(cpu_regs()->D), "ld D, (/s0+/n0)", "ld D, (/s0-/n0)");
		break;
	// 0x57 no instruction
	// 0x58 no instruction
	// 0x59 no instruction
	// 0x5A no instruction
	// 0x5B no instruction
	case 0x57:
	case 0x58:
	case 0x59:
	case 0x5A:
	case 0x5B:
		FALL_THROUGH_TO_UNPREFIXED(instruction);
		break;

	case 0x5C:	// ld e, indexreg8h
		cpu_instruction__ld_reg8_indexreg8h(instruction, &(cpu_regs()->E), "ld E, /s0");
		break;
	case 0x5D:	// ld e, indexreg8l
		cpu_instruction__ld_reg8_indexreg8l(instruction, &(cpu_regs()->E), "ld E, /s0");
		break;
	case 0x5E:	// ld e, (indexreg16+imm8)
		cpu_instruction__ld_reg8_indexreg16Ptr(instruction, &(cpu_regs()->E), "ld E, (/s0+/n0)", "ld E, (/s0-/n0)");
		break;
	// 0x5F no instruction
	case 0x5F:
		FALL_THROUGH_TO_UNPREFIXED(instruction);
		break;

	case 0x60:	// ld indexreg8h, b
		cpu_instruction__ld_indexreg8h_reg8(instruction, cpu_regs()->B, "ld /s0, B");
		break;
	case 0x61:	// ld indexreg8h, c
		cpu_instruction__ld_indexreg8h_reg8(instruction, cpu_regs()->C, "ld /s0, C");
		break;
	case 0x62:	// ld indexreg8h, d
		cpu_instruction__ld_indexreg8h_reg8(instruction, cpu_regs()->D, "ld /s0, D");
		break;
	case 0x63:	// ld indexreg8h, e
		cpu_instruction__ld_indexreg8h_reg8(instruction, cpu_regs()->E, "ld /s0, E");
		break;
	case 0x64:	// ld indexreg8h, indexreg8h
		cpu_finalize_instruction_decode(instruction, 0);
		indexRegName = cpu_get_indexreg8h_name(instruction);
		cpu_set_instruction_disassembled_name_formatted_str(instruction, "ld /s0, /s1", UNUSED, UNUSED, indexRegName, indexRegName);

		if (!cpu_must_execute()) break;
		//execution

		cpu_mark_instruction_executed(instruction);
		break;
	case 0x65:	// ld indexreg8h, indexreg8l
		cpu_instruction__ld_indexreg8h_indexreg8l(instruction);
		break;
	case 0x66:	// ld h, (indexreg16+imm8)
		cpu_instruction__ld_reg8_indexreg16Ptr(instruction, &(cpu_regs()->H), "ld H, (/s0+/n0)", "ld H, (/s0-/n0)");
		break;
	case 0x67:	// ld indexreg8h, a
		cpu_instruction__ld_indexreg8h_reg8(instruction, cpu_regs()->A, "ld /s0, A");
		break;
	case 0x68:	// ld indexreg8l, b
		cpu_instruction__ld_indexreg8l_reg8(instruction, cpu_regs()->B, "ld /s0, B");
		break;
	case 0x69:	// ld indexreg8l, c
		cpu_instruction__ld_indexreg8l_reg8(instruction, cpu_regs()->C, "ld /s0, C");
		break;
	case 0x6A:	// ld indexreg8l, d
		cpu_instruction__ld_indexreg8l_reg8(instruction, cpu_regs()->D, "ld /s0, D");
		break;
	case 0x6B:	// ld indexreg8l, e
		cpu_instruction__ld_indexreg8l_reg8(instruction, cpu_regs()->E, "ld /s0, E");
		break;
	case 0x6C:	// ld indexreg8l, indexreg8h
		cpu_instruction__ld_indexreg8l_indexreg8h(instruction);
		break;
	case 0x6D:	// ld indexreg8l, indexreg8l
		cpu_finalize_instruction_decode(instruction, 0);
		indexRegName = cpu_get_indexreg8l_name(instruction);
		cpu_set_instruction_disassembled_name_formatted_str(instruction, "ld /s0, /s1", UNUSED, UNUSED, indexRegName, indexRegName);

		if (!cpu_must_execute()) break;
		//execution

		cpu_mark_instruction_executed(instruction);
		break;
	case 0x6E:	// ld l, (indexreg16+imm8)
		cpu_instruction__ld_reg8_indexreg16Ptr(instruction, &(cpu_regs()->L), "ld L, (/s0+/n0)", "ld L, (/s0-/n0)");
		break;
	case 0x6F:	// ld indexreg8l, a
		cpu_instruction__ld_indexreg8l_reg8(instruction, cpu_regs()->A, "ld /s0, A");
		break;
	case 0x70:	// ld (indexreg16+imm8), b
		cpu_instruction__ld_indexreg16Ptr_reg8(instruction, cpu_regs()->B, "ld (/s0+/n0), B", "ld (/s0-/n0), B");
		break;
	case 0x71:	// ld (indexreg16+imm8), c
		cpu_instruction__ld_indexreg16Ptr_reg8(instruction, cpu_regs()->C, "ld (/s0+/n0), C", "ld (/s0-/n0), C");
		break;
	case 0x72:	// ld (indexreg16+imm8), d
		cpu_instruction__ld_indexreg16Ptr_reg8(instruction, cpu_regs()->D, "ld (/s0+/n0), D", "ld (/s0-/n0), D");
		break;
	case 0x73:	// ld (indexreg16+imm8), e
		cpu_instruction__ld_indexreg16Ptr_reg8(instruction, cpu_regs()->E, "ld (/s0+/n0), E", "ld (/s0-/n0), E");
		break;
	case 0x74:	// ld (indexreg16+imm8), h
		cpu_instruction__ld_indexreg16Ptr_reg8(instruction, cpu_regs()->H, "ld (/s0+/n0), H", "ld (/s0-/n0), H");
		break;
	case 0x75:	// ld (indexreg16+imm8), l
		cpu_instruction__ld_indexreg16Ptr_reg8(instruction, cpu_regs()->L, "ld (/s0+/n0), L", "ld (/s0-/n0), L");
		break;
	// 0x76 no instruction
	case 0x76:
		FALL_THROUGH_TO_UNPREFIXED(instruction);
		break;

	case 0x77:	// ld (indexreg16+imm8), a
		cpu_instruction__ld_indexreg16Ptr_reg8(instruction, cpu_regs()->A, "ld (/s0+/n0), A", "ld (/s0-/n0), A");
		break;
	// 0x78 no instruction
	// 0x79 no instruction
	// 0x7A no instruction
	// 0x7B no instruction
	case 0x78:
	case 0x79:
	case 0x7A:
	case 0x7B:
		FALL_THROUGH_TO_UNPREFIXED(instruction);
		break;

	case 0x7C:	// ld a, indexreg8h
		cpu_instruction__ld_reg8_indexreg8h(instruction, &(cpu_regs()->A), "ld A, /s0");
		break;
	case 0x7D:	// ld a, indexreg8l
		cpu_instruction__ld_reg8_indexreg8l(instruction, &(cpu_regs()->A), "ld A, /s0");
		break;
	case 0x7E:	// ld a, (indexreg16+imm8)
		cpu_instruction__ld_reg8_indexreg16Ptr(instruction, &(cpu_regs()->A), "ld A, (/s0+/n0)", "ld A, (/s0-/n0)");
		break;
	// 0x7F no instruction
	// 0x80 no instruction
	// 0x81 no instruction
	// 0x82 no instruction
	// 0x83 no instruction
	case 0x7F:
	case 0x80:
	case 0x81:
	case 0x82:
	case 0x83:
		FALL_THROUGH_TO_UNPREFIXED(instruction);
		break;

	case 0x84:	// add a, indexreg8h
		cpu_instruction__add_A_indexreg8h(instruction);
		break;
	case 0x85:	// add a, indexreg8l
		cpu_instruction__add_A_indexreg8l(instruction);
		break;
	case 0x86:	// add a, (indexreg16+imm8)
		cpu_instruction__add_A_indexreg16Ptr(instruction);
		break;
	// 0x87 no instruction
	// 0x88 no instruction
	// 0x89 no instruction
	// 0x8A no instruction
	// 0x8B no instruction
	case 0x87:
	case 0x88:
	case 0x89:
	case 0x8A:
	case 0x8B:
		FALL_THROUGH_TO_UNPREFIXED(instruction);
		break;

	case 0x8C:	// adc a, indexreg8h
		cpu_instruction__adc_A_indexreg8h(instruction);
		break;
	case 0x8D:	// adc a, indexreg8l
		cpu_instruction__adc_A_indexreg8l(instruction);
		break;
	case 0x8E:	// adc a, (indexreg16+imm8)
		cpu_instruction__adc_A_indexreg16Ptr(instruction);
		break;
	// 0x8F no instruction
	// 0x90 no instruction
	// 0x91 no instruction
	// 0x92 no instruction
	// 0x93 no instruction
	case 0x8F:
	case 0x90:
	case 0x91:
	case 0x92:
	case 0x93:
		FALL_THROUGH_TO_UNPREFIXED(instruction);
		break;

	case 0x94:	// sub indexreg8h
		cpu_instruction__sub_indexreg8h(instruction);
		break;
	case 0x95:	// sub indexreg8l
		cpu_instruction__sub_indexreg8l(instruction);
		break;
	case 0x96:	// sub (indexreg16+imm8)
		cpu_instruction__sub_indexreg16Ptr(instruction);
		break;
	// 0x97 no instruction
	// 0x98 no instruction
	// 0x99 no instruction
	// 0x9A no instruction
	// 0x9B no instruction
	case 0x97:
	case 0x98:
	case 0x99:
	case 0x9A:
	case 0x9B:
		FALL_THROUGH_TO_UNPREFIXED(instruction);
		break;

	case 0x9C:	// sbc a, indexreg8h
		cpu_instruction__sbc_A_indexreg8h(instruction);
		break;
	case 0x9D:	// sbc a, indexreg8l
		cpu_instruction__sbc_A_indexreg8l(instruction);
		break;
	case 0x9E:	// sbc a, (indexreg16+imm8)
		cpu_instruction__sbc_A_indexreg16Ptr(instruction);
		break;
	// 0x9F no instruction
	// 0xA0 no instruction
	// 0xA1 no instruction
	// 0xA2 no instruction
	// 0xA3 no instruction
	case 0x9F:
	case 0xA0:
	case 0xA1:
	case 0xA2:
	case 0xA3:
		FALL_THROUGH_TO_UNPREFIXED(instruction);
		break;

	case 0xA4:	// and indexreg8h
		cpu_instruction__and_indexreg8h(instruction);
		break;
	case 0xA5:	// and indexreg8l
		cpu_instruction__and_indexreg8l(instruction);
		break;
	case 0xA6:	// and (indexreg16+imm8)
		cpu_instruction__and_indexreg16Ptr(instruction);
		break;
	// 0xA7 no instruction
	// 0xA8 no instruction
	// 0xA9 no instruction
	// 0xAA no instruction
	// 0xAB no instruction
	case 0xA7:
	case 0xA8:
	case 0xA9:
	case 0xAA:
	case 0xAB:
		FALL_THROUGH_TO_UNPREFIXED(instruction);
		break;

	case 0xAC:	// xor indexreg8h
		cpu_instruction__xor_indexreg8h(instruction);
		break;
	case 0xAD:	// xor indexreg8l
		cpu_instruction__xor_indexreg8l(instruction);
		break;
	case 0xAE:	// xor (indexreg16+imm8)
		cpu_instruction__xor_indexreg16Ptr(instruction);
		break;
	// 0xAF no instruction
	// 0xB0 no instruction
	// 0xB1 no instruction
	// 0xB2 no instruction
	// 0xB3 no instruction
	case 0xAF:
	case 0xB0:
	case 0xB1:
	case 0xB2:
	case 0xB3:
		FALL_THROUGH_TO_UNPREFIXED(instruction);
		break;

	case 0xB4:	// or indexreg8h
		cpu_instruction__or_indexreg8h(instruction);
		break;
	case 0xB5:	// or indexreg8l
		cpu_instruction__or_indexreg8l(instruction);
		break;
	case 0xB6:	// or (indexreg16+imm8)
		cpu_instruction__or_indexreg16Ptr(instruction);
		break;
	// 0xB7 no instruction
	// 0xB8 no instruction
	// 0xB9 no instruction
	// 0xBA no instruction
	// 0xBB no instruction
	case 0xB7:
	case 0xB8:
	case 0xB9:
	case 0xBA:
	case 0xBB:
		FALL_THROUGH_TO_UNPREFIXED(instruction);
		break;

	case 0xBC:	// cp indexreg8h
		cpu_instruction__cp_indexreg8h(instruction);
		break;
	case 0xBD:	// cp indexreg8l
		cpu_instruction__cp_indexreg8l(instruction);
		break;
	case 0xBE:	// cp (indexreg16+imm8)
		cpu_instruction__cp_indexreg16Ptr(instruction);
		break;
	// 0xBF no instruction
	// 0xC0 no instruction
	// 0xC1 no instruction
	// 0xC2 no instruction
	// 0xC3 no instruction
	// 0xC4 no instruction
	// 0xC5 no instruction
	// 0xC6 no instruction
	// 0xC7 no instruction
	// 0xC8 no instruction
	// 0xC9 no instruction
	// 0xCA no instruction
	case 0xBF:
	case 0xC0:
	case 0xC1:
	case 0xC2:
	case 0xC3:
	case 0xC4:
	case 0xC5:
	case 0xC6:
	case 0xC7:
	case 0xC8:
	case 0xC9:
	case 0xCA:
		FALL_THROUGH_TO_UNPREFIXED(instruction);
		break;

	case 0xCB:	// NOT ALLOWED
		// CB is a prefix, and not an instruction opcode
		cpu_finalize_instruction_decode(instruction, 0);
		cpu_mark_instruction_unknown(instruction);
		break;
	// 0xCC no instruction
	// 0xCD no instruction
	// 0xCE no instruction
	// 0xCF no instruction
	// 0xD0 no instruction
	// 0xD1 no instruction
	// 0xD2 no instruction
	// 0xD3 no instruction
	// 0xD4 no instruction
	// 0xD5 no instruction
	// 0xD6 no instruction
	// 0xD7 no instruction
	// 0xD8 no instruction
	// 0xD9 no instruction
	// 0xDA no instruction
	// 0xDB no instruction
	// 0xDC no instruction
	// 0xDD no instruction
	// 0xDE no instruction
	// 0xDF no instruction
	// 0xE0 no instruction
	case 0xCC:
	case 0xCD:
	case 0xCE:
	case 0xCF:
	case 0xD0:
	case 0xD1:
	case 0xD2:
	case 0xD3:
	case 0xD4:
	case 0xD5:
	case 0xD6:
	case 0xD7:
	case 0xD8:
	case 0xD9:
	case 0xDA:
	case 0xDB:
	case 0xDC:
	case 0xDD:
	case 0xDE:
	case 0xDF:
	case 0xE0:
		FALL_THROUGH_TO_UNPREFIXED(instruction);
		break;

	case 0xE1:	// pop indexreg16
		cpu_instruction__pop_indexreg16(instruction);
		break;
	// 0xE2 no instruction
	case 0xE2:
		FALL_THROUGH_TO_UNPREFIXED(instruction);
		break;

	case 0xE3:	// ex (sp), indexreg16
		cpu_instruction__ex_spPtr_indexreg16(instruction);
		break;
	// 0xE4 no instruction
	case 0xE4:
		FALL_THROUGH_TO_UNPREFIXED(instruction);
		break;

	case 0xE5:	// push indexreg16
		cpu_instruction__push_indexreg16(instruction);
		break;
	// 0xE6 no instruction
	// 0xE7 no instruction
	// 0xE8 no instruction
	case 0xE6:
	case 0xE7:
	case 0xE8:
		FALL_THROUGH_TO_UNPREFIXED(instruction);
		break;

	case 0xE9:	// jp (indexreg16)
		cpu_instruction__jp_indexreg16Ptr(instruction);
		break;
	// 0xEA no instruction
	// 0xEB no instruction
	// 0xEC no instruction
	// 0xED no instruction
	// 0xEE no instruction
	// 0xEF no instruction
	// 0xF0 no instruction
	// 0xF1 no instruction
	// 0xF2 no instruction
	// 0xF3 no instruction
	// 0xF4 no instruction
	// 0xF5 no instruction
	// 0xF6 no instruction
	// 0xF7 no instruction
	// 0xF8 no instruction
	case 0xEA:
	case 0xEB:
	case 0xEC:
	case 0xED:
	case 0xEE:
	case 0xEF:
	case 0xF0:
	case 0xF1:
	case 0xF2:
	case 0xF3:
	case 0xF4:
	case 0xF5:
	case 0xF6:
	case 0xF7:
	case 0xF8:
		FALL_THROUGH_TO_UNPREFIXED(instruction);
		break;

	case 0xF9:	// ld sp, indexreg16
		cpu_instruction__ld_sp_indexreg16(instruction);
		break;
	// 0xFA no instruction
	// 0xFB no instruction
	// 0xFC no instruction
	// 0xFD no instruction
	// 0xFE no instruction
	// 0xFF no instruction
	case 0xFA:
	case 0xFB:
	case 0xFC:
	case 0xFD:
	case 0xFE:
	case 0xFF:
		FALL_THROUGH_TO_UNPREFIXED(instruction);
		break;

	default:
		cpu_finalize_instruction_decode(instruction, 0);
		cpu_mark_instruction_unknown(instruction);
		break;
	}
}
