Skip to content
Snippets Groups Projects
inst.rs 62.81 KiB
use crate::cpu::Cpu;

pub const INSTRUCTIONS: [Instruction; 256] = [
    // 0x0 opcodes
    (nop, 4, "NOP"),
    (ld_bc_u16, 12, "LD BC, u16"),
    (ld_mbc_a, 8, "LD [BC], A"),
    (inc_bc, 8, "INC BC"),
    (inc_b, 4, "INC B"),
    (dec_b, 4, "DEC B"),
    (ld_b_u8, 8, "LD B, u8"),
    (rlca, 4, "RLCA"),
    (ld_mu16_sp, 20, "LD [u16], SP"),
    (add_hl_bc, 8, "ADD HL, BC"),
    (ld_a_mbc, 8, "LD A, [BC]"),
    (dec_bc, 8, "DEC BC"),
    (inc_c, 4, "INC C"),
    (dec_c, 4, "DEC C"),
    (ld_c_u8, 8, "LD C, u8"),
    (rrca, 4, "RRCA"),
    // 0x1 opcodes
    (stop, 4, "STOP"),
    (ld_de_u16, 12, "LD DE, u16"),
    (ld_mde_a, 8, "LD [DE], A"),
    (inc_de, 8, "INC DE"),
    (inc_d, 4, "INC D"),
    (dec_d, 4, "DEC D"),
    (ld_d_u8, 8, "LD D, u8"),
    (rla, 4, "RLA"),
    (jr_i8, 12, "JR i8"),
    (add_hl_de, 8, "ADD HL, DE"),
    (ld_a_mde, 8, "LD A, [DE]"),
    (dec_de, 8, "DEC DE"),
    (inc_e, 4, "INC E"),
    (dec_e, 4, "DEC E"),
    (ld_e_u8, 8, "LD E, u8"),
    (rra, 4, "RRA"),
    // 0x2 opcodes
    (jr_nz_i8, 8, "JR NZ, i8"),
    (ld_hl_u16, 12, "LD HL, u16"),
    (ld_mhli_a, 8, "LD [HL+], A"),
    (inc_hl, 8, "INC HL"),
    (inc_h, 4, "INC H"),
    (dec_h, 4, "DEC H"),
    (ld_h_u8, 8, "LD H, u8"),
    (daa, 4, "DAA"),
    (jr_z_i8, 8, "JR Z, i8"),
    (add_hl_hl, 8, "ADD HL, HL"),
    (ld_a_mhli, 8, "LD A, [HL+] "),
    (dec_hl, 8, "DEC HL"),
    (inc_l, 4, "INC L"),
    (dec_l, 4, "DEC L"),
    (ld_l_u8, 8, "LD L, u8"),
    (cpl, 4, "CPL"),
    // 0x3 opcodes
    (jr_nc_i8, 8, "JR NC, i8"),
    (ld_sp_u16, 12, "LD SP, u16"),
    (ld_mhld_a, 8, "LD [HL-], A"),
    (inc_sp, 8, "INC SP"),
    (inc_mhl, 12, "INC [HL]"),
    (dec_mhl, 12, "DEC [HL]"),
    (ld_mhl_u8, 12, "LD [HL], u8 "),
    (scf, 4, "SCF"),
    (jr_c_i8, 8, "JR C, i8"),
    (add_hl_sp, 8, "ADD HL, SP"),
    (ld_a_mhld, 8, "LD A, [HL-]"),
    (dec_sp, 8, "DEC SP"),
    (inc_a, 4, "INC A"),
    (dec_a, 4, "DEC A"),
    (ld_a_u8, 8, "LD A, u8"),
    (ccf, 4, "CCF"),
    // 0x4 opcodes
    (ld_b_b, 4, "LD B, B"),
    (ld_b_c, 4, "LD B, C"),
    (ld_b_d, 4, "LD B, D"),
    (ld_b_e, 4, "LD B, E"),
    (ld_b_h, 4, "LD B, H"),
    (ld_b_l, 4, "LD B, L"),
    (ld_b_mhl, 8, "LD B, [HL]"),
    (ld_b_a, 4, "LD B, A"),
    (ld_c_b, 4, "LD C, B"),
    (ld_c_c, 4, "LD C, C"),
    (ld_c_d, 4, "LD C, D"),
    (ld_c_e, 4, "LD C, E"),
    (ld_c_h, 4, "LD C, H"),
    (ld_c_l, 4, "LD C, L"),
    (ld_c_mhl, 8, "LD C, [HL]"),
    (ld_c_a, 4, "LD C, A"),
    // 0x5 opcodes
    (ld_d_b, 4, "LD D, B"),
    (ld_d_c, 4, "LD D, C"),
    (ld_d_d, 4, "LD D, D"),
    (ld_d_e, 4, "LD D, E"),
    (ld_d_h, 4, "LD D, H"),
    (ld_d_l, 4, "LD D, L"),
    (ld_d_mhl, 8, "LD D, [HL]"),
    (ld_d_a, 4, "LD D, A"),
    (ld_e_b, 4, "LD E, B"),
    (ld_e_c, 4, "LD E, C"),
    (ld_e_d, 4, "LD E, D"),
    (ld_e_e, 4, "LD E, E"),
    (ld_e_h, 4, "LD E, H"),
    (ld_e_l, 4, "LD E, L"),
    (ld_e_mhl, 8, "LD E, [HL]"),
    (ld_e_a, 4, "LD E, A"),
    // 0x6 opcodes
    (ld_h_b, 4, "LD H, B"),
    (ld_h_c, 4, "LD H, C"),
    (ld_h_d, 4, "LD H, D"),
    (ld_h_e, 4, "LD H, E"),
    (ld_h_h, 4, "LD H, H"),
    (ld_h_l, 4, "LD H, L"),
    (ld_h_mhl, 8, "LD H, [HL]"),
    (ld_h_a, 4, "LD H, A"),
    (ld_l_b, 4, "LD L, B"),
    (ld_l_c, 4, "LD L, C"),
    (ld_l_d, 4, "LD L, D"),
    (ld_l_e, 4, "LD L, E"),
    (ld_l_h, 4, "LD L, H"),
    (ld_l_l, 4, "LD L, L"),
    (ld_l_mhl, 8, "LD L, [HL]"),
    (ld_l_a, 4, "LD L, A"),
    // 0x7 opcodes
    (ld_mhl_b, 8, "LD [HL], B"),
    (ld_mhl_c, 8, "LD [HL], C"),
    (ld_mhl_d, 8, "LD [HL], D"),
    (ld_mhl_e, 8, "LD [HL], E"),
    (ld_mhl_h, 8, "LD [HL], H"),
    (ld_mhl_l, 8, "LD [HL], L"),
    (halt, 4, "HALT"),
    (ld_mhl_a, 8, "LD [HL], A"),
    (ld_a_b, 4, "LD A, B"),
    (ld_a_c, 4, "LD A, C"),
    (ld_a_d, 4, "LD A, D"),
    (ld_a_e, 4, "LD A, E"),
    (ld_a_h, 4, "LD A, H"),
    (ld_a_l, 4, "LD A, L"),
    (ld_a_mhl, 8, "LD A, [HL]"),
    (ld_a_a, 4, "LD A, A"),
    // 0x8 opcodes
    (add_a_b, 4, "ADD A, B"),
    (add_a_c, 4, "ADD A, C"),
    (add_a_d, 4, "ADD A, D"),
    (add_a_e, 4, "ADD A, E"),
    (add_a_h, 4, "ADD A, H"),
    (add_a_l, 4, "ADD A, L"),
    (add_a_mhl, 8, "ADD A, [HL]"),
    (add_a_a, 4, "ADD A, A"),
    (adc_a_b, 4, "ADC A, B"),
    (adc_a_c, 4, "ADC A, C"),
    (adc_a_d, 4, "ADC A, D"),
    (adc_a_e, 4, "ADC A, E"),
    (adc_a_h, 4, "ADC A, H"),
    (adc_a_l, 4, "ADC A, L"),
    (adc_a_mhl, 8, "ADC A, [HL]"),
    (adc_a_a, 4, "ADC A, A"),
    // 0x9 opcodes
    (sub_a_b, 4, "SUB A, B"),
    (sub_a_c, 4, "SUB A, C"),
    (sub_a_d, 4, "SUB A, D"),
    (sub_a_e, 4, "SUB A, E"),
    (sub_a_h, 4, "SUB A, H"),
    (sub_a_l, 4, "SUB A, L"),
    (sub_a_mhl, 8, "SUB A, [HL]"),
    (sub_a_a, 4, "SUB A, A"),
    (sbc_a_b, 4, "SBC A, B"),
    (sbc_a_c, 4, "SBC A, C"),
    (sbc_a_d, 4, "SBC A, D"),
    (sbc_a_e, 4, "SBC A, E"),
    (sbc_a_h, 4, "SBC A, H"),
    (sbc_a_l, 4, "SBC A, L"),
    (sbc_a_mhl, 8, "SBC A, [HL]"),
    (sbc_a_a, 4, "SBC A, A"),
    // 0xA opcodes
    (and_a_b, 4, "AND A, B"),
    (and_a_c, 4, "AND A, C"),
    (and_a_d, 4, "AND A, D"),
    (and_a_e, 4, "AND A, E"),
    (and_a_h, 4, "AND A, H"),
    (and_a_l, 4, "AND A, L"),
    (and_a_mhl, 8, "AND A, [HL]"),
    (and_a_a, 4, "AND A, A"),
    (xor_a_b, 4, "XOR A, B"),
    (xor_a_c, 4, "XOR A, C"),
    (xor_a_d, 4, "XOR A, D"),
    (xor_a_e, 4, "XOR A, E"),
    (xor_a_h, 4, "XOR A, H"),
    (xor_a_l, 4, "XOR A, L"),
    (xor_a_mhl, 8, "XOR A, [HL]"),
    (xor_a_a, 4, "XOR A, A"),
    // 0xB opcodes
    (or_a_b, 4, "OR A, B"),
    (or_a_c, 4, "OR A, C"),
    (or_a_d, 4, "OR A, D"),
    (or_a_e, 4, "OR A, E"),
    (or_a_h, 4, "OR A, H"),
    (or_a_l, 4, "OR A, L"),
    (or_a_mhl, 8, "OR A, [HL]"),
    (or_a_a, 4, "OR A, A"),
    (cp_a_b, 4, "CP A, B"),
    (cp_a_c, 4, "CP A, C"),
    (cp_a_d, 4, "CP A, D"),
    (cp_a_e, 4, "CP A, E"),
    (cp_a_h, 4, "CP A, H"),
    (cp_a_l, 4, "CP A, L"),
    (cp_a_mhl, 8, "CP A, [HL]"),
    (cp_a_a, 4, "CP A, A"),
    // 0xC opcodes
    (ret_nz, 8, "RET NZ"),
    (pop_bc, 12, "POP BC"),
    (jp_nz_u16, 12, "JP NZ, u16"),
    (jp_u16, 16, "JP u16"),
    (call_nz_u16, 12, "CALL NZ, u16"),
    (push_bc, 16, "PUSH BC"),
    (add_a_u8, 8, "ADD A, u8"),
    (rst_00h, 16, "RST 00h"),
    (ret_z, 8, "RET Z"),
    (ret, 16, "RET"),
    (jp_z_u16, 12, "JP Z, u16"),
    (illegal, 4, "ILLEGAL"),
    (call_z_u16, 12, "CALL Z, u16"),
    (call_u16, 24, "CALL u16"),
    (adc_a_u8, 8, "ADC A, u8 "),
    (rst_08h, 16, "RST 08h"),
    // 0xD opcodes
    (ret_nc, 8, "RET NC"),
    (pop_de, 12, "POP DE"),
    (jp_nc_u16, 12, "JP NC, u16"),
    (illegal, 4, "ILLEGAL"),
    (call_nc_u16, 12, "CALL NC, u16 "),
    (push_de, 16, "PUSH DE"),
    (sub_a_u8, 8, "SUB A, u8"),
    (rst_10h, 16, "RST 10h"),
    (ret_c, 8, "RET C"),
    (reti, 16, "RETI"),
    (jp_c_u16, 12, "JP C, u16"),
    (illegal, 4, "ILLEGAL"),
    (call_c_u16, 12, "CALL C, u16"),
    (illegal, 4, "ILLEGAL"),
    (sbc_a_u8, 8, "SBC A, u8"),
    (rst_18h, 16, "RST 18h"),
    // 0xE opcodes
    (ld_mff00u8_a, 12, "LD [FF00+u8], A"),
    (pop_hl, 12, "POP HL"),
    (ld_mff00c_a, 8, "LD [FF00+C], A"),
    (illegal, 4, "ILLEGAL"),
    (illegal, 4, "ILLEGAL"),
    (push_hl, 16, "PUSH HL"),
    (and_a_u8, 8, "AND A, u8"),
    (rst_20h, 16, "RST 20h"),
    (add_sp_i8, 16, "ADD SP, i8"),
    (jp_hl, 4, "JP HL"),
    (ld_mu16_a, 16, "LD [u16], A"),
    (illegal, 4, "ILLEGAL"),
    (illegal, 4, "ILLEGAL"),
    (illegal, 4, "ILLEGAL"),
    (xor_a_u8, 8, "XOR A, u8"),
    (rst_28h, 16, "RST 28h"),
    // 0xF opcodes
    (ld_a_mff00u8, 12, "LD A, [FF00+u8]"),
    (pop_af, 12, "POP AF"),
    (ld_a_mff00c, 8, "LD A, [FF00+C]"),
    (di, 4, "DI"),
    (illegal, 4, "ILLEGAL"),
    (push_af, 16, "PUSH AF"),
    (or_a_u8, 8, "OR A, u8"),
    (rst_30h, 16, "RST 30h"),
    (ld_hl_spi8, 12, "LD HL, SP+i8"),
    (ld_sp_hl, 8, "LD SP, HL"),
    (ld_a_mu16, 16, "LD A [u16]"),
    (ei, 4, "EI"),
    (illegal, 4, "ILLEGAL"),
    (illegal, 4, "ILLEGAL"),
    (cp_a_u8, 8, "CP A, u8"),
    (rst_38h, 16, "RST 38h"),
];

