From 046c12572637bd702fac6e2832fd36738889f432 Mon Sep 17 00:00:00 2001 From: Jorge Gorbe Moya Date: Thu, 3 Jul 2008 15:54:23 +0200 Subject: [PATCH] HALT implemented --- gbcore.cc | 2050 +++++++++++++++++++++++++++-------------------------- gbcore.h | 1 + 2 files changed, 1031 insertions(+), 1020 deletions(-) diff --git a/gbcore.cc b/gbcore.cc index d86d402..db85565 100644 --- a/gbcore.cc +++ b/gbcore.cc @@ -144,6 +144,7 @@ GameBoy::run_status GameBoy::run_cycle() IF &= (~IRQ_VBLANK); do_call(0x40); logger.trace("VBLANK IRQ"); + HALT=false; } else if ((IF & IRQ_LCD_STAT) && (IE & IRQ_LCD_STAT)) { @@ -151,6 +152,7 @@ GameBoy::run_status GameBoy::run_cycle() IF &= (~IRQ_LCD_STAT); do_call(0x48); logger.trace("LCD STAT IRQ"); + HALT=false; } else if ((IF & IRQ_TIMER) && (IE & IRQ_TIMER)) { @@ -158,6 +160,7 @@ GameBoy::run_status GameBoy::run_cycle() IF &= (~IRQ_TIMER); do_call(0x50); logger.trace("TIMER IRQ"); + HALT=false; } else if ((IF & IRQ_SERIAL) && (IE & IRQ_SERIAL)) { @@ -165,6 +168,7 @@ GameBoy::run_status GameBoy::run_cycle() IF &= (~IRQ_SERIAL); do_call(0x58); logger.trace("SERIAL IRQ"); + HALT=false; } else if ((IF & IRQ_JOYPAD) && (IE & IRQ_JOYPAD)) { @@ -172,6 +176,7 @@ GameBoy::run_status GameBoy::run_cycle() IF &= (~IRQ_JOYPAD); do_call(0x60); logger.trace("JOYPAD IRQ"); + HALT=false; } } memory.high[GBMemory::I_IF] = IF; @@ -190,1119 +195,1124 @@ GameBoy::run_status GameBoy::run_cycle() int opcode; opcode = memory.read(regs.PC++); - switch(opcode & 0x80) + if (!(HALT || STOP)) { - case 0x00: - switch(opcode) + switch(opcode & 0x80) { - // LD n, nn - for_each_register(0x3E, 0x06, 0x0E, 0x16, 0x1E, 0x26, 0x2E, LD_reg_nn) - - // LD r1,r2 - for_each_register(0x7F, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, LD_A_reg) - for_each_register(0x47, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, LD_B_reg) - for_each_register(0x4F, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, LD_C_reg) - for_each_register(0x57, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, LD_D_reg) - for_each_register(0x5F, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, LD_E_reg) - for_each_register(0x67, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, LD_H_reg) - for_each_register(0x6F, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, LD_L_reg) - - // LD reg, (HL) - for_each_register(0x7E, 0x46, 0x4E, 0x56, 0x5E, 0x66, 0x6E, LD_reg__HL_) - - // LD (HL), reg - for_each_register(0x77, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, LD__HL__reg) - - case 0x36: // LD (HL), n - memory.write(regs.HL, memory.read(regs.PC++)); - cycles_until_next_instruction = 12; - break; - - // LD A, mem - case 0x0A: // LD A, (BC) - regs.A = memory.read(regs.BC); - cycles_until_next_instruction = 8; - break; - case 0x1A: // LD A, (DE) - regs.A = memory.read(regs.DE); - cycles_until_next_instruction = 8; - break; - - // LD mem, A - case 0x02: // LD (BC), A - memory.write(regs.BC, regs.A); - cycles_until_next_instruction = 8; - break; - case 0x12: // LD (DE), A - memory.write(regs.DE, regs.A); - cycles_until_next_instruction = 8; - break; - - // LD A, (HLD); LD A, (HL-); LDD A,(HL); - case 0x3A: - regs.A = memory.read(regs.HL); - --regs.HL; - cycles_until_next_instruction = 8; - break; - // LD (HLD), A; LD (HL-), A; LDD (HL), A; - case 0x32: - memory.write(regs.HL, regs.A); - --regs.HL; - cycles_until_next_instruction = 8; - break; - // LD A, (HLI); LD A, (HL+); LDI A, (HL); - case 0x2A: - regs.A = memory.read(regs.HL); - ++regs.HL; - cycles_until_next_instruction = 8; - break; - // LD (HLI), A; LD (HL+), A; LDI (HL), A; - case 0x22: - memory.write(regs.HL, regs.A); - ++regs.HL; - cycles_until_next_instruction = 8; - break; - - // LD n, nn - case 0x01: // LD BC, nn - regs.BC = memory.read16(regs.PC); - regs.PC +=2; - cycles_until_next_instruction = 12; - break; - case 0x11: // LD DE, nn - regs.DE = memory.read16(regs.PC); - regs.PC +=2; - cycles_until_next_instruction = 12; - break; - case 0x21: // LD HL, nn - regs.HL = memory.read16(regs.PC); - regs.PC +=2; - cycles_until_next_instruction = 12; - break; - case 0x31: // LD SP, nn - regs.SP = memory.read16(regs.PC); - regs.PC +=2; - cycles_until_next_instruction = 12; - break; - - - // LD (nn), SP - case 0x08: { - int addr = memory.read16(regs.PC); - regs.PC += 2; - memory.write(addr, regs.SP); - cycles_until_next_instruction = 20; - break; - } + case 0x00: + switch(opcode) + { + // LD n, nn + for_each_register(0x3E, 0x06, 0x0E, 0x16, 0x1E, 0x26, 0x2E, LD_reg_nn) + + // LD r1,r2 + for_each_register(0x7F, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, LD_A_reg) + for_each_register(0x47, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, LD_B_reg) + for_each_register(0x4F, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, LD_C_reg) + for_each_register(0x57, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, LD_D_reg) + for_each_register(0x5F, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, LD_E_reg) + for_each_register(0x67, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, LD_H_reg) + for_each_register(0x6F, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, LD_L_reg) + + // LD reg, (HL) + for_each_register(0x7E, 0x46, 0x4E, 0x56, 0x5E, 0x66, 0x6E, LD_reg__HL_) - // INC n - for_each_register(0x3C, 0x04, 0x0C, 0x14, 0x1C, 0x24, 0x2C, INC_reg) - - case 0x34: {//INC (HL) - int half_res = (memory.read(regs.HL) & 0x0F) + 1; - memory.write(regs.HL, memory.read(regs.HL) - 1); - reset_flag(ADD_SUB_FLAG); - set_flag_if (memory.read(regs.HL) == 0, ZERO_FLAG); - set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG); - cycles_until_next_instruction = 12; - break; - } - - // DEC n - for_each_register(0x3D, 0x05, 0x0D, 0x15, 0x1D, 0x25, 0x2D, DEC_reg) - - case 0x35: {//DEC (HL) - int half_res = (memory.read(regs.HL) & 0x0F) - 1; - memory.write(regs.HL, memory.read(regs.HL) - 1); - set_flag(ADD_SUB_FLAG); - set_flag_if (memory.read(regs.HL) == 0, ZERO_FLAG); - set_flag_if (half_res < 0, HALF_CARRY_FLAG); - cycles_until_next_instruction = 12; - break; - } + // LD (HL), reg + for_each_register(0x77, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, LD__HL__reg) + + case 0x36: // LD (HL), n + memory.write(regs.HL, memory.read(regs.PC++)); + cycles_until_next_instruction = 12; + break; + + // LD A, mem + case 0x0A: // LD A, (BC) + regs.A = memory.read(regs.BC); + cycles_until_next_instruction = 8; + break; + case 0x1A: // LD A, (DE) + regs.A = memory.read(regs.DE); + cycles_until_next_instruction = 8; + break; + + // LD mem, A + case 0x02: // LD (BC), A + memory.write(regs.BC, regs.A); + cycles_until_next_instruction = 8; + break; + case 0x12: // LD (DE), A + memory.write(regs.DE, regs.A); + cycles_until_next_instruction = 8; + break; - // 16-bit ALU - // ADD HL, n - for_each_register16(0x09, 0x19, 0x29, 0x39, ADD_HL_reg16) + // LD A, (HLD); LD A, (HL-); LDD A,(HL); + case 0x3A: + regs.A = memory.read(regs.HL); + --regs.HL; + cycles_until_next_instruction = 8; + break; + // LD (HLD), A; LD (HL-), A; LDD (HL), A; + case 0x32: + memory.write(regs.HL, regs.A); + --regs.HL; + cycles_until_next_instruction = 8; + break; + // LD A, (HLI); LD A, (HL+); LDI A, (HL); + case 0x2A: + regs.A = memory.read(regs.HL); + ++regs.HL; + cycles_until_next_instruction = 8; + break; + // LD (HLI), A; LD (HL+), A; LDI (HL), A; + case 0x22: + memory.write(regs.HL, regs.A); + ++regs.HL; + cycles_until_next_instruction = 8; + break; - // INC nn - for_each_register16(0x03, 0x13, 0x23, 0x33, INC_reg16) + // LD n, nn + case 0x01: // LD BC, nn + regs.BC = memory.read16(regs.PC); + regs.PC +=2; + cycles_until_next_instruction = 12; + break; + case 0x11: // LD DE, nn + regs.DE = memory.read16(regs.PC); + regs.PC +=2; + cycles_until_next_instruction = 12; + break; + case 0x21: // LD HL, nn + regs.HL = memory.read16(regs.PC); + regs.PC +=2; + cycles_until_next_instruction = 12; + break; + case 0x31: // LD SP, nn + regs.SP = memory.read16(regs.PC); + regs.PC +=2; + cycles_until_next_instruction = 12; + break; + - // DEC nn - for_each_register16(0x0B, 0x1B, 0x2B, 0x3B, DEC_reg16) + // LD (nn), SP + case 0x08: { + int addr = memory.read16(regs.PC); + regs.PC += 2; + memory.write(addr, regs.SP); + cycles_until_next_instruction = 20; + break; + } + // INC n + for_each_register(0x3C, 0x04, 0x0C, 0x14, 0x1C, 0x24, 0x2C, INC_reg) + + case 0x34: {//INC (HL) + int half_res = (memory.read(regs.HL) & 0x0F) + 1; + memory.write(regs.HL, memory.read(regs.HL) - 1); + reset_flag(ADD_SUB_FLAG); + set_flag_if (memory.read(regs.HL) == 0, ZERO_FLAG); + set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG); + cycles_until_next_instruction = 12; + break; + } + + // DEC n + for_each_register(0x3D, 0x05, 0x0D, 0x15, 0x1D, 0x25, 0x2D, DEC_reg) + + case 0x35: {//DEC (HL) + int half_res = (memory.read(regs.HL) & 0x0F) - 1; + memory.write(regs.HL, memory.read(regs.HL) - 1); + set_flag(ADD_SUB_FLAG); + set_flag_if (memory.read(regs.HL) == 0, ZERO_FLAG); + set_flag_if (half_res < 0, HALF_CARRY_FLAG); + cycles_until_next_instruction = 12; + break; + } - // DAA http://www.worldofspectrum.org/faq/reference/z80reference.htm#DAA - case 0x27: { - u8 corr_factor = 0; - if (regs.A > 0x99 || check_flag(CARRY_FLAG)) { - corr_factor = 0x60; - set_flag(CARRY_FLAG); - } else { - reset_flag(CARRY_FLAG); - } + // 16-bit ALU + // ADD HL, n + for_each_register16(0x09, 0x19, 0x29, 0x39, ADD_HL_reg16) - if (regs.A & 0x0F > 9 || check_flag(HALF_CARRY_FLAG)) { - corr_factor |= 0x06; - } + // INC nn + for_each_register16(0x03, 0x13, 0x23, 0x33, INC_reg16) - if (!check_flag(ADD_SUB_FLAG)) { - regs.A += corr_factor; - } else { - regs.A -= corr_factor; - } + // DEC nn + for_each_register16(0x0B, 0x1B, 0x2B, 0x3B, DEC_reg16) - set_flag_if(regs.A==0, ZERO_FLAG); - reset_flag(HALF_CARRY_FLAG); // GBCPUman.pdf contradicts previous reference :P - cycles_until_next_instruction = 4; - break; - } - // CPL - case 0x2F: - regs.A = ~regs.A; - set_flag(HALF_CARRY_FLAG); - set_flag(ADD_SUB_FLAG); - cycles_until_next_instruction = 4; - break; - - // CCF - case 0x3F: - if (check_flag(CARRY_FLAG)) - reset_flag(CARRY_FLAG); - else - set_flag(CARRY_FLAG); + // DAA http://www.worldofspectrum.org/faq/reference/z80reference.htm#DAA + case 0x27: { + u8 corr_factor = 0; + if (regs.A > 0x99 || check_flag(CARRY_FLAG)) { + corr_factor = 0x60; + set_flag(CARRY_FLAG); + } else { + reset_flag(CARRY_FLAG); + } - reset_flag(HALF_CARRY_FLAG); - reset_flag(ADD_SUB_FLAG); - cycles_until_next_instruction = 4; - break; + if (regs.A & 0x0F > 9 || check_flag(HALF_CARRY_FLAG)) { + corr_factor |= 0x06; + } - // SCF - case 0x37: - set_flag(CARRY_FLAG); - reset_flag(HALF_CARRY_FLAG); - reset_flag(ADD_SUB_FLAG); - cycles_until_next_instruction = 4; - break; + if (!check_flag(ADD_SUB_FLAG)) { + regs.A += corr_factor; + } else { + regs.A -= corr_factor; + } - // NOP - case 0x00: - cycles_until_next_instruction = 4; - break; - - // HALT - case 0x76: - HALT = true; - cycles_until_next_instruction = 4; - break; - - // STOP - case 0x10: { - int sub_opcode = memory.read(regs.PC++); - if (sub_opcode == 0x00) { - HALT = true; - } else { - logger.critical("Unknown sub-opcode after 0x10"); + set_flag_if(regs.A==0, ZERO_FLAG); + reset_flag(HALF_CARRY_FLAG); // GBCPUman.pdf contradicts previous reference :P + cycles_until_next_instruction = 4; + break; } - cycles_until_next_instruction = 4; - break; - } - - // Rotates and shifts - // RLCA - case 0x07: { - u8 bit7 = regs.A >>7; - regs.A = (regs.A << 1) | bit7; - set_flag_if(regs.A == 0, ZERO_FLAG); - reset_flag(ADD_SUB_FLAG); - reset_flag(HALF_CARRY_FLAG); - // TODO: Check which of GBCPUman.pdf or - // worldofspectrum z80 reference is correct - // - //set_flag_if(bit7, CARRY_FLAG); - cycles_until_next_instruction = 4; - break; - } - // RLA (through carry) - case 0x17: { - u8 bit7 = regs.A >> 7; - regs.A = (regs.A << 1) | check_flag(CARRY_FLAG); - set_flag_if(bit7, CARRY_FLAG); - set_flag_if(regs.A == 0, ZERO_FLAG); - reset_flag(ADD_SUB_FLAG); - reset_flag(HALF_CARRY_FLAG); - cycles_until_next_instruction = 4; - break; - } - - // RRCA - case 0x0F: { - u8 bit0 = regs.A & 1; - regs.A = (regs.A >> 1) | (bit0 << 7); - set_flag_if(regs.A == 0, ZERO_FLAG); - reset_flag(ADD_SUB_FLAG); - reset_flag(HALF_CARRY_FLAG); - // TODO: Check which of GBCPUman.pdf or - // worldofspectrum z80 reference is correct - // - //set_flag_if(bit0, CARRY_FLAG); - cycles_until_next_instruction = 4; - break; - } - - // RRA (through carry) - case 0x1F: { - u8 bit0 = regs.A & 1; - regs.A = (regs.A >> 1) | (check_flag(CARRY_FLAG) << 7); - set_flag_if(bit0, CARRY_FLAG); - set_flag_if(regs.A == 0, ZERO_FLAG); - reset_flag(ADD_SUB_FLAG); - reset_flag(HALF_CARRY_FLAG); - cycles_until_next_instruction = 4; - break; - } - - - // JR n - case 0x18: - // -1 because PC is now pointing past the opcode - regs.PC += static_cast(memory.read(regs.PC++)); - cycles_until_next_instruction = 8; - break; - - // JR cc, n - case 0x20: { // JR NZ, n - s8 offset = static_cast(memory.read(regs.PC++)); - if (!check_flag(ZERO_FLAG)) - regs.PC += offset; - cycles_until_next_instruction = 8; - break; - } - - case 0x28: { // JR Z, n - s8 offset = static_cast(memory.read(regs.PC++)); - if (check_flag(ZERO_FLAG)) - regs.PC += offset; - cycles_until_next_instruction = 8; - break; - } - - case 0x30: { // JR NC, n - s8 offset = static_cast(memory.read(regs.PC++)); - if (!check_flag(CARRY_FLAG)) - regs.PC += offset; - cycles_until_next_instruction = 8; - break; - } + // CPL + case 0x2F: + regs.A = ~regs.A; + set_flag(HALF_CARRY_FLAG); + set_flag(ADD_SUB_FLAG); + cycles_until_next_instruction = 4; + break; - case 0x38: { // JR C, n - s8 offset = static_cast(memory.read(regs.PC++)); - if (check_flag(CARRY_FLAG)) - regs.PC += offset; - cycles_until_next_instruction = 8; - break; - } + // CCF + case 0x3F: + if (check_flag(CARRY_FLAG)) + reset_flag(CARRY_FLAG); + else + set_flag(CARRY_FLAG); + reset_flag(HALF_CARRY_FLAG); + reset_flag(ADD_SUB_FLAG); + cycles_until_next_instruction = 4; + break; - - default: - std::ostringstream errmsg; - errmsg << "Unknown opcode 0x"; - errmsg << std::hex << std::setw(2) << std::setfill('0') << opcode; - errmsg << " at 0x" << std::hex << std::setw(4) << regs.PC-1; - errmsg << " (cycle count = " << std::dec << cycle_count << ")"; - logger.critical(errmsg.str()); - break; - - } // end switch - break; - case 0x80: - switch(opcode) - { - case 0xFA: // LD A, (nn) - regs.A = memory.read(memory.read16(regs.PC)); - regs.PC+=2; - cycles_until_next_instruction = 16; - break; - case 0xEA: // LD (nn), A - memory.write(memory.read16(regs.PC), regs.A); - regs.PC+=2; - cycles_until_next_instruction = 16; - break; - - // LD A, (C) - case 0xF2: - regs.A = memory.read(0xFF00 + regs.C); - cycles_until_next_instruction = 8; - break; - // LD (C), A - case 0xE2: - memory.write(0xFF00 + regs.C, regs.A); - cycles_until_next_instruction = 8; - break; - // LDH (n), A - case 0xE0: { - memory.high[memory.read(regs.PC++)] = regs.A; - cycles_until_next_instruction = 12; - break; - } - // LDH A, (n) - case 0xF0: - regs.A = memory.high[memory.read(regs.PC++)]; - cycles_until_next_instruction = 12; - break; - - // LD SP, HL - case 0xF9: - regs.SP = regs.HL; - cycles_until_next_instruction = 8; - break; - - // LD HL, SP+n - // LDHL SP, n - case 0xF8: { - s8 offset = memory.read(regs.PC++); - int res = regs.SP + offset; - - // TODO: Verificar si los flags van asi - set_flag_if (res > 0xFFFF, CARRY_FLAG); + // SCF + case 0x37: + set_flag(CARRY_FLAG); + reset_flag(HALF_CARRY_FLAG); + reset_flag(ADD_SUB_FLAG); + cycles_until_next_instruction = 4; + break; - // TODO: hacer lo apropiado con el half-carry flag - reset_flag(ADD_SUB_FLAG); - reset_flag(ZERO_FLAG); + // NOP + case 0x00: + cycles_until_next_instruction = 4; + break; - regs.HL = static_cast(res & 0xFFFF); - cycles_until_next_instruction = 12; - break; - } + // HALT + case 0x76: + HALT = true; + cycles_until_next_instruction = 4; + break; - // PUSH nn - PUSH(0xF5, A, flags) - PUSH(0xC5, B, C) - PUSH(0xD5, D, E) - PUSH(0xE5, H, L) - - // POP nn - POP(0xF1, A, flags) - POP(0xC1, B, C) - POP(0xD1, D, E) - POP(0xE1, H, L) - - // 8-bit ALU - // ADD A,reg - for_each_register(0x87, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, ADD_A_reg) - - case 0x86: {// ADD A, (HL) - int res = regs.A + memory.read(regs.HL); - int half_res = (regs.A & 0x0F) + (memory.read(regs.HL) & 0x0F); - regs.A = static_cast(res); - - reset_flag(ADD_SUB_FLAG); - set_flag_if (res > 0xFF, CARRY_FLAG); - set_flag_if (regs.A == 0, ZERO_FLAG); - set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG); - cycles_until_next_instruction = 8; - break; + // STOP + case 0x10: { + int sub_opcode = memory.read(regs.PC++); + if (sub_opcode == 0x00) { + HALT = true; + } else { + logger.critical("Unknown sub-opcode ", + std::hex, std::setw(2), std::setfill('0'), + sub_opcode, " after 0x10"); + } + cycles_until_next_instruction = 4; + break; } - case 0xC6: {//ADD A, # - int inm = memory.read(regs.PC++); - int res = regs.A + inm; - int half_res = (regs.A & 0x0F) + (inm & 0x0F); - regs.A = static_cast(res); - reset_flag(ADD_SUB_FLAG); - set_flag_if (res > 0xFF, CARRY_FLAG); - set_flag_if (regs.A == 0, ZERO_FLAG); - set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG); - cycles_until_next_instruction = 8; - break; + // Rotates and shifts + // RLCA + case 0x07: { + u8 bit7 = regs.A >>7; + regs.A = (regs.A << 1) | bit7; + set_flag_if(regs.A == 0, ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + reset_flag(HALF_CARRY_FLAG); + // TODO: Check which of GBCPUman.pdf or + // worldofspectrum z80 reference is correct + // + //set_flag_if(bit7, CARRY_FLAG); + cycles_until_next_instruction = 4; + break; } - // ADC A, n - for_each_register(0x8F, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, ADC_A_reg) - - case 0x8E: {// ADC A, (HL) - int carry = (check_flag(CARRY_FLAG)? 1 : 0); - int res = regs.A + memory.read(regs.HL) + carry; - int half_res = (regs.A & 0x0F) + (memory.read(regs.HL) & 0x0F) + carry; - regs.A = static_cast(res); - - reset_flag(ADD_SUB_FLAG); - set_flag_if (res > 0xFF, CARRY_FLAG); - set_flag_if (regs.A == 0, ZERO_FLAG); - set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG); - cycles_until_next_instruction = 8; - break; + // RLA (through carry) + case 0x17: { + u8 bit7 = regs.A >> 7; + regs.A = (regs.A << 1) | check_flag(CARRY_FLAG); + set_flag_if(bit7, CARRY_FLAG); + set_flag_if(regs.A == 0, ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + reset_flag(HALF_CARRY_FLAG); + cycles_until_next_instruction = 4; + break; } - case 0xCE: {//ADC A, # - int carry = (check_flag(CARRY_FLAG)? 1 : 0); - int inm = memory.read(regs.PC++); - int res = regs.A + inm + carry; - int half_res = (regs.A & 0x0F) + (inm & 0x0F) + carry; - regs.A = static_cast(res); - reset_flag(ADD_SUB_FLAG); - set_flag_if (res > 0xFF, CARRY_FLAG); - set_flag_if (regs.A == 0, ZERO_FLAG); - set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG); - cycles_until_next_instruction = 8; - break; + // RRCA + case 0x0F: { + u8 bit0 = regs.A & 1; + regs.A = (regs.A >> 1) | (bit0 << 7); + set_flag_if(regs.A == 0, ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + reset_flag(HALF_CARRY_FLAG); + // TODO: Check which of GBCPUman.pdf or + // worldofspectrum z80 reference is correct + // + //set_flag_if(bit0, CARRY_FLAG); + cycles_until_next_instruction = 4; + break; } - // SUB n - for_each_register(0x97, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, SUB_reg) + // RRA (through carry) + case 0x1F: { + u8 bit0 = regs.A & 1; + regs.A = (regs.A >> 1) | (check_flag(CARRY_FLAG) << 7); + set_flag_if(bit0, CARRY_FLAG); + set_flag_if(regs.A == 0, ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + reset_flag(HALF_CARRY_FLAG); + cycles_until_next_instruction = 4; + break; + } - case 0x96: {//SUB (HL) - int res = regs.A - memory.read(regs.HL); - int half_res = (regs.A & 0x0F) - (memory.read(regs.HL) & 0x0F); - regs.A = static_cast(res); + + // JR n + case 0x18: + // -1 because PC is now pointing past the opcode + regs.PC += static_cast(memory.read(regs.PC++)); + cycles_until_next_instruction = 8; + break; - set_flag(ADD_SUB_FLAG); - set_flag_if (res < 0, CARRY_FLAG); - set_flag_if (res == 0, ZERO_FLAG); - set_flag_if (half_res < 0, HALF_CARRY_FLAG); - cycles_until_next_instruction = 8; - break; + // JR cc, n + case 0x20: { // JR NZ, n + s8 offset = static_cast(memory.read(regs.PC++)); + if (!check_flag(ZERO_FLAG)) + regs.PC += offset; + cycles_until_next_instruction = 8; + break; } - - case 0xD6: {//SUB # - int inm = memory.read(regs.PC++); - int res = regs.A - inm; - int half_res = (regs.A & 0x0F) - (inm & 0x0F); - regs.A = static_cast(res); - - set_flag(ADD_SUB_FLAG); - set_flag_if (res < 0, CARRY_FLAG); - set_flag_if (res == 0, ZERO_FLAG); - set_flag_if (half_res < 0, HALF_CARRY_FLAG); - cycles_until_next_instruction = 8; - break; + + case 0x28: { // JR Z, n + s8 offset = static_cast(memory.read(regs.PC++)); + if (check_flag(ZERO_FLAG)) + regs.PC += offset; + cycles_until_next_instruction = 8; + break; } - // SBC n - for_each_register(0x9F, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, SBC_reg) - - case 0x9E: {//SBC (HL) - int carry = (check_flag(CARRY_FLAG)? 1 : 0); - int res = regs.A - memory.read(regs.HL) - carry; - int half_res = (regs.A & 0x0F) - (memory.read(regs.HL) & 0x0F) - carry; - regs.A = static_cast(res); - - set_flag(ADD_SUB_FLAG); - set_flag_if (res < 0, CARRY_FLAG); - set_flag_if (res == 0, ZERO_FLAG); - set_flag_if (half_res < 0, HALF_CARRY_FLAG); - cycles_until_next_instruction = 8; - break; + case 0x30: { // JR NC, n + s8 offset = static_cast(memory.read(regs.PC++)); + if (!check_flag(CARRY_FLAG)) + regs.PC += offset; + cycles_until_next_instruction = 8; + break; } - // There is no SBC inm - - // AND n - for_each_register(0xA7, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, AND_reg) - - case 0xA6: //AND (HL) - regs.A &= memory.read(regs.HL); - if (regs.A == 0) set_flag(ZERO_FLAG); - reset_flag(ADD_SUB_FLAG); - set_flag(HALF_CARRY_FLAG); - reset_flag(CARRY_FLAG); - cycles_until_next_instruction = 8; - break; - - case 0xE6: //AND inm - regs.A &= memory.read(regs.PC++); - if (regs.A == 0) set_flag(ZERO_FLAG); - reset_flag(ADD_SUB_FLAG); - set_flag(HALF_CARRY_FLAG); - reset_flag(CARRY_FLAG); - cycles_until_next_instruction = 8; - break; - - // OR n - for_each_register(0xB7, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, OR_reg) - - case 0xB6: //OR (HL) - regs.A |= memory.read(regs.HL); - if (regs.A == 0) set_flag(ZERO_FLAG); - reset_flag(ADD_SUB_FLAG); - reset_flag(HALF_CARRY_FLAG); - reset_flag(CARRY_FLAG); - cycles_until_next_instruction = 8; - break; - - case 0xF6: //OR inm - regs.A |= memory.read(regs.PC++); - if (regs.A == 0) set_flag(ZERO_FLAG); - reset_flag(ADD_SUB_FLAG); - reset_flag(HALF_CARRY_FLAG); - reset_flag(CARRY_FLAG); - cycles_until_next_instruction = 8; - break; - - // XOR n - for_each_register(0xAF, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, XOR_reg) - - case 0xAE: //XOR (HL) - regs.A ^= memory.read(regs.HL); - if (regs.A == 0) set_flag(ZERO_FLAG); - reset_flag(ADD_SUB_FLAG); - reset_flag(HALF_CARRY_FLAG); - reset_flag(CARRY_FLAG); - cycles_until_next_instruction = 8; - break; - - case 0xEE: //XOR inm - regs.A ^= memory.read(regs.PC++); - if (regs.A == 0) set_flag(ZERO_FLAG); - reset_flag(ADD_SUB_FLAG); - reset_flag(HALF_CARRY_FLAG); - reset_flag(CARRY_FLAG); - cycles_until_next_instruction = 8; - break; - - // CP n - for_each_register(0xBF, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, CP_reg) - - case 0xBE: {//CP (HL) - int res = regs.A - memory.read(regs.HL); - int half_res = (regs.A & 0x0F) - (memory.read(regs.HL) & 0x0F); - - set_flag(ADD_SUB_FLAG); - set_flag_if (res < 0, CARRY_FLAG); - set_flag_if (res == 0, ZERO_FLAG); - set_flag_if (half_res < 0, HALF_CARRY_FLAG); - cycles_until_next_instruction = 8; - break; + case 0x38: { // JR C, n + s8 offset = static_cast(memory.read(regs.PC++)); + if (check_flag(CARRY_FLAG)) + regs.PC += offset; + cycles_until_next_instruction = 8; + break; } + + - case 0xFE: {//CP # - int inm = memory.read(regs.PC++); - int res = regs.A - inm; - int half_res = (regs.A & 0x0F) - (inm & 0x0F); - - set_flag(ADD_SUB_FLAG); - set_flag_if (res < 0, CARRY_FLAG); - set_flag_if (res == 0, ZERO_FLAG); - set_flag_if (half_res < 0, HALF_CARRY_FLAG); - cycles_until_next_instruction = 8; - break; + default: + std::ostringstream errmsg; + errmsg << "Unknown opcode 0x"; + errmsg << std::hex << std::setw(2) << std::setfill('0') << opcode; + errmsg << " at 0x" << std::hex << std::setw(4) << regs.PC-1; + errmsg << " (cycle count = " << std::dec << cycle_count << ")"; + logger.critical(errmsg.str()); + break; + + } // end switch + break; + case 0x80: + switch(opcode) + { + case 0xFA: // LD A, (nn) + regs.A = memory.read(memory.read16(regs.PC)); + regs.PC+=2; + cycles_until_next_instruction = 16; + break; + case 0xEA: // LD (nn), A + memory.write(memory.read16(regs.PC), regs.A); + regs.PC+=2; + cycles_until_next_instruction = 16; + break; + + // LD A, (C) + case 0xF2: + regs.A = memory.read(0xFF00 + regs.C); + cycles_until_next_instruction = 8; + break; + // LD (C), A + case 0xE2: + memory.write(0xFF00 + regs.C, regs.A); + cycles_until_next_instruction = 8; + break; + // LDH (n), A + case 0xE0: { + memory.high[memory.read(regs.PC++)] = regs.A; + cycles_until_next_instruction = 12; + break; } + // LDH A, (n) + case 0xF0: + regs.A = memory.high[memory.read(regs.PC++)]; + cycles_until_next_instruction = 12; + break; - // ADD SP, # - case 0xE8: { - // FIXME: No se que hacer con el half carry, en 4 o en 11? - int n = static_cast(memory.read(regs.PC++)); - int res = regs.SP + n; - regs.SP = static_cast(res); - reset_flag(ZERO_FLAG); - reset_flag(ADD_SUB_FLAG); - set_flag_if(res > 0xFFFF, CARRY_FLAG); - cycles_until_next_instruction = 16; - break; - } + // LD SP, HL + case 0xF9: + regs.SP = regs.HL; + cycles_until_next_instruction = 8; + break; - // Miscellaneous instructions - case 0xCB: { - int sub_opcode = memory.read(regs.PC++); - switch(sub_opcode) - { - // SWAP n - for_each_register(0x37, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, SWAP_reg) - - // SWAP (HL) - case 0x36: { - u8 tmp = memory.read(regs.HL); - tmp = ((tmp & 0x0F) << 4) | ((tmp & 0xF0)>>4); - memory.write(regs.HL, tmp); - - set_flag_if(tmp==0, ZERO_FLAG); - reset_flag(CARRY_FLAG); - reset_flag(HALF_CARRY_FLAG); - reset_flag(ADD_SUB_FLAG); - cycles_until_next_instruction = 16; - break; - } + // LD HL, SP+n + // LDHL SP, n + case 0xF8: { + s8 offset = memory.read(regs.PC++); + int res = regs.SP + offset; + + // TODO: Verificar si los flags van asi + set_flag_if (res > 0xFFFF, CARRY_FLAG); - // RLC n - for_each_register(0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, RLC_reg) - - // RLC (HL) - case 0x06: { - u8 value = memory.read(regs.HL); - u8 bit7 = value >> 7; - value = (value << 1) | bit7; - memory.write(regs.HL, value); - set_flag_if(value == 0, ZERO_FLAG); - reset_flag(ADD_SUB_FLAG); - reset_flag(HALF_CARRY_FLAG); - cycles_until_next_instruction = 16; - break; - } + // TODO: hacer lo apropiado con el half-carry flag + reset_flag(ADD_SUB_FLAG); + reset_flag(ZERO_FLAG); - // RL n (through carry) - for_each_register(0x17, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, RL_reg) - - // RL (HL) (through carry) - case 0x16: { - u8 value = memory.read(regs.HL); - u8 bit7 = value >> 7; - value = (value << 1) | check_flag(CARRY_FLAG); - memory.write(regs.HL, value); - set_flag_if(bit7, CARRY_FLAG); - set_flag_if(value == 0, ZERO_FLAG); - reset_flag(ADD_SUB_FLAG); - reset_flag(HALF_CARRY_FLAG); - cycles_until_next_instruction = 16; - break; + regs.HL = static_cast(res & 0xFFFF); + cycles_until_next_instruction = 12; + break; } - // RRC n - for_each_register(0x0F, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, RRC_reg) - - // RRC (HL) - case 0x0E: { - u8 value = memory.read(regs.HL); - u8 bit0 = value & 1; - value = (value >> 1) | (bit0 << 7); - memory.write(regs.HL, value); - set_flag_if(value == 0, ZERO_FLAG); - reset_flag(ADD_SUB_FLAG); - reset_flag(HALF_CARRY_FLAG); - cycles_until_next_instruction = 16; - break; + // PUSH nn + PUSH(0xF5, A, flags) + PUSH(0xC5, B, C) + PUSH(0xD5, D, E) + PUSH(0xE5, H, L) + + // POP nn + POP(0xF1, A, flags) + POP(0xC1, B, C) + POP(0xD1, D, E) + POP(0xE1, H, L) + + // 8-bit ALU + // ADD A,reg + for_each_register(0x87, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, ADD_A_reg) + + case 0x86: {// ADD A, (HL) + int res = regs.A + memory.read(regs.HL); + int half_res = (regs.A & 0x0F) + (memory.read(regs.HL) & 0x0F); + regs.A = static_cast(res); + + reset_flag(ADD_SUB_FLAG); + set_flag_if (res > 0xFF, CARRY_FLAG); + set_flag_if (regs.A == 0, ZERO_FLAG); + set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG); + cycles_until_next_instruction = 8; + break; } - - // RR n (through carry) - for_each_register(0x1F, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, RR_reg) - - // RR (HL) (through carry) - case 0x1E: { - u8 value = memory.read(regs.HL); - u8 bit0 = value & 1; - value = (value >> 1) | (check_flag(CARRY_FLAG) << 7); - memory.write(regs.HL, value); - set_flag_if(bit0, CARRY_FLAG); - set_flag_if(value == 0, ZERO_FLAG); - reset_flag(ADD_SUB_FLAG); - reset_flag(HALF_CARRY_FLAG); - cycles_until_next_instruction = 16; - break; + case 0xC6: {//ADD A, # + int inm = memory.read(regs.PC++); + int res = regs.A + inm; + int half_res = (regs.A & 0x0F) + (inm & 0x0F); + regs.A = static_cast(res); + + reset_flag(ADD_SUB_FLAG); + set_flag_if (res > 0xFF, CARRY_FLAG); + set_flag_if (regs.A == 0, ZERO_FLAG); + set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG); + cycles_until_next_instruction = 8; + break; } + + // ADC A, n + for_each_register(0x8F, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, ADC_A_reg) + + case 0x8E: {// ADC A, (HL) + int carry = (check_flag(CARRY_FLAG)? 1 : 0); + int res = regs.A + memory.read(regs.HL) + carry; + int half_res = (regs.A & 0x0F) + (memory.read(regs.HL) & 0x0F) + carry; + regs.A = static_cast(res); - // SLA n - for_each_register(0x27, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, SLA_reg) - - // SLA (HL) - case 0x26: { - u8 value = memory.read(regs.HL); - bool carry = (value & 0x80) != 0; - value <<= 1; - memory.write(regs.HL, value); - set_flag_if(value == 0, ZERO_FLAG); - reset_flag(ADD_SUB_FLAG); - reset_flag(HALF_CARRY_FLAG); - set_flag_if(carry, CARRY_FLAG); - cycles_until_next_instruction = 16; - break; + reset_flag(ADD_SUB_FLAG); + set_flag_if (res > 0xFF, CARRY_FLAG); + set_flag_if (regs.A == 0, ZERO_FLAG); + set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG); + cycles_until_next_instruction = 8; + break; } + case 0xCE: {//ADC A, # + int carry = (check_flag(CARRY_FLAG)? 1 : 0); + int inm = memory.read(regs.PC++); + int res = regs.A + inm + carry; + int half_res = (regs.A & 0x0F) + (inm & 0x0F) + carry; + regs.A = static_cast(res); - // SRA n - for_each_register(0x2F, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, SRA_reg) - - // SRA (HL) - case 0x2E: { - u8 value = memory.read(regs.HL); - bool carry = (value & 0x01) != 0; - u8 MSB = value & 0x80; - value = (value >> 1) | MSB; - memory.write(regs.HL, value); - set_flag_if(value == 0, ZERO_FLAG); - reset_flag(ADD_SUB_FLAG); - reset_flag(HALF_CARRY_FLAG); - set_flag_if(carry, CARRY_FLAG); - cycles_until_next_instruction = 16; - break; + reset_flag(ADD_SUB_FLAG); + set_flag_if (res > 0xFF, CARRY_FLAG); + set_flag_if (regs.A == 0, ZERO_FLAG); + set_flag_if (half_res > 0x0F, HALF_CARRY_FLAG); + cycles_until_next_instruction = 8; + break; } - // SRL n - for_each_register(0x3F, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, SRL_reg) - - // SRL (HL) - case 0x3E: { - u8 value = memory.read(regs.HL); - bool carry = (value & 0x01) != 0; - value >>= 1; - memory.write(regs.HL, value); - set_flag_if(value == 0, ZERO_FLAG); - reset_flag(ADD_SUB_FLAG); - reset_flag(HALF_CARRY_FLAG); - set_flag_if(carry, CARRY_FLAG); - cycles_until_next_instruction = 16; - break; + // SUB n + for_each_register(0x97, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, SUB_reg) + + case 0x96: {//SUB (HL) + int res = regs.A - memory.read(regs.HL); + int half_res = (regs.A & 0x0F) - (memory.read(regs.HL) & 0x0F); + regs.A = static_cast(res); + + set_flag(ADD_SUB_FLAG); + set_flag_if (res < 0, CARRY_FLAG); + set_flag_if (res == 0, ZERO_FLAG); + set_flag_if (half_res < 0, HALF_CARRY_FLAG); + cycles_until_next_instruction = 8; + break; + } + + case 0xD6: {//SUB # + int inm = memory.read(regs.PC++); + int res = regs.A - inm; + int half_res = (regs.A & 0x0F) - (inm & 0x0F); + regs.A = static_cast(res); + + set_flag(ADD_SUB_FLAG); + set_flag_if (res < 0, CARRY_FLAG); + set_flag_if (res == 0, ZERO_FLAG); + set_flag_if (half_res < 0, HALF_CARRY_FLAG); + cycles_until_next_instruction = 8; + break; } - default: { - int bit_op = sub_opcode >> 6; - int reg = sub_opcode & 7; - int b = (sub_opcode >> 3) & 7; - bool res; - switch (bit_op) - { - case 1: // BIT - switch(reg) - { - case 0: - res = check_bit(regs.B, b); - set_flag_if(res == false, ZERO_FLAG); - reset_flag(ADD_SUB_FLAG); - set_flag(HALF_CARRY_FLAG); - cycles_until_next_instruction = 8; - break; - case 1: - res = check_bit(regs.C, b); - set_flag_if(res == false, ZERO_FLAG); - reset_flag(ADD_SUB_FLAG); - set_flag(HALF_CARRY_FLAG); - cycles_until_next_instruction = 8; - break; - case 2: - res = check_bit(regs.D, b); - set_flag_if(res == false, ZERO_FLAG); - reset_flag(ADD_SUB_FLAG); - set_flag(HALF_CARRY_FLAG); - cycles_until_next_instruction = 8; - break; - case 3: - res = check_bit(regs.E, b); - set_flag_if(res == false, ZERO_FLAG); - reset_flag(ADD_SUB_FLAG); - set_flag(HALF_CARRY_FLAG); - cycles_until_next_instruction = 8; - break; - case 4: - res = check_bit(regs.H, b); - set_flag_if(res == false, ZERO_FLAG); - reset_flag(ADD_SUB_FLAG); - set_flag(HALF_CARRY_FLAG); - cycles_until_next_instruction = 8; - break; - case 5: - res = check_bit(regs.L, b); - set_flag_if(res == false, ZERO_FLAG); - reset_flag(ADD_SUB_FLAG); - set_flag(HALF_CARRY_FLAG); - cycles_until_next_instruction = 8; - break; - case 6: - res = check_bit(memory.read(regs.HL), b); - set_flag_if(res == false, ZERO_FLAG); - reset_flag(ADD_SUB_FLAG); - set_flag(HALF_CARRY_FLAG); - cycles_until_next_instruction = 16; - break; - case 7: - res = check_bit(regs.A, b); - set_flag_if(res == false, ZERO_FLAG); - reset_flag(ADD_SUB_FLAG); - set_flag(HALF_CARRY_FLAG); - cycles_until_next_instruction = 8; - break; - } - break; + // SBC n + for_each_register(0x9F, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, SBC_reg) - case 2: // RES - switch(reg) - { - case 0: - regs.B = reset_bit(regs.B, b); - cycles_until_next_instruction = 8; - break; - case 1: - regs.C = reset_bit(regs.C, b); - cycles_until_next_instruction = 8; - break; - case 2: - regs.D = reset_bit(regs.D, b); - cycles_until_next_instruction = 8; - break; - case 3: - regs.E = reset_bit(regs.E, b); - cycles_until_next_instruction = 8; - break; - case 4: - regs.H = reset_bit(regs.H, b); - cycles_until_next_instruction = 8; - break; - case 5: - regs.L = reset_bit(regs.L, b); - cycles_until_next_instruction = 8; - break; - case 6: - memory.write(regs.HL, reset_bit(memory.read(regs.HL), b)); - cycles_until_next_instruction = 16; - break; - case 7: - regs.A = reset_bit(regs.A, b); - cycles_until_next_instruction = 8; - break; - } - break; + case 0x9E: {//SBC (HL) + int carry = (check_flag(CARRY_FLAG)? 1 : 0); + int res = regs.A - memory.read(regs.HL) - carry; + int half_res = (regs.A & 0x0F) - (memory.read(regs.HL) & 0x0F) - carry; + regs.A = static_cast(res); - case 3: // SET - switch(reg) - { - case 0: - regs.B = set_bit(regs.B, b); - cycles_until_next_instruction = 8; - break; - case 1: - regs.C = set_bit(regs.C, b); - cycles_until_next_instruction = 8; - break; - case 2: - regs.D = set_bit(regs.D, b); - cycles_until_next_instruction = 8; - break; - case 3: - regs.E = set_bit(regs.E, b); - cycles_until_next_instruction = 8; - break; - case 4: - regs.H = set_bit(regs.H, b); - cycles_until_next_instruction = 8; - break; - case 5: - regs.L = set_bit(regs.L, b); - cycles_until_next_instruction = 8; - break; - case 6: - memory.write(regs.HL, set_bit(memory.read(regs.HL), b)); - cycles_until_next_instruction = 16; - break; - case 7: - regs.A = set_bit(regs.A, b); - cycles_until_next_instruction = 8; - break; - } - break; - - default: - logger.critical("Unknown sub-opcode after 0xCB"); - break; - } + set_flag(ADD_SUB_FLAG); + set_flag_if (res < 0, CARRY_FLAG); + set_flag_if (res == 0, ZERO_FLAG); + set_flag_if (half_res < 0, HALF_CARRY_FLAG); + cycles_until_next_instruction = 8; + break; } - + + // There is no SBC inm + + // AND n + for_each_register(0xA7, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, AND_reg) + + case 0xA6: //AND (HL) + regs.A &= memory.read(regs.HL); + if (regs.A == 0) set_flag(ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + set_flag(HALF_CARRY_FLAG); + reset_flag(CARRY_FLAG); + cycles_until_next_instruction = 8; + break; + + case 0xE6: //AND inm + regs.A &= memory.read(regs.PC++); + if (regs.A == 0) set_flag(ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + set_flag(HALF_CARRY_FLAG); + reset_flag(CARRY_FLAG); + cycles_until_next_instruction = 8; + break; + + // OR n + for_each_register(0xB7, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, OR_reg) + + case 0xB6: //OR (HL) + regs.A |= memory.read(regs.HL); + if (regs.A == 0) set_flag(ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + reset_flag(HALF_CARRY_FLAG); + reset_flag(CARRY_FLAG); + cycles_until_next_instruction = 8; + break; + + case 0xF6: //OR inm + regs.A |= memory.read(regs.PC++); + if (regs.A == 0) set_flag(ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + reset_flag(HALF_CARRY_FLAG); + reset_flag(CARRY_FLAG); + cycles_until_next_instruction = 8; + break; + + // XOR n + for_each_register(0xAF, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, XOR_reg) + + case 0xAE: //XOR (HL) + regs.A ^= memory.read(regs.HL); + if (regs.A == 0) set_flag(ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + reset_flag(HALF_CARRY_FLAG); + reset_flag(CARRY_FLAG); + cycles_until_next_instruction = 8; + break; + + case 0xEE: //XOR inm + regs.A ^= memory.read(regs.PC++); + if (regs.A == 0) set_flag(ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + reset_flag(HALF_CARRY_FLAG); + reset_flag(CARRY_FLAG); + cycles_until_next_instruction = 8; + break; + + // CP n + for_each_register(0xBF, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, CP_reg) + + case 0xBE: {//CP (HL) + int res = regs.A - memory.read(regs.HL); + int half_res = (regs.A & 0x0F) - (memory.read(regs.HL) & 0x0F); + + set_flag(ADD_SUB_FLAG); + set_flag_if (res < 0, CARRY_FLAG); + set_flag_if (res == 0, ZERO_FLAG); + set_flag_if (half_res < 0, HALF_CARRY_FLAG); + cycles_until_next_instruction = 8; + break; + } + + case 0xFE: {//CP # + int inm = memory.read(regs.PC++); + int res = regs.A - inm; + int half_res = (regs.A & 0x0F) - (inm & 0x0F); + + set_flag(ADD_SUB_FLAG); + set_flag_if (res < 0, CARRY_FLAG); + set_flag_if (res == 0, ZERO_FLAG); + set_flag_if (half_res < 0, HALF_CARRY_FLAG); + cycles_until_next_instruction = 8; + break; + } + + // ADD SP, # + case 0xE8: { + // FIXME: No se que hacer con el half carry, en 4 o en 11? + int n = static_cast(memory.read(regs.PC++)); + int res = regs.SP + n; + regs.SP = static_cast(res); + reset_flag(ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + set_flag_if(res > 0xFFFF, CARRY_FLAG); + cycles_until_next_instruction = 16; + break; } - break; - } - // DI - case 0xF3: - IME = 0; - cycles_until_next_instruction = 4; - break; - - // EI - case 0xFB: - IME = 1; - cycles_until_next_instruction = 4; - break; - - // Jumps - // JP nn - case 0xC3: - regs.PC = memory.read16(regs.PC); - cycles_until_next_instruction = 12; - break; - - // JP cc, nn - case 0xC2: { // JP NZ, nn - u16 dst = memory.read16(regs.PC); - if (!check_flag(ZERO_FLAG)) - regs.PC = dst; - else - regs.PC += 2; // if !cc, skip 2 dst bytes - cycles_until_next_instruction = 12; - break; - } - case 0xCA: { // JP Z, nn - u16 dst = memory.read16(regs.PC); - if (check_flag(ZERO_FLAG)) - regs.PC = dst; - else - regs.PC += 2; // if !cc, skip 2 dst bytes - cycles_until_next_instruction = 12; - break; - } + // Miscellaneous instructions + case 0xCB: { + int sub_opcode = memory.read(regs.PC++); + switch(sub_opcode) + { + // SWAP n + for_each_register(0x37, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, SWAP_reg) + + // SWAP (HL) + case 0x36: { + u8 tmp = memory.read(regs.HL); + tmp = ((tmp & 0x0F) << 4) | ((tmp & 0xF0)>>4); + memory.write(regs.HL, tmp); + + set_flag_if(tmp==0, ZERO_FLAG); + reset_flag(CARRY_FLAG); + reset_flag(HALF_CARRY_FLAG); + reset_flag(ADD_SUB_FLAG); + cycles_until_next_instruction = 16; + break; + } - case 0xD2: { // JP NC, nn - u16 dst = memory.read16(regs.PC); - if (!check_flag(CARRY_FLAG)) - regs.PC = dst; - else - regs.PC += 2; // if !cc, skip 2 dst bytes - cycles_until_next_instruction = 12; - break; - } + // RLC n + for_each_register(0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, RLC_reg) + + // RLC (HL) + case 0x06: { + u8 value = memory.read(regs.HL); + u8 bit7 = value >> 7; + value = (value << 1) | bit7; + memory.write(regs.HL, value); + set_flag_if(value == 0, ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + reset_flag(HALF_CARRY_FLAG); + cycles_until_next_instruction = 16; + break; + } - case 0xDA: { // JP C, nn - u16 dst = memory.read16(regs.PC); - if (check_flag(CARRY_FLAG)) - regs.PC = dst; - else - regs.PC += 2; // if !cc, skip 2 dst bytes - cycles_until_next_instruction = 12; - break; - } + // RL n (through carry) + for_each_register(0x17, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, RL_reg) + + // RL (HL) (through carry) + case 0x16: { + u8 value = memory.read(regs.HL); + u8 bit7 = value >> 7; + value = (value << 1) | check_flag(CARRY_FLAG); + memory.write(regs.HL, value); + set_flag_if(bit7, CARRY_FLAG); + set_flag_if(value == 0, ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + reset_flag(HALF_CARRY_FLAG); + cycles_until_next_instruction = 16; + break; + } - // JP (HL) - case 0xE9: - regs.PC = regs.HL; - cycles_until_next_instruction = 4; - break; - - // Calls - // CALL nn - case 0xCD: { - u16 addr = memory.read16(regs.PC); - regs.PC += 2; - do_call(addr); - cycles_until_next_instruction = 12; - break; - } + // RRC n + for_each_register(0x0F, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, RRC_reg) + + // RRC (HL) + case 0x0E: { + u8 value = memory.read(regs.HL); + u8 bit0 = value & 1; + value = (value >> 1) | (bit0 << 7); + memory.write(regs.HL, value); + set_flag_if(value == 0, ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + reset_flag(HALF_CARRY_FLAG); + cycles_until_next_instruction = 16; + break; + } - // CALL cc, nn - case 0xC4: { // CALL NZ, nn - if (!check_flag(ZERO_FLAG)) { - u16 addr = memory.read16(regs.PC); - regs.PC += 2; - do_call(addr); - } else { - regs.PC += 2; // if !cc, skip 2 (nn) bytes + // RR n (through carry) + for_each_register(0x1F, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, RR_reg) + + // RR (HL) (through carry) + case 0x1E: { + u8 value = memory.read(regs.HL); + u8 bit0 = value & 1; + value = (value >> 1) | (check_flag(CARRY_FLAG) << 7); + memory.write(regs.HL, value); + set_flag_if(bit0, CARRY_FLAG); + set_flag_if(value == 0, ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + reset_flag(HALF_CARRY_FLAG); + cycles_until_next_instruction = 16; + break; + } + + // SLA n + for_each_register(0x27, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, SLA_reg) + + // SLA (HL) + case 0x26: { + u8 value = memory.read(regs.HL); + bool carry = (value & 0x80) != 0; + value <<= 1; + memory.write(regs.HL, value); + set_flag_if(value == 0, ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + reset_flag(HALF_CARRY_FLAG); + set_flag_if(carry, CARRY_FLAG); + cycles_until_next_instruction = 16; + break; + } + + // SRA n + for_each_register(0x2F, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, SRA_reg) + + // SRA (HL) + case 0x2E: { + u8 value = memory.read(regs.HL); + bool carry = (value & 0x01) != 0; + u8 MSB = value & 0x80; + value = (value >> 1) | MSB; + memory.write(regs.HL, value); + set_flag_if(value == 0, ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + reset_flag(HALF_CARRY_FLAG); + set_flag_if(carry, CARRY_FLAG); + cycles_until_next_instruction = 16; + break; + } + + // SRL n + for_each_register(0x3F, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, SRL_reg) + + // SRL (HL) + case 0x3E: { + u8 value = memory.read(regs.HL); + bool carry = (value & 0x01) != 0; + value >>= 1; + memory.write(regs.HL, value); + set_flag_if(value == 0, ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + reset_flag(HALF_CARRY_FLAG); + set_flag_if(carry, CARRY_FLAG); + cycles_until_next_instruction = 16; + break; + } + + default: { + int bit_op = sub_opcode >> 6; + int reg = sub_opcode & 7; + int b = (sub_opcode >> 3) & 7; + bool res; + switch (bit_op) + { + case 1: // BIT + switch(reg) + { + case 0: + res = check_bit(regs.B, b); + set_flag_if(res == false, ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + set_flag(HALF_CARRY_FLAG); + cycles_until_next_instruction = 8; + break; + case 1: + res = check_bit(regs.C, b); + set_flag_if(res == false, ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + set_flag(HALF_CARRY_FLAG); + cycles_until_next_instruction = 8; + break; + case 2: + res = check_bit(regs.D, b); + set_flag_if(res == false, ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + set_flag(HALF_CARRY_FLAG); + cycles_until_next_instruction = 8; + break; + case 3: + res = check_bit(regs.E, b); + set_flag_if(res == false, ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + set_flag(HALF_CARRY_FLAG); + cycles_until_next_instruction = 8; + break; + case 4: + res = check_bit(regs.H, b); + set_flag_if(res == false, ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + set_flag(HALF_CARRY_FLAG); + cycles_until_next_instruction = 8; + break; + case 5: + res = check_bit(regs.L, b); + set_flag_if(res == false, ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + set_flag(HALF_CARRY_FLAG); + cycles_until_next_instruction = 8; + break; + case 6: + res = check_bit(memory.read(regs.HL), b); + set_flag_if(res == false, ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + set_flag(HALF_CARRY_FLAG); + cycles_until_next_instruction = 16; + break; + case 7: + res = check_bit(regs.A, b); + set_flag_if(res == false, ZERO_FLAG); + reset_flag(ADD_SUB_FLAG); + set_flag(HALF_CARRY_FLAG); + cycles_until_next_instruction = 8; + break; + } + break; + + case 2: // RES + switch(reg) + { + case 0: + regs.B = reset_bit(regs.B, b); + cycles_until_next_instruction = 8; + break; + case 1: + regs.C = reset_bit(regs.C, b); + cycles_until_next_instruction = 8; + break; + case 2: + regs.D = reset_bit(regs.D, b); + cycles_until_next_instruction = 8; + break; + case 3: + regs.E = reset_bit(regs.E, b); + cycles_until_next_instruction = 8; + break; + case 4: + regs.H = reset_bit(regs.H, b); + cycles_until_next_instruction = 8; + break; + case 5: + regs.L = reset_bit(regs.L, b); + cycles_until_next_instruction = 8; + break; + case 6: + memory.write(regs.HL, reset_bit(memory.read(regs.HL), b)); + cycles_until_next_instruction = 16; + break; + case 7: + regs.A = reset_bit(regs.A, b); + cycles_until_next_instruction = 8; + break; + } + break; + + case 3: // SET + switch(reg) + { + case 0: + regs.B = set_bit(regs.B, b); + cycles_until_next_instruction = 8; + break; + case 1: + regs.C = set_bit(regs.C, b); + cycles_until_next_instruction = 8; + break; + case 2: + regs.D = set_bit(regs.D, b); + cycles_until_next_instruction = 8; + break; + case 3: + regs.E = set_bit(regs.E, b); + cycles_until_next_instruction = 8; + break; + case 4: + regs.H = set_bit(regs.H, b); + cycles_until_next_instruction = 8; + break; + case 5: + regs.L = set_bit(regs.L, b); + cycles_until_next_instruction = 8; + break; + case 6: + memory.write(regs.HL, set_bit(memory.read(regs.HL), b)); + cycles_until_next_instruction = 16; + break; + case 7: + regs.A = set_bit(regs.A, b); + cycles_until_next_instruction = 8; + break; + } + break; + + default: + logger.critical("Unknown sub-opcode after 0xCB"); + break; + } + } + + } + break; } - cycles_until_next_instruction = 12; - break; - } + // DI + case 0xF3: + IME = 0; + cycles_until_next_instruction = 4; + break; - case 0xCC: { // CALL Z, nn - if (check_flag(ZERO_FLAG)) { - u16 addr = memory.read16(regs.PC); - regs.PC += 2; - do_call(addr); - } else { - regs.PC += 2; // if !cc, skip 2 (nn) bytes + // EI + case 0xFB: + IME = 1; + cycles_until_next_instruction = 4; + break; + + // Jumps + // JP nn + case 0xC3: + regs.PC = memory.read16(regs.PC); + cycles_until_next_instruction = 12; + break; + + // JP cc, nn + case 0xC2: { // JP NZ, nn + u16 dst = memory.read16(regs.PC); + if (!check_flag(ZERO_FLAG)) + regs.PC = dst; + else + regs.PC += 2; // if !cc, skip 2 dst bytes + cycles_until_next_instruction = 12; + break; } - cycles_until_next_instruction = 12; - break; - } - case 0xD4: { // CALL NC, nn - if (!check_flag(CARRY_FLAG)) { - u16 addr = memory.read16(regs.PC); - regs.PC += 2; - do_call(addr); - } else { - regs.PC += 2; // if !cc, skip 2 (nn) bytes + case 0xCA: { // JP Z, nn + u16 dst = memory.read16(regs.PC); + if (check_flag(ZERO_FLAG)) + regs.PC = dst; + else + regs.PC += 2; // if !cc, skip 2 dst bytes + cycles_until_next_instruction = 12; + break; + } + + case 0xD2: { // JP NC, nn + u16 dst = memory.read16(regs.PC); + if (!check_flag(CARRY_FLAG)) + regs.PC = dst; + else + regs.PC += 2; // if !cc, skip 2 dst bytes + cycles_until_next_instruction = 12; + break; + } + + case 0xDA: { // JP C, nn + u16 dst = memory.read16(regs.PC); + if (check_flag(CARRY_FLAG)) + regs.PC = dst; + else + regs.PC += 2; // if !cc, skip 2 dst bytes + cycles_until_next_instruction = 12; + break; } - cycles_until_next_instruction = 12; - break; - } - case 0xDC: { // CALL C, nn - if (check_flag(CARRY_FLAG)) { + // JP (HL) + case 0xE9: + regs.PC = regs.HL; + cycles_until_next_instruction = 4; + break; + + // Calls + // CALL nn + case 0xCD: { u16 addr = memory.read16(regs.PC); regs.PC += 2; do_call(addr); - } else { - regs.PC += 2; // if !cc, skip 2 (nn) bytes + cycles_until_next_instruction = 12; + break; } - cycles_until_next_instruction = 12; - break; - } - // Restarts - RST(0xC7, 0x00) - RST(0xCF, 0x08) - RST(0xD7, 0x10) - RST(0xDF, 0x18) - RST(0xE7, 0x20) - RST(0xEF, 0x28) - RST(0xF7, 0x30) - RST(0xFF, 0x38) - - // Returns - // RET - case 0xC9: { - u16 retaddr = memory.read16(regs.SP); - regs.SP += 2; - regs.PC = retaddr; - cycles_until_next_instruction = 8; - break; - } + // CALL cc, nn + case 0xC4: { // CALL NZ, nn + if (!check_flag(ZERO_FLAG)) { + u16 addr = memory.read16(regs.PC); + regs.PC += 2; + do_call(addr); + } else { + regs.PC += 2; // if !cc, skip 2 (nn) bytes + } + cycles_until_next_instruction = 12; + break; + } - // RET cc - case 0xC0: // RET NZ - if (!check_flag(ZERO_FLAG)) { - u16 retaddr = memory.read16(regs.SP); - regs.SP += 2; - regs.PC = retaddr; + case 0xCC: { // CALL Z, nn + if (check_flag(ZERO_FLAG)) { + u16 addr = memory.read16(regs.PC); + regs.PC += 2; + do_call(addr); + } else { + regs.PC += 2; // if !cc, skip 2 (nn) bytes + } + cycles_until_next_instruction = 12; + break; } - cycles_until_next_instruction = 8; - break; - case 0xC8: // RET Z - if (check_flag(ZERO_FLAG)) { - u16 retaddr = memory.read16(regs.SP); - regs.SP += 2; - regs.PC = retaddr; + case 0xD4: { // CALL NC, nn + if (!check_flag(CARRY_FLAG)) { + u16 addr = memory.read16(regs.PC); + regs.PC += 2; + do_call(addr); + } else { + regs.PC += 2; // if !cc, skip 2 (nn) bytes + } + cycles_until_next_instruction = 12; + break; + } + + case 0xDC: { // CALL C, nn + if (check_flag(CARRY_FLAG)) { + u16 addr = memory.read16(regs.PC); + regs.PC += 2; + do_call(addr); + } else { + regs.PC += 2; // if !cc, skip 2 (nn) bytes + } + cycles_until_next_instruction = 12; + break; } - cycles_until_next_instruction = 8; - break; - case 0xD0: // RET NC - if (!check_flag(CARRY_FLAG)) { + // Restarts + RST(0xC7, 0x00) + RST(0xCF, 0x08) + RST(0xD7, 0x10) + RST(0xDF, 0x18) + RST(0xE7, 0x20) + RST(0xEF, 0x28) + RST(0xF7, 0x30) + RST(0xFF, 0x38) + + // Returns + // RET + case 0xC9: { u16 retaddr = memory.read16(regs.SP); regs.SP += 2; regs.PC = retaddr; + cycles_until_next_instruction = 8; + break; } - cycles_until_next_instruction = 8; - break; - case 0xD8: // RET C - if (check_flag(CARRY_FLAG)) { + // RET cc + case 0xC0: // RET NZ + if (!check_flag(ZERO_FLAG)) { + u16 retaddr = memory.read16(regs.SP); + regs.SP += 2; + regs.PC = retaddr; + } + cycles_until_next_instruction = 8; + break; + + case 0xC8: // RET Z + if (check_flag(ZERO_FLAG)) { + u16 retaddr = memory.read16(regs.SP); + regs.SP += 2; + regs.PC = retaddr; + } + cycles_until_next_instruction = 8; + break; + + case 0xD0: // RET NC + if (!check_flag(CARRY_FLAG)) { + u16 retaddr = memory.read16(regs.SP); + regs.SP += 2; + regs.PC = retaddr; + } + cycles_until_next_instruction = 8; + break; + + case 0xD8: // RET C + if (check_flag(CARRY_FLAG)) { + u16 retaddr = memory.read16(regs.SP); + regs.SP += 2; + regs.PC = retaddr; + } + cycles_until_next_instruction = 8; + break; + + // RETI + case 0xD9: { + // RET && EI u16 retaddr = memory.read16(regs.SP); regs.SP += 2; regs.PC = retaddr; + IME=1; + cycles_until_next_instruction = 8; + break; } - cycles_until_next_instruction = 8; - break; - - // RETI - case 0xD9: { - // RET && EI - u16 retaddr = memory.read16(regs.SP); - regs.SP += 2; - regs.PC = retaddr; - IME=1; - cycles_until_next_instruction = 8; - break; + + default: + std::ostringstream errmsg; + errmsg << "Unknown opcode 0x"; + errmsg << std::hex << std::setw(2) << std::setfill('0') << opcode; + errmsg << " at 0x" << std::hex << std::setw(4) << regs.PC-1; + errmsg << " (cycle count = " << std::dec << cycle_count << ")"; + logger.critical(errmsg.str()); + break; } - - default: - std::ostringstream errmsg; - errmsg << "Unknown opcode 0x"; - errmsg << std::hex << std::setw(2) << std::setfill('0') << opcode; - errmsg << " at 0x" << std::hex << std::setw(4) << regs.PC-1; - errmsg << " (cycle count = " << std::dec << cycle_count << ")"; - logger.critical(errmsg.str()); - break; + break; } - break; } - + if (cycles_until_video_update <= 0) cycles_until_video_update = video.update(); diff --git a/gbcore.h b/gbcore.h index 495fa41..9469d9c 100644 --- a/gbcore.h +++ b/gbcore.h @@ -68,6 +68,7 @@ class GameBoy u8 IME; // Interrupt master enable flag u8 HALT; // Is the CPU halted waiting for an interrupt? + u8 STOP; // Is the CPU & LCD halted waiting for a keypress? u32 cycle_count; u32 cycles_until_video_update; -- 2.34.1