#include "Constants.h"
#include "Cpu.h"
#include "Memory.h"
#include "Io.h"
#include "CpuUtilities.h"


void daa() {
	int t = 0;
	Uint8 A = cpu_regs()->A;
	Uint8 N = cpu_regs()->F & CPU_FLAG_N_SUBTRACT;
	Uint8 H = cpu_regs()->F & CPU_FLAG_H_HALF_CARRY;
	Uint8 C = cpu_regs()->F & CPU_FLAG_C_CARRY;

	if (H || ((A & 0xF) > 9)) {
		t++;
	}

	if (C || (A > 0x99)) {
		t += 2;
		cpu_regs()->F |= CPU_FLAG_C_CARRY;
	}
	else {
		cpu_regs()->F &= ~CPU_FLAG_C_CARRY;
	}
	C = cpu_regs()->F & CPU_FLAG_C_CARRY;

	// builds final H flag
	if (N && !H) {
		cpu_regs()->F &= ~CPU_FLAG_H_HALF_CARRY;
	}
	else {
		if (N && H) {
			if (((A & 0x0F)) < 6) cpu_regs()->F |= CPU_FLAG_H_HALF_CARRY; else cpu_regs()->F &= ~CPU_FLAG_H_HALF_CARRY;
		}
		else {
			if ((A & 0x0F) >= 0x0A) cpu_regs()->F |= CPU_FLAG_H_HALF_CARRY; else cpu_regs()->F &= ~CPU_FLAG_H_HALF_CARRY;
		}
	}

	N = cpu_regs()->F & CPU_FLAG_N_SUBTRACT;

	switch (t) {
	case 1:
		A += N ? 0xFA : 0x06; // -6:6
		break;
	case 2:
		A += N ? 0xA0 : 0x60; // -0x60:0x60
		break;
	case 3:
		A += N ? 0x9A : 0x66; // -0x66:0x66
		break;
	}

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

	cpu_regs()->A = A;
}

void daa2()
{
	uint8_t a = cpu_regs()->A;
	if (cpu_regs()->F & CPU_FLAG_N_SUBTRACT) {
		if ((cpu_regs()->F & CPU_FLAG_H_HALF_CARRY) | ((cpu_regs()->A & 0xf) > 9)) a -= 6;
		if ((cpu_regs()->F & CPU_FLAG_C_CARRY) | (cpu_regs()->A > 0x99)) a -= 0x60;
	}
	else {
		if ((cpu_regs()->F & CPU_FLAG_H_HALF_CARRY) | ((cpu_regs()->A & 0xf) > 9)) a += 6;
		if ((cpu_regs()->F & CPU_FLAG_C_CARRY) | (cpu_regs()->A > 0x99)) a += 0x60;
	}

	cpu_regs()->F = (cpu_regs()->F & (CPU_FLAG_C_CARRY | CPU_FLAG_N_SUBTRACT)) | (cpu_regs()->A > 0x99) | ((cpu_regs()->A ^ a) & CPU_FLAG_H_HALF_CARRY);
	if (cpu_parity(a)) cpu_regs()->F |= CPU_FLAG_PV_PARITY_OVERFLOW; else cpu_regs()->F &= ~CPU_FLAG_PV_PARITY_OVERFLOW;

	cpu_regs()->A = a;
}