pub const EXTENDED: [Instruction; 256] = [
    // 0x0 opcodes
    (rlc_b, 8, "RLC B"),
    (rlc_c, 8, "RLC C"),
    (rlc_d, 8, "RLC D"),
    (rlc_e, 8, "RLC E"),
    (rlc_h, 8, "RLC H"),
    (rlc_l, 8, "RLC L"),
    (rlc_mhl, 16, "RLC [HL]"),
    (rlc_a, 8, "RLC A"),
    (rrc_b, 8, "RRC B"),
    (rrc_c, 8, "RRC C"),
    (rrc_d, 8, "RRC D"),
    (rrc_e, 8, "RRC E"),
    (rrc_h, 8, "RRC H"),
    (rrc_l, 8, "RRC L"),
    (rrc_mhl, 16, "RRC [HL]"),
    (rrc_a, 8, "RRC A"),
    // 0x1 opcodes
    (rl_b, 8, "RL B"),
    (rl_c, 8, "RL C"),
    (rl_d, 8, "RL D"),
    (rl_e, 8, "RL E"),
    (rl_h, 8, "RL H"),
    (rl_l, 8, "RL L"),
    (rl_mhl, 16, "RL [HL]"),
    (rl_a, 8, "RL A"),
    (rr_b, 8, "RR B"),
    (rr_c, 8, "RR C"),
    (rr_d, 8, "RR D"),
    (rr_e, 8, "RR E"),
    (rr_h, 8, "RR H"),
    (rr_l, 8, "RR L"),
    (rr_mhl, 16, "RR [HL]"),
    (rr_a, 8, "RR A"),
    // 0x2 opcodes
    (sla_b, 8, "SLA B"),
    (sla_c, 8, "SLA C"),
    (sla_d, 8, "SLA D"),
    (sla_e, 8, "SLA E"),
    (sla_h, 8, "SLA H"),
    (sla_l, 8, "SLA L"),
    (sla_mhl, 16, "SLA [HL]"),
    (sla_a, 8, "SLA A"),
    (sra_b, 8, "SRA B"),
    (sra_c, 8, "SRA C"),
    (sra_d, 8, "SRA D"),
    (sra_e, 8, "SRA E"),
    (sra_h, 8, "SRA H"),
    (sra_l, 8, "SRA L"),
    (sra_mhl, 16, "SRA [HL]"),
    (sra_a, 8, "SRA A"),
    // 0x3 opcodes
    (swap_b, 8, "SWAP B"),
    (swap_c, 8, "SWAP C"),
    (swap_d, 8, "SWAP D"),
    (swap_e, 8, "SWAP E"),
    (swap_h, 8, "SWAP H"),
    (swap_l, 8, "SWAP L"),
    (swap_mhl, 16, "SWAP [HL]"),
    (swap_a, 8, "SWAP A"),
    (srl_b, 8, "SRL B"),
    (srl_c, 8, "SRL B"),
    (srl_d, 8, "SRL D"),
    (srl_e, 8, "SRL E"),
    (srl_h, 8, "SRL H"),
    (srl_l, 8, "SRL L"),
    (srl_mhl, 16, "SRL [HL]"),
    (srl_a, 8, "SRL A"),
    // 0x4 opcodes
    (bit_0_b, 8, "BIT 0, B"),
    (bit_0_c, 8, "BIT 0, C"),
    (bit_0_d, 8, "BIT 0, D"),
    (bit_0_e, 8, "BIT 0, E"),
    (bit_0_h, 8, "BIT 0, H"),
    (bit_0_l, 8, "BIT 0, L"),
    (bit_0_mhl, 12, "BIT 0, [HL]"),
    (bit_0_a, 8, "BIT 0, A"),
    (bit_1_b, 8, "BIT 1, B"),
    (bit_1_c, 8, "BIT 1, C"),
    (bit_1_d, 8, "BIT 1, D"),
    (bit_1_e, 8, "BIT 1, E"),
    (bit_1_h, 8, "BIT 1, H"),
    (bit_1_l, 8, "BIT 1, L"),
    (bit_1_mhl, 12, "BIT 1, [HL]"),
    (bit_1_a, 8, "BIT 1, A"),
    // 0x5 opcodes
    (bit_2_b, 8, "BIT 2, B"),
    (bit_2_c, 8, "BIT 2, C"),
    (bit_2_d, 8, "BIT 2, D"),
    (bit_2_e, 8, "BIT 2, E"),
    (bit_2_h, 8, "BIT 2, H"),
    (bit_2_l, 8, "BIT 2, L"),
    (bit_2_mhl, 12, "BIT 2, [HL]"),
    (bit_2_a, 8, "BIT 2, A"),
    (bit_3_b, 8, "BIT 3, B"),
    (bit_3_c, 8, "BIT 3, C"),
    (bit_3_d, 8, "BIT 3, D"),
    (bit_3_e, 8, "BIT 3, E"),
    (bit_3_h, 8, "BIT 3, H"),
    (bit_3_l, 8, "BIT 3, L"),
    (bit_3_mhl, 12, "BIT 3, [HL]"),
    (bit_3_a, 8, "BIT 3, A"),
    // 0x6 opcodes
    (bit_4_b, 8, "BIT 4, B"),
    (bit_4_c, 8, "BIT 4, C"),
    (bit_4_d, 8, "BIT 4, D"),
    (bit_4_e, 8, "BIT 4, E"),
    (bit_4_h, 8, "BIT 4, H"),
    (bit_4_l, 8, "BIT 4, L"),
    (bit_4_mhl, 12, "BIT 4, [HL]"),
    (bit_4_a, 8, "BIT 4, A"),
    (bit_5_b, 8, "BIT 5, B"),
    (bit_5_c, 8, "BIT 5, C"),
    (bit_5_d, 8, "BIT 5, D"),
    (bit_5_e, 8, "BIT 5, E"),
    (bit_5_h, 8, "BIT 5, H"),
    (bit_5_l, 8, "BIT 5, L"),
    (bit_5_mhl, 12, "BIT 5, [HL]"),
    (bit_5_a, 8, "BIT 5, A"),
    // 0x7 opcodes
    (bit_6_b, 8, "BIT 6, B"),
    (bit_6_c, 8, "BIT 6, C"),
    (bit_6_d, 8, "BIT 6, D"),
    (bit_6_e, 8, "BIT 6, E"),
    (bit_6_h, 8, "BIT 6, H"),
    (bit_6_l, 8, "BIT 6, L"),
    (bit_6_mhl, 12, "BIT 6, [HL]"),
    (bit_6_a, 8, "BIT 6, A"),
    (bit_7_b, 8, "BIT 7, B"),
    (bit_7_c, 8, "BIT 7, C"),
    (bit_7_d, 8, "BIT 7, D"),
    (bit_7_e, 8, "BIT 7, E"),
    (bit_7_h, 8, "BIT 7, H"),
    (bit_7_l, 8, "BIT 7, L"),
    (bit_7_mhl, 12, "BIT 7, [HL]"),
    (bit_7_a, 8, "BIT 7, A"),
    // 0x8 opcodes
    (res_0_b, 8, "RES 0, B"),
    (res_0_c, 8, "RES 0, C"),
    (res_0_d, 8, "RES 0, D"),
    (res_0_e, 8, "RES 0, E"),
    (res_0_h, 8, "RES 0, H"),
    (res_0_l, 8, "RES 0, L"),
    (res_0_mhl, 16, "RES 0, A"),
    (res_0_a, 8, "RES 0, A"),
    (res_1_b, 8, "RES 1, B"),
    (res_1_c, 8, "RES 1, C"),
    (res_1_d, 8, "RES 1, D"),
    (res_1_e, 8, "RES 1, E"),
    (res_1_h, 8, "RES 1, H"),
    (res_1_l, 8, "RES 1, L"),
    (res_1_mhl, 16, "RES 1, A"),
    (res_1_a, 8, "RES 1, A"),
    // 0x9 opcodes
    (res_2_b, 8, "RES 2, B"),
    (res_2_c, 8, "RES 2, C"),
    (res_2_d, 8, "RES 2, D"),
    (res_2_e, 8, "RES 2, E"),
    (res_2_h, 8, "RES 2, H"),
    (res_2_l, 8, "RES 2, L"),
    (res_2_mhl, 16, "RES 2, A"),
    (res_2_a, 8, "RES 2, A"),
    (res_3_b, 8, "RES 3, B"),
    (res_3_c, 8, "RES 3, C"),
    (res_3_d, 8, "RES 3, D"),
    (res_3_e, 8, "RES 3, E"),
    (res_3_h, 8, "RES 3, H"),
    (res_3_l, 8, "RES 3, L"),
    (res_3_mhl, 16, "RES 3, A"),
    (res_3_a, 8, "RES 3, A"),
    // 0xA opcodes
    (res_4_b, 8, "RES 4, B"),
    (res_4_c, 8, "RES 4, C"),
    (res_4_d, 8, "RES 4, D"),
    (res_4_e, 8, "RES 4, E"),
    (res_4_h, 8, "RES 4, H"),
    (res_4_l, 8, "RES 4, L"),
    (res_4_mhl, 16, "RES 4, A"),
    (res_4_a, 8, "RES 4, A"),
    (res_5_b, 8, "RES 5, B"),
    (res_5_c, 8, "RES 5, C"),
    (res_5_d, 8, "RES 5, D"),
    (res_5_e, 8, "RES 5, E"),
    (res_5_h, 8, "RES 5, H"),
    (res_5_l, 8, "RES 5, L"),
    (res_5_mhl, 16, "RES 5, A"),
    (res_5_a, 8, "RES 5, A"),
    // 0xB opcodes
    (res_6_b, 8, "RES 6, B"),
    (res_6_c, 8, "RES 6, C"),
    (res_6_d, 8, "RES 6, D"),
    (res_6_e, 8, "RES 6, E"),
    (res_6_h, 8, "RES 6, H"),
    (res_6_l, 8, "RES 6, L"),
    (res_6_mhl, 16, "RES 6, A"),
    (res_6_a, 8, "RES 6, A"),
    (res_7_b, 8, "RES 7, B"),
    (res_7_c, 8, "RES 7, C"),
    (res_7_d, 8, "RES 7, D"),
    (res_7_e, 8, "RES 7, E"),
    (res_7_h, 8, "RES 7, H"),
    (res_7_l, 8, "RES 7, L"),
    (res_7_mhl, 16, "RES 7, A"),
    (res_7_a, 8, "RES 7, A"),
    // 0xC opcodes
    (set_0_b, 8, "SET 0, B"),
    (set_0_c, 8, "SET 0, C"),
    (set_0_d, 8, "SET 0, D"),
    (set_0_e, 8, "SET 0, E"),
    (set_0_h, 8, "SET 0, H"),
    (set_0_l, 8, "SET 0, L"),
    (set_0_mhl, 16, "SET 0, [HL]"),
    (set_0_a, 8, "SET 0, A"),
    (set_1_b, 8, "SET 1, B"),
    (set_1_c, 8, "SET 1, C"),
    (set_1_d, 8, "SET 1, D"),
    (set_1_e, 8, "SET 1, E"),
    (set_1_h, 8, "SET 1, H"),
    (set_1_l, 8, "SET 1, L"),
    (set_1_mhl, 16, "SET 1, [HL]"),
    (set_1_a, 8, "SET 1, A"),
    // 0xD opcodes
    (set_2_b, 8, "SET 2, B"),
    (set_2_c, 8, "SET 2, C"),
    (set_2_d, 8, "SET 2, D"),
    (set_2_e, 8, "SET 2, E"),
    (set_2_h, 8, "SET 2, H"),
    (set_2_l, 8, "SET 2, L"),
    (set_2_mhl, 16, "SET 2, [HL]"),
    (set_2_a, 8, "SET 2, A"),
    (set_3_b, 8, "SET 3, B"),
    (set_3_c, 8, "SET 3, C"),
    (set_3_d, 8, "SET 3, D"),
    (set_3_e, 8, "SET 3, E"),
    (set_3_h, 8, "SET 3, H"),
    (set_3_l, 8, "SET 3, L"),
    (set_3_mhl, 16, "SET 3, [HL]"),
    (set_3_a, 8, "SET 3, A"),
    // 0xE opcodes
    (set_4_b, 8, "SET 4, B"),
    (set_4_c, 8, "SET 4, C"),
    (set_4_d, 8, "SET 4, D"),
    (set_4_e, 8, "SET 4, E"),
    (set_4_h, 8, "SET 4, H"),
    (set_4_l, 8, "SET 4, L"),
    (set_4_mhl, 16, "SET 4, [HL]"),
    (set_4_a, 8, "SET 4, A"),
    (set_5_b, 8, "SET 5, B"),
    (set_5_c, 8, "SET 5, C"),
    (set_5_d, 8, "SET 5, D"),
    (set_5_e, 8, "SET 5, E"),
    (set_5_h, 8, "SET 5, H"),
    (set_5_l, 8, "SET 5, L"),
    (set_5_mhl, 16, "SET 5, [HL]"),
    (set_5_a, 8, "SET 5, A"),
    // 0xF opcodes
    (set_6_b, 8, "SET 6, B"),
    (set_6_c, 8, "SET 6, C"),
    (set_6_d, 8, "SET 6, D"),
    (set_6_e, 8, "SET 6, E"),
    (set_6_h, 8, "SET 6, H"),
    (set_6_l, 8, "SET 6, L"),
    (set_6_mhl, 16, "SET 6, [HL]"),
    (set_6_a, 8, "SET 6, A"),
    (set_7_b, 8, "SET 7, B"),
    (set_7_c, 8, "SET 7, C"),
    (set_7_d, 8, "SET 7, D"),
    (set_7_e, 8, "SET 7, E"),
    (set_7_h, 8, "SET 7, H"),
    (set_7_l, 8, "SET 7, L"),
    (set_7_mhl, 16, "SET 7, [HL]"),
    (set_7_a, 8, "SET 7, A"),
];

