From ec12456f4bf6c0229e53699bc4ad0c13d964aead Mon Sep 17 00:00:00 2001 From: slack Date: Sat, 5 Jul 2008 03:30:09 +0200 Subject: [PATCH] Timer and divider implemented --- GBMemory.cc | 10 +- GBMemory.h | 10 +- gbcore.cc | 2216 ++++++++++++++++++++++++++------------------------- gbcore.h | 2 + 4 files changed, 1148 insertions(+), 1090 deletions(-) diff --git a/GBMemory.cc b/GBMemory.cc index 60b052e..ebd1b5e 100644 --- a/GBMemory.cc +++ b/GBMemory.cc @@ -14,7 +14,12 @@ void GBMemory::write(int addr, u8 value) else if (addr < 0xE000) WRAM[addr - WRAM_BASE] = value; else if (addr < 0xFE00) write(addr-0x2000, value); else if (addr < 0xFEA0) core->video.write_OAM (addr, value); - else if (addr >= 0xFF00) high[addr-0xFF00] = value; + else if (addr >= 0xFF00) { + high[addr-0xFF00] = value; + if (addr == DIV) { + high[I_DIV] = 0; + } + } else { std::ostringstream errmsg; errmsg << "Invalid write address 0x" << @@ -39,7 +44,8 @@ u8 GBMemory::read(int addr) const errmsg << "Invalid read address 0x" << std::hex << std::setw(4) << std::setfill('0') << addr; logger.error(errmsg.str()); - return *(static_cast(0)); + //return *(static_cast(0)); + return 0; } } diff --git a/GBMemory.h b/GBMemory.h index a8c0784..4d44aa7 100644 --- a/GBMemory.h +++ b/GBMemory.h @@ -41,6 +41,10 @@ class GBMemory void write(int addr, u8 value); public: + static const u16 DIV = 0xFF04; // Divider register (R/W) + static const u16 TIMA = 0xFF05; // Timer counter (R/W) + static const u16 TMA = 0xFF06; // Timer modulo (R/W) + static const u16 TAC = 0xFF07; // Timer control (R/W) static const u16 LCDC = 0xFF40; // LCD Control (R/W) static const u16 STAT = 0xFF41; // LCD Status (R/W) static const u16 SCY = 0xFF42; // Scroll Y (R/W) @@ -54,9 +58,13 @@ class GBMemory static const u16 OBP1 = 0xFF49; // Object Pallete 1 data(R/W) static const u16 DMA = 0xFF46; // DMA Transfer & Start addr (W) static const u16 IF = 0xFF0F; // Interrupt flag (R/W) - static const u16 IE = 0xFF0F; // Interrupt enable (R/W) + static const u16 IE = 0xFF0F; // Interrupt enable (R/W) private: + static const u16 I_DIV = 0xFF04 - IO_BASE; // Divider register (R/W) + static const u16 I_TIMA = 0xFF05 - IO_BASE; // Timer counter (R/W) + static const u16 I_TMA = 0xFF06 - IO_BASE; // Timer modulo (R/W) + static const u16 I_TAC = 0xFF07 - IO_BASE; // Timer control (R/W) static const u16 I_LCDC = 0xFF40 - IO_BASE; // LCD Control (R/W) static const u16 I_STAT = 0xFF41 - IO_BASE; // LCD Status (R/W) static const u16 I_SCY = 0xFF42 - IO_BASE; // Scroll Y (R/W) diff --git a/gbcore.cc b/gbcore.cc index db85565..90e40ba 100644 --- a/gbcore.cc +++ b/gbcore.cc @@ -17,9 +17,12 @@ GameBoy::GameBoy(std::string rom_name, GameBoyType type): regs(), IME(1), HALT(0), + STOP(0), cycle_count(0), cycles_until_video_update(0), cycles_until_next_instruction(0), + divider_count(0), + timer_count(0), breakpoints(), last_breakpoint_id(0) { @@ -48,7 +51,20 @@ void GameBoy::reset() regs.HL = 0x014D; regs.SP = 0xFFFE; - for (int i=0; i<0xFFFF; i++) + // Clear VRAM, external RAM and work RAM + for (int i=0x8000; i<0xE000; i++) + { + memory.write(i, 0); + } + + // Clear OAM + for (int i=0xFE00; i<0xFEA0; i++) + { + memory.write(i, 0); + } + + // Clear HRAM + for (int i=0xFF80; i<0xFFFF; i++) { memory.write(i, 0); } @@ -117,1208 +133,1234 @@ GameBoy::run_status GameBoy::run_cycle() { cycle_count += CYCLE_STEP; - if (cycles_until_next_instruction > 0) - { - if (cycles_until_video_update <= 0) - cycles_until_video_update = video.update(); - - cycles_until_video_update -= CYCLE_STEP; - cycles_until_next_instruction -= CYCLE_STEP; - - if (cycles_until_next_instruction > 0) return WAIT; - else return NORMAL; - } - - // Check for interrupts before opcode fetching - u8 IE=memory.high[GBMemory::I_IE]; - //logger.trace("IME=", int(IME), " IE=", int(IE)); - if (IME && IE) + if (cycles_until_next_instruction <= 0) { - u8 IF = memory.high[GBMemory::I_IF]; - //logger.trace("Dispatching interrupts: IE=", int(IE), " IF=", int(IF)); - if (IF) + // Check for interrupts before opcode fetching + u8 IE=memory.high[GBMemory::I_IE]; + //logger.trace("IME=", int(IME), " IE=", int(IE)); + if (IME && IE) { - if ((IF & IRQ_VBLANK) && (IE & IRQ_VBLANK)) + u8 IF = memory.high[GBMemory::I_IF]; + //logger.trace("Dispatching interrupts: IE=", int(IE), " IF=", int(IF)); + if (IF) { - IME = 0; - IF &= (~IRQ_VBLANK); - do_call(0x40); - logger.trace("VBLANK IRQ"); - HALT=false; - } - else if ((IF & IRQ_LCD_STAT) && (IE & IRQ_LCD_STAT)) - { - IME = 0; - IF &= (~IRQ_LCD_STAT); - do_call(0x48); - logger.trace("LCD STAT IRQ"); - HALT=false; - } - else if ((IF & IRQ_TIMER) && (IE & IRQ_TIMER)) - { - IME = 0; - IF &= (~IRQ_TIMER); - do_call(0x50); - logger.trace("TIMER IRQ"); - HALT=false; - } - else if ((IF & IRQ_SERIAL) && (IE & IRQ_SERIAL)) - { - IME = 0; - IF &= (~IRQ_SERIAL); - do_call(0x58); - logger.trace("SERIAL IRQ"); - HALT=false; - } - else if ((IF & IRQ_JOYPAD) && (IE & IRQ_JOYPAD)) - { - IME = 0; - IF &= (~IRQ_JOYPAD); - do_call(0x60); - logger.trace("JOYPAD IRQ"); - HALT=false; + if ((IF & IRQ_VBLANK) && (IE & IRQ_VBLANK)) + { + IME = 0; + IF &= (~IRQ_VBLANK); + do_call(0x40); + logger.trace("VBLANK IRQ"); + HALT=false; + } + else if ((IF & IRQ_LCD_STAT) && (IE & IRQ_LCD_STAT)) + { + IME = 0; + IF &= (~IRQ_LCD_STAT); + do_call(0x48); + logger.trace("LCD STAT IRQ"); + HALT=false; + } + else if ((IF & IRQ_TIMER) && (IE & IRQ_TIMER)) + { + IME = 0; + IF &= (~IRQ_TIMER); + do_call(0x50); + logger.trace("TIMER IRQ"); + HALT=false; + } + else if ((IF & IRQ_SERIAL) && (IE & IRQ_SERIAL)) + { + IME = 0; + IF &= (~IRQ_SERIAL); + do_call(0x58); + logger.trace("SERIAL IRQ"); + HALT=false; + } + else if ((IF & IRQ_JOYPAD) && (IE & IRQ_JOYPAD)) + { + IME = 0; + IF &= (~IRQ_JOYPAD); + do_call(0x60); + logger.trace("JOYPAD IRQ"); + HALT=false; + } } + memory.high[GBMemory::I_IF] = IF; } - memory.high[GBMemory::I_IF] = IF; - } - /* - for(BreakpointMap::iterator i=breakpoints.begin(); - i != breakpoints.end(); - i++) - { - if (i->second.addr == regs.PC && i->second.enabled) - return BREAKPOINT; - } - */ - - int opcode; - opcode = memory.read(regs.PC++); + for(BreakpointMap::iterator i=breakpoints.begin(); + i != breakpoints.end(); + i++) + { + if (i->second.addr == regs.PC && i->second.enabled) + return BREAKPOINT; + } + + int opcode; + opcode = memory.read(regs.PC++); - if (!(HALT || STOP)) - { - 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_) + 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_) - // 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 (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 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 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; - } + // 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; - } + // 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; + } - // 16-bit ALU - // ADD HL, n - for_each_register16(0x09, 0x19, 0x29, 0x39, ADD_HL_reg16) + // 16-bit ALU + // ADD HL, n + for_each_register16(0x09, 0x19, 0x29, 0x39, ADD_HL_reg16) - // INC nn - for_each_register16(0x03, 0x13, 0x23, 0x33, INC_reg16) + // INC nn + for_each_register16(0x03, 0x13, 0x23, 0x33, INC_reg16) - // DEC nn - for_each_register16(0x0B, 0x1B, 0x2B, 0x3B, DEC_reg16) + // DEC nn + for_each_register16(0x0B, 0x1B, 0x2B, 0x3B, DEC_reg16) - // 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); - } + // 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); + } - if (regs.A & 0x0F > 9 || check_flag(HALF_CARRY_FLAG)) { - corr_factor |= 0x06; - } + if (regs.A & 0x0F > 9 || check_flag(HALF_CARRY_FLAG)) { + corr_factor |= 0x06; + } + + if (!check_flag(ADD_SUB_FLAG)) { + regs.A += corr_factor; + } else { + regs.A -= corr_factor; + } - if (!check_flag(ADD_SUB_FLAG)) { - regs.A += corr_factor; - } else { - regs.A -= corr_factor; + 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; } - 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; - // 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); - // CCF - case 0x3F: - if (check_flag(CARRY_FLAG)) - reset_flag(CARRY_FLAG); - else + reset_flag(HALF_CARRY_FLAG); + reset_flag(ADD_SUB_FLAG); + cycles_until_next_instruction = 4; + break; + + // SCF + case 0x37: set_flag(CARRY_FLAG); + reset_flag(HALF_CARRY_FLAG); + reset_flag(ADD_SUB_FLAG); + cycles_until_next_instruction = 4; + break; - reset_flag(HALF_CARRY_FLAG); - reset_flag(ADD_SUB_FLAG); - cycles_until_next_instruction = 4; - break; + // NOP + case 0x00: + cycles_until_next_instruction = 4; + break; - // SCF - case 0x37: - set_flag(CARRY_FLAG); - reset_flag(HALF_CARRY_FLAG); - reset_flag(ADD_SUB_FLAG); - cycles_until_next_instruction = 4; - break; + // HALT + case 0x76: + HALT = true; + cycles_until_next_instruction = 4; + break; - // NOP - case 0x00: - 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 ", + std::hex, std::setw(2), std::setfill('0'), + sub_opcode, " after 0x10"); + } + 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; + } - // HALT - case 0x76: - HALT = true; - 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; + } - // 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"); + // 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; } - 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; - } + + // 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; - // 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 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; + } - - // 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; + 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; + } - // 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 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; + } - 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 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 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; - } - 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; - } + + 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; - - 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; + // 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; - } // 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 SP, HL + case 0xF9: + regs.SP = regs.HL; + cycles_until_next_instruction = 8; + 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 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); - // LD SP, HL - case 0xF9: - regs.SP = regs.HL; - cycles_until_next_instruction = 8; - break; + // TODO: hacer lo apropiado con el half-carry flag + reset_flag(ADD_SUB_FLAG); + reset_flag(ZERO_FLAG); - // LD HL, SP+n - // LDHL SP, n - case 0xF8: { - s8 offset = memory.read(regs.PC++); - int res = regs.SP + offset; + regs.HL = static_cast(res & 0xFFFF); + cycles_until_next_instruction = 12; + 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) - // TODO: Verificar si los flags van asi - set_flag_if (res > 0xFFFF, CARRY_FLAG); + 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; + } + 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; + } - // TODO: hacer lo apropiado con el half-carry flag - reset_flag(ADD_SUB_FLAG); - reset_flag(ZERO_FLAG); + // ADC A, n + for_each_register(0x8F, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, ADC_A_reg) - regs.HL = static_cast(res & 0xFFFF); - cycles_until_next_instruction = 12; - break; - } + 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; + } + 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; + } - // 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; - } - 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; - } + // SUB n + for_each_register(0x97, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, SUB_reg) - // ADC A, n - for_each_register(0x8F, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, ADC_A_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); - 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; - } - 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); + 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; + } - 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; - } - - // 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); + 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; + } - 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; - } + // SBC n + for_each_register(0x9F, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, SBC_reg) - // 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); - 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; + } - 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 - // There is no SBC inm + // AND n + for_each_register(0xA7, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, AND_reg) - // 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 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; - 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) - // 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 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; - 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) - // 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 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; + } - 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; } - // 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; - } - - // 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; - } + // 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; + } - // 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; - } + // 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; + } - // 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; - } + // 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; + } - // 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; - } + // 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; + } - // 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; - } + // 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; - } + // 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; + 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; } - 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; + // DI + case 0xF3: + IME = 0; + cycles_until_next_instruction = 4; + 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; - } + // 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; - 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; - } + // 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 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 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 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; - } + 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; + } - // JP (HL) - case 0xE9: - regs.PC = regs.HL; - cycles_until_next_instruction = 4; - 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; + } - // Calls - // CALL nn - case 0xCD: { - u16 addr = memory.read16(regs.PC); - regs.PC += 2; - do_call(addr); - cycles_until_next_instruction = 12; - break; - } + // JP (HL) + case 0xE9: + regs.PC = regs.HL; + cycles_until_next_instruction = 4; + break; - // CALL cc, nn - case 0xC4: { // CALL NZ, nn - if (!check_flag(ZERO_FLAG)) { + // 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; - } - 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 + // 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; } - 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 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 = 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 + 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; } - 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; - } - - // RET cc - case 0xC0: // RET NZ - if (!check_flag(ZERO_FLAG)) { - u16 retaddr = memory.read16(regs.SP); - regs.SP += 2; - regs.PC = retaddr; + 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 0xC8: // RET Z - if (check_flag(ZERO_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 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; + // 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)) { + 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; } } + // Video if (cycles_until_video_update <= 0) cycles_until_video_update = video.update(); - cycles_until_video_update -= CYCLE_STEP; - cycles_until_next_instruction -= CYCLE_STEP; + // Divider + divider_count++; + if (divider_count == 0) + { + memory.high[GBMemory::I_DIV]++; + } + + // Timer + // Bit 2 - Timer Stop (0=Stop, 1=Start) + // Bits 1-0 - Input Clock Select + // 00: 4096 Hz - every 1024 cycles + // 01: 262144 Hz - every 16 cycles + // 10: 65536 Hz - every 64 cycles + // 11: 16384 Hz - every 256 cycles + u8 TAC = memory.high[GBMemory::I_TAC]; + if (TAC & 0x04) + { + timer_count++; + u32 limit; + u32 val = TAC & 0x03; + if (val) + limit = 16 << (2*val); + else + limit = 1024; + + if (timer_count >= limit) + { + timer_count = 0; + if (++memory.high[GBMemory::I_TIMA] == 0) + { + memory.high[GBMemory::I_TIMA] = memory.high[GBMemory::I_TMA]; + irq(IRQ_TIMER); + } + } + } + + + cycles_until_next_instruction -= CYCLE_STEP; if (cycles_until_next_instruction > 0) return WAIT; else return NORMAL; } diff --git a/gbcore.h b/gbcore.h index 9469d9c..d8bf8bb 100644 --- a/gbcore.h +++ b/gbcore.h @@ -73,6 +73,8 @@ class GameBoy u32 cycle_count; u32 cycles_until_video_update; u32 cycles_until_next_instruction; + u8 divider_count; // resets every 256 cycles, so we don't need a cmp + u32 timer_count; static const u32 CYCLE_STEP = 4; inline void do_call(u16 addr) -- 2.34.1