void cpu_instruction__inc_reg8(struct instruction* instruction, Uint8* reg, const char* disassembledName) {
	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted2(instruction, disassembledName, UNUSED, UNUSED);

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

	cpu_save_flags();
	cpu_addc_binary8(reg, 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_reg8(struct instruction* instruction, Uint8* reg, const char* disassembledName) {
	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted2(instruction, disassembledName, UNUSED, UNUSED);

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

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

void cpu_instruction__sub_reg8(struct instruction* instruction, Uint8 value8, const char* disassembledName) {
	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted2(instruction, disassembledName, value8, UNUSED);

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

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

void cpu_instruction__sbc_A_reg8(struct instruction* instruction, Uint8 value8, const char* disassembledName) {
	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted2(instruction, disassembledName, UNUSED, UNUSED);

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

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

void cpu_instruction__add_A_reg8(struct instruction* instruction, Uint8 value8, const char* disassembledName) {
	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted2(instruction, disassembledName, UNUSED, UNUSED);

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

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

void cpu_instruction__adc_A_reg8(struct instruction* instruction, Uint8 value8, const char* disassembledName) {
	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted2(instruction, disassembledName, UNUSED, UNUSED);

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

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

void cpu_instruction__adc_A_HLptr(struct instruction* instruction, const char* disassembledName) {
	cpu_finalize_instruction_decode(instruction, 3);
	cpu_set_instruction_disassembled_name_formatted2(instruction, disassembledName, UNUSED, UNUSED);

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

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

void cpu_instruction__adc_A_imm8(struct instruction* instruction) {
	cpu_read_imm8(instruction);
	cpu_finalize_instruction_decode(instruction, 3);
	cpu_set_instruction_disassembled_name_formatted2(instruction, "adc A, /n0", instruction->immediate.value.eightBit, UNUSED);

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

	Uint8 carry = cpu_regs()->F & CPU_FLAG_C_CARRY ? 1 : 0;
	cpu_addc_binary8(&(cpu_regs()->A), instruction->immediate.value.eightBit, carry);
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__ld_reg8_imm8(struct instruction* instruction, Uint8* reg, const char* disassembledName) {
	cpu_read_imm8(instruction);
	cpu_finalize_instruction_decode(instruction, 3);
	cpu_set_instruction_disassembled_name_formatted2(instruction, disassembledName, instruction->immediate.value.eightBit, UNUSED);

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

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

void cpu_instruction__ld_reg16_imm16(struct instruction* instruction, Uint16* reg, const char* disassembledName) {
	cpu_read_imm16(instruction);
	cpu_finalize_instruction_decode(instruction, 6);
	cpu_set_instruction_disassembled_name_formatted2(instruction, disassembledName, instruction->immediate.value.sixteenBit, UNUSED);

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

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

void cpu_instruction__ld_ptr16_reg8(struct instruction* instruction, Uint16 address16, Uint8 val8, const char* disassembledName) {
	cpu_finalize_instruction_decode(instruction, 3);
	cpu_set_instruction_disassembled_name_formatted2(instruction, disassembledName, UNUSED, UNUSED);

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

	memory_write8(address16, val8);
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__inc_reg16(struct instruction* instruction, Uint16* reg, const char* disassembledName) {
	cpu_finalize_instruction_decode(instruction, 2);
	cpu_set_instruction_disassembled_name_formatted2(instruction, disassembledName, UNUSED, UNUSED);

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

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

void cpu_instruction__ld_reg8_ptr16(struct instruction* instruction, Uint8* reg, Uint16 address16, const char* disassembledName) {
	cpu_finalize_instruction_decode(instruction, 3);
	cpu_set_instruction_disassembled_name_formatted2(instruction, disassembledName, UNUSED, UNUSED);

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

	*reg = memory_read8(address16);
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__dec_reg16(struct instruction* instruction, Uint16* reg, const char* disassembledName) {
	cpu_finalize_instruction_decode(instruction, 2);
	cpu_set_instruction_disassembled_name_formatted2(instruction, disassembledName, UNUSED, UNUSED);

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

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

void cpu_instruction__jr_cc(struct instruction* instruction, Uint8 condition, const char* disassembledName) {
	cpu_read_imm8(instruction);
	if (condition) {
		cpu_finalize_instruction_decode(instruction, 8);
	}
	else {
		cpu_finalize_instruction_decode(instruction, 3);
	}

	Uint16 branchTarget = cpu_regs()->PC + (Sint8)instruction->immediate.value.eightBit;
	cpu_set_instruction_disassembled_name_formatted2(instruction, disassembledName, branchTarget, UNUSED);

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

	if (condition) {
		cpu_regs()->PC = branchTarget;
	}
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__ret_cc(struct instruction* instruction, Uint8 condition, const char* disassembledName) {
	if (condition) {
		cpu_finalize_instruction_decode(instruction, 7);
	}
	else {
		cpu_finalize_instruction_decode(instruction, 1);
	}

	cpu_set_instruction_disassembled_name_formatted2(instruction, disassembledName, UNUSED, UNUSED);

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

	if (condition) {
		Uint16 branchTarget = cpu_pop16();
		cpu_regs()->PC = branchTarget;
	}
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__jp_cc(struct instruction* instruction, Uint8 condition, const char* disassembledName) {
	cpu_read_imm16(instruction);
	cpu_finalize_instruction_decode(instruction, 6);

	Uint16 branchTarget = instruction->immediate.value.sixteenBit;
	cpu_set_instruction_disassembled_name_formatted2(instruction, disassembledName, branchTarget, UNUSED);

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

	if (condition) {
		cpu_regs()->PC = branchTarget;
	}
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__call_cc(struct instruction* instruction, Uint8 condition, const char* disassembledName) {
	cpu_read_imm16(instruction);

	if (condition) {
		cpu_finalize_instruction_decode(instruction, 13);
	}
	else {
		cpu_finalize_instruction_decode(instruction, 6);
	}

	Uint16 branchTarget = instruction->immediate.value.sixteenBit;
	cpu_set_instruction_disassembled_name_formatted2(instruction, disassembledName, branchTarget, UNUSED);

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

	if (condition) {
		cpu_push_PC();
		cpu_regs()->PC = branchTarget;
	}
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__ld_reg8_reg8(struct instruction* instruction, Uint8* reg, Uint8 reg2, const char* disassembledName) {
	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted2(instruction, disassembledName, UNUSED, UNUSED);

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

	*reg = reg2;
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__ld_reg8_HLptr(struct instruction* instruction, Uint8* reg, const char* disassembledName) {
	instruction->tstatesElapsed += 3;
	Uint8 value = memory_read8(*cpu_regs()->HL);
	cpu_instruction__ld_reg8_reg8(instruction, reg, value, disassembledName);
}

void cpu_instruction__ld_HLptr_reg8(struct instruction* instruction, Uint8 regVal8, const char* disassembledName) {
	cpu_finalize_instruction_decode(instruction, 3);
	cpu_set_instruction_disassembled_name_formatted2(instruction, disassembledName, UNUSED, UNUSED);

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

	memory_write8(*cpu_regs()->HL, regVal8);
	cpu_mark_instruction_executed(instruction);
}

void cpu_instruction__and_reg8(struct instruction* instruction, Uint8 value8, const char* disassembledName) {
	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted2(instruction, disassembledName, UNUSED, UNUSED);

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

	cpu_regs()->A &= value8;
	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_reg8(struct instruction* instruction, Uint8 value8, const char* disassembledName) {
	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted2(instruction, disassembledName, UNUSED, UNUSED);

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

	cpu_regs()->A ^= value8;
	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_reg8(struct instruction* instruction, Uint8 value8, const char* disassembledName) {
	cpu_finalize_instruction_decode(instruction, 0);
	cpu_set_instruction_disassembled_name_formatted2(instruction, disassembledName, UNUSED, UNUSED);

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

	cpu_regs()->A |= value8;
	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_reg8(struct instruction* instruction, Uint8 value8, const char* disassembledName) {
	Uint8 oldAcc = cpu_regs()->A;	// save A
	cpu_instruction__sub_reg8(instruction, value8, disassembledName);
	cpu_regs()->A = oldAcc;			// restore A
}

void cpu_instruction__rst(struct instruction* instruction, Uint16 mem16, const char* disassembledName) {
	cpu_finalize_instruction_decode(instruction, 7);
	cpu_set_instruction_disassembled_name_formatted2(instruction, disassembledName, mem16, UNUSED);

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

	cpu_push_PC();
	cpu_regs()->PC = mem16;
	cpu_mark_instruction_executed(instruction);
}

void cpu_run_no_prefix(struct instruction* instruction) {
	Uint8 condition;

	switch (instruction->opcodeValue) {
	case 0x00:	// nop
		cpu_finalize_instruction_decode(instruction, 0);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "nop", UNUSED, UNUSED);

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

		cpu_mark_instruction_executed(instruction);
		break;
	case 0x01:	// ld bc, imm16
		cpu_instruction__ld_reg16_imm16(instruction, cpu_regs()->BC, "ld BC, /n0");
		break;
	case 0x02:	// ld (bc), a
		cpu_instruction__ld_ptr16_reg8(instruction, *(cpu_regs()->BC), cpu_regs()->A, "ld (BC), A");
		break;
	case 0x03:	// inc bc
		cpu_instruction__inc_reg16(instruction, cpu_regs()->BC, "inc BC");
		break;
	case 0x04:	// inc b
		cpu_instruction__inc_reg8(instruction, &(cpu_regs()->B), "inc B");
		break;
	case 0x05:	// dec b
		cpu_instruction__dec_reg8(instruction, &(cpu_regs()->B), "dec B");
		break;
	case 0x06:	// ld b, imm8
		cpu_instruction__ld_reg8_imm8(instruction, &(cpu_regs()->B), "ld B, /n0");
		break;
	case 0x07:	// rlca
		cpu_finalize_instruction_decode(instruction, 0);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "rlca", UNUSED, UNUSED);

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

		Uint16 acc = (Uint16)(cpu_regs()->A);
		Uint8 bit7 = acc >> 7;
		if( bit7 ) cpu_regs()->F |= CPU_FLAG_C_CARRY; else cpu_regs()->F &= ~CPU_FLAG_C_CARRY;
		
		acc = acc << 1;		// bit 0 := 0
		acc |= bit7;		// bit 0 := bit 7
		cpu_regs()->A = (Uint8)acc;

		cpu_regs()->F &= ~CPU_FLAG_H_HALF_CARRY;
		cpu_regs()->F &= ~CPU_FLAG_N_SUBTRACT;
		cpu_mark_instruction_executed(instruction);
		break;
	case 0x08:	// ex af, af'
		cpu_finalize_instruction_decode(instruction, 0);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "ex AF, AF'", UNUSED, UNUSED);

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

		Uint8 t = cpu_regs()->A;
		cpu_regs()->A = cpu_regs()->A_alt;
		cpu_regs()->A_alt = t;
		t = cpu_regs()->F;
		cpu_regs()->F = cpu_regs()->F_alt;
		cpu_regs()->F_alt = t;
		cpu_mark_instruction_executed(instruction);
		break;
	case 0x09:	// add hl, bc
		cpu_instruction__add_reg16_reg16(instruction, cpu_regs()->HL, *cpu_regs()->BC, "add HL, BC");
		break;
	case 0x0A:	// ld a, (bc)
		cpu_instruction__ld_reg8_ptr16(instruction, &(cpu_regs()->A), *cpu_regs()->BC, "ld A, (BC)");
		break;
	case 0x0B:	// dec bc
		cpu_instruction__dec_reg16(instruction, cpu_regs()->BC, "dec BC");
		break;
	case 0x0C:	// inc c
		cpu_instruction__inc_reg8(instruction, &(cpu_regs()->C), "inc C");
		break;
	case 0x0D:	// dec c
		cpu_instruction__dec_reg8(instruction, &(cpu_regs()->C), "dec C");
		break;
	case 0x0E:	// ld c, imm8
		cpu_instruction__ld_reg8_imm8(instruction, &(cpu_regs()->C), "ld C, /n0");
		break;
	case 0x0F:	// rrca
		cpu_finalize_instruction_decode(instruction, 0);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "rrca", UNUSED, UNUSED);

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

		Uint8 bit0 = cpu_regs()->A & 0x01;
		if (bit0) cpu_regs()->F |= CPU_FLAG_C_CARRY; else cpu_regs()->F &= ~CPU_FLAG_C_CARRY;

		cpu_regs()->A = cpu_regs()->A >> 1;
		if (bit0)cpu_regs()->A |= 0x80; else cpu_regs()->A &= 0x7F;

		cpu_regs()->F &= ~CPU_FLAG_H_HALF_CARRY;
		cpu_regs()->F &= ~CPU_FLAG_N_SUBTRACT;
		cpu_mark_instruction_executed(instruction);
		break;
	case 0x10:	// djnz
		cpu_read_imm8(instruction);

		if (cpu_regs()->B == 1) {
			cpu_finalize_instruction_decode(instruction, 4);
		}
		else {
			cpu_finalize_instruction_decode(instruction, 9);
		}

		Uint16 branchTarget = cpu_regs()->PC + (Sint8)instruction->immediate.value.eightBit;
		cpu_set_instruction_disassembled_name_formatted2(instruction, "djnz /n0", branchTarget, UNUSED);

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

		cpu_regs()->B--;
		if (cpu_regs()->B != 0) {
			// it's branching
			cpu_regs()->PC = branchTarget;
		}

		cpu_mark_instruction_executed(instruction);
		break;
	case 0x11:	// ld de, imm16
		cpu_instruction__ld_reg16_imm16(instruction, cpu_regs()->DE, "ld DE, /n0");
		break;
	case 0x12:	// ld (de), a
		cpu_instruction__ld_ptr16_reg8(instruction, *(cpu_regs()->DE), cpu_regs()->A, "ld (DE), A");
		break;
	case 0x13:	// inc de
		cpu_instruction__inc_reg16(instruction, cpu_regs()->DE, "inc DE");
		break;
	case 0x14:	// inc d
		cpu_instruction__inc_reg8(instruction, &(cpu_regs()->D), "inc D");
		break;
	case 0x15:	// dec d
		cpu_instruction__dec_reg8(instruction, &(cpu_regs()->D), "dec D");
		break;
	case 0x16:	// ld d, imm8
		cpu_instruction__ld_reg8_imm8(instruction, &(cpu_regs()->D), "ld D, /n0");
		break;
	case 0x17:	// rla
		cpu_finalize_instruction_decode(instruction, 0);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "rla", UNUSED, UNUSED);

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

		Uint8 oldCarry = 0;
		if (cpu_regs()->F & CPU_FLAG_C_CARRY) {
			oldCarry = 1;
		}

		acc = (Uint16)(cpu_regs()->A);
		bit7 = acc >> 7;
		if (bit7) cpu_regs()->F |= CPU_FLAG_C_CARRY; else cpu_regs()->F &= ~CPU_FLAG_C_CARRY;

		acc = acc << 1;		// bit 0 := 0
		acc |= oldCarry;
		cpu_regs()->A = (Uint8)acc;

		cpu_regs()->F &= ~CPU_FLAG_H_HALF_CARRY;
		cpu_regs()->F &= ~CPU_FLAG_N_SUBTRACT;
		cpu_mark_instruction_executed(instruction);
		break;
	case 0x18:	// jr imm8
		cpu_read_imm8(instruction);
		cpu_finalize_instruction_decode(instruction, 8);

		branchTarget = cpu_regs()->PC + (Sint8)instruction->immediate.value.eightBit;
		cpu_set_instruction_disassembled_name_formatted2(instruction, "jr /n0", branchTarget, UNUSED);

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

		cpu_regs()->PC = branchTarget;
		cpu_mark_instruction_executed(instruction);
		break;
	case 0x19:	// add hl, de
		cpu_instruction__add_reg16_reg16(instruction, cpu_regs()->HL, *cpu_regs()->DE, "add HL, DE");
		break;
	case 0x1A:	// ld a, (de)
		cpu_instruction__ld_reg8_ptr16(instruction, &(cpu_regs()->A), *cpu_regs()->DE, "ld A, (DE)");
		break;
	case 0x1B:	// dec de
		cpu_instruction__dec_reg16(instruction, cpu_regs()->DE, "dec DE");
		break;
	case 0x1C:	// inc e
		cpu_instruction__inc_reg8(instruction, &(cpu_regs()->E), "inc E");
		break;
	case 0x1D:	// dec e
		cpu_instruction__dec_reg8(instruction, &(cpu_regs()->E), "dec E");
		break;
	case 0x1E:	// ld e, imm8
		cpu_instruction__ld_reg8_imm8(instruction, &(cpu_regs()->E), "ld E, /n0");
		break;
	case 0x1F:	// rra
		cpu_finalize_instruction_decode(instruction, 0);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "rra", UNUSED, UNUSED);

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

		oldCarry = 0;
		if (cpu_regs()->F & CPU_FLAG_C_CARRY) {
			oldCarry = 1;
		}

		acc = (Uint16)(cpu_regs()->A);
		if (acc & 1) cpu_regs()->F |= CPU_FLAG_C_CARRY; else cpu_regs()->F &= ~CPU_FLAG_C_CARRY;

		acc = acc >> 1;
		if (oldCarry) acc |= 0x80; else; acc &= 0x7FF;
		cpu_regs()->A = (Uint8)acc;

		cpu_regs()->F &= ~CPU_FLAG_H_HALF_CARRY;
		cpu_regs()->F &= ~CPU_FLAG_N_SUBTRACT;
		cpu_mark_instruction_executed(instruction);
		break;
	case 0x20:	// jr nz, imm8
		condition = !(cpu_regs()->F & CPU_FLAG_Z_ZERO);
		cpu_instruction__jr_cc(instruction, condition, "jr nz, /n0");
		break;
	case 0x21:	// ld hl, imm16
		cpu_instruction__ld_reg16_imm16(instruction, cpu_regs()->HL, "ld HL, /n0");
		break;
	case 0x22:	// ld (mem16), hl
		cpu_read_imm16(instruction);
		cpu_finalize_instruction_decode(instruction, 12);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "ld (/n0), HL", instruction->immediate.value.sixteenBit, UNUSED);

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

		memory_write16(instruction->immediate.value.sixteenBit, *cpu_regs()->HL);
		cpu_mark_instruction_executed(instruction);
		break;
	case 0x23:	// inc hl
		cpu_instruction__inc_reg16(instruction, cpu_regs()->HL, "inc HL");
		break;
	case 0x24:	// inc h
		cpu_instruction__inc_reg8(instruction, &(cpu_regs()->H), "inc H");
		break;
	case 0x25:	// dec h
		cpu_instruction__dec_reg8(instruction, &(cpu_regs()->H), "dec H");
		break;
	case 0x26:	// ld h, imm8
		cpu_instruction__ld_reg8_imm8(instruction, &(cpu_regs()->H), "ld H, /n0");
		break;
	case 0x27:	// daa
		cpu_finalize_instruction_decode(instruction, 0);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "daa", UNUSED, UNUSED);

		if (!cpu_must_execute()) break;
		//execution
		
		daa2();
		cpu_mark_instruction_executed(instruction);
		break;
	case 0x28:	// jr z, imm8
		condition = (cpu_regs()->F & CPU_FLAG_Z_ZERO);
		cpu_instruction__jr_cc(instruction, condition, "jr z, /n0");
		break;
	case 0x29:	// add hl, hl
		cpu_instruction__add_reg16_reg16(instruction, cpu_regs()->HL, *cpu_regs()->HL, "add HL, HL");
		break;
	case 0x2A:	// ld hl, (mem16)
		cpu_read_imm16(instruction);
		cpu_finalize_instruction_decode(instruction, 12);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "ld HL, (/n0)", instruction->immediate.value.sixteenBit, UNUSED);

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

		*cpu_regs()->HL = memory_read16(instruction->immediate.value.sixteenBit);
		cpu_mark_instruction_executed(instruction);
		break;
	case 0x2B:	// dec hl
		cpu_instruction__dec_reg16(instruction, cpu_regs()->HL, "dec HL");
		break;
	case 0x2C:	// inc l
		cpu_instruction__inc_reg8(instruction, &(cpu_regs()->L), "inc L");
		break;
	case 0x2D:	// dec l
		cpu_instruction__dec_reg8(instruction, &(cpu_regs()->L), "dec L");
		break;
	case 0x2E:	// ld l, imm8
		cpu_instruction__ld_reg8_imm8(instruction, &(cpu_regs()->L), "ld L, /n0");
		break;
	case 0x2F:	// cpl
		cpu_finalize_instruction_decode(instruction, 0);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "cpl", UNUSED, UNUSED);

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

		cpu_regs()->A ^= 0xFF;
		cpu_regs()->F |= CPU_FLAG_H_HALF_CARRY;
		cpu_regs()->F |= CPU_FLAG_N_SUBTRACT;
		cpu_mark_instruction_executed(instruction);
		break;
	case 0x30:	// jr nc, imm8
		condition = !(cpu_regs()->F & CPU_FLAG_C_CARRY);
		cpu_instruction__jr_cc(instruction, condition, "jr nc, /n0");
		break;
	case 0x31:	// ld sp, imm16
		cpu_instruction__ld_reg16_imm16(instruction, &cpu_regs()->SP, "ld SP, /n0");
		break;
	case 0x32:	// ld (mem16), a
		cpu_read_imm16(instruction);
		cpu_finalize_instruction_decode(instruction, 9);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "ld (/n0), A", instruction->immediate.value.sixteenBit, UNUSED);

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

		memory_write8(instruction->immediate.value.sixteenBit, cpu_regs()->A);
		cpu_mark_instruction_executed(instruction);
		break;
	case 0x33:	// inc sp
		cpu_instruction__inc_reg16(instruction, &cpu_regs()->SP, "inc SP");
		break;
	case 0x34:	// inc (hl)
		cpu_finalize_instruction_decode(instruction, 7);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "inc (HL)", UNUSED, UNUSED);

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

		Uint8 temp8 = memory_read8(*cpu_regs()->HL);
		cpu_save_flags();
		cpu_addc_binary8(&temp8, 1, 0);
		memory_write8(*cpu_regs()->HL, temp8);
		cpu_restore_flags(CPU_FLAG_C_CARRY);			// some flags are unaffected, so preserve them
		cpu_mark_instruction_executed(instruction);
		break;
	case 0x35:	// dec (hl)
		cpu_finalize_instruction_decode(instruction, 7);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "dec (HL)", UNUSED, UNUSED);

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

		temp8 = memory_read8(*cpu_regs()->HL);
		cpu_save_flags();
		cpu_subc_binary8(&temp8, 1, 0);
		memory_write8(*cpu_regs()->HL, temp8);
		cpu_restore_flags(CPU_FLAG_C_CARRY);			// some flags are unaffected, so preserve them
		cpu_mark_instruction_executed(instruction);
		break;
	case 0x36:	// ld (hl), imm8
		cpu_read_imm8(instruction);
		cpu_finalize_instruction_decode(instruction, 6);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "ld (HL), /n0", instruction->immediate.value.eightBit, UNUSED);

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

		memory_write8(*cpu_regs()->HL, instruction->immediate.value.eightBit);
		cpu_mark_instruction_executed(instruction);
		break;
	case 0x37:	// scf
		cpu_finalize_instruction_decode(instruction, 0);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "scf", UNUSED, UNUSED);

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

		cpu_regs()->F |= CPU_FLAG_C_CARRY;
		cpu_regs()->F &= ~CPU_FLAG_H_HALF_CARRY;
		cpu_regs()->F &= ~CPU_FLAG_N_SUBTRACT;
		cpu_mark_instruction_executed(instruction);
		break;
	case 0x38:	// jr c, imm8
		condition = (cpu_regs()->F & CPU_FLAG_C_CARRY);
		cpu_instruction__jr_cc(instruction, condition, "jr c, /n0");
		break;
	case 0x39:	// add hl, sp
		cpu_instruction__add_reg16_reg16(instruction, cpu_regs()->HL, cpu_regs()->SP, "add HL, SP");
		break;
	case 0x3A:	// ld a, (mem16)
		cpu_read_imm16(instruction);
		cpu_finalize_instruction_decode(instruction, 9);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "ld A, (/n0)", instruction->immediate.value.sixteenBit, UNUSED);

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

		cpu_regs()->A = memory_read8(instruction->immediate.value.sixteenBit);
		cpu_mark_instruction_executed(instruction);
		break;
	case 0x3B:	// dec sp
		cpu_instruction__dec_reg16(instruction, &cpu_regs()->SP, "dec SP");
		break;
	case 0x3C:	// inc a
		cpu_instruction__inc_reg8(instruction, &(cpu_regs()->A), "inc A");
		break;
	case 0x3D:	// dec a
		cpu_instruction__dec_reg8(instruction, &(cpu_regs()->A), "dec A");
		break;
	case 0x3E:	// ld a, imm8
		cpu_instruction__ld_reg8_imm8(instruction, &(cpu_regs()->A), "ld A, /n0");
		break;
	case 0x3F:	// ccf
		cpu_finalize_instruction_decode(instruction, 0);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "ccf", UNUSED, UNUSED);

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

		// confusing... some sources say H := ~C
		//              others say H := ~H
		
		// H := ~C
		if(cpu_regs()->F & CPU_FLAG_C_CARRY) cpu_regs()->F |= CPU_FLAG_H_HALF_CARRY; else cpu_regs()->F &= ~CPU_FLAG_H_HALF_CARRY;
		cpu_regs()->F &= ~CPU_FLAG_N_SUBTRACT;
		cpu_regs()->F ^= CPU_FLAG_C_CARRY;	// C := ~C
		cpu_mark_instruction_executed(instruction);
		break;
	case 0x40:	// ld b, b
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->B), cpu_regs()->B, "ld B, B");
		break;
	case 0x41:	// ld b, c
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->B), cpu_regs()->C, "ld B, C");
		break;
	case 0x42:	// ld b, d
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->B), cpu_regs()->D, "ld B, D");
		break;
	case 0x43:	// ld b, e
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->B), cpu_regs()->E, "ld B, E");
		break;
	case 0x44:	// ld b, h
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->B), cpu_regs()->H, "ld B, H");
		break;
	case 0x45:	// ld b, l
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->B), cpu_regs()->L, "ld B, L");
		break;
	case 0x46:	// ld b, (hl)
		cpu_instruction__ld_reg8_HLptr(instruction, &(cpu_regs()->B), "ld B, (HL)");
		break;
	case 0x47:	// ld b, a
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->B), cpu_regs()->A, "ld B, A");
		break;
	case 0x48:	// ld c, b
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->C), cpu_regs()->B, "ld C, B");
		break;
	case 0x49:	// ld c, c
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->C), cpu_regs()->C, "ld C, C");
		break;
	case 0x4A:	// ld c, d
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->C), cpu_regs()->D, "ld C, D");
		break;
	case 0x4B:	// ld c, e
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->C), cpu_regs()->E, "ld C, E");
		break;
	case 0x4C:	// ld c, h
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->C), cpu_regs()->H, "ld C, H");
		break;
	case 0x4D:	// ld c, l
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->C), cpu_regs()->L, "ld C, L");
		break;
	case 0x4E:	// ld c, (hl)
		cpu_instruction__ld_reg8_HLptr(instruction, &(cpu_regs()->C), "ld C, (HL)");
		break;
	case 0x4F:	// ld c, a
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->C), cpu_regs()->A, "ld C, A");
		break;
	case 0x50:	// ld d, b
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->D), cpu_regs()->B, "ld D, B");
		break;
	case 0x51:	// ld d, c
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->D), cpu_regs()->C, "ld D, C");
		break;
	case 0x52:	// ld d, d
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->D), cpu_regs()->D, "ld D, D");
		break;
	case 0x53:	// ld d, e
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->D), cpu_regs()->E, "ld D, E");
		break;
	case 0x54:	// ld d, h
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->D), cpu_regs()->H, "ld D, H");
		break;
	case 0x55:	// ld d, l
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->D), cpu_regs()->L, "ld D, L");
		break;
	case 0x56:	// ld d, (hl)
		cpu_instruction__ld_reg8_HLptr(instruction, &(cpu_regs()->D), "ld D, (HL)");
		break;
	case 0x57:	// ld d, a
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->D), cpu_regs()->A, "ld D, A");
		break;
	case 0x58:	// ld e, b
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->E), cpu_regs()->B, "ld E, B");
		break;
	case 0x59:	// ld e, c
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->E), cpu_regs()->C, "ld E, C");
		break;
	case 0x5A:	// ld e, d
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->E), cpu_regs()->D, "ld E, D");
		break;
	case 0x5B:	// ld e, e
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->E), cpu_regs()->E, "ld E, E");
		break;
	case 0x5C:	// ld e, h
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->E), cpu_regs()->H, "ld E, H");
		break;
	case 0x5D:	// ld e, l
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->E), cpu_regs()->L, "ld E, L");
		break;
	case 0x5E:	// ld e, (hl)
		cpu_instruction__ld_reg8_HLptr(instruction, &(cpu_regs()->E), "ld E, (HL)");
		break;
	case 0x5F:	// ld e, a
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->E), cpu_regs()->A, "ld E, A");
		break;
	case 0x60:	// ld h, b
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->H), cpu_regs()->B, "ld H, B");
		break;
	case 0x61:	// ld h, c
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->H), cpu_regs()->C, "ld H, C");
		break;
	case 0x62:	// ld h, d
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->H), cpu_regs()->D, "ld H, D");
		break;
	case 0x63:	// ld h, e
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->H), cpu_regs()->E, "ld H, E");
		break;
	case 0x64:	// ld h, h
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->H), cpu_regs()->H, "ld H, H");
		break;
	case 0x65:	// ld h, l
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->H), cpu_regs()->L, "ld H, L");
		break;
	case 0x66:	// ld H, (hl)
		cpu_instruction__ld_reg8_HLptr(instruction, &(cpu_regs()->H), "ld H, (HL)");
		break;
	case 0x67:	// ld h, a
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->H), cpu_regs()->A, "ld H, A");
		break;
	case 0x68:	// ld l, b
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->L), cpu_regs()->B, "ld L, B");
		break;
	case 0x69:	// ld l, c
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->L), cpu_regs()->C, "ld L, C");
		break;
	case 0x6A:	// ld l, d
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->L), cpu_regs()->D, "ld L, D");
		break;
	case 0x6B:	// ld l, e
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->L), cpu_regs()->E, "ld L, E");
		break;
	case 0x6C:	// ld l, h
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->L), cpu_regs()->H, "ld L, H");
		break;
	case 0x6D:	// ld l, l
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->L), cpu_regs()->L, "ld L, L");
		break;
	case 0x6E:	// ld l, (hl)
		cpu_instruction__ld_reg8_HLptr(instruction, &(cpu_regs()->L), "ld L, (HL)");
		break;
	case 0x6F:	// ld l, a
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->L), cpu_regs()->A, "ld L, A");
		break;
	case 0x70:	// ld (hl), b
		cpu_instruction__ld_HLptr_reg8(instruction, cpu_regs()->B, "ld (HL), B");
		break;
	case 0x71:	// ld (hl), c
		cpu_instruction__ld_HLptr_reg8(instruction, cpu_regs()->C, "ld (HL), C");
		break;
	case 0x72:	// ld (hl), d
		cpu_instruction__ld_HLptr_reg8(instruction, cpu_regs()->D, "ld (HL), D");
		break;
	case 0x73:	// ld (hl), e
		cpu_instruction__ld_HLptr_reg8(instruction, cpu_regs()->E, "ld (HL), E");
		break;
	case 0x74:	// ld (hl), h
		cpu_instruction__ld_HLptr_reg8(instruction, cpu_regs()->H, "ld (HL), H");
		break;
	case 0x75:	// ld (hl), l
		cpu_instruction__ld_HLptr_reg8(instruction, cpu_regs()->L, "ld (HL), L");
		break;
	case 0x76:	// halt
		cpu_finalize_instruction_decode(instruction, 0);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "halt", UNUSED, UNUSED);

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

		cpu_halt();
		cpu_mark_instruction_executed(instruction);
		break;
	case 0x77:	// ld (hl), a
		cpu_instruction__ld_HLptr_reg8(instruction, cpu_regs()->A, "ld (HL), A");
		break;
	case 0x78:	// ld a, b
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->A), cpu_regs()->B, "ld A, B");
		break;
	case 0x79:	// ld a, c
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->A), cpu_regs()->C, "ld A, C");
		break;
	case 0x7A:	// ld a, d
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->A), cpu_regs()->D, "ld A, D");
		break;
	case 0x7B:	// ld a, e
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->A), cpu_regs()->E, "ld A, E");
		break;
	case 0x7C:	// ld a, h
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->A), cpu_regs()->H, "ld A, H");
		break;
	case 0x7D:	// ld a, l
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->A), cpu_regs()->L, "ld A, L");
		break;
	case 0x7E:	// ld a, (hl)
		cpu_instruction__ld_reg8_HLptr(instruction, &(cpu_regs()->A), "ld A, (HL)");
		break;
	case 0x7F:	// ld a, a
		cpu_instruction__ld_reg8_reg8(instruction, &(cpu_regs()->A), cpu_regs()->A, "ld A, A");
		break;
	case 0x80:	// add a, b
		cpu_instruction__add_A_reg8(instruction, cpu_regs()->B, "add A, B");
		break;
	case 0x81:	// add a, c
		cpu_instruction__add_A_reg8(instruction, cpu_regs()->C, "add A, C");
		break;
	case 0x82:	// add a, d
		cpu_instruction__add_A_reg8(instruction, cpu_regs()->D, "add A, D");
		break;
	case 0x83:	// add a, e
		cpu_instruction__add_A_reg8(instruction, cpu_regs()->E, "add A, E");
		break;
	case 0x84:	// add a, h
		cpu_instruction__add_A_reg8(instruction, cpu_regs()->H, "add A, H");
		break;
	case 0x85:	// add a, l
		cpu_instruction__add_A_reg8(instruction, cpu_regs()->L, "add A, L");
		break;
	case 0x86:	// add a, (hl)
		cpu_finalize_instruction_decode(instruction, 3);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "add A, (HL)", UNUSED, UNUSED);

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

		temp8 = memory_read8(*cpu_regs()->HL);
		cpu_addc_binary8(&(cpu_regs()->A), temp8, 0);
		cpu_mark_instruction_executed(instruction);
		break;
	case 0x87:	// add a, a
		cpu_instruction__add_A_reg8(instruction, cpu_regs()->A, "add A, A");
		break;
	case 0x88:	// adc a, b
		cpu_instruction__adc_A_reg8(instruction, cpu_regs()->B, "adc A, B");
		break;
	case 0x89:	// adc a, c
		cpu_instruction__adc_A_reg8(instruction, cpu_regs()->C, "adc A, C");
		break;
	case 0x8A:	// adc a, d
		cpu_instruction__adc_A_reg8(instruction, cpu_regs()->D, "adc A, D");
		break;
	case 0x8B:	// adc a, e
		cpu_instruction__adc_A_reg8(instruction, cpu_regs()->E, "adc A, E");
		break;
	case 0x8C:	// adc a, h
		cpu_instruction__adc_A_reg8(instruction, cpu_regs()->H, "adc A, H");
		break;
	case 0x8D:	// adc a, l
		cpu_instruction__adc_A_reg8(instruction, cpu_regs()->L, "adc A, L");
		break;
	case 0x8E:	// adc a, (hl)
		cpu_instruction__adc_A_HLptr(instruction, "adc A, (HL)");
		break;
	case 0x8F:	// adc a, a
		cpu_instruction__adc_A_reg8(instruction, cpu_regs()->A, "adc A, A");
		break;
	case 0x90:	// sub b
		cpu_instruction__sub_reg8(instruction, cpu_regs()->B, "sub B");
		break;
	case 0x91:	// sub c
		cpu_instruction__sub_reg8(instruction, cpu_regs()->C, "sub C");
		break;
	case 0x92:	// sub d
		cpu_instruction__sub_reg8(instruction, cpu_regs()->D, "sub D");
		break;
	case 0x93:	// sub e
		cpu_instruction__sub_reg8(instruction, cpu_regs()->E, "sub E");
		break;
	case 0x94:	// sub h
		cpu_instruction__sub_reg8(instruction, cpu_regs()->H, "sub H");
		break;
	case 0x95:	// sub l
		cpu_instruction__sub_reg8(instruction, cpu_regs()->L, "sub L");
		break;
	case 0x96:	// sub (hl)
		cpu_finalize_instruction_decode(instruction, 0);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "sub (HL)", UNUSED, UNUSED);

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

		temp8 = memory_read8(*cpu_regs()->HL);
		cpu_subc_binary8(&(cpu_regs()->A), temp8, 0);
		cpu_mark_instruction_executed(instruction);
		break;
	case 0x97:	// sub a
		cpu_instruction__sub_reg8(instruction, cpu_regs()->A, "sub A");
		break;
	case 0x98:	// sbc a, b
		cpu_instruction__sbc_A_reg8(instruction, cpu_regs()->B, "sbc A, B");
		break;
	case 0x99:	// sbc a, c
		cpu_instruction__sbc_A_reg8(instruction, cpu_regs()->C, "sbc A, C");
		break;
	case 0x9A:	// sbc a, d
		cpu_instruction__sbc_A_reg8(instruction, cpu_regs()->D, "sbc A, D");
		break;
	case 0x9B:	// sbc a, e
		cpu_instruction__sbc_A_reg8(instruction, cpu_regs()->E, "sbc A, E");
		break;
	case 0x9C:	// sbc a, h
		cpu_instruction__sbc_A_reg8(instruction, cpu_regs()->H, "sbc A, H");
		break;
	case 0x9D:	// sbc a, l
		cpu_instruction__sbc_A_reg8(instruction, cpu_regs()->L, "sbc A, L");
		break;
	case 0x9E:	// sbc a, (hl)
		cpu_finalize_instruction_decode(instruction, 3);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "sbc A, (HL)", UNUSED, UNUSED);

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

		temp8 = memory_read8(*cpu_regs()->HL);
		Uint8 carry = cpu_regs()->F & CPU_FLAG_C_CARRY ? 1 : 0;
		cpu_subc_binary8(&(cpu_regs()->A), temp8, carry);
		cpu_mark_instruction_executed(instruction);
		break;
	case 0x9F:	// sbc a, a
		cpu_instruction__sbc_A_reg8(instruction, cpu_regs()->A, "sbc A, A");
		break;
	case 0xA0:	// and b
		cpu_instruction__and_reg8(instruction, cpu_regs()->B, "and B");
		break;
	case 0xA1:	// and c
		cpu_instruction__and_reg8(instruction, cpu_regs()->C, "and C");
		break;
	case 0xA2:	// and d
		cpu_instruction__and_reg8(instruction, cpu_regs()->D, "and D");
		break;
	case 0xA3:	// and e
		cpu_instruction__and_reg8(instruction, cpu_regs()->E, "and E");
		break;
	case 0xA4:	// and h
		cpu_instruction__and_reg8(instruction, cpu_regs()->H, "and H");
		break;
	case 0xA5:	// and l
		cpu_instruction__and_reg8(instruction, cpu_regs()->L, "and L");
		break;
	case 0xA6:	// and (hl)
		cpu_finalize_instruction_decode(instruction, 3);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "and (HL)", UNUSED, UNUSED);

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

		temp8 = memory_read8(*cpu_regs()->HL);
		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);
		break;
	case 0xA7:	// and a
		cpu_instruction__and_reg8(instruction, cpu_regs()->A, "and A");
		break;
	case 0xA8:	// xor b
		cpu_instruction__xor_reg8(instruction, cpu_regs()->B, "xor B");
		break;
	case 0xA9:	// xor c
		cpu_instruction__xor_reg8(instruction, cpu_regs()->C, "xor C");
		break;
	case 0xAA:	// xor d
		cpu_instruction__xor_reg8(instruction, cpu_regs()->D, "xor D");
		break;
	case 0xAB:	// xor e
		cpu_instruction__xor_reg8(instruction, cpu_regs()->E, "xor E");
		break;
	case 0xAC:	// xor h
		cpu_instruction__xor_reg8(instruction, cpu_regs()->H, "xor H");
		break;
	case 0xAD:	// xor l
		cpu_instruction__xor_reg8(instruction, cpu_regs()->L, "xor L");
		break;
	case 0xAE:	// xor (hl)
		cpu_finalize_instruction_decode(instruction, 3);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "xor (HL)", UNUSED, UNUSED);

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

		temp8 = memory_read8(*cpu_regs()->HL);
		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);
		break;
	case 0xAF:	// xor a
		cpu_instruction__xor_reg8(instruction, cpu_regs()->A, "xor A");
		break;
	case 0xB0:	// or b
		cpu_instruction__or_reg8(instruction, cpu_regs()->B, "or B");
		break;
	case 0xB1:	// or c
		cpu_instruction__or_reg8(instruction, cpu_regs()->C, "or C");
		break;
	case 0xB2:	// or d
		cpu_instruction__or_reg8(instruction, cpu_regs()->D, "or D");
		break;
	case 0xB3:	// or e
		cpu_instruction__or_reg8(instruction, cpu_regs()->E, "or E");
		break;
	case 0xB4:	// or h
		cpu_instruction__or_reg8(instruction, cpu_regs()->H, "or H");
		break;
	case 0xB5:	// or l
		cpu_instruction__or_reg8(instruction, cpu_regs()->L, "or L");
		break;
	case 0xB6:	// or (hl)		
		cpu_finalize_instruction_decode(instruction, 0);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "or (HL)", UNUSED, UNUSED);

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

		temp8 = memory_read8(*cpu_regs()->HL);
		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);
		break;
	case 0xB7:	// or a
		cpu_instruction__or_reg8(instruction, cpu_regs()->A, "or A");
		break;
	case 0xB8:	// cp b
		cpu_instruction__cp_reg8(instruction, cpu_regs()->B, "cp B");
		break;
	case 0xB9:	// cp c
		cpu_instruction__cp_reg8(instruction, cpu_regs()->C, "cp C");
		break;
	case 0xBA:	// cp d
		cpu_instruction__cp_reg8(instruction, cpu_regs()->D, "cp D");
		break;
	case 0xBB:	// cp e
		cpu_instruction__cp_reg8(instruction, cpu_regs()->E, "cp E");
		break;
	case 0xBC:	// cp h
		cpu_instruction__cp_reg8(instruction, cpu_regs()->H, "cp H");
		break;
	case 0xBD:	// cp l
		cpu_instruction__cp_reg8(instruction, cpu_regs()->L, "cp L");
		break;
	case 0xBE:	// cp (hl)
		temp8 = memory_read8(*cpu_regs()->HL);
		Uint8 oldAcc = cpu_regs()->A;	// save A
		instruction->tstatesElapsed += 3;
		cpu_instruction__sub_reg8(instruction, temp8, "cp (HL)");
		cpu_regs()->A = oldAcc;			// restore A
		break;
	case 0xBF:	// cp a
		cpu_instruction__cp_reg8(instruction, cpu_regs()->A, "cp A");
		break;
	case 0xC0:	// ret nz
		condition = !(cpu_regs()->F & CPU_FLAG_Z_ZERO);
		cpu_instruction__ret_cc(instruction, condition, "ret nz");
		break;
	case 0xC1:	// pop bc
		cpu_instruction__pop_reg16(instruction, cpu_regs()->BC, "pop BC");
		break;
	case 0xC2:	// jp nz, imm16
		condition = !(cpu_regs()->F & CPU_FLAG_Z_ZERO);
		cpu_instruction__jp_cc(instruction, condition, "jp nz, /n0");
		break;
	case 0xC3:	// jp imm16
		condition = 1;	// it's actually unconditional, but identical in all aspects (timing, flag affection, etc.)
		cpu_instruction__jp_cc(instruction, condition, "jp /n0");
		break;
	case 0xC4:	// call nz, imm16
		condition = !(cpu_regs()->F & CPU_FLAG_Z_ZERO);
		cpu_instruction__call_cc(instruction, condition, "call nz, /n0");
		break;
	case 0xC5:	// push bc
		cpu_instruction__push_reg16(instruction, *cpu_regs()->BC, "push BC");
		break;
	case 0xC6:	// add a, imm8
		cpu_read_imm8(instruction);
		cpu_finalize_instruction_decode(instruction, 3);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "add A, /n0", instruction->immediate.value.eightBit, UNUSED);

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

		cpu_addc_binary8(&(cpu_regs()->A), instruction->immediate.value.eightBit, 0);
		cpu_mark_instruction_executed(instruction);
		break;
	case 0xC7:	// rst 0x00
		cpu_instruction__rst(instruction, 0x00, "rst /n0");
		break;
	case 0xC8:	// ret z
		condition = (cpu_regs()->F & CPU_FLAG_Z_ZERO);
		cpu_instruction__ret_cc(instruction, condition, "ret z");
		break;
	case 0xC9:	// ret
		condition = 1;
		instruction->tstatesElapsed -= 1;
		cpu_instruction__ret_cc(instruction, condition, "ret");
		break;
	case 0xCA:	// jp z, imm16
		condition = (cpu_regs()->F & CPU_FLAG_Z_ZERO);
		cpu_instruction__jp_cc(instruction, condition, "jp z, /n0");
		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;
	case 0xCC:	// call z, imm16
		condition = (cpu_regs()->F & CPU_FLAG_Z_ZERO);
		cpu_instruction__call_cc(instruction, condition, "call z, /n0");
		break;
	case 0xCD:	// call imm16
		condition = 1;
		cpu_instruction__call_cc(instruction, condition, "call /n0");
		break;
	case 0xCE:	// adc a, imm8
		cpu_instruction__adc_A_imm8(instruction);
		break;
	case 0xCF:	// rst 0x08
		cpu_instruction__rst(instruction, 0x08, "rst /n0");
		break;
	case 0xD0:	// ret nc
		condition = !(cpu_regs()->F & CPU_FLAG_C_CARRY);
		cpu_instruction__ret_cc(instruction, condition, "ret nc");
		break;
	case 0xD1:	// pop de
		cpu_instruction__pop_reg16(instruction, cpu_regs()->DE, "pop DE");
		break;
	case 0xD2:	// jp nc, imm16
		condition = !(cpu_regs()->F & CPU_FLAG_C_CARRY);
		cpu_instruction__jp_cc(instruction, condition, "jp nc, /n0");
		break;
	case 0xD3:	// out (imm8), a
		cpu_read_imm8(instruction);
		cpu_finalize_instruction_decode(instruction, 7);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "out (/n0), A", instruction->immediate.value.eightBit, UNUSED);

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

		Uint16 address16 = (cpu_regs()->A << 8) + instruction->immediate.value.eightBit;
		io_write8_16bitaddr(address16, cpu_regs()->A);
		cpu_mark_instruction_executed(instruction);
		break;
	case 0xD4:	// call nc, imm16
		condition = !(cpu_regs()->F & CPU_FLAG_C_CARRY);
		cpu_instruction__call_cc(instruction, condition, "call nc, /n0");
		break;
	case 0xD5:	// push de
		cpu_instruction__push_reg16(instruction, *cpu_regs()->DE, "push DE");
		break;
	case 0xD6:	// sub imm8
		cpu_read_imm8(instruction);
		cpu_finalize_instruction_decode(instruction, 3);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "sub /n0", instruction->immediate.value.eightBit, UNUSED);

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

		cpu_subc_binary8(&(cpu_regs()->A), instruction->immediate.value.eightBit, 0);
		cpu_mark_instruction_executed(instruction);
		break;
	case 0xD7:	// rst 0x10
		cpu_instruction__rst(instruction, 0x10, "rst /n0");
		break;
	case 0xD8:	// ret c
		condition = (cpu_regs()->F & CPU_FLAG_C_CARRY);
		cpu_instruction__ret_cc(instruction, condition, "ret c");
		break;
	case 0xD9:	// exx
		cpu_finalize_instruction_decode(instruction, 0);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "exx", UNUSED, UNUSED);

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

		cpu_swap16(cpu_regs()->BC, cpu_regs()->BC_alt);
		cpu_swap16(cpu_regs()->DE, cpu_regs()->DE_alt);
		cpu_swap16(cpu_regs()->HL, cpu_regs()->HL_alt);
		cpu_mark_instruction_executed(instruction);
		break;
	case 0xDA:	// jp c, imm16
		condition = (cpu_regs()->F & CPU_FLAG_C_CARRY);
		cpu_instruction__jp_cc(instruction, condition, "jp c, /n0");
		break;
	case 0xDB:	// in a, (imm8)
		cpu_read_imm8(instruction);
		cpu_finalize_instruction_decode(instruction, 7);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "in A, (/n0)", instruction->immediate.value.eightBit, UNUSED);

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

		address16 = (cpu_regs()->A << 8) + instruction->immediate.value.eightBit;
		temp8 = io_read8_16bitaddr(address16);
		cpu_regs()->A = temp8;
		cpu_mark_instruction_executed(instruction);
		break;
	case 0xDC:	// call c, imm16
		condition = (cpu_regs()->F & CPU_FLAG_C_CARRY);
		cpu_instruction__call_cc(instruction, condition, "call c, /n0");
		break;
	case 0xDD:	// NOT ALLOWED
		// DD is a prefix, and not an instruction opcode
		cpu_finalize_instruction_decode(instruction, 0);
		cpu_mark_instruction_unknown(instruction);
		break;
	case 0xDE:	// sbc a, imm8
		cpu_read_imm8(instruction);
		cpu_finalize_instruction_decode(instruction, 3);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "sbc A, /n0", instruction->immediate.value.eightBit, UNUSED);

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

		carry = cpu_regs()->F & CPU_FLAG_C_CARRY ? 1 : 0;
		cpu_subc_binary8(&(cpu_regs()->A), instruction->immediate.value.eightBit, carry);
		cpu_mark_instruction_executed(instruction);
		break;
	case 0xDF:	// rst 0x18
		cpu_instruction__rst(instruction, 0x18, "rst /n0");
		break;
	case 0xE0:	// ret po
		condition = !(cpu_regs()->F & CPU_FLAG_PV_PARITY_OVERFLOW);
		cpu_instruction__ret_cc(instruction, condition, "ret po");
		break;
	case 0xE1:	// pop hl
		cpu_instruction__pop_reg16(instruction, cpu_regs()->HL, "pop HL");
		break;
	case 0xE2:	// jp po, imm16
		condition = !(cpu_regs()->F & CPU_FLAG_PV_PARITY_OVERFLOW);
		cpu_instruction__jp_cc(instruction, condition, "jp po, /n0");
		break;
	case 0xE3:	// ex (sp), hl
		cpu_finalize_instruction_decode(instruction, 15);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "ex (SP), HL", UNUSED, UNUSED);

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

		Uint16 temp16 = memory_read16(cpu_regs()->SP);
		memory_write16(cpu_regs()->SP, *cpu_regs()->HL);
		*cpu_regs()->HL = temp16;
		cpu_mark_instruction_executed(instruction);
		break;
	case 0xE4:	// call po, imm16
		condition = !(cpu_regs()->F & CPU_FLAG_PV_PARITY_OVERFLOW);
		cpu_instruction__call_cc(instruction, condition, "call po, /n0");
		break;
	case 0xE5:	// push hl
		cpu_instruction__push_reg16(instruction, *cpu_regs()->HL, "push HL");
		break;
	case 0xE6:	// and imm8
		cpu_read_imm8(instruction);
		cpu_finalize_instruction_decode(instruction, 3);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "and /n0", instruction->immediate.value.eightBit, UNUSED);

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

		cpu_regs()->A &= instruction->immediate.value.eightBit;
		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);
		break;
	case 0xE7:	// rst 0x20
		cpu_instruction__rst(instruction, 0x20, "rst /n0");
		break;
	case 0xE8:	// ret pe
		condition = (cpu_regs()->F & CPU_FLAG_PV_PARITY_OVERFLOW);
		cpu_instruction__ret_cc(instruction, condition, "ret pe");
		break;
	case 0xE9:	// jp (hl)
		cpu_finalize_instruction_decode(instruction, 0);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "jp (HL)", UNUSED, UNUSED);

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

		cpu_regs()->PC = *cpu_regs()->HL;
		cpu_mark_instruction_executed(instruction);
		break;
	case 0xEA:	// jp pe, imm16
		condition = (cpu_regs()->F & CPU_FLAG_PV_PARITY_OVERFLOW);
		cpu_instruction__jp_cc(instruction, condition, "jp pe, /n0");
		break;
	case 0xEB:	// ex de, hl
		cpu_finalize_instruction_decode(instruction, 0);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "ex DE, HL", UNUSED, UNUSED);

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

		cpu_swap16(cpu_regs()->DE, cpu_regs()->HL);
		cpu_mark_instruction_executed(instruction);
		break;
	case 0xEC:	// call pe, imm16
		condition = (cpu_regs()->F & CPU_FLAG_PV_PARITY_OVERFLOW);
		cpu_instruction__call_cc(instruction, condition, "call pe, /n0");
		break;
	case 0xED:	// NOT ALLOWED
		// ED is a prefix, and not an instruction opcode
		cpu_finalize_instruction_decode(instruction, 0);
		cpu_mark_instruction_unknown(instruction);
		break;
	case 0xEE:	// xor imm8
		cpu_read_imm8(instruction);
		cpu_finalize_instruction_decode(instruction, 3);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "xor /n0", instruction->immediate.value.eightBit, UNUSED);

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

		cpu_regs()->A ^= instruction->immediate.value.eightBit;
		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);
		break;
	case 0xEF:	// rst 0x28
		cpu_instruction__rst(instruction, 0x28, "rst /n0");
		break;
	case 0xF0:	// ret p
		condition = !(cpu_regs()->F & CPU_FLAG_S_SIGN);
		cpu_instruction__ret_cc(instruction, condition, "ret p");
		break;
	case 0xF1:	// pop af
		cpu_instruction__pop_reg16(instruction, cpu_regs()->AF, "pop AF");
		break;
	case 0xF2:	// jp p, imm16
		condition = !(cpu_regs()->F & CPU_FLAG_S_SIGN);
		cpu_instruction__jp_cc(instruction, condition, "jp p, /n0");
		break;
	case 0xF3:	// di
		cpu_finalize_instruction_decode(instruction, 0);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "di", UNUSED, UNUSED);

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

		cpu_regs()->IFF = 0;
		cpu_mark_instruction_executed(instruction);
		break;
	case 0xF4:	// call p, imm16
		condition = !(cpu_regs()->F & CPU_FLAG_S_SIGN);
		cpu_instruction__call_cc(instruction, condition, "call p, /n0");
		break;
	case 0xF5:	// push af
		cpu_instruction__push_reg16(instruction, *cpu_regs()->AF, "push AF");
		break;
	case 0xF6:	// or imm8
		cpu_read_imm8(instruction);
		cpu_finalize_instruction_decode(instruction, 3);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "or /n0", instruction->immediate.value.eightBit, UNUSED);

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

		cpu_regs()->A |= instruction->immediate.value.eightBit;
		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);
		break;
	case 0xF7:	// rst 0x30
		cpu_instruction__rst(instruction, 0x30, "rst /n0");
		break;
	case 0xF8:	// ret m
		condition = (cpu_regs()->F & CPU_FLAG_S_SIGN);
		cpu_instruction__ret_cc(instruction, condition, "ret m");
		break;
	case 0xF9:	// ld sp, hl
		cpu_finalize_instruction_decode(instruction, 2);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "ld SP, HL", instruction->immediate.value.eightBit, UNUSED);

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

		cpu_regs()->SP = *cpu_regs()->HL;
		cpu_mark_instruction_executed(instruction);
		break;
	case 0xFA:	// jp m, imm16
		condition = (cpu_regs()->F & CPU_FLAG_S_SIGN);
		cpu_instruction__jp_cc(instruction, condition, "jp m, /n0");
		break;
	case 0xFB:	// ei
		cpu_finalize_instruction_decode(instruction, 0);
		cpu_set_instruction_disassembled_name_formatted2(instruction, "ei", UNUSED, UNUSED);

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

		cpu_regs()->IFF |= CPU_IFF1_BIT;
		cpu_regs()->IFF |= CPU_IFF2_BIT;
		cpu_mark_instruction_executed(instruction);
		break;
	case 0xFC:	// call m, imm16
		condition = (cpu_regs()->F & CPU_FLAG_S_SIGN);
		cpu_instruction__call_cc(instruction, condition, "call m, /n0");
		break;
	case 0xFD:	// NOT ALLOWED
		// FD is a prefix, and not an instruction opcode
		cpu_finalize_instruction_decode(instruction, 0);
		cpu_mark_instruction_unknown(instruction);
		break;
	case 0xFE:	// cp imm8
		cpu_read_imm8(instruction);
		instruction->tstatesElapsed += 3;
		oldAcc = cpu_regs()->A;	// save A
		cpu_instruction__sub_reg8(instruction, instruction->immediate.value.eightBit, "cp /n0");
		cpu_regs()->A = oldAcc;			// restore A
		break;
	case 0xFF:	// rst 0x38
		cpu_instruction__rst(instruction, 0x38, "rst /n0");
		break;

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