pub type Instruction = (fn(&mut Cpu), u8, &'static str);

fn nop(_cpu: &mut Cpu) {}

fn illegal(_cpu: &mut Cpu) {
    panic!("Illegal instruction");
}
fn ld_bc_u16(cpu: &mut Cpu) {
    let word = cpu.read_u16();
    cpu.set_bc(word);
}

fn ld_mbc_a(cpu: &mut Cpu) {
    cpu.mmu.write(cpu.bc(), cpu.a);
}

fn inc_bc(cpu: &mut Cpu) {
    cpu.set_bc(cpu.bc().wrapping_add(1));
}

fn inc_b(cpu: &mut Cpu) {
    let b = cpu.b;
    let value = b.wrapping_add(1);

    cpu.set_sub(false);
    cpu.set_zero(value == 0);
    cpu.set_half_carry((b & 0xf) == 0xf);

    cpu.b = value;
}

fn dec_b(cpu: &mut Cpu) {
    let b = cpu.b;
    let value = b.wrapping_sub(1);

    cpu.set_sub(true);
    cpu.set_zero(value == 0);
    cpu.set_half_carry((b & 0xf) == 0x0);

    cpu.b = value;
}

fn ld_b_u8(cpu: &mut Cpu) {
    let byte = cpu.read_u8();
    cpu.b = byte;
}

fn rlca(cpu: &mut Cpu) {
    let carry = cpu.a >> 7;

    cpu.a = cpu.a << 1 | carry;

    cpu.set_sub(false);
    cpu.set_zero(false);
    cpu.set_half_carry(false);
    cpu.set_carry(carry == 1);
}

fn ld_mu16_sp(cpu: &mut Cpu) {
    let word = cpu.read_u16();
    cpu.mmu.write(word, cpu.sp as u8);
    cpu.mmu.write(word + 1, (cpu.sp >> 8) as u8);
}

fn add_hl_bc(cpu: &mut Cpu) {
    let value = add_u16_u16(cpu, cpu.hl(), cpu.bc());
    cpu.set_hl(value);
}

fn ld_a_mbc(cpu: &mut Cpu) {
    let byte = cpu.mmu.read(cpu.bc());
    cpu.a = byte;
}

fn dec_bc(cpu: &mut Cpu) {
    cpu.set_bc(cpu.bc().wrapping_sub(1));
}

fn inc_c(cpu: &mut Cpu) {
    let c = cpu.c;
    let value = cpu.c.wrapping_add(1);

    cpu.set_sub(false);
    cpu.set_zero(value == 0);
    cpu.set_half_carry((c & 0xf) == 0xf);

    cpu.c = value;
}

fn dec_c(cpu: &mut Cpu) {
    let c = cpu.c;
    let value = c.wrapping_sub(1);

    cpu.set_sub(true);
    cpu.set_zero(value == 0);
    cpu.set_half_carry((c & 0xf) == 0x0);

    cpu.c = value;
}

fn ld_c_u8(cpu: &mut Cpu) {
    let byte = cpu.read_u8();
    cpu.c = byte;
}

fn rrca(cpu: &mut Cpu) {
    let carry = cpu.a & 0x1;
    cpu.a = (cpu.a >> 1) | (carry << 7);

    cpu.set_sub(false);
    cpu.set_zero(false);
    cpu.set_half_carry(false);
    cpu.set_carry(carry == 0x1);
}

fn stop(cpu: &mut Cpu) {
    cpu.stop();
}

fn ld_de_u16(cpu: &mut Cpu) {
    let word = cpu.read_u16();
    cpu.set_de(word);
}

fn ld_mde_a(cpu: &mut Cpu) {
    cpu.mmu.write(cpu.de(), cpu.a);
}

fn inc_de(cpu: &mut Cpu) {
    cpu.set_de(cpu.de().wrapping_add(1));
}

fn inc_d(cpu: &mut Cpu) {
    let d = cpu.d;
    let value = d.wrapping_add(1);

    cpu.set_sub(false);
    cpu.set_zero(value == 0);
    cpu.set_half_carry((d & 0xf) == 0xf);

    cpu.d = value;
}

fn dec_d(cpu: &mut Cpu) {
    let d = cpu.d;
    let value = d.wrapping_sub(1);
    cpu.set_sub(true);
    cpu.set_zero(value == 0);
    cpu.set_half_carry((d & 0xf) == 0x0);

    cpu.d = value;
}

fn ld_d_u8(cpu: &mut Cpu) {
    let byte = cpu.read_u8();
    cpu.d = byte;
}

fn rla(cpu: &mut Cpu) {
    let carry = cpu.carry();

    cpu.set_carry(cpu.a & 0x80 == 0x80);

    cpu.a = cpu.a << 1 | carry as u8;

    cpu.set_sub(false);
    cpu.set_zero(false);
    cpu.set_half_carry(false);
}

fn jr_i8(cpu: &mut Cpu) {
    let byte = cpu.read_u8() as i8;
    cpu.pc = (cpu.pc as i16).wrapping_add(byte as i16) as u16;
}

fn add_hl_de(cpu: &mut Cpu) {
    let value = add_u16_u16(cpu, cpu.hl(), cpu.de());
    cpu.set_hl(value);
}

fn ld_a_mde(cpu: &mut Cpu) {
    let byte = cpu.mmu.read(cpu.de());
    cpu.a = byte;
}

fn dec_de(cpu: &mut Cpu) {
    cpu.set_de(cpu.de().wrapping_sub(1));
}

fn inc_e(cpu: &mut Cpu) {
    let e = cpu.e;
    let value = cpu.e.wrapping_add(1);

    cpu.set_sub(false);
    cpu.set_zero(value == 0);
    cpu.set_half_carry((e & 0xf) == 0xf);

    cpu.e = value;
}

fn dec_e(cpu: &mut Cpu) {
    let e = cpu.e;
    let value = e.wrapping_sub(1);

    cpu.set_sub(true);
    cpu.set_zero(value == 0);
    cpu.set_half_carry((e & 0xf) == 0x0);

    cpu.e = value;
}

fn ld_e_u8(cpu: &mut Cpu) {
    let byte = cpu.read_u8();
    cpu.e = byte;
}
fn rra(cpu: &mut Cpu) {
    let carry = cpu.carry();

    cpu.set_carry((cpu.a & 0x1) == 0x1);

    cpu.a = cpu.a >> 1 | ((carry as u8) << 7);

    cpu.set_sub(false);
    cpu.set_zero(false);
    cpu.set_half_carry(false);
}

fn jr_nz_i8(cpu: &mut Cpu) {
    let byte = cpu.read_u8() as i8;

    if cpu.zero() {
        return;
    }

    cpu.pc = (cpu.pc as i16).wrapping_add(byte as i16) as u16;
    cpu.cycles = cpu.cycles.wrapping_add(4);
}

fn ld_hl_u16(cpu: &mut Cpu) {
    let word = cpu.read_u16();
    cpu.set_hl(word);
}

fn ld_mhli_a(cpu: &mut Cpu) {
    cpu.mmu.write(cpu.hl(), cpu.a);
    cpu.set_hl(cpu.hl().wrapping_add(1));
}

fn inc_hl(cpu: &mut Cpu) {
    cpu.set_hl(cpu.hl().wrapping_add(1));
}

fn inc_h(cpu: &mut Cpu) {
    let h = cpu.h;
    let value = cpu.h.wrapping_add(1);

    cpu.set_sub(false);
    cpu.set_zero(value == 0);
    cpu.set_half_carry((h & 0xf) == 0xf);

    cpu.h = value;
}

fn dec_h(cpu: &mut Cpu) {
    let h = cpu.h;
    let value = h.wrapping_sub(1);

    cpu.set_sub(true);
    cpu.set_zero(value == 0);
    cpu.set_half_carry((h & 0xf) == 0x0);

    cpu.h = value;
}

fn ld_h_u8(cpu: &mut Cpu) {
    let byte = cpu.read_u8();
    cpu.h = byte;
}

fn daa(cpu: &mut Cpu) {
    let a = cpu.a;
    let mut adjust = 0;

    if cpu.half_carry() {
        adjust |= 0x06;
    }

    if cpu.carry() {
        // Yes, we have to adjust it.
        adjust |= 0x60;
    }

    let res = if cpu.sub() {
        a.wrapping_sub(adjust)
    } else {
        if a & 0x0f > 0x09 {
            adjust |= 0x06;
        }

        if a > 0x99 {
            adjust |= 0x60;
        }

        a.wrapping_add(adjust)
    };

    cpu.a = res;

    cpu.set_zero(res == 0);
    cpu.set_half_carry(false);
    cpu.set_carry(adjust & 0x60 == 0x60);
}

fn jr_z_i8(cpu: &mut Cpu) {
    let byte = cpu.read_u8() as i8;

    if !cpu.zero() {
        return;
    }

    cpu.pc = (cpu.pc as i16).wrapping_add(byte as i16) as u16;
    cpu.cycles = cpu.cycles.wrapping_add(4);
}

fn add_hl_hl(cpu: &mut Cpu) {
    let value = add_u16_u16(cpu, cpu.hl(), cpu.hl());
    cpu.set_hl(value);
}

fn ld_a_mhli(cpu: &mut Cpu) {
    let byte = cpu.mmu.read(cpu.hl());
    cpu.a = byte;
    cpu.set_hl(cpu.hl().wrapping_add(1));
}

fn dec_hl(cpu: &mut Cpu) {
    cpu.set_hl(cpu.hl().wrapping_sub(1));
}

fn inc_l(cpu: &mut Cpu) {
    let l = cpu.l;
    let value = l.wrapping_add(1);

    cpu.set_sub(false);
    cpu.set_zero(value == 0);
    cpu.set_half_carry((l & 0xf) == 0xf);

    cpu.l = value;
}

fn dec_l(cpu: &mut Cpu) {
    let l = cpu.l;
    let value = l.wrapping_sub(1);

    cpu.set_sub(true);
    cpu.set_zero(value == 0);
    cpu.set_half_carry((l & 0xf) == 0x0);

    cpu.l = value;
}

fn ld_l_u8(cpu: &mut Cpu) {
    let byte = cpu.read_u8();
    cpu.l = byte;
}

fn cpl(cpu: &mut Cpu) {
    cpu.a = !cpu.a;

    cpu.set_sub(true);
    cpu.set_half_carry(true);
}

fn ld_sp_u16(cpu: &mut Cpu) {
    cpu.sp = cpu.read_u16();
}

fn jr_nc_i8(cpu: &mut Cpu) {
    let byte = cpu.read_u8() as i8;

    if cpu.carry() {
        return;
    }

    cpu.pc = (cpu.pc as i16).wrapping_add(byte as i16) as u16;
    cpu.cycles = cpu.cycles.wrapping_add(4);
}

fn ld_mhld_a(cpu: &mut Cpu) {
    cpu.mmu.write(cpu.hl(), cpu.a);
    cpu.set_hl(cpu.hl().wrapping_sub(1));
}

fn inc_sp(cpu: &mut Cpu) {
    cpu.sp = cpu.sp.wrapping_add(1);
}

fn inc_mhl(cpu: &mut Cpu) {
    let byte = cpu.mmu.read(cpu.hl());
    let value = byte.wrapping_add(1);

    cpu.set_sub(false);
    cpu.set_zero(value == 0);
    cpu.set_half_carry((byte & 0xf) == 0xf);

    cpu.mmu.write(cpu.hl(), value);
}

fn dec_mhl(cpu: &mut Cpu) {
    let byte = cpu.mmu.read(cpu.hl());
    let value = byte.wrapping_sub(1);

    cpu.set_sub(true);
    cpu.set_zero(value == 0);
    cpu.set_half_carry((byte & 0xf) == 0x0);

    cpu.mmu.write(cpu.hl(), value);
}

fn ld_mhl_u8(cpu: &mut Cpu) {
    let byte = cpu.read_u8();
    cpu.mmu.write(cpu.hl(), byte);
}

fn scf(cpu: &mut Cpu) {
    cpu.set_sub(false);
    cpu.set_half_carry(false);
    cpu.set_carry(true);
}

fn jr_c_i8(cpu: &mut Cpu) {
    let byte = cpu.read_u8() as i8;

    if !cpu.carry() {
        return;
    }

    cpu.pc = (cpu.pc as i16).wrapping_add(byte as i16) as u16;
    cpu.cycles = cpu.cycles.wrapping_add(4);
}

fn add_hl_sp(cpu: &mut Cpu) {
    let value = add_u16_u16(cpu, cpu.hl(), cpu.sp());
    cpu.set_hl(value);
}

fn ld_a_mhld(cpu: &mut Cpu) {
    let byte = cpu.mmu.read(cpu.hl());
    cpu.a = byte;
    cpu.set_hl(cpu.hl().wrapping_sub(1));
}

fn dec_sp(cpu: &mut Cpu) {
    cpu.sp = cpu.sp.wrapping_sub(1);
}

fn inc_a(cpu: &mut Cpu) {
    let a = cpu.a;
    let value = a.wrapping_add(1);

    cpu.set_sub(false);
    cpu.set_zero(value == 0);
    cpu.set_half_carry((a & 0xf) == 0xf);

    cpu.a = value;
}

fn dec_a(cpu: &mut Cpu) {
    let a = cpu.a;
    let value = a.wrapping_sub(1);

    cpu.set_sub(true);
    cpu.set_zero(value == 0);
    cpu.set_half_carry((a & 0xf) == 0x0);

    cpu.a = value;
}

fn ld_a_u8(cpu: &mut Cpu) {
    let byte = cpu.read_u8();
    cpu.a = byte;
}

fn ccf(cpu: &mut Cpu) {
    cpu.set_sub(false);
    cpu.set_half_carry(false);
    cpu.set_carry(!cpu.carry());
}

fn ld_b_b(_cpu: &mut Cpu) {}

fn ld_b_c(cpu: &mut Cpu) {
    cpu.b = cpu.c;
}
fn ld_b_d(cpu: &mut Cpu) {
    cpu.b = cpu.d;
}

fn ld_b_e(cpu: &mut Cpu) {
    cpu.b = cpu.e;
}

fn ld_b_h(cpu: &mut Cpu) {
    cpu.b = cpu.h;
}

fn ld_b_l(cpu: &mut Cpu) {
    cpu.b = cpu.l;
}

fn ld_b_mhl(cpu: &mut Cpu) {
    let byte = cpu.mmu.read(cpu.hl());
    cpu.b = byte;
}

fn ld_b_a(cpu: &mut Cpu) {
    cpu.b = cpu.a;
}

fn ld_c_b(cpu: &mut Cpu) {
    cpu.c = cpu.b;
}

fn ld_c_c(_cpu: &mut Cpu) {}

fn ld_c_d(cpu: &mut Cpu) {
    cpu.c = cpu.d;
}

fn ld_c_e(cpu: &mut Cpu) {
    cpu.c = cpu.e;
}

fn ld_c_h(cpu: &mut Cpu) {
    cpu.c = cpu.h;
}

fn ld_c_l(cpu: &mut Cpu) {
    cpu.c = cpu.l;
}

fn ld_c_mhl(cpu: &mut Cpu) {
    let byte = cpu.mmu.read(cpu.hl());
    cpu.c = byte;
}

fn ld_c_a(cpu: &mut Cpu) {
    cpu.c = cpu.a;
}

fn ld_d_b(cpu: &mut Cpu) {
    cpu.d = cpu.b;
}

fn ld_d_c(cpu: &mut Cpu) {
    cpu.d = cpu.c;
}

fn ld_d_d(_cpu: &mut Cpu) {}

fn ld_d_e(cpu: &mut Cpu) {
    cpu.d = cpu.e;
}
fn ld_d_h(cpu: &mut Cpu) {
    cpu.d = cpu.h;
}

fn ld_d_l(cpu: &mut Cpu) {
    cpu.d = cpu.l;
}

fn ld_d_mhl(cpu: &mut Cpu) {
    let byte = cpu.mmu.read(cpu.hl());
    cpu.d = byte;
}

fn ld_d_a(cpu: &mut Cpu) {
    cpu.d = cpu.a;
}

fn ld_e_b(cpu: &mut Cpu) {
    cpu.e = cpu.b;
}

fn ld_e_c(cpu: &mut Cpu) {
    cpu.e = cpu.c;
}

fn ld_e_d(cpu: &mut Cpu) {
    cpu.e = cpu.d;
}

fn ld_e_e(_cpu: &mut Cpu) {}

fn ld_e_h(cpu: &mut Cpu) {
    cpu.e = cpu.h;
}

fn ld_e_l(cpu: &mut Cpu) {
    cpu.e = cpu.l;
}

fn ld_e_mhl(cpu: &mut Cpu) {
    let byte = cpu.mmu.read(cpu.hl());
    cpu.e = byte;
}

fn ld_e_a(cpu: &mut Cpu) {
    cpu.e = cpu.a;
}

fn ld_h_b(cpu: &mut Cpu) {
    cpu.h = cpu.b;
}

fn ld_h_c(cpu: &mut Cpu) {
    cpu.h = cpu.c;
}

fn ld_h_d(cpu: &mut Cpu) {
    cpu.h = cpu.d;
}

fn ld_h_e(cpu: &mut Cpu) {
    cpu.h = cpu.e;
}

fn ld_h_h(_cpu: &mut Cpu) {}

fn ld_h_l(cpu: &mut Cpu) {
    cpu.h = cpu.l;
}
fn ld_h_mhl(cpu: &mut Cpu) {
    let byte = cpu.mmu.read(cpu.hl());
    cpu.h = byte;
}

fn ld_h_a(cpu: &mut Cpu) {
    cpu.h = cpu.a;
}

fn ld_l_b(cpu: &mut Cpu) {
    cpu.l = cpu.b;
}

fn ld_l_c(cpu: &mut Cpu) {
    cpu.l = cpu.c;
}

fn ld_l_d(cpu: &mut Cpu) {
    cpu.l = cpu.d;
}

fn ld_l_e(cpu: &mut Cpu) {
    cpu.l = cpu.e;
}

fn ld_l_h(cpu: &mut Cpu) {
    cpu.l = cpu.h;
}

fn ld_l_l(_cpu: &mut Cpu) {}

fn ld_l_mhl(cpu: &mut Cpu) {
    let byte = cpu.mmu.read(cpu.hl());
    cpu.l = byte;
}

fn ld_l_a(cpu: &mut Cpu) {
    cpu.l = cpu.a;
}

fn ld_mhl_b(cpu: &mut Cpu) {
    cpu.mmu.write(cpu.hl(), cpu.b);
}

fn ld_mhl_c(cpu: &mut Cpu) {
    cpu.mmu.write(cpu.hl(), cpu.c);
}

fn ld_mhl_d(cpu: &mut Cpu) {
    cpu.mmu.write(cpu.hl(), cpu.d);
}

fn ld_mhl_e(cpu: &mut Cpu) {
    cpu.mmu.write(cpu.hl(), cpu.e);
}

fn ld_mhl_h(cpu: &mut Cpu) {
    cpu.mmu.write(cpu.hl(), cpu.h);
}

fn ld_mhl_l(cpu: &mut Cpu) {
    cpu.mmu.write(cpu.hl(), cpu.l);
}

fn halt(cpu: &mut Cpu) {
    cpu.halt();
}

fn ld_mhl_a(cpu: &mut Cpu) {
    cpu.mmu.write(cpu.hl(), cpu.a);
}

fn ld_a_b(cpu: &mut Cpu) {
    cpu.a = cpu.b;
}

fn ld_a_c(cpu: &mut Cpu) {
    cpu.a = cpu.c;
}

fn ld_a_d(cpu: &mut Cpu) {
    cpu.a = cpu.d;
}

fn ld_a_e(cpu: &mut Cpu) {
    cpu.a = cpu.e;
}

fn ld_a_h(cpu: &mut Cpu) {
    cpu.a = cpu.h;
}

fn ld_a_l(cpu: &mut Cpu) {
    cpu.a = cpu.l;
}

fn ld_a_mhl(cpu: &mut Cpu) {
    let byte = cpu.mmu.read(cpu.hl());
    cpu.a = byte;
}

fn ld_a_a(_cpu: &mut Cpu) {}

fn add_a_b(cpu: &mut Cpu) {
    cpu.a = add_set_flags(cpu, cpu.a, cpu.b);
}

fn add_a_c(cpu: &mut Cpu) {
    cpu.a = add_set_flags(cpu, cpu.a, cpu.c);
}

fn add_a_d(cpu: &mut Cpu) {
    cpu.a = add_set_flags(cpu, cpu.a, cpu.d);
}

fn add_a_e(cpu: &mut Cpu) {
    cpu.a = add_set_flags(cpu, cpu.a, cpu.e);
}

fn add_a_h(cpu: &mut Cpu) {
    cpu.a = add_set_flags(cpu, cpu.a, cpu.h);
}

fn add_a_l(cpu: &mut Cpu) {
    cpu.a = add_set_flags(cpu, cpu.a, cpu.l);
}

fn add_a_mhl(cpu: &mut Cpu) {
    let byte = cpu.mmu.read(cpu.hl());
    cpu.a = add_set_flags(cpu, cpu.a, byte);
}

fn add_a_a(cpu: &mut Cpu) {
    cpu.a = add_set_flags(cpu, cpu.a, cpu.a);
}

fn adc_a_b(cpu: &mut Cpu) {
    cpu.a = add_carry_set_flags(cpu, cpu.a, cpu.b);
}
fn adc_a_c(cpu: &mut Cpu) {
    cpu.a = add_carry_set_flags(cpu, cpu.a, cpu.c);
}

fn adc_a_d(cpu: &mut Cpu) {
    cpu.a = add_carry_set_flags(cpu, cpu.a, cpu.d);
}

fn adc_a_e(cpu: &mut Cpu) {
    cpu.a = add_carry_set_flags(cpu, cpu.a, cpu.e);
}

fn adc_a_h(cpu: &mut Cpu) {
    cpu.a = add_carry_set_flags(cpu, cpu.a, cpu.h);
}

fn adc_a_l(cpu: &mut Cpu) {
    cpu.a = add_carry_set_flags(cpu, cpu.a, cpu.l);
}

fn adc_a_mhl(cpu: &mut Cpu) {
    let byte = cpu.mmu.read(cpu.hl());
    cpu.a = add_carry_set_flags(cpu, cpu.a, byte);
}

fn adc_a_a(cpu: &mut Cpu) {
    cpu.a = add_carry_set_flags(cpu, cpu.a, cpu.a);
}

fn sub_a_b(cpu: &mut Cpu) {
    cpu.a = sub_set_flags(cpu, cpu.a, cpu.b);
}

fn sub_a_c(cpu: &mut Cpu) {
    cpu.a = sub_set_flags(cpu, cpu.a, cpu.c);
}

fn sub_a_d(cpu: &mut Cpu) {
    cpu.a = sub_set_flags(cpu, cpu.a, cpu.d);
}

fn sub_a_e(cpu: &mut Cpu) {
    cpu.a = sub_set_flags(cpu, cpu.a, cpu.e);
}

fn sub_a_h(cpu: &mut Cpu) {
    cpu.a = sub_set_flags(cpu, cpu.a, cpu.h);
}

fn sub_a_l(cpu: &mut Cpu) {
    cpu.a = sub_set_flags(cpu, cpu.a, cpu.l);
}

fn sub_a_mhl(cpu: &mut Cpu) {
    let byte = cpu.mmu.read(cpu.hl());
    cpu.a = sub_set_flags(cpu, cpu.a, byte);
}

fn sub_a_a(cpu: &mut Cpu) {
    cpu.a = sub_set_flags(cpu, cpu.a, cpu.a);
}

fn sbc_a_b(cpu: &mut Cpu) {
    cpu.a = sub_carry_set_flags(cpu, cpu.a, cpu.b);
}

fn sbc_a_c(cpu: &mut Cpu) {
    cpu.a = sub_carry_set_flags(cpu, cpu.a, cpu.c);
}
fn sbc_a_d(cpu: &mut Cpu) {
    cpu.a = sub_carry_set_flags(cpu, cpu.a, cpu.d);
}

fn sbc_a_e(cpu: &mut Cpu) {
    cpu.a = sub_carry_set_flags(cpu, cpu.a, cpu.e);
}

fn sbc_a_h(cpu: &mut Cpu) {
    cpu.a = sub_carry_set_flags(cpu, cpu.a, cpu.h);
}

fn sbc_a_l(cpu: &mut Cpu) {
    cpu.a = sub_carry_set_flags(cpu, cpu.a, cpu.l);
}

fn sbc_a_mhl(cpu: &mut Cpu) {
    let byte = cpu.mmu.read(cpu.hl());
    cpu.a = sub_carry_set_flags(cpu, cpu.a, byte);
}

fn sbc_a_a(cpu: &mut Cpu) {
    cpu.a = sub_carry_set_flags(cpu, cpu.a, cpu.a);
}

fn and_a_b(cpu: &mut Cpu) {
    cpu.a &= cpu.b;

    cpu.set_sub(false);
    cpu.set_zero(cpu.a == 0);
    cpu.set_half_carry(true);
    cpu.set_carry(false);
}

fn and_a_c(cpu: &mut Cpu) {
    cpu.a &= cpu.c;

    cpu.set_sub(false);
    cpu.set_zero(cpu.a == 0);
    cpu.set_half_carry(true);
    cpu.set_carry(false);
}

fn and_a_d(cpu: &mut Cpu) {
    cpu.a &= cpu.d;

    cpu.set_sub(false);
    cpu.set_zero(cpu.a == 0);
    cpu.set_half_carry(true);
    cpu.set_carry(false);
}

fn and_a_e(cpu: &mut Cpu) {
    cpu.a &= cpu.e;

    cpu.set_sub(false);
    cpu.set_zero(cpu.a == 0);
    cpu.set_half_carry(true);
    cpu.set_carry(false);
}

fn and_a_h(cpu: &mut Cpu) {
    cpu.a &= cpu.h;

    cpu.set_sub(false);
    cpu.set_zero(cpu.a == 0);
    cpu.set_half_carry(true);
    cpu.set_carry(false);
}
fn and_a_l(cpu: &mut Cpu) {
    cpu.a &= cpu.l;

    cpu.set_sub(false);
    cpu.set_zero(cpu.a == 0);
    cpu.set_half_carry(true);
    cpu.set_carry(false);
}

fn and_a_mhl(cpu: &mut Cpu) {
    let byte = cpu.mmu.read(cpu.hl());
    cpu.a &= byte;

    cpu.set_sub(false);
    cpu.set_zero(cpu.a == 0);
    cpu.set_half_carry(true);
    cpu.set_carry(false);
}

fn and_a_a(cpu: &mut Cpu) {
    cpu.a &= cpu.a;

    cpu.set_sub(false);
    cpu.set_zero(cpu.a == 0);
    cpu.set_half_carry(true);
    cpu.set_carry(false);
}

fn xor_a_b(cpu: &mut Cpu) {
    cpu.a ^= cpu.b;

    cpu.set_sub(false);
    cpu.set_zero(cpu.a == 0);
    cpu.set_half_carry(false);
    cpu.set_carry(false);
}

fn xor_a_c(cpu: &mut Cpu) {
    cpu.a ^= cpu.c;

    cpu.set_sub(false);
    cpu.set_zero(cpu.a == 0);
    cpu.set_half_carry(false);
    cpu.set_carry(false);
}

fn xor_a_d(cpu: &mut Cpu) {
    cpu.a ^= cpu.d;

    cpu.set_sub(false);
    cpu.set_zero(cpu.a == 0);
    cpu.set_half_carry(false);
    cpu.set_carry(false);
}

fn xor_a_e(cpu: &mut Cpu) {
    cpu.a ^= cpu.e;

    cpu.set_sub(false);
    cpu.set_zero(cpu.a == 0);
    cpu.set_half_carry(false);
    cpu.set_carry(false);
}

fn xor_a_h(cpu: &mut Cpu) {
    cpu.a ^= cpu.h;

    cpu.set_sub(false);
    cpu.set_zero(cpu.a == 0);
    cpu.set_half_carry(false);
    cpu.set_carry(false);
}

fn xor_a_l(cpu: &mut Cpu) {
    cpu.a ^= cpu.l;

    cpu.set_sub(false);
    cpu.set_zero(cpu.a == 0);
    cpu.set_half_carry(false);
    cpu.set_carry(false);
}

fn xor_a_mhl(cpu: &mut Cpu) {
    let byte = cpu.mmu.read(cpu.hl());
    cpu.a ^= byte;

    cpu.set_sub(false);
    cpu.set_zero(cpu.a == 0);
    cpu.set_half_carry(false);
    cpu.set_carry(false);
}

fn xor_a_a(cpu: &mut Cpu) {
    cpu.a ^= cpu.a;

    cpu.set_sub(false);
    cpu.set_zero(cpu.a == 0);
    cpu.set_half_carry(false);
    cpu.set_carry(false);
}

fn or_a_b(cpu: &mut Cpu) {
    cpu.a |= cpu.b;

    cpu.set_sub(false);
    cpu.set_zero(cpu.a == 0);
    cpu.set_half_carry(false);
    cpu.set_carry(false);
}

fn or_a_c(cpu: &mut Cpu) {
    cpu.a |= cpu.c;

    cpu.set_sub(false);
    cpu.set_zero(cpu.a == 0);
    cpu.set_half_carry(false);
    cpu.set_carry(false);
}

fn or_a_d(cpu: &mut Cpu) {
    cpu.a |= cpu.d;

    cpu.set_sub(false);
    cpu.set_zero(cpu.a == 0);
    cpu.set_half_carry(false);
    cpu.set_carry(false);
}

fn or_a_e(cpu: &mut Cpu) {
    cpu.a |= cpu.e;

    cpu.set_sub(false);
    cpu.set_zero(cpu.a == 0);
    cpu.set_half_carry(false);
    cpu.set_carry(false);
}

fn or_a_h(cpu: &mut Cpu) {
    cpu.a |= cpu.h;
    cpu.set_sub(false);
    cpu.set_zero(cpu.a == 0);
    cpu.set_half_carry(false);
    cpu.set_carry(false);
}

fn or_a_l(cpu: &mut Cpu) {
    cpu.a |= cpu.l;

    cpu.set_sub(false);
    cpu.set_zero(cpu.a == 0);
    cpu.set_half_carry(false);
    cpu.set_carry(false);
}

fn or_a_mhl(cpu: &mut Cpu) {
    let byte = cpu.mmu.read(cpu.hl());
    cpu.a |= byte;

    cpu.set_sub(false);
    cpu.set_zero(cpu.a == 0);
    cpu.set_half_carry(false);
    cpu.set_carry(false);
}

fn or_a_a(cpu: &mut Cpu) {
    cpu.a |= cpu.a;

    cpu.set_sub(false);
    cpu.set_zero(cpu.a == 0);
    cpu.set_half_carry(false);
    cpu.set_carry(false);
}

fn cp_a_b(cpu: &mut Cpu) {
    sub_set_flags(cpu, cpu.a, cpu.b);
}

fn cp_a_c(cpu: &mut Cpu) {
    sub_set_flags(cpu, cpu.a, cpu.c);
}

fn cp_a_d(cpu: &mut Cpu) {
    sub_set_flags(cpu, cpu.a, cpu.d);
}

fn cp_a_e(cpu: &mut Cpu) {
    sub_set_flags(cpu, cpu.a, cpu.e);
}

fn cp_a_h(cpu: &mut Cpu) {
    sub_set_flags(cpu, cpu.a, cpu.h);
}

fn cp_a_l(cpu: &mut Cpu) {
    sub_set_flags(cpu, cpu.a, cpu.l);
}

fn cp_a_mhl(cpu: &mut Cpu) {
    let byte = cpu.mmu.read(cpu.hl());
    sub_set_flags(cpu, cpu.a, byte);
}

fn cp_a_a(cpu: &mut Cpu) {
    sub_set_flags(cpu, cpu.a, cpu.a);
}

fn ret_nz(cpu: &mut Cpu) {
    if cpu.zero() {
        return;
    }

    cpu.pc = cpu.pop_word();
    cpu.cycles = cpu.cycles.wrapping_add(12);
}

fn pop_bc(cpu: &mut Cpu) {
    let word = cpu.pop_word();
    cpu.set_bc(word);
}

fn jp_nz_u16(cpu: &mut Cpu) {
    let word = cpu.read_u16();

    if cpu.zero() {
        return;
    }

    cpu.pc = word;
    cpu.cycles = cpu.cycles.wrapping_add(4);
}

fn jp_u16(cpu: &mut Cpu) {
    let word = cpu.read_u16();
    cpu.pc = word;
}

fn call_nz_u16(cpu: &mut Cpu) {
    let word = cpu.read_u16();

    if cpu.zero() {
        return;
    }

    cpu.push_word(cpu.pc);
    cpu.pc = word;
    cpu.cycles = cpu.cycles.wrapping_add(12);
}

fn push_bc(cpu: &mut Cpu) {
    cpu.push_word(cpu.bc());
}

fn add_a_u8(cpu: &mut Cpu) {
    let byte = cpu.read_u8();
    cpu.a = add_set_flags(cpu, cpu.a, byte);
}

fn rst_00h(cpu: &mut Cpu) {
    rst(cpu, 0x0000);
}

fn ret_z(cpu: &mut Cpu) {
    if !cpu.zero() {
        return;
    }

    cpu.pc = cpu.pop_word();
    cpu.cycles = cpu.cycles.wrapping_add(12);
}

fn ret(cpu: &mut Cpu) {
    cpu.pc = cpu.pop_word();
}

fn jp_z_u16(cpu: &mut Cpu) {
    let word = cpu.read_u16();

    if !cpu.zero() {
        return;
    }

    cpu.pc = word;
    cpu.cycles = cpu.cycles.wrapping_add(4);
}

fn call_z_u16(cpu: &mut Cpu) {
    let word = cpu.read_u16();

    if !cpu.zero() {
        return;
    }

    cpu.push_word(cpu.pc);
    cpu.pc = word;
    cpu.cycles = cpu.cycles.wrapping_add(12);
}

fn call_u16(cpu: &mut Cpu) {
    let word = cpu.read_u16();
    cpu.push_word(cpu.pc);
    cpu.pc = word;
}

fn adc_a_u8(cpu: &mut Cpu) {
    let byte = cpu.read_u8();
    cpu.a = add_carry_set_flags(cpu, cpu.a, byte);
}

fn rst_08h(cpu: &mut Cpu) {
    rst(cpu, 0x0008);
}

fn ret_nc(cpu: &mut Cpu) {
    if cpu.carry() {
        return;
    }

    cpu.pc = cpu.pop_word();
    cpu.cycles = cpu.cycles.wrapping_add(12);
}

fn pop_de(cpu: &mut Cpu) {
    let word = cpu.pop_word();
    cpu.set_de(word);
}

fn jp_nc_u16(cpu: &mut Cpu) {
    let word = cpu.read_u16();

    if cpu.carry() {
        return;
    }

    cpu.pc = word;
    cpu.cycles = cpu.cycles.wrapping_add(4);
}

fn call_nc_u16(cpu: &mut Cpu) {
    let word = cpu.read_u16();

    if cpu.carry() {
        return;
    }

    cpu.push_word(cpu.pc);
    cpu.pc = word;
    cpu.cycles = cpu.cycles.wrapping_add(12);
}
fn push_de(cpu: &mut Cpu) {
    cpu.push_word(cpu.de());
}

fn sub_a_u8(cpu: &mut Cpu) {
    let byte = cpu.read_u8();
    cpu.a = sub_set_flags(cpu, cpu.a, byte);
}

fn rst_10h(cpu: &mut Cpu) {
    rst(cpu, 0x0010);
}

fn ret_c(cpu: &mut Cpu) {
    if !cpu.carry() {
        return;
    }

    cpu.pc = cpu.pop_word();
    cpu.cycles = cpu.cycles.wrapping_add(12);
}

fn reti(cpu: &mut Cpu) {
    cpu.pc = cpu.pop_word();
    cpu.enable_int();
}

fn jp_c_u16(cpu: &mut Cpu) {
    let word = cpu.read_u16();

    if !cpu.carry() {
        return;
    }

    cpu.pc = word;
    cpu.cycles = cpu.cycles.wrapping_add(4);
}

fn call_c_u16(cpu: &mut Cpu) {
    let word = cpu.read_u16();

    if !cpu.carry() {
        return;
    }

    cpu.push_word(cpu.pc);
    cpu.pc = word;
    cpu.cycles = cpu.cycles.wrapping_add(12);
}

fn sbc_a_u8(cpu: &mut Cpu) {
    let byte = cpu.read_u8();
    cpu.a = sub_carry_set_flags(cpu, cpu.a, byte);
}

fn rst_18h(cpu: &mut Cpu) {
    rst(cpu, 0x0018);
}

fn ld_mff00u8_a(cpu: &mut Cpu) {
    let byte = cpu.read_u8();
    cpu.mmu.write(0xff00 + byte as u16, cpu.a);
}

fn pop_hl(cpu: &mut Cpu) {
    let word = cpu.pop_word();
    cpu.set_hl(word);
}

fn ld_mff00c_a(cpu: &mut Cpu) {
    cpu.mmu.write(0xff00 + cpu.c as u16, cpu.a);
}

fn push_hl(cpu: &mut Cpu) {
    cpu.push_word(cpu.hl());
}

fn and_a_u8(cpu: &mut Cpu) {
    let byte = cpu.read_u8();

    cpu.a &= byte;

    cpu.set_sub(false);
    cpu.set_zero(cpu.a == 0);
    cpu.set_half_carry(true);
    cpu.set_carry(false);
}

fn rst_20h(cpu: &mut Cpu) {
    rst(cpu, 0x0020);
}

fn add_sp_i8(cpu: &mut Cpu) {
    let sp = cpu.sp as i32;
    let byte = cpu.read_u8() as i8;
    let byte_i32 = byte as i32;

    let result = sp.wrapping_add(byte_i32);

    cpu.set_sub(false);
    cpu.set_zero(false);
    cpu.set_half_carry((sp ^ byte_i32 ^ result) & 0x10 == 0x10);
    cpu.set_carry((sp ^ byte_i32 ^ result) & 0x100 == 0x100);

    cpu.sp = result as u16;
}

fn jp_hl(cpu: &mut Cpu) {
    cpu.pc = cpu.hl();
}

fn ld_mu16_a(cpu: &mut Cpu) {
    let word = cpu.read_u16();
    cpu.mmu.write(word, cpu.a);
}

fn xor_a_u8(cpu: &mut Cpu) {
    let byte = cpu.read_u8();
    cpu.a ^= byte;

    cpu.set_sub(false);
    cpu.set_zero(cpu.a == 0);
    cpu.set_half_carry(false);
    cpu.set_carry(false);
}

fn rst_28h(cpu: &mut Cpu) {
    rst(cpu, 0x0028);
}

fn ld_a_mff00u8(cpu: &mut Cpu) {
    let byte = cpu.read_u8();
    cpu.a = cpu.mmu.read(0xff00 + byte as u16);
}

fn pop_af(cpu: &mut Cpu) {
    let word = cpu.pop_word();
    cpu.set_af(word);
}
fn ld_a_mff00c(cpu: &mut Cpu) {
    cpu.a = cpu.mmu.read(0xff00 + cpu.c as u16);
}

fn di(cpu: &mut Cpu) {
    cpu.disable_int();
}

fn push_af(cpu: &mut Cpu) {
    cpu.push_word(cpu.af());
}

fn or_a_u8(cpu: &mut Cpu) {
    let byte = cpu.read_u8();
    cpu.a |= byte;

    cpu.set_sub(false);
    cpu.set_zero(cpu.a == 0);
    cpu.set_half_carry(false);
    cpu.set_carry(false);
}

fn rst_30h(cpu: &mut Cpu) {
    rst(cpu, 0x0030);
}

fn ld_hl_spi8(cpu: &mut Cpu) {
    let sp = cpu.sp as i32;
    let byte = cpu.read_u8() as i8;
    let byte_i32 = byte as i32;

    let result = sp.wrapping_add(byte_i32);

    cpu.set_sub(false);
    cpu.set_zero(false);
    cpu.set_half_carry((sp ^ byte_i32 ^ result) & 0x10 == 0x10);
    cpu.set_carry((sp ^ byte_i32 ^ result) & 0x100 == 0x100);

    cpu.set_hl(result as u16);
}

fn ld_sp_hl(cpu: &mut Cpu) {
    cpu.sp = cpu.hl();
}

fn ld_a_mu16(cpu: &mut Cpu) {
    let word = cpu.read_u16();
    let byte = cpu.mmu.read(word);
    cpu.a = byte;
}

fn ei(cpu: &mut Cpu) {
    cpu.enable_int();
}

fn cp_a_u8(cpu: &mut Cpu) {
    let byte = cpu.read_u8();
    sub_set_flags(cpu, cpu.a, byte);
}

fn rst_38h(cpu: &mut Cpu) {
    rst(cpu, 0x0038);
}

fn rlc_b(cpu: &mut Cpu) {
    cpu.b = rlc(cpu, cpu.b);
}

fn rlc_c(cpu: &mut Cpu) {
    cpu.c = rlc(cpu, cpu.c);
}

fn rlc_d(cpu: &mut Cpu) {
    cpu.d = rlc(cpu, cpu.d);
}

fn rlc_e(cpu: &mut Cpu) {
    cpu.e = rlc(cpu, cpu.e);
}

fn rlc_h(cpu: &mut Cpu) {
    cpu.h = rlc(cpu, cpu.h);
}

fn rlc_l(cpu: &mut Cpu) {
    cpu.l = rlc(cpu, cpu.l);
}

fn rlc_mhl(cpu: &mut Cpu) {
    let hl = cpu.hl();
    let byte = cpu.mmu.read(hl);
    let result = rlc(cpu, byte);
    cpu.mmu.write(hl, result);
}

fn rlc_a(cpu: &mut Cpu) {
    cpu.a = rlc(cpu, cpu.a);
}

fn rrc_b(cpu: &mut Cpu) {
    cpu.b = rrc(cpu, cpu.b);
}

fn rrc_c(cpu: &mut Cpu) {
    cpu.c = rrc(cpu, cpu.c);
}

fn rrc_d(cpu: &mut Cpu) {
    cpu.d = rrc(cpu, cpu.d);
}

fn rrc_e(cpu: &mut Cpu) {
    cpu.e = rrc(cpu, cpu.e);
}

fn rrc_h(cpu: &mut Cpu) {
    cpu.h = rrc(cpu, cpu.h);
}

fn rrc_l(cpu: &mut Cpu) {
    cpu.l = rrc(cpu, cpu.l);
}

fn rrc_mhl(cpu: &mut Cpu) {
    let hl = cpu.hl();
    let byte = cpu.mmu.read(hl);
    let result = rrc(cpu, byte);
    cpu.mmu.write(hl, result);
}

fn rrc_a(cpu: &mut Cpu) {
    cpu.a = rrc(cpu, cpu.a);
}

fn rl_b(cpu: &mut Cpu) {
    cpu.b = rl(cpu, cpu.b);
}

fn rl_c(cpu: &mut Cpu) {
    cpu.c = rl(cpu, cpu.c);
}

fn rl_d(cpu: &mut Cpu) {
    cpu.d = rl(cpu, cpu.d);
}

fn rl_e(cpu: &mut Cpu) {
    cpu.e = rl(cpu, cpu.e);
}

fn rl_h(cpu: &mut Cpu) {
    cpu.h = rl(cpu, cpu.h);
}

fn rl_l(cpu: &mut Cpu) {
    cpu.l = rl(cpu, cpu.l);
}

fn rl_mhl(cpu: &mut Cpu) {
    let hl = cpu.hl();
    let byte = cpu.mmu.read(hl);
    let result = rl(cpu, byte);
    cpu.mmu.write(hl, result);
}

fn rl_a(cpu: &mut Cpu) {
    cpu.a = rl(cpu, cpu.a);
}

fn rr_b(cpu: &mut Cpu) {
    cpu.b = rr(cpu, cpu.b);
}

fn rr_c(cpu: &mut Cpu) {
    cpu.c = rr(cpu, cpu.c);
}

fn rr_d(cpu: &mut Cpu) {
    cpu.d = rr(cpu, cpu.d);
}

fn rr_e(cpu: &mut Cpu) {
    cpu.e = rr(cpu, cpu.e);
}

fn rr_h(cpu: &mut Cpu) {
    cpu.h = rr(cpu, cpu.h);
}

fn rr_l(cpu: &mut Cpu) {
    cpu.l = rr(cpu, cpu.l);
}

fn rr_mhl(cpu: &mut Cpu) {
    let hl = cpu.hl();
    let byte = cpu.mmu.read(hl);
    let result = rr(cpu, byte);
    cpu.mmu.write(hl, result);
}

fn rr_a(cpu: &mut Cpu) {
    cpu.a = rr(cpu, cpu.a);
}

fn sla_b(cpu: &mut Cpu) {
    cpu.b = sla(cpu, cpu.b);
}

fn sla_c(cpu: &mut Cpu) {
    cpu.c = sla(cpu, cpu.c);
}

fn sla_d(cpu: &mut Cpu) {
    cpu.d = sla(cpu, cpu.d);
}

fn sla_e(cpu: &mut Cpu) {
    cpu.e = sla(cpu, cpu.e);
}

fn sla_h(cpu: &mut Cpu) {
    cpu.h = sla(cpu, cpu.h);
}

fn sla_l(cpu: &mut Cpu) {
    cpu.l = sla(cpu, cpu.l);
}

fn sla_mhl(cpu: &mut Cpu) {
    let hl = cpu.hl();
    let byte = cpu.mmu.read(hl);
    let result = sla(cpu, byte);
    cpu.mmu.write(hl, result);
}

fn sla_a(cpu: &mut Cpu) {
    cpu.a = sla(cpu, cpu.a);
}

fn sra_b(cpu: &mut Cpu) {
    cpu.b = sra(cpu, cpu.b);
}

fn sra_c(cpu: &mut Cpu) {
    cpu.c = sra(cpu, cpu.c);
}

fn sra_d(cpu: &mut Cpu) {
    cpu.d = sra(cpu, cpu.d);
}

fn sra_e(cpu: &mut Cpu) {
    cpu.e = sra(cpu, cpu.e);
}

fn sra_h(cpu: &mut Cpu) {
    cpu.h = sra(cpu, cpu.h);
}

fn sra_l(cpu: &mut Cpu) {
    cpu.l = sra(cpu, cpu.l);
}

fn sra_mhl(cpu: &mut Cpu) {
    let hl = cpu.hl();
    let byte = cpu.mmu.read(hl);
    let result = sra(cpu, byte);
    cpu.mmu.write(hl, result);
}

fn sra_a(cpu: &mut Cpu) {
    cpu.a = sra(cpu, cpu.a);
}

fn swap_b(cpu: &mut Cpu) {
    cpu.b = swap(cpu, cpu.b)
}

fn swap_c(cpu: &mut Cpu) {
    cpu.c = swap(cpu, cpu.c)
}

fn swap_d(cpu: &mut Cpu) {
    cpu.d = swap(cpu, cpu.d)
}

fn swap_e(cpu: &mut Cpu) {
    cpu.e = swap(cpu, cpu.e)
}

fn swap_h(cpu: &mut Cpu) {
    cpu.h = swap(cpu, cpu.h)
}

fn swap_l(cpu: &mut Cpu) {
    cpu.l = swap(cpu, cpu.l)
}

fn swap_mhl(cpu: &mut Cpu) {
    let hl = cpu.hl();
    let byte = cpu.mmu.read(hl);
    let result = swap(cpu, byte);
    cpu.mmu.write(hl, result);
}

fn swap_a(cpu: &mut Cpu) {
    cpu.a = swap(cpu, cpu.a)
}

fn srl_b(cpu: &mut Cpu) {
    cpu.b = srl(cpu, cpu.b);
}

fn srl_c(cpu: &mut Cpu) {
    cpu.c = srl(cpu, cpu.c);
}

fn srl_d(cpu: &mut Cpu) {
    cpu.d = srl(cpu, cpu.d);
}

fn srl_e(cpu: &mut Cpu) {
    cpu.e = srl(cpu, cpu.e);
}

fn srl_h(cpu: &mut Cpu) {
    cpu.h = srl(cpu, cpu.h);
}

fn srl_l(cpu: &mut Cpu) {
    cpu.l = srl(cpu, cpu.l);
}

fn srl_mhl(cpu: &mut Cpu) {
    let hl = cpu.hl();
    let byte = cpu.mmu.read(hl);
    let result = srl(cpu, byte);
    cpu.mmu.write(hl, result);
}

fn srl_a(cpu: &mut Cpu) {
    cpu.a = srl(cpu, cpu.a);
}

fn bit_0_b(cpu: &mut Cpu) {
    bit_b(cpu, 0);
}

fn bit_0_c(cpu: &mut Cpu) {
    bit_c(cpu, 0);
}

fn bit_0_d(cpu: &mut Cpu) {
    bit_d(cpu, 0);
}

fn bit_0_e(cpu: &mut Cpu) {
    bit_e(cpu, 0);
}

fn bit_0_h(cpu: &mut Cpu) {
    bit_h(cpu, 0);
}

fn bit_0_l(cpu: &mut Cpu) {
    bit_l(cpu, 0);
}

fn bit_0_mhl(cpu: &mut Cpu) {
    bit_mhl(cpu, 0);
}

fn bit_0_a(cpu: &mut Cpu) {
    bit_a(cpu, 0);
}

fn bit_1_b(cpu: &mut Cpu) {
    bit_b(cpu, 1);
}

fn bit_1_c(cpu: &mut Cpu) {
    bit_c(cpu, 1);
}

fn bit_1_d(cpu: &mut Cpu) {
    bit_d(cpu, 1);
}

fn bit_1_e(cpu: &mut Cpu) {
    bit_e(cpu, 1);
}

fn bit_1_h(cpu: &mut Cpu) {
    bit_h(cpu, 1);
}

fn bit_1_l(cpu: &mut Cpu) {
    bit_l(cpu, 1);
}

fn bit_1_mhl(cpu: &mut Cpu) {
    bit_mhl(cpu, 1);
}

fn bit_1_a(cpu: &mut Cpu) {
    bit_a(cpu, 1);
}

fn bit_2_b(cpu: &mut Cpu) {
    bit_b(cpu, 2);
}

fn bit_2_c(cpu: &mut Cpu) {
    bit_c(cpu, 2);
}

fn bit_2_d(cpu: &mut Cpu) {
    bit_d(cpu, 2);
}
fn bit_2_e(cpu: &mut Cpu) {
    bit_e(cpu, 2);
}

fn bit_2_h(cpu: &mut Cpu) {
    bit_h(cpu, 2);
}

fn bit_2_l(cpu: &mut Cpu) {
    bit_l(cpu, 2);
}

fn bit_2_mhl(cpu: &mut Cpu) {
    bit_mhl(cpu, 2);
}

fn bit_2_a(cpu: &mut Cpu) {
    bit_a(cpu, 2);
}

fn bit_3_b(cpu: &mut Cpu) {
    bit_b(cpu, 3);
}

fn bit_3_c(cpu: &mut Cpu) {
    bit_c(cpu, 3);
}

fn bit_3_d(cpu: &mut Cpu) {
    bit_d(cpu, 3);
}

fn bit_3_e(cpu: &mut Cpu) {
    bit_e(cpu, 3);
}

fn bit_3_h(cpu: &mut Cpu) {
    bit_h(cpu, 3);
}

fn bit_3_l(cpu: &mut Cpu) {
    bit_l(cpu, 3);
}

fn bit_3_mhl(cpu: &mut Cpu) {
    bit_mhl(cpu, 3);
}

fn bit_3_a(cpu: &mut Cpu) {
    bit_a(cpu, 3);
}

fn bit_4_b(cpu: &mut Cpu) {
    bit_b(cpu, 4);
}

fn bit_4_c(cpu: &mut Cpu) {
    bit_c(cpu, 4);
}

fn bit_4_d(cpu: &mut Cpu) {
    bit_d(cpu, 4);
}

fn bit_4_e(cpu: &mut Cpu) {
    bit_e(cpu, 4);
}

fn bit_4_h(cpu: &mut Cpu) {
    bit_h(cpu, 4);
}

fn bit_4_l(cpu: &mut Cpu) {
    bit_l(cpu, 4);
}

fn bit_4_mhl(cpu: &mut Cpu) {
    bit_mhl(cpu, 4);
}

fn bit_4_a(cpu: &mut Cpu) {
    bit_a(cpu, 4);
}

fn bit_5_b(cpu: &mut Cpu) {
    bit_b(cpu, 5);
}

fn bit_5_c(cpu: &mut Cpu) {
    bit_c(cpu, 5);
}

fn bit_5_d(cpu: &mut Cpu) {
    bit_d(cpu, 5);
}

fn bit_5_e(cpu: &mut Cpu) {
    bit_e(cpu, 5);
}

fn bit_5_h(cpu: &mut Cpu) {
    bit_h(cpu, 5);
}

fn bit_5_l(cpu: &mut Cpu) {
    bit_l(cpu, 5);
}

fn bit_5_mhl(cpu: &mut Cpu) {
    bit_mhl(cpu, 5);
}

fn bit_5_a(cpu: &mut Cpu) {
    bit_a(cpu, 5);
}

fn bit_6_b(cpu: &mut Cpu) {
    bit_b(cpu, 6);
}

fn bit_6_c(cpu: &mut Cpu) {
    bit_c(cpu, 6);
}

fn bit_6_d(cpu: &mut Cpu) {
    bit_d(cpu, 6);
}

fn bit_6_e(cpu: &mut Cpu) {
    bit_e(cpu, 6);
}

fn bit_6_h(cpu: &mut Cpu) {
    bit_h(cpu, 6);
}

fn bit_6_l(cpu: &mut Cpu) {
    bit_l(cpu, 6);
}
fn bit_6_mhl(cpu: &mut Cpu) {
    bit_mhl(cpu, 6);
}

fn bit_6_a(cpu: &mut Cpu) {
    bit_a(cpu, 6);
}

fn bit_7_b(cpu: &mut Cpu) {
    bit_b(cpu, 7);
}

fn bit_7_c(cpu: &mut Cpu) {
    bit_c(cpu, 7);
}

fn bit_7_d(cpu: &mut Cpu) {
    bit_d(cpu, 7);
}

fn bit_7_e(cpu: &mut Cpu) {
    bit_e(cpu, 7);
}

fn bit_7_h(cpu: &mut Cpu) {
    bit_h(cpu, 7);
}

fn bit_7_l(cpu: &mut Cpu) {
    bit_l(cpu, 7);
}

fn bit_7_mhl(cpu: &mut Cpu) {
    bit_mhl(cpu, 7);
}

fn bit_7_a(cpu: &mut Cpu) {
    bit_a(cpu, 7);
}

fn res_0_b(cpu: &mut Cpu) {
    cpu.b = res(cpu.b, 0);
}

fn res_0_c(cpu: &mut Cpu) {
    cpu.c = res(cpu.c, 0);
}

fn res_0_d(cpu: &mut Cpu) {
    cpu.d = res(cpu.d, 0);
}

fn res_0_e(cpu: &mut Cpu) {
    cpu.e = res(cpu.e, 0);
}

fn res_0_h(cpu: &mut Cpu) {
    cpu.h = res(cpu.h, 0);
}

fn res_0_l(cpu: &mut Cpu) {
    cpu.l = res(cpu.l, 0);
}

fn res_0_mhl(cpu: &mut Cpu) {
    let hl = cpu.hl();
    let byte = cpu.mmu.read(hl);
    let value = res(byte, 0);
    cpu.mmu.write(hl, value);
}

fn res_0_a(cpu: &mut Cpu) {
    cpu.a = res(cpu.a, 0);
}

fn res_1_b(cpu: &mut Cpu) {
    cpu.b = res(cpu.b, 1);
}

fn res_1_c(cpu: &mut Cpu) {
    cpu.c = res(cpu.c, 1);
}

fn res_1_d(cpu: &mut Cpu) {
    cpu.d = res(cpu.d, 1);
}

fn res_1_e(cpu: &mut Cpu) {
    cpu.e = res(cpu.e, 1);
}

fn res_1_h(cpu: &mut Cpu) {
    cpu.h = res(cpu.h, 1);
}

fn res_1_l(cpu: &mut Cpu) {
    cpu.l = res(cpu.l, 1);
}

fn res_1_mhl(cpu: &mut Cpu) {
    let hl = cpu.hl();
    let byte = cpu.mmu.read(hl);
    let value = res(byte, 1);
    cpu.mmu.write(hl, value);
}

fn res_1_a(cpu: &mut Cpu) {
    cpu.a = res(cpu.a, 1);
}

fn res_2_b(cpu: &mut Cpu) {
    cpu.b = res(cpu.b, 2);
}

fn res_2_c(cpu: &mut Cpu) {
    cpu.c = res(cpu.c, 2);
}

fn res_2_d(cpu: &mut Cpu) {
    cpu.d = res(cpu.d, 2);
}

fn res_2_e(cpu: &mut Cpu) {
    cpu.e = res(cpu.e, 2);
}

fn res_2_h(cpu: &mut Cpu) {
    cpu.h = res(cpu.h, 2);
}

fn res_2_l(cpu: &mut Cpu) {
    cpu.l = res(cpu.l, 2);
}

fn res_2_mhl(cpu: &mut Cpu) {
    let hl = cpu.hl();
    let byte = cpu.mmu.read(hl);
    let value = res(byte, 2);
    cpu.mmu.write(hl, value);
}

fn res_2_a(cpu: &mut Cpu) {
    cpu.a = res(cpu.a, 2);
}

fn res_3_b(cpu: &mut Cpu) {
    cpu.b = res(cpu.b, 3);
}

fn res_3_c(cpu: &mut Cpu) {
    cpu.c = res(cpu.c, 3);
}

fn res_3_d(cpu: &mut Cpu) {
    cpu.d = res(cpu.d, 3);
}

fn res_3_e(cpu: &mut Cpu) {
    cpu.e = res(cpu.e, 3);
}

fn res_3_h(cpu: &mut Cpu) {
    cpu.h = res(cpu.h, 3);
}

fn res_3_l(cpu: &mut Cpu) {
    cpu.l = res(cpu.l, 3);
}

fn res_3_mhl(cpu: &mut Cpu) {
    let hl = cpu.hl();
    let byte = cpu.mmu.read(hl);
    let value = res(byte, 3);
    cpu.mmu.write(hl, value);
}

fn res_3_a(cpu: &mut Cpu) {
    cpu.a = res(cpu.a, 3);
}

fn res_4_b(cpu: &mut Cpu) {
    cpu.b = res(cpu.b, 4);
}

fn res_4_c(cpu: &mut Cpu) {
    cpu.c = res(cpu.c, 4);
}

fn res_4_d(cpu: &mut Cpu) {
    cpu.d = res(cpu.d, 4);
}

fn res_4_e(cpu: &mut Cpu) {
    cpu.e = res(cpu.e, 4);
}

fn res_4_h(cpu: &mut Cpu) {
    cpu.h = res(cpu.h, 4);
}

fn res_4_l(cpu: &mut Cpu) {
    cpu.l = res(cpu.l, 4);
}

fn res_4_mhl(cpu: &mut Cpu) {
    let hl = cpu.hl();
    let byte = cpu.mmu.read(hl);
    let value = res(byte, 4);
    cpu.mmu.write(hl, value);
}

fn res_4_a(cpu: &mut Cpu) {
    cpu.a = res(cpu.a, 4);
}

fn res_5_b(cpu: &mut Cpu) {
    cpu.b = res(cpu.b, 5);
}

fn res_5_c(cpu: &mut Cpu) {
    cpu.c = res(cpu.c, 5);
}

fn res_5_d(cpu: &mut Cpu) {
    cpu.d = res(cpu.d, 5);
}

fn res_5_e(cpu: &mut Cpu) {
    cpu.e = res(cpu.e, 5);
}

fn res_5_h(cpu: &mut Cpu) {
    cpu.h = res(cpu.h, 5);
}

fn res_5_l(cpu: &mut Cpu) {
    cpu.l = res(cpu.l, 5);
}

fn res_5_mhl(cpu: &mut Cpu) {
    let hl = cpu.hl();
    let byte = cpu.mmu.read(hl);
    let value = res(byte, 5);
    cpu.mmu.write(hl, value);
}

fn res_5_a(cpu: &mut Cpu) {
    cpu.a = res(cpu.a, 5);
}

fn res_6_b(cpu: &mut Cpu) {
    cpu.b = res(cpu.b, 6);
}

fn res_6_c(cpu: &mut Cpu) {
    cpu.c = res(cpu.c, 6);
}

fn res_6_d(cpu: &mut Cpu) {
    cpu.d = res(cpu.d, 6);
}

fn res_6_e(cpu: &mut Cpu) {
    cpu.e = res(cpu.e, 6);
}

fn res_6_h(cpu: &mut Cpu) {
    cpu.h = res(cpu.h, 6);
}

fn res_6_l(cpu: &mut Cpu) {
    cpu.l = res(cpu.l, 6);
}

fn res_6_mhl(cpu: &mut Cpu) {
    let hl = cpu.hl();
    let byte = cpu.mmu.read(hl);
    let value = res(byte, 6);
    cpu.mmu.write(hl, value);
}

fn res_6_a(cpu: &mut Cpu) {
    cpu.a = res(cpu.a, 6);
}

fn res_7_b(cpu: &mut Cpu) {
    cpu.b = res(cpu.b, 7);
}

fn res_7_c(cpu: &mut Cpu) {
    cpu.c = res(cpu.c, 7);
}

fn res_7_d(cpu: &mut Cpu) {
    cpu.d = res(cpu.d, 7);
}

fn res_7_e(cpu: &mut Cpu) {
    cpu.e = res(cpu.e, 7);
}

fn res_7_h(cpu: &mut Cpu) {
    cpu.h = res(cpu.h, 7);
}

fn res_7_l(cpu: &mut Cpu) {
    cpu.l = res(cpu.l, 7);
}

fn res_7_mhl(cpu: &mut Cpu) {
    let hl = cpu.hl();
    let byte = cpu.mmu.read(hl);
    let value = res(byte, 7);
    cpu.mmu.write(hl, value);
}

fn res_7_a(cpu: &mut Cpu) {
    cpu.a = res(cpu.a, 7);
}

fn set_0_b(cpu: &mut Cpu) {
    cpu.b = set(cpu.b, 0);
}

fn set_0_c(cpu: &mut Cpu) {
    cpu.c = set(cpu.c, 0);
}

fn set_0_d(cpu: &mut Cpu) {
    cpu.d = set(cpu.d, 0);
}

fn set_0_e(cpu: &mut Cpu) {
    cpu.e = set(cpu.e, 0);
}

fn set_0_h(cpu: &mut Cpu) {
    cpu.h = set(cpu.h, 0);
}

fn set_0_l(cpu: &mut Cpu) {
    cpu.l = set(cpu.l, 0);
}

fn set_0_mhl(cpu: &mut Cpu) {
    let hl = cpu.hl();
    let byte = cpu.mmu.read(hl);
    let value = set(byte, 0);
    cpu.mmu.write(hl, value);
}

fn set_0_a(cpu: &mut Cpu) {
    cpu.a = set(cpu.a, 0);
}

fn set_1_b(cpu: &mut Cpu) {
    cpu.b = set(cpu.b, 1);
}

fn set_1_c(cpu: &mut Cpu) {
    cpu.c = set(cpu.c, 1);
}

fn set_1_d(cpu: &mut Cpu) {
    cpu.d = set(cpu.d, 1);
}

fn set_1_e(cpu: &mut Cpu) {
    cpu.e = set(cpu.e, 1);
}

fn set_1_h(cpu: &mut Cpu) {
    cpu.h = set(cpu.h, 1);
}

fn set_1_l(cpu: &mut Cpu) {
    cpu.l = set(cpu.l, 1);
}

fn set_1_mhl(cpu: &mut Cpu) {
    let hl = cpu.hl();
    let byte = cpu.mmu.read(hl);
    let value = set(byte, 1);
    cpu.mmu.write(hl, value);
}

fn set_1_a(cpu: &mut Cpu) {
    cpu.a = set(cpu.a, 1);
}

fn set_2_b(cpu: &mut Cpu) {
    cpu.b = set(cpu.b, 2);
}

fn set_2_c(cpu: &mut Cpu) {
    cpu.c = set(cpu.c, 2);
}

fn set_2_d(cpu: &mut Cpu) {
    cpu.d = set(cpu.d, 2);
}

fn set_2_e(cpu: &mut Cpu) {
    cpu.e = set(cpu.e, 2);
}

fn set_2_h(cpu: &mut Cpu) {
    cpu.h = set(cpu.h, 2);
}

fn set_2_l(cpu: &mut Cpu) {
    cpu.l = set(cpu.l, 2);
}

fn set_2_mhl(cpu: &mut Cpu) {
    let hl = cpu.hl();
    let byte = cpu.mmu.read(hl);
    let value = set(byte, 2);
    cpu.mmu.write(hl, value);
}

fn set_2_a(cpu: &mut Cpu) {
    cpu.a = set(cpu.a, 2);
}

fn set_3_b(cpu: &mut Cpu) {
    cpu.b = set(cpu.b, 3);
}

fn set_3_c(cpu: &mut Cpu) {
    cpu.c = set(cpu.c, 3);
}

fn set_3_d(cpu: &mut Cpu) {
    cpu.d = set(cpu.d, 3);
}

fn set_3_e(cpu: &mut Cpu) {
    cpu.e = set(cpu.e, 3);
}

fn set_3_h(cpu: &mut Cpu) {
    cpu.h = set(cpu.h, 3);
}

fn set_3_l(cpu: &mut Cpu) {
    cpu.l = set(cpu.l, 3);
}

fn set_3_mhl(cpu: &mut Cpu) {
    let hl = cpu.hl();
    let byte = cpu.mmu.read(hl);
    let value = set(byte, 3);
    cpu.mmu.write(hl, value);
}

fn set_3_a(cpu: &mut Cpu) {
    cpu.a = set(cpu.a, 3);
}

fn set_4_b(cpu: &mut Cpu) {
    cpu.b = set(cpu.b, 4);
}

fn set_4_c(cpu: &mut Cpu) {
    cpu.c = set(cpu.c, 4);
}

fn set_4_d(cpu: &mut Cpu) {
    cpu.d = set(cpu.d, 4);
}

fn set_4_e(cpu: &mut Cpu) {
    cpu.e = set(cpu.e, 4);
}

fn set_4_h(cpu: &mut Cpu) {
    cpu.h = set(cpu.h, 4);
}

fn set_4_l(cpu: &mut Cpu) {
    cpu.l = set(cpu.l, 4);
}

fn set_4_mhl(cpu: &mut Cpu) {
    let hl = cpu.hl();
    let byte = cpu.mmu.read(hl);
    let value = set(byte, 4);
    cpu.mmu.write(hl, value);
}

fn set_4_a(cpu: &mut Cpu) {
    cpu.a = set(cpu.a, 4);
}

fn set_5_b(cpu: &mut Cpu) {
    cpu.b = set(cpu.b, 5);
}

fn set_5_c(cpu: &mut Cpu) {
    cpu.c = set(cpu.c, 5);
}

fn set_5_d(cpu: &mut Cpu) {
    cpu.d = set(cpu.d, 5);
}

fn set_5_e(cpu: &mut Cpu) {
    cpu.e = set(cpu.e, 5);
}

fn set_5_h(cpu: &mut Cpu) {
    cpu.h = set(cpu.h, 5);
}

fn set_5_l(cpu: &mut Cpu) {
    cpu.l = set(cpu.l, 5);
}

fn set_5_mhl(cpu: &mut Cpu) {
    let hl = cpu.hl();
    let byte = cpu.mmu.read(hl);
    let value = set(byte, 5);
    cpu.mmu.write(hl, value);
}

fn set_5_a(cpu: &mut Cpu) {
    cpu.a = set(cpu.a, 5);
}

fn set_6_b(cpu: &mut Cpu) {
    cpu.b = set(cpu.b, 6);
}

fn set_6_c(cpu: &mut Cpu) {
    cpu.c = set(cpu.c, 6);
}

fn set_6_d(cpu: &mut Cpu) {
    cpu.d = set(cpu.d, 6);
}

fn set_6_e(cpu: &mut Cpu) {
    cpu.e = set(cpu.e, 6);
}

fn set_6_h(cpu: &mut Cpu) {
    cpu.h = set(cpu.h, 6);
}

fn set_6_l(cpu: &mut Cpu) {
    cpu.l = set(cpu.l, 6);
}

fn set_6_mhl(cpu: &mut Cpu) {
    let hl = cpu.hl();
    let byte = cpu.mmu.read(hl);
    let value = set(byte, 6);
    cpu.mmu.write(hl, value);
}

fn set_6_a(cpu: &mut Cpu) {
    cpu.a = set(cpu.a, 6);
}

fn set_7_b(cpu: &mut Cpu) {
    cpu.b = set(cpu.b, 7);
}

fn set_7_c(cpu: &mut Cpu) {
    cpu.c = set(cpu.c, 7);
}

fn set_7_d(cpu: &mut Cpu) {
    cpu.d = set(cpu.d, 7);
}

fn set_7_e(cpu: &mut Cpu) {
    cpu.e = set(cpu.e, 7);
}

fn set_7_h(cpu: &mut Cpu) {
    cpu.h = set(cpu.h, 7);
}

fn set_7_l(cpu: &mut Cpu) {
    cpu.l = set(cpu.l, 7);
}

fn set_7_mhl(cpu: &mut Cpu) {
    let hl = cpu.hl();
    let byte = cpu.mmu.read(hl);
    let value = set(byte, 7);
    cpu.mmu.write(hl, value);
}

fn set_7_a(cpu: &mut Cpu) {
    cpu.a = set(cpu.a, 7);
}

/// Helper function to set one bit in a u8.
fn set(value: u8, bit: u8) -> u8 {
    value | (1u8 << (bit as usize))
}

/// Helper function to clear one bit in a u8.
fn res(value: u8, bit: u8) -> u8 {
    value & !(1u8 << (bit as usize))
}

/// Helper function that rotates (shifts) left the given
/// byte (probably from a register) and updates the
/// proper flag registers.
fn rl(cpu: &mut Cpu, value: u8) -> u8 {
    let carry = cpu.carry();

    cpu.set_carry((value & 0x80) == 0x80);

    let result = (value << 1) | carry as u8;

    cpu.set_sub(false);
    cpu.set_zero(result == 0);
    cpu.set_half_carry(false);

    result
}

fn rlc(cpu: &mut Cpu, value: u8) -> u8 {
    cpu.set_carry((value & 0x80) == 0x80);
    let result = (value << 1) | (value >> 7);

    cpu.set_sub(false);
    cpu.set_zero(result == 0);
    cpu.set_half_carry(false);

    result
}

/// Helper function that rotates (shifts) right the given
/// byte (probably from a register) and updates the
/// proper flag registers.
fn rr(cpu: &mut Cpu, value: u8) -> u8 {
    let carry = cpu.carry();

    cpu.set_carry((value & 0x1) == 0x1);

    let result = (value >> 1) | ((carry as u8) << 7);

    cpu.set_sub(false);
    cpu.set_zero(result == 0);
    cpu.set_half_carry(false);

    result
}

fn rrc(cpu: &mut Cpu, value: u8) -> u8 {
    cpu.set_carry((value & 0x1) == 0x1);

    let result = (value >> 1) | (value << 7);

    cpu.set_sub(false);
    cpu.set_zero(result == 0);
    cpu.set_half_carry(false);

    result
}

/// Helper function to test one bit in a u8.
/// Returns true if bit is 0.
fn bit_zero(val: u8, bit: u8) -> bool {
    (val & (1u8 << (bit as usize))) == 0
}

fn bit_a(cpu: &mut Cpu, bit: u8) {
    cpu.set_sub(false);
    cpu.set_zero(bit_zero(cpu.a, bit));
    cpu.set_half_carry(true);
}

fn bit_b(cpu: &mut Cpu, bit: u8) {
    cpu.set_sub(false);
    cpu.set_zero(bit_zero(cpu.b, bit));
    cpu.set_half_carry(true);
}

fn bit_c(cpu: &mut Cpu, bit: u8) {
    cpu.set_sub(false);
    cpu.set_zero(bit_zero(cpu.c, bit));
    cpu.set_half_carry(true);
}

fn bit_d(cpu: &mut Cpu, bit: u8) {
    cpu.set_sub(false);
    cpu.set_zero(bit_zero(cpu.d, bit));
    cpu.set_half_carry(true);
}

fn bit_e(cpu: &mut Cpu, bit: u8) {
    cpu.set_sub(false);
    cpu.set_zero(bit_zero(cpu.e, bit));
    cpu.set_half_carry(true);
}

fn bit_h(cpu: &mut Cpu, bit: u8) {
    cpu.set_sub(false);
    cpu.set_zero(bit_zero(cpu.h, bit));
    cpu.set_half_carry(true);
}

fn bit_l(cpu: &mut Cpu, bit: u8) {
    cpu.set_sub(false);
    cpu.set_zero(bit_zero(cpu.l, bit));
    cpu.set_half_carry(true);
}

fn bit_mhl(cpu: &mut Cpu, bit: u8) {
    let byte = cpu.mmu.read(cpu.hl());
    cpu.set_sub(false);
    cpu.set_zero(bit_zero(byte, bit));
    cpu.set_half_carry(true);
}

fn add_set_flags(cpu: &mut Cpu, first: u8, second: u8) -> u8 {
    let first = first as u32;
    let second = second as u32;

    let result = first.wrapping_add(second);
    let result_b = result as u8;

    cpu.set_sub(false);
    cpu.set_zero(result_b == 0);
    cpu.set_half_carry((first ^ second ^ result) & 0x10 == 0x10);
    cpu.set_carry((result & 0x100) == 0x100);

    result_b
}

fn add_carry_set_flags(cpu: &mut Cpu, first: u8, second: u8) -> u8 {
    let first = first as u32;
    let second = second as u32;
    let carry = cpu.carry() as u32;

    let result = first.wrapping_add(second).wrapping_add(carry);
    let result_b = result as u8;

    cpu.set_sub(false);
    cpu.set_zero(result_b == 0);
    cpu.set_half_carry((first ^ second ^ result) & 0x10 == 0x10);
    cpu.set_carry((result & 0x100) == 0x100);

    result_b
}

fn sub_set_flags(cpu: &mut Cpu, first: u8, second: u8) -> u8 {
    let first = first as u32;
    let second = second as u32;

    let result = first.wrapping_sub(second);
    let result_b = result as u8;

    cpu.set_sub(true);
    cpu.set_zero(result_b == 0);
    cpu.set_half_carry((first ^ second ^ result) & 0x10 == 0x10);
    cpu.set_carry((result & 0x100) == 0x100);

    result_b
}

fn sub_carry_set_flags(cpu: &mut Cpu, first: u8, second: u8) -> u8 {
    let first = first as u32;
    let second = second as u32;
    let carry = cpu.carry() as u32;

    let result = first.wrapping_sub(second).wrapping_sub(carry);
    let result_b = result as u8;

    cpu.set_sub(true);
    cpu.set_zero(result_b == 0);
    cpu.set_half_carry((first ^ second ^ result) & 0x10 == 0x10);
    cpu.set_carry((result & 0x100) == 0x100);

    result_b
}

fn add_u16_u16(cpu: &mut Cpu, first: u16, second: u16) -> u16 {
    let first = first as u32;
    let second = second as u32;
    let result = first.wrapping_add(second);

    cpu.set_sub(false);
    cpu.set_half_carry((first ^ second ^ result) & 0x1000 == 0x1000);
    cpu.set_carry((result & 0x10000) == 0x10000);

    result as u16
}

fn swap(cpu: &mut Cpu, value: u8) -> u8 {
    cpu.set_sub(false);
    cpu.set_zero(value == 0);
    cpu.set_half_carry(false);
    cpu.set_carry(false);

    (value << 4) | (value >> 4)
}

/// Helper function to shift an `u8` to the left and update CPU
/// flags.
fn sla(cpu: &mut Cpu, value: u8) -> u8 {
    let result = value << 1;

    cpu.set_sub(false);
    cpu.set_zero(result == 0);
    cpu.set_half_carry(false);
    cpu.set_carry((value & 0x80) == 0x80);

    result
}

fn sra(cpu: &mut Cpu, value: u8) -> u8 {
    let result = (value >> 1) | (value & 0x80);

    cpu.set_sub(false);
    cpu.set_zero(result == 0);
    cpu.set_half_carry(false);
    cpu.set_carry((value & 0x1) == 0x1);

    result
}

fn srl(cpu: &mut Cpu, value: u8) -> u8 {
    let result = value >> 1;

    cpu.set_sub(false);
    cpu.set_zero(result == 0);
    cpu.set_half_carry(false);
    cpu.set_carry((value & 0x1) == 0x1);

    result
}

/// Helper function for RST instructions, pushes the
/// current PC to the stack and jumps to the provided
/// address.
fn rst(cpu: &mut Cpu, addr: u16) {
    cpu.push_word(cpu.pc);
    cpu.pc = addr;
}