/* * Gearboy - Nintendo Game Boy Emulator * Copyright (C) 2012 Ignacio Sanchez * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/ * */ #include "Processor.h" #include "Memory.h" #include "opcode_timing.h" void Processor::OPCode0x00() { // NOP } void Processor::OPCode0x01() { // LD BC,nn OPCodes_LD(BC.GetLowRegister(), PC.GetValue()); PC.Increment(); OPCodes_LD(BC.GetHighRegister(), PC.GetValue()); PC.Increment(); } void Processor::OPCode0x02() { // LD (BC),A OPCodes_LD(BC.GetValue(), AF.GetHigh()); } void Processor::OPCode0x03() { // INC BC BC.Increment(); } void Processor::OPCode0x04() { // INC B OPCodes_INC(BC.GetHighRegister()); } void Processor::OPCode0x05() { // DEC B OPCodes_DEC(BC.GetHighRegister()); } void Processor::OPCode0x06() { // LD B,n OPCodes_LD(BC.GetHighRegister(), PC.GetValue()); PC.Increment(); } void Processor::OPCode0x07() { // RLCA OPCodes_RLC(AF.GetHighRegister(), true); } void Processor::OPCode0x08() { // LD (nn),SP u8 l = m_pMemory->Read(PC.GetValue()); PC.Increment(); u8 h = m_pMemory->Read(PC.GetValue()); PC.Increment(); u16 address = ((h << 8) + l); m_pMemory->Write(address, SP.GetLow()); m_pMemory->Write(address + 1, SP.GetHigh()); } void Processor::OPCode0x09() { // ADD HL,BC OPCodes_ADD_HL(BC.GetValue()); } void Processor::OPCode0x0A() { // LD A,(BC) OPCodes_LD(AF.GetHighRegister(), BC.GetValue()); } void Processor::OPCode0x0B() { // DEC BC BC.Decrement(); } void Processor::OPCode0x0C() { // INC C OPCodes_INC(BC.GetLowRegister()); } void Processor::OPCode0x0D() { // DEC C OPCodes_DEC(BC.GetLowRegister()); } void Processor::OPCode0x0E() { // LD C,n OPCodes_LD(BC.GetLowRegister(), PC.GetValue()); PC.Increment(); } void Processor::OPCode0x0F() { // RRCA OPCodes_RRC(AF.GetHighRegister(), true); } void Processor::OPCode0x10() { // STOP PC.Increment(); if (m_bCGB) { u8 current_key1 = m_pMemory->Retrieve(0xFF4D); if (IsSetBit(current_key1, 0)) { m_bCGBSpeed = !m_bCGBSpeed; if (m_bCGBSpeed) { m_iSpeedMultiplier = 1; m_pMemory->Load(0xFF4D, 0x80); } else { m_iSpeedMultiplier = 0; m_pMemory->Load(0xFF4D, 0x00); } } } } void Processor::OPCode0x11() { // LD DE,nn OPCodes_LD(DE.GetLowRegister(), PC.GetValue()); PC.Increment(); OPCodes_LD(DE.GetHighRegister(), PC.GetValue()); PC.Increment(); } void Processor::OPCode0x12() { // LD (DE),A OPCodes_LD(DE.GetValue(), AF.GetHigh()); } void Processor::OPCode0x13() { // INC DE DE.Increment(); } void Processor::OPCode0x14() { // INC D OPCodes_INC(DE.GetHighRegister()); } void Processor::OPCode0x15() { // DEC D OPCodes_DEC(DE.GetHighRegister()); } void Processor::OPCode0x16() { // LD D,n OPCodes_LD(DE.GetHighRegister(), PC.GetValue()); PC.Increment(); } void Processor::OPCode0x17() { // RLA OPCodes_RL(AF.GetHighRegister(), true); } void Processor::OPCode0x18() { // JR n PC.SetValue(PC.GetValue() + 1 + (static_cast (m_pMemory->Read(PC.GetValue())))); } void Processor::OPCode0x19() { // ADD HL,DE OPCodes_ADD_HL(DE.GetValue()); } void Processor::OPCode0x1A() { // LD A,(DE) OPCodes_LD(AF.GetHighRegister(), DE.GetValue()); } void Processor::OPCode0x1B() { // DEC DE DE.Decrement(); } void Processor::OPCode0x1C() { // INC E OPCodes_INC(DE.GetLowRegister()); } void Processor::OPCode0x1D() { // DEC E OPCodes_DEC(DE.GetLowRegister()); } void Processor::OPCode0x1E() { // LD E,n OPCodes_LD(DE.GetLowRegister(), PC.GetValue()); PC.Increment(); } void Processor::OPCode0x1F() { // RRA OPCodes_RR(AF.GetHighRegister(), true); } void Processor::OPCode0x20() { // JR NZ,n if (!IsSetFlag(FLAG_ZERO)) { PC.SetValue(PC.GetValue() + 1 + (static_cast (m_pMemory->Read(PC.GetValue())))); m_bBranchTaken = true; } else { PC.Increment(); } } void Processor::OPCode0x21() { // LD HL,nn OPCodes_LD(HL.GetLowRegister(), PC.GetValue()); PC.Increment(); OPCodes_LD(HL.GetHighRegister(), PC.GetValue()); PC.Increment(); } void Processor::OPCode0x22() { // LD (HLI),A OPCodes_LD(HL.GetValue(), AF.GetHigh()); HL.Increment(); } void Processor::OPCode0x23() { // INC HL HL.Increment(); } void Processor::OPCode0x24() { // INC H OPCodes_INC(HL.GetHighRegister()); } void Processor::OPCode0x25() { // DEC H OPCodes_DEC(HL.GetHighRegister()); } void Processor::OPCode0x26() { // LD H,n OPCodes_LD(HL.GetHighRegister(), PC.GetValue()); PC.Increment(); } void Processor::OPCode0x27() { // DAA int a = AF.GetHigh(); if (!IsSetFlag(FLAG_SUB)) { if (IsSetFlag(FLAG_HALF) || ((a & 0xF) > 9)) a += 0x06; if (IsSetFlag(FLAG_CARRY) || (a > 0x9F)) a += 0x60; } else { if (IsSetFlag(FLAG_HALF)) a = (a - 6) & 0xFF; if (IsSetFlag(FLAG_CARRY)) a -= 0x60; } UntoggleFlag(FLAG_HALF); UntoggleFlag(FLAG_ZERO); if ((a & 0x100) == 0x100) ToggleFlag(FLAG_CARRY); a &= 0xFF; ToggleZeroFlagFromResult(a); AF.SetHigh(a); } void Processor::OPCode0x28() { // JR Z,n if (IsSetFlag(FLAG_ZERO)) { PC.SetValue(PC.GetValue() + 1 + (static_cast (m_pMemory->Read(PC.GetValue())))); m_bBranchTaken = true; } else { PC.Increment(); } } void Processor::OPCode0x29() { // ADD HL,HL OPCodes_ADD_HL(HL.GetValue()); } void Processor::OPCode0x2A() { // LD A,(HLI) OPCodes_LD(AF.GetHighRegister(), HL.GetValue()); HL.Increment(); } void Processor::OPCode0x2B() { // DEC HL HL.Decrement(); } void Processor::OPCode0x2C() { // INC L OPCodes_INC(HL.GetLowRegister()); } void Processor::OPCode0x2D() { // DEC L OPCodes_DEC(HL.GetLowRegister()); } void Processor::OPCode0x2E() { // LD L,n OPCodes_LD(HL.GetLowRegister(), PC.GetValue()); PC.Increment(); } void Processor::OPCode0x2F() { // CPL AF.SetHigh(~AF.GetHigh()); ToggleFlag(FLAG_HALF); ToggleFlag(FLAG_SUB); } void Processor::OPCode0x30() { // JR NC,n if (!IsSetFlag(FLAG_CARRY)) { PC.SetValue(PC.GetValue() + 1 + (static_cast (m_pMemory->Read(PC.GetValue())))); m_bBranchTaken = true; } else { PC.Increment(); } } void Processor::OPCode0x31() { // LD SP,nn SP.SetLow(m_pMemory->Read(PC.GetValue())); PC.Increment(); SP.SetHigh(m_pMemory->Read(PC.GetValue())); PC.Increment(); } void Processor::OPCode0x32() { // LD (HLD), A OPCodes_LD(HL.GetValue(), AF.GetHigh()); HL.Decrement(); } void Processor::OPCode0x33() { // INC SP SP.Increment(); } void Processor::OPCode0x34() { // INC (HL) OPCodes_INC_HL(); } void Processor::OPCode0x35() { // DEC (HL) OPCodes_DEC_HL(); } void Processor::OPCode0x36() { // LD (HL),n m_pMemory->Write(HL.GetValue(), m_pMemory->Read(PC.GetValue())); PC.Increment(); } void Processor::OPCode0x37() { // SCF ToggleFlag(FLAG_CARRY); UntoggleFlag(FLAG_HALF); UntoggleFlag(FLAG_SUB); } void Processor::OPCode0x38() { // JR C,n if (IsSetFlag(FLAG_CARRY)) { PC.SetValue(PC.GetValue() + 1 + (static_cast (m_pMemory->Read(PC.GetValue())))); m_bBranchTaken = true; } else { PC.Increment(); } } void Processor::OPCode0x39() { // ADD HL,SP OPCodes_ADD_HL(SP.GetValue()); } void Processor::OPCode0x3A() { // LD A,(HLD) OPCodes_LD(AF.GetHighRegister(), HL.GetValue()); HL.Decrement(); } void Processor::OPCode0x3B() { // DEC SP SP.Decrement(); } void Processor::OPCode0x3C() { // INC A OPCodes_INC(AF.GetHighRegister()); } void Processor::OPCode0x3D() { // DEC A OPCodes_DEC(AF.GetHighRegister()); } void Processor::OPCode0x3E() { // LD A,n OPCodes_LD(AF.GetHighRegister(), PC.GetValue()); PC.Increment(); } void Processor::OPCode0x3F() { // CCF FlipFlag(FLAG_CARRY); UntoggleFlag(FLAG_HALF); UntoggleFlag(FLAG_SUB); } void Processor::OPCode0x40() { // LD B,B OPCodes_LD(BC.GetHighRegister(), BC.GetHigh()); } void Processor::OPCode0x41() { // LD B,C OPCodes_LD(BC.GetHighRegister(), BC.GetLow()); } void Processor::OPCode0x42() { // LD B,D OPCodes_LD(BC.GetHighRegister(), DE.GetHigh()); } void Processor::OPCode0x43() { // LD B,E OPCodes_LD(BC.GetHighRegister(), DE.GetLow()); } void Processor::OPCode0x44() { // LD B,H OPCodes_LD(BC.GetHighRegister(), HL.GetHigh()); } void Processor::OPCode0x45() { // LD B,L OPCodes_LD(BC.GetHighRegister(), HL.GetLow()); } void Processor::OPCode0x46() { // LD B,(HL) OPCodes_LD(BC.GetHighRegister(), HL.GetValue()); } void Processor::OPCode0x47() { // LD B,A OPCodes_LD(BC.GetHighRegister(), AF.GetHigh()); } void Processor::OPCode0x48() { // LD C,B OPCodes_LD(BC.GetLowRegister(), BC.GetHigh()); } void Processor::OPCode0x49() { // LD C,C OPCodes_LD(BC.GetLowRegister(), BC.GetLow()); } void Processor::OPCode0x4A() { // LD C,D OPCodes_LD(BC.GetLowRegister(), DE.GetHigh()); } void Processor::OPCode0x4B() { // LD C,E OPCodes_LD(BC.GetLowRegister(), DE.GetLow()); } void Processor::OPCode0x4C() { // LD C,H OPCodes_LD(BC.GetLowRegister(), HL.GetHigh()); } void Processor::OPCode0x4D() { // LD C,L OPCodes_LD(BC.GetLowRegister(), HL.GetLow()); } void Processor::OPCode0x4E() { // LD C,(HL) OPCodes_LD(BC.GetLowRegister(), HL.GetValue()); } void Processor::OPCode0x4F() { // LD C,A OPCodes_LD(BC.GetLowRegister(), AF.GetHigh()); } void Processor::OPCode0x50() { // LD D,B OPCodes_LD(DE.GetHighRegister(), BC.GetHigh()); } void Processor::OPCode0x51() { // LD D,C OPCodes_LD(DE.GetHighRegister(), BC.GetLow()); } void Processor::OPCode0x52() { // LD D,D OPCodes_LD(DE.GetHighRegister(), DE.GetHigh()); } void Processor::OPCode0x53() { // LD D,E OPCodes_LD(DE.GetHighRegister(), DE.GetLow()); } void Processor::OPCode0x54() { // LD D,H OPCodes_LD(DE.GetHighRegister(), HL.GetHigh()); } void Processor::OPCode0x55() { // LD D,L OPCodes_LD(DE.GetHighRegister(), HL.GetLow()); } void Processor::OPCode0x56() { // LD D,(HL) OPCodes_LD(DE.GetHighRegister(), HL.GetValue()); } void Processor::OPCode0x57() { // LD D,A OPCodes_LD(DE.GetHighRegister(), AF.GetHigh()); } void Processor::OPCode0x58() { // LD E,B OPCodes_LD(DE.GetLowRegister(), BC.GetHigh()); } void Processor::OPCode0x59() { // LD E,C OPCodes_LD(DE.GetLowRegister(), BC.GetLow()); } void Processor::OPCode0x5A() { // LD E,D OPCodes_LD(DE.GetLowRegister(), DE.GetHigh()); } void Processor::OPCode0x5B() { // LD E,E OPCodes_LD(DE.GetLowRegister(), DE.GetLow()); } void Processor::OPCode0x5C() { // LD E,H OPCodes_LD(DE.GetLowRegister(), HL.GetHigh()); } void Processor::OPCode0x5D() { // LD E,L OPCodes_LD(DE.GetLowRegister(), HL.GetLow()); } void Processor::OPCode0x5E() { // LD E,(HL) OPCodes_LD(DE.GetLowRegister(), HL.GetValue()); } void Processor::OPCode0x5F() { // LD E,A OPCodes_LD(DE.GetLowRegister(), AF.GetHigh()); } void Processor::OPCode0x60() { // LD H,B OPCodes_LD(HL.GetHighRegister(), BC.GetHigh()); } void Processor::OPCode0x61() { // LD H,C OPCodes_LD(HL.GetHighRegister(), BC.GetLow()); } void Processor::OPCode0x62() { // LD H,D OPCodes_LD(HL.GetHighRegister(), DE.GetHigh()); } void Processor::OPCode0x63() { // LD H,E OPCodes_LD(HL.GetHighRegister(), DE.GetLow()); } void Processor::OPCode0x64() { // LD H,H OPCodes_LD(HL.GetHighRegister(), HL.GetHigh()); } void Processor::OPCode0x65() { // LD H,L OPCodes_LD(HL.GetHighRegister(), HL.GetLow()); } void Processor::OPCode0x66() { // LD H,(HL) OPCodes_LD(HL.GetHighRegister(), HL.GetValue()); } void Processor::OPCode0x67() { // LD H,A OPCodes_LD(HL.GetHighRegister(), AF.GetHigh()); } void Processor::OPCode0x68() { // LD L,B OPCodes_LD(HL.GetLowRegister(), BC.GetHigh()); } void Processor::OPCode0x69() { // LD L,C OPCodes_LD(HL.GetLowRegister(), BC.GetLow()); } void Processor::OPCode0x6A() { // LD L,D OPCodes_LD(HL.GetLowRegister(), DE.GetHigh()); } void Processor::OPCode0x6B() { // LD L,E OPCodes_LD(HL.GetLowRegister(), DE.GetLow()); } void Processor::OPCode0x6C() { // LD L,H OPCodes_LD(HL.GetLowRegister(), HL.GetHigh()); } void Processor::OPCode0x6D() { // LD L,L OPCodes_LD(HL.GetLowRegister(), HL.GetLow()); } void Processor::OPCode0x6E() { // LD L,(HL) OPCodes_LD(HL.GetLowRegister(), HL.GetValue()); } void Processor::OPCode0x6F() { // LD L,A OPCodes_LD(HL.GetLowRegister(), AF.GetHigh()); } void Processor::OPCode0x70() { // LD (HL),B OPCodes_LD(HL.GetValue(), BC.GetHigh()); } void Processor::OPCode0x71() { // LD (HL),C OPCodes_LD(HL.GetValue(), BC.GetLow()); } void Processor::OPCode0x72() { // LD (HL),D OPCodes_LD(HL.GetValue(), DE.GetHigh()); } void Processor::OPCode0x73() { // LD (HL),E OPCodes_LD(HL.GetValue(), DE.GetLow()); } void Processor::OPCode0x74() { // LD (HL),H OPCodes_LD(HL.GetValue(), HL.GetHigh()); } void Processor::OPCode0x75() { // LD (HL),L OPCodes_LD(HL.GetValue(), HL.GetLow()); } void Processor::OPCode0x76() { // HALT if (m_iIMECycles > 0) { // If EI is pending interrupts are triggered before Halt m_iIMECycles = 0; m_bIME = true; PC.Decrement(); } else { u8 if_reg = m_pMemory->Retrieve(0xFF0F); u8 ie_reg = m_pMemory->Retrieve(0xFFFF); m_bHalt = true; if (!m_bCGB && !m_bIME && (if_reg & ie_reg & 0x1F)) { m_bSkipPCBug = true; } } } void Processor::OPCode0x77() { // LD (HL),A OPCodes_LD(HL.GetValue(), AF.GetHigh()); } void Processor::OPCode0x78() { // LD A,B OPCodes_LD(AF.GetHighRegister(), BC.GetHigh()); } void Processor::OPCode0x79() { // LD A,C OPCodes_LD(AF.GetHighRegister(), BC.GetLow()); } void Processor::OPCode0x7A() { // LD A,D OPCodes_LD(AF.GetHighRegister(), DE.GetHigh()); } void Processor::OPCode0x7B() { // LD A,E OPCodes_LD(AF.GetHighRegister(), DE.GetLow()); } void Processor::OPCode0x7C() { // LD A,H OPCodes_LD(AF.GetHighRegister(), HL.GetHigh()); } void Processor::OPCode0x7D() { // LD A,L OPCodes_LD(AF.GetHighRegister(), HL.GetLow()); } void Processor::OPCode0x7E() { // LD A,(HL) OPCodes_LD(AF.GetHighRegister(), HL.GetValue()); } void Processor::OPCode0x7F() { // LD A,A OPCodes_LD(AF.GetHighRegister(), AF.GetHigh()); } void Processor::OPCode0x80() { // ADD A,B OPCodes_ADD(BC.GetHigh()); } void Processor::OPCode0x81() { // ADD A,C OPCodes_ADD(BC.GetLow()); } void Processor::OPCode0x82() { // ADD A,D OPCodes_ADD(DE.GetHigh()); } void Processor::OPCode0x83() { // ADD A,E OPCodes_ADD(DE.GetLow()); } void Processor::OPCode0x84() { // ADD A,H OPCodes_ADD(HL.GetHigh()); } void Processor::OPCode0x85() { // ADD A,L OPCodes_ADD(HL.GetLow()); } void Processor::OPCode0x86() { // ADD A,(HL) OPCodes_ADD(m_pMemory->Read(HL.GetValue())); } void Processor::OPCode0x87() { // ADD A,A OPCodes_ADD(AF.GetHigh()); } void Processor::OPCode0x88() { // ADC A,B OPCodes_ADC(BC.GetHigh()); } void Processor::OPCode0x89() { // ADC A,C OPCodes_ADC(BC.GetLow()); } void Processor::OPCode0x8A() { // ADC A,D OPCodes_ADC(DE.GetHigh()); } void Processor::OPCode0x8B() { // ADC A,E OPCodes_ADC(DE.GetLow()); } void Processor::OPCode0x8C() { // ADC A,H OPCodes_ADC(HL.GetHigh()); } void Processor::OPCode0x8D() { // ADC A,L OPCodes_ADC(HL.GetLow()); } void Processor::OPCode0x8E() { // ADC A,(HL) OPCodes_ADC(m_pMemory->Read(HL.GetValue())); } void Processor::OPCode0x8F() { // ADC A,A OPCodes_ADC(AF.GetHigh()); } void Processor::OPCode0x90() { // SUB B OPCodes_SUB(BC.GetHigh()); } void Processor::OPCode0x91() { // SUB C OPCodes_SUB(BC.GetLow()); } void Processor::OPCode0x92() { // SUB D OPCodes_SUB(DE.GetHigh()); } void Processor::OPCode0x93() { // SUB E OPCodes_SUB(DE.GetLow()); } void Processor::OPCode0x94() { // SUB H OPCodes_SUB(HL.GetHigh()); } void Processor::OPCode0x95() { // SUB L OPCodes_SUB(HL.GetLow()); } void Processor::OPCode0x96() { // SUB (HL) OPCodes_SUB(m_pMemory->Read(HL.GetValue())); } void Processor::OPCode0x97() { // SUB A OPCodes_SUB(AF.GetHigh()); } void Processor::OPCode0x98() { // SBC B OPCodes_SBC(BC.GetHigh()); } void Processor::OPCode0x99() { // SBC C OPCodes_SBC(BC.GetLow()); } void Processor::OPCode0x9A() { // SBC D OPCodes_SBC(DE.GetHigh()); } void Processor::OPCode0x9B() { // SBC E OPCodes_SBC(DE.GetLow()); } void Processor::OPCode0x9C() { // SBC H OPCodes_SBC(HL.GetHigh()); } void Processor::OPCode0x9D() { // SBC L OPCodes_SBC(HL.GetLow()); } void Processor::OPCode0x9E() { // SBC (HL) OPCodes_SBC(m_pMemory->Read(HL.GetValue())); } void Processor::OPCode0x9F() { // SBC A OPCodes_SBC(AF.GetHigh()); } void Processor::OPCode0xA0() { // AND B OPCodes_AND(BC.GetHigh()); } void Processor::OPCode0xA1() { // AND C OPCodes_AND(BC.GetLow()); } void Processor::OPCode0xA2() { // AND D OPCodes_AND(DE.GetHigh()); } void Processor::OPCode0xA3() { // AND E OPCodes_AND(DE.GetLow()); } void Processor::OPCode0xA4() { // AND H OPCodes_AND(HL.GetHigh()); } void Processor::OPCode0xA5() { // AND L OPCodes_AND(HL.GetLow()); } void Processor::OPCode0xA6() { // AND (HL) OPCodes_AND(m_pMemory->Read(HL.GetValue())); } void Processor::OPCode0xA7() { // AND A OPCodes_AND(AF.GetHigh()); } void Processor::OPCode0xA8() { // XOR B OPCodes_XOR(BC.GetHigh()); } void Processor::OPCode0xA9() { // XOR C OPCodes_XOR(BC.GetLow()); } void Processor::OPCode0xAA() { // XOR D OPCodes_XOR(DE.GetHigh()); } void Processor::OPCode0xAB() { // XOR E OPCodes_XOR(DE.GetLow()); } void Processor::OPCode0xAC() { // XOR H OPCodes_XOR(HL.GetHigh()); } void Processor::OPCode0xAD() { // XOR L OPCodes_XOR(HL.GetLow()); } void Processor::OPCode0xAE() { // XOR (HL) OPCodes_XOR(m_pMemory->Read(HL.GetValue())); } void Processor::OPCode0xAF() { // XOR A OPCodes_XOR(AF.GetHigh()); } void Processor::OPCode0xB0() { // OR B OPCodes_OR(BC.GetHigh()); } void Processor::OPCode0xB1() { // OR C OPCodes_OR(BC.GetLow()); } void Processor::OPCode0xB2() { // OR D OPCodes_OR(DE.GetHigh()); } void Processor::OPCode0xB3() { // OR E OPCodes_OR(DE.GetLow()); } void Processor::OPCode0xB4() { // OR H OPCodes_OR(HL.GetHigh()); } void Processor::OPCode0xB5() { // OR L OPCodes_OR(HL.GetLow()); } void Processor::OPCode0xB6() { // OR (HL) OPCodes_OR(m_pMemory->Read(HL.GetValue())); } void Processor::OPCode0xB7() { // OR A OPCodes_OR(AF.GetHigh()); } void Processor::OPCode0xB8() { // CP B OPCodes_CP(BC.GetHigh()); } void Processor::OPCode0xB9() { // CP C OPCodes_CP(BC.GetLow()); } void Processor::OPCode0xBA() { // CP D OPCodes_CP(DE.GetHigh()); } void Processor::OPCode0xBB() { // CP E OPCodes_CP(DE.GetLow()); } void Processor::OPCode0xBC() { // CP H OPCodes_CP(HL.GetHigh()); } void Processor::OPCode0xBD() { // CP L OPCodes_CP(HL.GetLow()); } void Processor::OPCode0xBE() { // CP (HL) OPCodes_CP(m_pMemory->Read(HL.GetValue())); } void Processor::OPCode0xBF() { // CP A OPCodes_CP(AF.GetHigh()); } void Processor::OPCode0xC0() { // RET NZ if (!IsSetFlag(FLAG_ZERO)) { StackPop(&PC); m_bBranchTaken = true; } } void Processor::OPCode0xC1() { // POP BC StackPop(&BC); } void Processor::OPCode0xC2() { // JP NZ,nn if (!IsSetFlag(FLAG_ZERO)) { u8 l = m_pMemory->Read(PC.GetValue()); PC.Increment(); u8 h = m_pMemory->Read(PC.GetValue()); PC.SetHigh(h); PC.SetLow(l); m_bBranchTaken = true; } else { PC.Increment(); PC.Increment(); } } void Processor::OPCode0xC3() { // JP nn u8 l = m_pMemory->Read(PC.GetValue()); PC.Increment(); u8 h = m_pMemory->Read(PC.GetValue()); PC.SetHigh(h); PC.SetLow(l); } void Processor::OPCode0xC4() { // CALL NZ,nn if (!IsSetFlag(FLAG_ZERO)) { u8 l = m_pMemory->Read(PC.GetValue()); PC.Increment(); u8 h = m_pMemory->Read(PC.GetValue()); PC.Increment(); StackPush(&PC); PC.SetHigh(h); PC.SetLow(l); m_bBranchTaken = true; } else { PC.Increment(); PC.Increment(); } } void Processor::OPCode0xC5() { // PUSH BC StackPush(&BC); } void Processor::OPCode0xC6() { // ADD A,n OPCodes_ADD(m_pMemory->Read(PC.GetValue())); PC.Increment(); } void Processor::OPCode0xC7() { // RST 00H StackPush(&PC); PC.SetValue(0x0000); } void Processor::OPCode0xC8() { // RET Z if (IsSetFlag(FLAG_ZERO)) { StackPop(&PC); m_bBranchTaken = true; } } void Processor::OPCode0xC9() { // RET StackPop(&PC); } void Processor::OPCode0xCA() { // JP Z,nn if (IsSetFlag(FLAG_ZERO)) { u8 l = m_pMemory->Read(PC.GetValue()); PC.Increment(); u8 h = m_pMemory->Read(PC.GetValue()); PC.SetHigh(h); PC.SetLow(l); m_bBranchTaken = true; } else { PC.Increment(); PC.Increment(); } } void Processor::OPCode0xCB() { // CB prefixed instruction } void Processor::OPCode0xCC() { // CALL Z,nn if (IsSetFlag(FLAG_ZERO)) { u8 l = m_pMemory->Read(PC.GetValue()); PC.Increment(); u8 h = m_pMemory->Read(PC.GetValue()); PC.Increment(); StackPush(&PC); PC.SetHigh(h); PC.SetLow(l); m_bBranchTaken = true; } else { PC.Increment(); PC.Increment(); } } void Processor::OPCode0xCD() { // CALL nn u8 l = m_pMemory->Read(PC.GetValue()); PC.Increment(); u8 h = m_pMemory->Read(PC.GetValue()); PC.Increment(); StackPush(&PC); PC.SetHigh(h); PC.SetLow(l); } void Processor::OPCode0xCE() { // ADC A,n OPCodes_ADC(m_pMemory->Read(PC.GetValue())); PC.Increment(); } void Processor::OPCode0xCF() { // RST 08H StackPush(&PC); PC.SetValue(0x0008); } void Processor::OPCode0xD0() { // RET NC if (!IsSetFlag(FLAG_CARRY)) { StackPop(&PC); m_bBranchTaken = true; } } void Processor::OPCode0xD1() { // POP DE StackPop(&DE); } void Processor::OPCode0xD2() { // JP NC,nn if (!IsSetFlag(FLAG_CARRY)) { u8 l = m_pMemory->Read(PC.GetValue()); PC.Increment(); u8 h = m_pMemory->Read(PC.GetValue()); PC.SetHigh(h); PC.SetLow(l); m_bBranchTaken = true; } else { PC.Increment(); PC.Increment(); } } void Processor::OPCode0xD3() { InvalidOPCode(); } void Processor::OPCode0xD4() { // CALL NC,nn if (!IsSetFlag(FLAG_CARRY)) { u8 l = m_pMemory->Read(PC.GetValue()); PC.Increment(); u8 h = m_pMemory->Read(PC.GetValue()); PC.Increment(); StackPush(&PC); PC.SetHigh(h); PC.SetLow(l); m_bBranchTaken = true; } else { PC.Increment(); PC.Increment(); } } void Processor::OPCode0xD5() { // PUSH DE StackPush(&DE); } void Processor::OPCode0xD6() { // SUB n OPCodes_SUB(m_pMemory->Read(PC.GetValue())); PC.Increment(); } void Processor::OPCode0xD7() { // RST 10H StackPush(&PC); PC.SetValue(0x0010); } void Processor::OPCode0xD8() { // RET C if (IsSetFlag(FLAG_CARRY)) { StackPop(&PC); m_bBranchTaken = true; } } void Processor::OPCode0xD9() { // RETI StackPop(&PC); m_bIME = true; } void Processor::OPCode0xDA() { // JP C,nn if (IsSetFlag(FLAG_CARRY)) { u8 l = m_pMemory->Read(PC.GetValue()); PC.Increment(); u8 h = m_pMemory->Read(PC.GetValue()); PC.SetHigh(h); PC.SetLow(l); m_bBranchTaken = true; } else { PC.Increment(); PC.Increment(); } } void Processor::OPCode0xDB() { InvalidOPCode(); } void Processor::OPCode0xDC() { // CALL C,nn if (IsSetFlag(FLAG_CARRY)) { u8 l = m_pMemory->Read(PC.GetValue()); PC.Increment(); u8 h = m_pMemory->Read(PC.GetValue()); PC.Increment(); StackPush(&PC); PC.SetHigh(h); PC.SetLow(l); m_bBranchTaken = true; } else { PC.Increment(); PC.Increment(); } } void Processor::OPCode0xDD() { InvalidOPCode(); } void Processor::OPCode0xDE() { // SBC n OPCodes_SBC(m_pMemory->Read(PC.GetValue())); PC.Increment(); } void Processor::OPCode0xDF() { // RST 18H StackPush(&PC); PC.SetValue(0x0018); } void Processor::OPCode0xE0() { // LD (0xFF00+n),A OPCodes_LD(static_cast (0xFF00 + m_pMemory->Read(PC.GetValue())), AF.GetHigh()); PC.Increment(); } void Processor::OPCode0xE1() { // POP HL StackPop(&HL); } void Processor::OPCode0xE2() { // LD (0xFF00+C),A OPCodes_LD(static_cast (0xFF00 + BC.GetLow()), AF.GetHigh()); } void Processor::OPCode0xE3() { InvalidOPCode(); } void Processor::OPCode0xE4() { InvalidOPCode(); } void Processor::OPCode0xE5() { // PUSH HL StackPush(&HL); } void Processor::OPCode0xE6() { // AND n OPCodes_AND(m_pMemory->Read(PC.GetValue())); PC.Increment(); } void Processor::OPCode0xE7() { // RST 20H StackPush(&PC); PC.SetValue(0x0020); } void Processor::OPCode0xE8() { // ADD SP,n OPCodes_ADD_SP(static_cast (m_pMemory->Read(PC.GetValue()))); PC.Increment(); } void Processor::OPCode0xE9() { // JP (HL) PC.SetValue(HL.GetValue()); } void Processor::OPCode0xEA() { // LD (nn),A SixteenBitRegister tmp; tmp.SetLow(m_pMemory->Read(PC.GetValue())); PC.Increment(); tmp.SetHigh(m_pMemory->Read(PC.GetValue())); PC.Increment(); OPCodes_LD(tmp.GetValue(), AF.GetHigh()); } void Processor::OPCode0xEB() { InvalidOPCode(); } void Processor::OPCode0xEC() { InvalidOPCode(); } void Processor::OPCode0xED() { InvalidOPCode(); } void Processor::OPCode0xEE() { // XOR n OPCodes_XOR(m_pMemory->Read(PC.GetValue())); PC.Increment(); } void Processor::OPCode0xEF() { // RST 28H StackPush(&PC); PC.SetValue(0x28); } void Processor::OPCode0xF0() { // LD A,(0xFF00+n) OPCodes_LD(AF.GetHighRegister(), static_cast (0xFF00 + m_pMemory->Read(PC.GetValue()))); PC.Increment(); } void Processor::OPCode0xF1() { // POP AF StackPop(&AF); AF.SetLow(AF.GetLow() & 0xF0); } void Processor::OPCode0xF2() { // LD A,(C) OPCodes_LD(AF.GetHighRegister(), static_cast (0xFF00 + BC.GetLow())); } void Processor::OPCode0xF3() { // DI m_bIME = false; m_iIMECycles = 0; } void Processor::OPCode0xF4() { InvalidOPCode(); } void Processor::OPCode0xF5() { // PUSH AF StackPush(&AF); } void Processor::OPCode0xF6() { // OR n OPCodes_OR(m_pMemory->Read(PC.GetValue())); PC.Increment(); } void Processor::OPCode0xF7() { // RST 30H StackPush(&PC); PC.SetValue(0x0030); } void Processor::OPCode0xF8() { // LD HL,SP+n s8 n = m_pMemory->Read(PC.GetValue()); u16 result = SP.GetValue() + n; ClearAllFlags(); if (((SP.GetValue() ^ n ^ result) & 0x100) == 0x100) ToggleFlag(FLAG_CARRY); if (((SP.GetValue() ^ n ^ result) & 0x10) == 0x10) ToggleFlag(FLAG_HALF); HL.SetValue(result); PC.Increment(); } void Processor::OPCode0xF9() { // LD SP,HL SP.SetValue(HL.GetValue()); } void Processor::OPCode0xFA() { // LD A,(nn) SixteenBitRegister tmp; tmp.SetLow(m_pMemory->Read(PC.GetValue())); PC.Increment(); tmp.SetHigh(m_pMemory->Read(PC.GetValue())); PC.Increment(); OPCodes_LD(AF.GetHighRegister(), tmp.GetValue()); } void Processor::OPCode0xFB() { // EI int ei_cycles = kOPCodeMachineCycles[0xFB] * AdjustedCycles(4); m_iIMECycles = ei_cycles + 1; } void Processor::OPCode0xFC() { InvalidOPCode(); } void Processor::OPCode0xFD() { InvalidOPCode(); } void Processor::OPCode0xFE() { // CP n OPCodes_CP(m_pMemory->Read(PC.GetValue())); PC.Increment(); } void Processor::OPCode0xFF() { // RST 38H StackPush(&PC); PC.SetValue(0x0038); }