From 3bd1ef34d805dd46266fc8f35a5e193804c1462d Mon Sep 17 00:00:00 2001 From: YayIguess Date: Fri, 13 Mar 2026 18:07:43 -0700 Subject: [PATCH] formatting --- src/addressSpace.cpp | 96 +- src/addressSpace.hpp | 723 +++--- src/defines.hpp | 106 +- src/extendedOpcodeResolver.cpp | 3087 ++++++++++++------------ src/gameboy.cpp | 358 ++- src/gameboy.hpp | 290 ++- src/interupts.cpp | 126 +- src/joypad.cpp | 72 +- src/main.cpp | 147 +- src/opcodeResolver.cpp | 4052 ++++++++++++++++---------------- src/ppu.cpp | 616 ++--- src/testing.hpp | 56 +- src/timing.cpp | 76 +- 13 files changed, 4873 insertions(+), 4932 deletions(-) diff --git a/src/addressSpace.cpp b/src/addressSpace.cpp index 6f2e4f7..dcb27c7 100644 --- a/src/addressSpace.cpp +++ b/src/addressSpace.cpp @@ -2,66 +2,58 @@ #include #include -bool AddressSpace::getBootromState() const { - return bootromLoaded; +bool AddressSpace::getBootromState() const { return bootromLoaded; } + +void AddressSpace::unmapBootrom() { bootromLoaded = false; } + +void AddressSpace::mapBootrom() { bootromLoaded = true; } + +void AddressSpace::loadBootrom(const std::string &filename) { + std::ifstream file; + file.open(filename, std::ios::binary); + + if (!file.is_open()) { + std::cerr << "Bootrom was not found!\nQuitting!\n" << std::endl; + exit(1); + } + + const uintmax_t size = std::filesystem::file_size(filename); + if (size != 256) { + std::cerr << "Bootrom was an unexpected size!\nQuitting!\n" << std::endl; + exit(1); + } + file.read(reinterpret_cast(bootrom), BOOTROM_SIZE); } -void AddressSpace::unmapBootrom() { - bootromLoaded = false; -} +void AddressSpace::loadGame(const std::string &filename) { + std::ifstream rom(filename, std::ios::binary); + rom.unsetf(std::ios::skipws); -void AddressSpace::mapBootrom() { - bootromLoaded = true; -} + if (!rom.is_open()) { + std::cerr << "Game was not found!\nQuitting!\n" << std::endl; + exit(1); + } -void AddressSpace::loadBootrom(const std::string& filename) { - std::ifstream file; - file.open(filename, std::ios::binary); + rom.seekg(0, std::ios::end); + const std::streampos rom_size = rom.tellg(); + rom.seekg(0, std::ios::beg); - if (!file.is_open()) { - std::cerr << "Bootrom was not found!\nQuitting!\n" << std::endl; - exit(1); - } + game.reserve(rom_size); + game.insert(game.begin(), std::istream_iterator(rom), + std::istream_iterator()); - const uintmax_t size = std::filesystem::file_size(filename); - if (size != 256) { - std::cerr << "Bootrom was an unexpected size!\nQuitting!\n" << std::endl; - exit(1); - } - file.read(reinterpret_cast(bootrom), BOOTROM_SIZE); -} - -void AddressSpace::loadGame(const std::string& filename) { - std::ifstream rom(filename, std::ios::binary); - rom.unsetf(std::ios::skipws); - - if (!rom.is_open()) { - std::cerr << "Game was not found!\nQuitting!\n" << std::endl; - exit(1); - } - - rom.seekg(0, std::ios::end); - const std::streampos rom_size = rom.tellg(); - rom.seekg(0, std::ios::beg); - - game.reserve(rom_size); - game.insert(game.begin(), - std::istream_iterator(rom), - std::istream_iterator()); - - memoryLayout.romBank0 = game.data(); - memoryLayout.romBankSwitch = game.data() + ROM_BANK_SIZE; + memoryLayout.romBank0 = game.data(); + memoryLayout.romBankSwitch = game.data() + ROM_BANK_SIZE; } void AddressSpace::dmaTransfer() { - dmaTransferRequested = false; - const Word addr = memoryLayout.DMA << 8; - for (int i = 0; i < 0xA0; i++) { - const Byte data = (*this)[addr + i];; - (*this)[0xFE00 + i] = data; - } + dmaTransferRequested = false; + const Word addr = memoryLayout.DMA << 8; + for (int i = 0; i < 0xA0; i++) { + const Byte data = (*this)[addr + i]; + ; + (*this)[0xFE00 + i] = data; + } } -void AddressSpace::setTesting(const bool state) { - testing = state; -} +void AddressSpace::setTesting(const bool state) { testing = state; } diff --git a/src/addressSpace.hpp b/src/addressSpace.hpp index b55a5ac..b87b84f 100644 --- a/src/addressSpace.hpp +++ b/src/addressSpace.hpp @@ -1,383 +1,384 @@ #ifndef ADDRESSSPACE_HPP #define ADDRESSSPACE_HPP -#include -#include #include #include +#include +#include #include #include #include "defines.hpp" class AddressSpace { - bool bootromLoaded = true; - Byte bootrom[BOOTROM_SIZE] = {0}; - std::vector game; - bool testing; - Byte testRam[0xFFFF]; - Byte* cartridgeRam = nullptr; + bool bootromLoaded = true; + Byte bootrom[BOOTROM_SIZE] = {0}; + std::vector game; + bool testing; + Byte testRam[0xFFFF]; + Byte *cartridgeRam = nullptr; public: - AddressSpace() { - // Initialize the memory to zero - memoryLayout = {}; - } + AddressSpace() { + // Initialize the memory to zero + memoryLayout = {}; + } - struct { - Byte* romBank0; //[ROM_BANK_SIZE] Mapped to 0x0000 - Byte* romBankSwitch; //[ROM_BANK_SIZE] Mapped to 0x4000 - Byte vram[0x2000]; //Mapped to 0x8000 - Byte* externalRam; //[0x2000]; Mapped to 0xA000 - Byte memoryBank1[0x1000]; //Mapped to 0xC000 - Byte memoryBank2[0x1000]; //Mapped to 0xD000 - Byte oam[0xA0]; //Mapped to 0xFE00 - Byte notUsable[0x60]; //Mapped to 0xFEA0 - //General purpose hardware registers - Byte JOYP = 0xCF; - Byte SB; - Byte SC = 0x7E; - Byte DIV; - //Timer registers - Byte TIMA; - Byte TMA; - Byte TAC = 0xF8; - //interrupt flag and enable - Byte IF = 0xE1;; - //Sound registers - Byte NR10; - Byte NR11; - Byte NR12; - Byte NR13; - Byte NR14; - Byte NR20; //not used - Byte NR21; - Byte NR22; - Byte NR23; - Byte NR24; - Byte NR30; - Byte NR31; - Byte NR32; - Byte NR33; - Byte NR34; - Byte NR40; //unused - Byte NR41; - Byte NR42; - Byte NR43; - Byte NR44; - Byte NR50; - Byte NR51; - Byte NR52; - Byte waveRam[0x10]; - //PPU registers - Byte LCDC; - Byte STAT; - Byte SCY; - Byte SCX; - Byte LY; - Byte LYC; - Byte DMA; - Byte BGP; - Byte OBP0; - Byte OBP1; - Byte WY; - Byte WX; - Byte specialRam[0x7F]; //Mapped to 0xFF80 - Byte IE; // Mapped to 0xFFFF - } memoryLayout{}; + struct { + Byte *romBank0; //[ROM_BANK_SIZE] Mapped to 0x0000 + Byte *romBankSwitch; //[ROM_BANK_SIZE] Mapped to 0x4000 + Byte vram[0x2000]; // Mapped to 0x8000 + Byte *externalRam; //[0x2000]; Mapped to 0xA000 + Byte memoryBank1[0x1000]; // Mapped to 0xC000 + Byte memoryBank2[0x1000]; // Mapped to 0xD000 + Byte oam[0xA0]; // Mapped to 0xFE00 + Byte notUsable[0x60]; // Mapped to 0xFEA0 + // General purpose hardware registers + Byte JOYP = 0xCF; + Byte SB; + Byte SC = 0x7E; + Byte DIV; + // Timer registers + Byte TIMA; + Byte TMA; + Byte TAC = 0xF8; + // interrupt flag and enable + Byte IF = 0xE1; + ; + // Sound registers + Byte NR10; + Byte NR11; + Byte NR12; + Byte NR13; + Byte NR14; + Byte NR20; // not used + Byte NR21; + Byte NR22; + Byte NR23; + Byte NR24; + Byte NR30; + Byte NR31; + Byte NR32; + Byte NR33; + Byte NR34; + Byte NR40; // unused + Byte NR41; + Byte NR42; + Byte NR43; + Byte NR44; + Byte NR50; + Byte NR51; + Byte NR52; + Byte waveRam[0x10]; + // PPU registers + Byte LCDC; + Byte STAT; + Byte SCY; + Byte SCX; + Byte LY; + Byte LYC; + Byte DMA; + Byte BGP; + Byte OBP0; + Byte OBP1; + Byte WY; + Byte WX; + Byte specialRam[0x7F]; // Mapped to 0xFF80 + Byte IE; // Mapped to 0xFFFF + } memoryLayout{}; - void unmapBootrom(); - void mapBootrom(); - bool getBootromState() const; - void loadBootrom(const std::string& filename); - void loadGame(const std::string& filename); + void unmapBootrom(); + void mapBootrom(); + bool getBootromState() const; + void loadBootrom(const std::string &filename); + void loadGame(const std::string &filename); - void determineMBCInfo(); - bool MBCWrite(Word address); - Byte* MBCRead(Word address); - //prevents seg faults when programs with no MBC try to write to ROM - Byte dummyVal = 0; - void MBCUpdate(); - void loadRomBank(); - void createRamBank(); - void loadRamBank(); - MBCType MBC = {}; - uint32_t romSize = 0; - uint32_t romBanks = 0; - uint32_t externalRamSize = 0; - uint32_t externalRamBanks = 0; + void determineMBCInfo(); + bool MBCWrite(Word address); + Byte *MBCRead(Word address); + // prevents seg faults when programs with no MBC try to write to ROM + Byte dummyVal = 0; + void MBCUpdate(); + void loadRomBank(); + void createRamBank(); + void loadRamBank(); + MBCType MBC = {}; + uint32_t romSize = 0; + uint32_t romBanks = 0; + uint32_t externalRamSize = 0; + uint32_t externalRamBanks = 0; - bool dmaTransferRequested = false; - void dmaTransfer(); + bool dmaTransferRequested = false; + void dmaTransfer(); - //Selected ROM Bank = (Secondary Bank << 5) + ROM Bank - Byte selectedRomBank = 0; - Byte romBankRegister = 0x00; - //2 bit register acts as secondary rom bank register or ram bank number - Byte twoBitBankRegister = 0x0; - Byte selectedExternalRamBank = 0; - Byte romRamSelect = 0x00; - Byte ramEnable = 0x00; - //MBC3 - Byte latchClockData = 0x00; - Byte ramBankRTCRegister = 0x00; + // Selected ROM Bank = (Secondary Bank << 5) + ROM Bank + Byte selectedRomBank = 0; + Byte romBankRegister = 0x00; + // 2 bit register acts as secondary rom bank register or ram bank number + Byte twoBitBankRegister = 0x0; + Byte selectedExternalRamBank = 0; + Byte romRamSelect = 0x00; + Byte ramEnable = 0x00; + // MBC3 + Byte latchClockData = 0x00; + Byte ramBankRTCRegister = 0x00; - void setTesting(bool state); + void setTesting(bool state); - //read - Byte operator[](const Word address) const { - if (testing) - return testRam[address]; - if (address < 0x0100 && bootromLoaded) - return bootrom[address]; - if (address < 0x4000) - return memoryLayout.romBank0[address]; - if (address < 0x8000) - return memoryLayout.romBankSwitch[address - 0x4000]; - if (address < 0xA000) - return memoryLayout.vram[address - 0x8000]; - if (address < 0xC000) { - if (externalRamSize == 0) - return 0xFF; - return memoryLayout.externalRam[address - 0xA000]; - } - if (address < 0xD000) - return memoryLayout.memoryBank1[address - 0xC000]; - if (address < 0xE000) - return memoryLayout.memoryBank2[address - 0xD000]; - if (address < 0xFE00) - return memoryLayout.memoryBank1[address - 0xE000]; - if (address < 0xFEA0) - return memoryLayout.oam[address - 0xFE00]; - if (address < 0xFF00) { - if ((memoryLayout.STAT & 0x03) == 2 || (memoryLayout.STAT & 0x03) == 3) - return 0xFF; - return 0x00; - } - if (address < 0xFF80) - switch (address) { - case 0xFF00: - return memoryLayout.JOYP; - case 0xFF01: - return memoryLayout.SB; - case 0xFF02: - return memoryLayout.SC; - case 0xFF04: - return memoryLayout.DIV; - case 0xFF05: - return memoryLayout.TIMA; - case 0xFF06: - return memoryLayout.TMA; - case 0xFF07: - return memoryLayout.TAC | 0xF8;; - case 0xFF0F: - return memoryLayout.IF | 0xE0; - case 0xFF10: - return memoryLayout.NR10; - case 0xFF11: - return memoryLayout.NR11; - case 0xFF12: - return memoryLayout.NR12; - case 0xFF13: - return memoryLayout.NR13; - case 0xFF14: - return memoryLayout.NR14; - case 0xFF16: - return memoryLayout.NR21; - case 0xFF17: - return memoryLayout.NR22; - case 0xFF18: - return memoryLayout.NR23; - case 0xFF19: - return memoryLayout.NR24; - case 0xFF1A: - return memoryLayout.NR30; - case 0xFF1B: - return memoryLayout.NR31; - case 0xFF1C: - return memoryLayout.NR32; - case 0xFF1D: - return memoryLayout.NR33; - case 0xFF1E: - return memoryLayout.NR34; - case 0xFF20: - return memoryLayout.NR41; - case 0xFF21: - return memoryLayout.NR42; - case 0xFF22: - return memoryLayout.NR43; - case 0xFF23: - return memoryLayout.NR44; - case 0xFF24: - return memoryLayout.NR50; - case 0xFF25: - return memoryLayout.NR51; - case 0xFF26: - return memoryLayout.NR52; - // PPU registers - case 0xFF40: - return memoryLayout.LCDC; - case 0xFF41: - return memoryLayout.STAT; - case 0xFF42: - return memoryLayout.SCY; - case 0xFF43: - return memoryLayout.SCX; - case 0xFF44: - //for debugging only - //return 0x90; - return memoryLayout.LY; - case 0xFF45: - return memoryLayout.LYC; - case 0xFF46: - return memoryLayout.DMA; - case 0xFF47: - return memoryLayout.BGP; - case 0xFF48: - return memoryLayout.OBP0; - case 0xFF49: - return memoryLayout.OBP1; - case 0xFF4A: - return memoryLayout.WY; - case 0xFF4B: - return memoryLayout.WX; - default: - if (address >= 0xFF30 && address <= 0xFF3F) { - return memoryLayout.waveRam[address - 0xFF30]; - } - return 0xFF; - } - if (address < 0xFFFF) - return memoryLayout.specialRam[address - 0xFF80]; - //0xFFFF - return memoryLayout.IE; - } + // read + Byte operator[](const Word address) const { + if (testing) + return testRam[address]; + if (address < 0x0100 && bootromLoaded) + return bootrom[address]; + if (address < 0x4000) + return memoryLayout.romBank0[address]; + if (address < 0x8000) + return memoryLayout.romBankSwitch[address - 0x4000]; + if (address < 0xA000) + return memoryLayout.vram[address - 0x8000]; + if (address < 0xC000) { + if (externalRamSize == 0) + return 0xFF; + return memoryLayout.externalRam[address - 0xA000]; + } + if (address < 0xD000) + return memoryLayout.memoryBank1[address - 0xC000]; + if (address < 0xE000) + return memoryLayout.memoryBank2[address - 0xD000]; + if (address < 0xFE00) + return memoryLayout.memoryBank1[address - 0xE000]; + if (address < 0xFEA0) + return memoryLayout.oam[address - 0xFE00]; + if (address < 0xFF00) { + if ((memoryLayout.STAT & 0x03) == 2 || (memoryLayout.STAT & 0x03) == 3) + return 0xFF; + return 0x00; + } + if (address < 0xFF80) + switch (address) { + case 0xFF00: + return memoryLayout.JOYP; + case 0xFF01: + return memoryLayout.SB; + case 0xFF02: + return memoryLayout.SC; + case 0xFF04: + return memoryLayout.DIV; + case 0xFF05: + return memoryLayout.TIMA; + case 0xFF06: + return memoryLayout.TMA; + case 0xFF07: + return memoryLayout.TAC | 0xF8; + ; + case 0xFF0F: + return memoryLayout.IF | 0xE0; + case 0xFF10: + return memoryLayout.NR10; + case 0xFF11: + return memoryLayout.NR11; + case 0xFF12: + return memoryLayout.NR12; + case 0xFF13: + return memoryLayout.NR13; + case 0xFF14: + return memoryLayout.NR14; + case 0xFF16: + return memoryLayout.NR21; + case 0xFF17: + return memoryLayout.NR22; + case 0xFF18: + return memoryLayout.NR23; + case 0xFF19: + return memoryLayout.NR24; + case 0xFF1A: + return memoryLayout.NR30; + case 0xFF1B: + return memoryLayout.NR31; + case 0xFF1C: + return memoryLayout.NR32; + case 0xFF1D: + return memoryLayout.NR33; + case 0xFF1E: + return memoryLayout.NR34; + case 0xFF20: + return memoryLayout.NR41; + case 0xFF21: + return memoryLayout.NR42; + case 0xFF22: + return memoryLayout.NR43; + case 0xFF23: + return memoryLayout.NR44; + case 0xFF24: + return memoryLayout.NR50; + case 0xFF25: + return memoryLayout.NR51; + case 0xFF26: + return memoryLayout.NR52; + // PPU registers + case 0xFF40: + return memoryLayout.LCDC; + case 0xFF41: + return memoryLayout.STAT; + case 0xFF42: + return memoryLayout.SCY; + case 0xFF43: + return memoryLayout.SCX; + case 0xFF44: + // for debugging only + // return 0x90; + return memoryLayout.LY; + case 0xFF45: + return memoryLayout.LYC; + case 0xFF46: + return memoryLayout.DMA; + case 0xFF47: + return memoryLayout.BGP; + case 0xFF48: + return memoryLayout.OBP0; + case 0xFF49: + return memoryLayout.OBP1; + case 0xFF4A: + return memoryLayout.WY; + case 0xFF4B: + return memoryLayout.WX; + default: + if (address >= 0xFF30 && address <= 0xFF3F) { + return memoryLayout.waveRam[address - 0xFF30]; + } + return 0xFF; + } + if (address < 0xFFFF) + return memoryLayout.specialRam[address - 0xFF80]; + // 0xFFFF + return memoryLayout.IE; + } - //write - Byte& operator[](const Word address) { - dummyVal = 0xFF; - if (testing) - return testRam[address]; - if (address < 0x0100 && bootromLoaded) - return bootrom[address]; - if (address < 0x8000) - return (*MBCRead(address)); - if (address < 0xA000) - return memoryLayout.vram[address - 0x8000]; - if (address < 0xC000) { - if (externalRamSize == 0) - return dummyVal; - return memoryLayout.externalRam[address - 0xA000]; - } - if (address < 0xD000) - return memoryLayout.memoryBank1[address - 0xC000]; - if (address < 0xE000) - return memoryLayout.memoryBank2[address - 0xD000]; - if (address < 0xFE00) - return memoryLayout.memoryBank1[address - 0xE000]; - if (address < 0xFEA0) - return memoryLayout.oam[address - 0xFE00]; - if (address < 0xFF00) - return memoryLayout.notUsable[address - 0xFEA0]; - if (address < 0xFF80) - switch (address) { - case 0xFF00: - return memoryLayout.JOYP; - case 0xFF01: - return memoryLayout.SB; - case 0xFF02: - return memoryLayout.SC; - case 0xFF04: - memoryLayout.DIV = 0; - return dummyVal; - // Timer registers - case 0xFF05: - return memoryLayout.TIMA; - case 0xFF06: - return memoryLayout.TMA; - case 0xFF07: - return memoryLayout.TAC; - case 0xFF0F: - return memoryLayout.IF; - case 0xFF10: - return memoryLayout.NR10; - case 0xFF11: - return memoryLayout.NR11; - case 0xFF12: - return memoryLayout.NR12; - case 0xFF13: - return memoryLayout.NR13; - case 0xFF14: - return memoryLayout.NR14; - case 0xFF16: - return memoryLayout.NR21; - case 0xFF17: - return memoryLayout.NR22; - case 0xFF18: - return memoryLayout.NR23; - case 0xFF19: - return memoryLayout.NR24; - case 0xFF1A: - return memoryLayout.NR30; - case 0xFF1B: - return memoryLayout.NR31; - case 0xFF1C: - return memoryLayout.NR32; - case 0xFF1D: - return memoryLayout.NR33; - case 0xFF1E: - return memoryLayout.NR34; - case 0xFF20: - return memoryLayout.NR41; - case 0xFF21: - return memoryLayout.NR42; - case 0xFF22: - return memoryLayout.NR43; - case 0xFF23: - return memoryLayout.NR44; - case 0xFF24: - return memoryLayout.NR50; - case 0xFF25: - return memoryLayout.NR51; - case 0xFF26: - return memoryLayout.NR52; - case 0xFF40: - return memoryLayout.LCDC; - case 0xFF41: - return memoryLayout.STAT; - case 0xFF42: - return memoryLayout.SCY; - case 0xFF43: - return memoryLayout.SCX; - case 0xFF44: - dummyVal = memoryLayout.LY; - return dummyVal; - case 0xFF45: - return memoryLayout.LYC; - case 0xFF46: - dmaTransferRequested = true; - return memoryLayout.DMA; - case 0xFF47: - return memoryLayout.BGP; - case 0xFF48: - return memoryLayout.OBP0; - case 0xFF49: - return memoryLayout.OBP1; - case 0xFF4A: - return memoryLayout.WY; - case 0xFF4B: - return memoryLayout.WX; - default: - if (address >= 0xFF30 && address <= 0xFF3F) { - return memoryLayout.waveRam[address - 0xFF30]; - } - return dummyVal; - } - if (address < 0xFFFF) - return memoryLayout.specialRam[address - 0xFF80]; - //0xFFFF - return memoryLayout.IE; - } + // write + Byte &operator[](const Word address) { + dummyVal = 0xFF; + if (testing) + return testRam[address]; + if (address < 0x0100 && bootromLoaded) + return bootrom[address]; + if (address < 0x8000) + return (*MBCRead(address)); + if (address < 0xA000) + return memoryLayout.vram[address - 0x8000]; + if (address < 0xC000) { + if (externalRamSize == 0) + return dummyVal; + return memoryLayout.externalRam[address - 0xA000]; + } + if (address < 0xD000) + return memoryLayout.memoryBank1[address - 0xC000]; + if (address < 0xE000) + return memoryLayout.memoryBank2[address - 0xD000]; + if (address < 0xFE00) + return memoryLayout.memoryBank1[address - 0xE000]; + if (address < 0xFEA0) + return memoryLayout.oam[address - 0xFE00]; + if (address < 0xFF00) + return memoryLayout.notUsable[address - 0xFEA0]; + if (address < 0xFF80) + switch (address) { + case 0xFF00: + return memoryLayout.JOYP; + case 0xFF01: + return memoryLayout.SB; + case 0xFF02: + return memoryLayout.SC; + case 0xFF04: + memoryLayout.DIV = 0; + return dummyVal; + // Timer registers + case 0xFF05: + return memoryLayout.TIMA; + case 0xFF06: + return memoryLayout.TMA; + case 0xFF07: + return memoryLayout.TAC; + case 0xFF0F: + return memoryLayout.IF; + case 0xFF10: + return memoryLayout.NR10; + case 0xFF11: + return memoryLayout.NR11; + case 0xFF12: + return memoryLayout.NR12; + case 0xFF13: + return memoryLayout.NR13; + case 0xFF14: + return memoryLayout.NR14; + case 0xFF16: + return memoryLayout.NR21; + case 0xFF17: + return memoryLayout.NR22; + case 0xFF18: + return memoryLayout.NR23; + case 0xFF19: + return memoryLayout.NR24; + case 0xFF1A: + return memoryLayout.NR30; + case 0xFF1B: + return memoryLayout.NR31; + case 0xFF1C: + return memoryLayout.NR32; + case 0xFF1D: + return memoryLayout.NR33; + case 0xFF1E: + return memoryLayout.NR34; + case 0xFF20: + return memoryLayout.NR41; + case 0xFF21: + return memoryLayout.NR42; + case 0xFF22: + return memoryLayout.NR43; + case 0xFF23: + return memoryLayout.NR44; + case 0xFF24: + return memoryLayout.NR50; + case 0xFF25: + return memoryLayout.NR51; + case 0xFF26: + return memoryLayout.NR52; + case 0xFF40: + return memoryLayout.LCDC; + case 0xFF41: + return memoryLayout.STAT; + case 0xFF42: + return memoryLayout.SCY; + case 0xFF43: + return memoryLayout.SCX; + case 0xFF44: + dummyVal = memoryLayout.LY; + return dummyVal; + case 0xFF45: + return memoryLayout.LYC; + case 0xFF46: + dmaTransferRequested = true; + return memoryLayout.DMA; + case 0xFF47: + return memoryLayout.BGP; + case 0xFF48: + return memoryLayout.OBP0; + case 0xFF49: + return memoryLayout.OBP1; + case 0xFF4A: + return memoryLayout.WY; + case 0xFF4B: + return memoryLayout.WX; + default: + if (address >= 0xFF30 && address <= 0xFF3F) { + return memoryLayout.waveRam[address - 0xFF30]; + } + return dummyVal; + } + if (address < 0xFFFF) + return memoryLayout.specialRam[address - 0xFF80]; + // 0xFFFF + return memoryLayout.IE; + } }; - -#endif //ADDRESSSPACE_HPP +#endif // ADDRESSSPACE_HPP diff --git a/src/defines.hpp b/src/defines.hpp index 785f28b..f6eaca5 100644 --- a/src/defines.hpp +++ b/src/defines.hpp @@ -10,10 +10,10 @@ // 5 h - - Half Carry Flag (BCD) // 4 cy C NC Carry Flag // 3-0 - - - Not used -#define CARRY_FLAG 4 //'C' +#define CARRY_FLAG 4 //'C' #define HALFCARRY_FLAG 5 //'H' -#define SUBTRACT_FLAG 6 //'N' -#define ZERO_FLAG 7 //'Z' +#define SUBTRACT_FLAG 6 //'N' +#define ZERO_FLAG 7 //'Z' #define VBLANK_INTERRUPT 0 #define LCD_STAT_INTERRUPT 1 @@ -21,9 +21,9 @@ #define SERIAL_INTERRUPT 3 #define JOYPAD_INTERRUPT 4 -#define T_CLOCK_FREQ 4194304 //2^22 +#define T_CLOCK_FREQ 4194304 // 2^22 -#define DIVIDER_REGISTER_FREQ (4194304/16384) +#define DIVIDER_REGISTER_FREQ (4194304 / 16384) #define BOOTROM_SIZE 0x100 @@ -31,7 +31,7 @@ #define RESOLUTION_Y 144 #define SCREEN_BPP 3 -//lcdc +// lcdc #define BG_WINDOW_ENABLE 0 #define OBJ_ENABLE 1 #define OBJ_SIZE 2 @@ -41,13 +41,12 @@ #define WINDOW_TILE_MAP_AREA 6 #define LCD_ENABLE 7 -//oam +// oam #define PRIORITY 7 #define Y_FLIP 6 #define X_FLIP 5 #define OBJ_PALETTE 4 - #define ROM_BANK_SIZE 0x4000 #define RAM_BANK_SIZE 0x2000 @@ -59,10 +58,10 @@ #define H_SYNC 9198 #define V_SYNC 59.73 -#define HBLANK_DURATION 204 //PPU_MODE 0 +#define HBLANK_DURATION 204 // PPU_MODE 0 #define VBLANK_DURATION 4560 -#define SCANLINE_OAM_FREQ 80 //PPU_MODE 2 -#define SCANLINE_VRAM_FREQ 80 //PPU_MODE 3 +#define SCANLINE_OAM_FREQ 80 // PPU_MODE 2 +#define SCANLINE_VRAM_FREQ 80 // PPU_MODE 3 #define WHITE 0xFFFFFFFF; #define LIGHT_GRAY 0xFFAAAAAA; @@ -70,52 +69,57 @@ #define BLACK 0xFF000000 struct Input { - bool UP = false; - bool DOWN = false; - bool LEFT = false; - bool RIGHT = false; - bool B = false; - bool A = false; - bool START = false; - bool SELECT = false; + bool UP = false; + bool DOWN = false; + bool LEFT = false; + bool RIGHT = false; + bool B = false; + bool A = false; + bool START = false; + bool SELECT = false; }; enum MBCType { - romOnly = 0x00, - MBC1 = 0x01, - MBC1Ram = 0x02, - MBC1RamBattery = 0x03, - MBC2 = 0x05, - MBC2Battery = 0x06, - RomRam = 0x08, //unused - RomRamBattery = 0x09, //unused - MMM01 = 0x0B, //multigame roms only - MMM01Ram = 0x0C, - MMM01RamBattery = 0x0D, - MBC3TimerBattery = 0x0F, - MBC3TimerRamBattery = 0x10, - MBC3 = 0x11, - MBC3Ram = 0x12, // MBC3 with 64 KiB of SRAM refers to MBC30, used only in Pocket Monsters: Crystal Version. - MBC3RamBattery = 0x13, - MBC5 = 0x19, - MBC5Ram = 0x1A, - MBC5RamBattery = 0x1B, - MBC5Rumble = 0x1C, - MBC5RumbleRam = 0x1D, - MBC5RumbleRamBattery = 0x1E, - MBC6 = 0x20, - MBC7SensorRumbleRamBattery = 0x22, - PocketCamera = 0xFC, - BandaiTama5 = 0xFD, - HuC3 = 0xFE, - HuC1RamBattery = 0xFF + romOnly = 0x00, + MBC1 = 0x01, + MBC1Ram = 0x02, + MBC1RamBattery = 0x03, + MBC2 = 0x05, + MBC2Battery = 0x06, + RomRam = 0x08, // unused + RomRamBattery = 0x09, // unused + MMM01 = 0x0B, // multigame roms only + MMM01Ram = 0x0C, + MMM01RamBattery = 0x0D, + MBC3TimerBattery = 0x0F, + MBC3TimerRamBattery = 0x10, + MBC3 = 0x11, + MBC3Ram = 0x12, // MBC3 with 64 KiB of SRAM refers to MBC30, used only in + // Pocket Monsters: Crystal Version. + MBC3RamBattery = 0x13, + MBC5 = 0x19, + MBC5Ram = 0x1A, + MBC5RamBattery = 0x1B, + MBC5Rumble = 0x1C, + MBC5RumbleRam = 0x1D, + MBC5RumbleRamBattery = 0x1E, + MBC6 = 0x20, + MBC7SensorRumbleRamBattery = 0x22, + PocketCamera = 0xFC, + BandaiTama5 = 0xFD, + HuC3 = 0xFE, + HuC1RamBattery = 0xFF }; enum PPUMode { - mode0, // Horizontal Blank (Mode 0): No access to video RAM, occurs during horizontal blanking period. - mode1, // Vertical Blank (Mode 1): No access to video RAM, occurs during vertical blanking period. - mode2, // OAM Search (Mode 2): Access to OAM (Object Attribute Memory) only, sprite evaluation. - mode3 // Pixel Transfer (Mode 3): Access to both OAM and video RAM, actual pixel transfer to the screen. + mode0, // Horizontal Blank (Mode 0): No access to video RAM, occurs during + // horizontal blanking period. + mode1, // Vertical Blank (Mode 1): No access to video RAM, occurs during + // vertical blanking period. + mode2, // OAM Search (Mode 2): Access to OAM (Object Attribute Memory) only, + // sprite evaluation. + mode3 // Pixel Transfer (Mode 3): Access to both OAM and video RAM, actual + // pixel transfer to the screen. }; #endif diff --git a/src/extendedOpcodeResolver.cpp b/src/extendedOpcodeResolver.cpp index bdc72ac..7770c08 100644 --- a/src/extendedOpcodeResolver.cpp +++ b/src/extendedOpcodeResolver.cpp @@ -1,1547 +1,1548 @@ #include "gameboy.hpp" void GameBoy::extendedOpcodeResolver() { - PC += 1; - - switch (readOnlyAddressSpace[PC]) { - case 0x00: - rlc(BC.hi); - PC += 1; - addCycles(8); - break; - - case 0x01: - rlc(BC.lo); - PC += 1; - addCycles(8); - break; - - case 0x02: - rlc(DE.hi); - PC += 1; - addCycles(8); - break; - - case 0x03: - rlc(DE.lo); - PC += 1; - addCycles(8); - break; - - case 0x04: - rlc(HL.hi); - PC += 1; - addCycles(8); - break; - - case 0x05: - rlc(HL.lo); - PC += 1; - addCycles(8); - break; - - case 0x06: - rlc(addressSpace[HL.reg]); - PC += 1; - addCycles(16); - break; - - case 0x07: - rlc(AF.hi); - PC += 1; - addCycles(8); - break; - - case 0x08: - rrc(BC.hi); - PC += 1; - addCycles(8); - break; - - case 0x09: - rrc(BC.lo); - PC += 1; - addCycles(8); - break; - - case 0x0A: - rrc(DE.hi); - PC += 1; - addCycles(8); - break; - - case 0x0B: - rrc(DE.lo); - PC += 1; - addCycles(8); - break; - - case 0x0C: - rrc(HL.hi); - PC += 1; - addCycles(8); - break; - - case 0x0D: - rrc(HL.lo); - PC += 1; - addCycles(8); - break; - - case 0x0E: - rrc(addressSpace[HL.reg]); - PC += 1; - addCycles(16); - break; - - case 0x0F: - rrc(AF.hi); - PC += 1; - addCycles(8); - break; - - case 0x10: - rl(BC.hi); - PC += 1; - addCycles(8); - break; - - case 0x11: - rl(BC.lo); - PC += 1; - addCycles(8); - break; - - case 0x12: - rl(DE.hi); - PC += 1; - addCycles(8); - break; - - case 0x13: - rl(DE.lo); - PC += 1; - addCycles(8); - break; - - case 0x14: - rl(HL.hi); - PC += 1; - addCycles(8); - break; - - case 0x15: - rl(HL.lo); - PC += 1; - addCycles(8); - break; - - case 0x16: - rl(addressSpace[HL.reg]); - PC += 1; - addCycles(16); - break; - - case 0x17: - rl(AF.hi); - PC += 1; - addCycles(8); - break; - - case 0x18: - rr(BC.hi); - PC += 1; - addCycles(8); - break; - - case 0x19: - rr(BC.lo); - PC += 1; - addCycles(8); - break; - - case 0x1A: - rr(DE.hi); - PC += 1; - addCycles(8); - break; - - case 0x1B: - rr(DE.lo); - PC += 1; - addCycles(8); - break; - - case 0x1C: - rr(HL.hi); - PC += 1; - addCycles(8); - break; - - case 0x1D: - rr(HL.lo); - PC += 1; - addCycles(8); - break; - - case 0x1E: - rr(addressSpace[HL.reg]); - PC += 1; - addCycles(16); - break; - - case 0x1F: - rr(AF.hi); - PC += 1; - addCycles(8); - break; - - case 0x20: - sla(BC.hi); - PC += 1; - addCycles(8); - break; - - case 0x21: - sla(BC.lo); - PC += 1; - addCycles(8); - break; - - case 0x22: - sla(DE.hi); - PC += 1; - addCycles(8); - break; - - case 0x23: - sla(DE.lo); - PC += 1; - addCycles(8); - break; - - case 0x24: - sla(HL.hi); - PC += 1; - addCycles(8); - break; - - case 0x25: - sla(HL.lo); - PC += 1; - addCycles(8); - break; - - case 0x26: - sla(addressSpace[HL.reg]); - PC += 1; - addCycles(16); - break; - - case 0x27: - sla(AF.hi); - PC += 1; - addCycles(8); - break; - - case 0x28: - sra(BC.hi); - PC += 1; - addCycles(8); - break; - - case 0x29: - sra(BC.lo); - PC += 1; - addCycles(8); - break; - - case 0x2A: - sra(DE.hi); - PC += 1; - addCycles(8); - break; - - case 0x2B: - sra(DE.lo); - PC += 1; - addCycles(8); - break; - - case 0x2C: - sra(HL.hi); - PC += 1; - addCycles(8); - break; - - case 0x2D: - sra(HL.lo); - PC += 1; - addCycles(8); - break; - - case 0x2E: - sra(addressSpace[HL.reg]); - PC += 1; - addCycles(16); - break; - - case 0x2F: - sra(AF.hi); - PC += 1; - addCycles(8); - break; - - case 0x30: - swap(BC.hi); - PC += 1; - addCycles(8); - break; - - case 0x31: - swap(BC.lo); - PC += 1; - addCycles(8); - break; - - case 0x32: - swap(DE.hi); - PC += 1; - addCycles(8); - break; - - case 0x33: - swap(DE.lo); - PC += 1; - addCycles(8); - break; - - case 0x34: - swap(HL.hi); - PC += 1; - addCycles(8); - break; - - case 0x35: - swap(HL.lo); - PC += 1; - addCycles(8); - break; - - case 0x36: - swap(addressSpace[HL.reg]); - PC += 1; - addCycles(16); - break; - - case 0x37: - swap(AF.hi); - PC += 1; - addCycles(8); - break; - - case 0x38: - srl(BC.hi); - PC += 1; - addCycles(8); - break; - - case 0x39: - srl(BC.lo); - PC += 1; - addCycles(8); - break; - - case 0x3A: - srl(DE.hi); - PC += 1; - addCycles(8); - break; - - case 0x3B: - srl(DE.lo); - PC += 1; - addCycles(8); - break; - - case 0x3C: - srl(HL.hi); - PC += 1; - addCycles(8); - break; - - case 0x3D: - srl(HL.lo); - PC += 1; - addCycles(8); - break; - - case 0x3E: - srl(addressSpace[HL.reg]); - PC += 1; - addCycles(16); - break; - - case 0x3F: - srl(AF.hi); - PC += 1; - addCycles(8); - break; - - case 0x40: - bit(0, BC.hi); - PC += 1; - addCycles(8); - break; - - case 0x41: - bit(0, BC.lo); - PC += 1; - addCycles(8); - break; - - case 0x42: - bit(0, DE.hi); - PC += 1; - addCycles(8); - break; - - case 0x43: - bit(0, DE.lo); - PC += 1; - addCycles(8); - break; - - case 0x44: - bit(0, HL.hi); - PC += 1; - addCycles(8); - break; - - case 0x45: - bit(0, HL.lo); - PC += 1; - addCycles(8); - break; - - case 0x46: - bit(0, readOnlyAddressSpace[HL.reg]); - PC += 1; - addCycles(12); - break; - - case 0x47: - bit(0, AF.hi); - PC += 1; - addCycles(8); - break; - - case 0x48: - bit(1, BC.hi); - PC += 1; - addCycles(8); - break; - - case 0x49: - bit(1, BC.lo); - PC += 1; - addCycles(8); - break; - - case 0x4A: - bit(1, DE.hi); - PC += 1; - addCycles(8); - break; - - case 0x4B: - bit(1, DE.lo); - PC += 1; - addCycles(8); - break; - - case 0x4C: - bit(1, HL.hi); - PC += 1; - addCycles(8); - break; - - case 0x4D: - bit(1, HL.lo); - PC += 1; - addCycles(8); - break; - - case 0x4E: - bit(1, readOnlyAddressSpace[HL.reg]); - PC += 1; - addCycles(12); - break; - - case 0x4F: - bit(1, AF.hi); - PC += 1; - addCycles(8); - break; - - case 0x50: - bit(2, BC.hi); - PC += 1; - addCycles(8); - break; - - case 0x51: - bit(2, BC.lo); - PC += 1; - addCycles(8); - break; - - case 0x52: - bit(2, DE.hi); - PC += 1; - addCycles(8); - break; - - case 0x53: - bit(2, DE.lo); - PC += 1; - addCycles(8); - break; - - case 0x54: - bit(2, HL.hi); - PC += 1; - addCycles(8); - break; - - case 0x55: - bit(2, HL.lo); - PC += 1; - addCycles(8); - break; - - case 0x56: - bit(2, readOnlyAddressSpace[HL.reg]); - PC += 1; - addCycles(12); - break; - - case 0x57: - bit(2, AF.hi); - PC += 1; - addCycles(8); - break; - - case 0x58: - bit(3, BC.hi); - PC += 1; - addCycles(8); - break; - - case 0x59: - bit(3, BC.lo); - PC += 1; - addCycles(8); - break; - - case 0x5A: - bit(3, DE.hi); - PC += 1; - addCycles(8); - break; - - case 0x5B: - bit(3, DE.lo); - PC += 1; - addCycles(8); - break; - - case 0x5C: - bit(3, HL.hi); - PC += 1; - addCycles(8); - break; - - case 0x5D: - bit(3, HL.lo); - PC += 1; - addCycles(8); - break; - - case 0x5E: - bit(3, readOnlyAddressSpace[HL.reg]); - PC += 1; - addCycles(12); - break; - - case 0x5F: - bit(3, AF.hi); - PC += 1; - addCycles(8); - break; - - case 0x60: - bit(4, BC.hi); - PC += 1; - addCycles(8); - break; - - case 0x61: - bit(4, BC.lo); - PC += 1; - addCycles(8); - break; - - case 0x62: - bit(4, DE.hi); - PC += 1; - addCycles(8); - break; - - case 0x63: - bit(4, DE.lo); - PC += 1; - addCycles(8); - break; - - case 0x64: - bit(4, HL.hi); - PC += 1; - addCycles(8); - break; - - case 0x65: - bit(4, HL.lo); - PC += 1; - addCycles(8); - break; - - case 0x66: - bit(4, readOnlyAddressSpace[HL.reg]); - PC += 1; - addCycles(12); - break; - - case 0x67: - bit(4, AF.hi); - PC += 1; - addCycles(8); - break; - - case 0x68: - bit(5, BC.hi); - PC += 1; - addCycles(8); - break; - - case 0x69: - bit(5, BC.lo); - PC += 1; - addCycles(8); - break; - - case 0x6A: - bit(5, DE.hi); - PC += 1; - addCycles(8); - break; - - case 0x6B: - bit(5, DE.lo); - PC += 1; - addCycles(8); - break; - - case 0x6C: - bit(5, HL.hi); - PC += 1; - addCycles(8); - break; - - case 0x6D: - bit(5, HL.lo); - PC += 1; - addCycles(8); - break; - - case 0x6E: - bit(5, readOnlyAddressSpace[HL.reg]); - PC += 1; - addCycles(12); - break; - - case 0x6F: - bit(5, AF.hi); - PC += 1; - addCycles(8); - break; - - case 0x70: - bit(6, BC.hi); - PC += 1; - addCycles(8); - break; - - case 0x71: - bit(6, BC.lo); - PC += 1; - addCycles(8); - break; - - case 0x72: - bit(6, DE.hi); - PC += 1; - addCycles(8); - break; - - case 0x73: - bit(6, DE.lo); - PC += 1; - addCycles(8); - break; - - case 0x74: - bit(6, HL.hi); - PC += 1; - addCycles(8); - break; - - case 0x75: - bit(6, HL.lo); - PC += 1; - addCycles(8); - break; - - case 0x76: - bit(6, readOnlyAddressSpace[HL.reg]); - PC += 1; - addCycles(12); - break; - - case 0x77: - bit(6, AF.hi); - PC += 1; - addCycles(8); - break; - - case 0x78: - bit(7, BC.hi); - PC += 1; - addCycles(8); - break; - - case 0x79: - bit(7, BC.lo); - PC += 1; - addCycles(8); - break; - - case 0x7A: - bit(7, DE.hi); - PC += 1; - addCycles(8); - break; - - case 0x7B: - bit(7, DE.lo); - PC += 1; - addCycles(8); - break; - - case 0x7C: - bit(7, HL.hi); - PC += 1; - addCycles(8); - break; - - case 0x7D: - bit(7, HL.lo); - PC += 1; - addCycles(8); - break; - - case 0x7E: - bit(7, readOnlyAddressSpace[HL.reg]); - PC += 1; - addCycles(12); - break; - - case 0x7F: - bit(7, AF.hi); - PC += 1; - addCycles(8); - break; - - case 0x80: - res(0, BC.hi); - PC += 1; - addCycles(8); - break; - - case 0x81: - res(0, BC.lo); - PC += 1; - addCycles(8); - break; - - case 0x82: - res(0, DE.hi); - PC += 1; - addCycles(8); - break; - - case 0x83: - res(0, DE.lo); - PC += 1; - addCycles(8); - break; - - case 0x84: - res(0, HL.hi); - PC += 1; - addCycles(8); - break; - - case 0x85: - res(0, HL.lo); - PC += 1; - addCycles(8); - break; - - case 0x86: - res(0, addressSpace[HL.reg]); - PC += 1; - addCycles(16); - break; - - case 0x87: - res(0, AF.hi); - PC += 1; - addCycles(8); - break; - - case 0x88: - res(1, BC.hi); - PC += 1; - addCycles(8); - break; - - case 0x89: - res(1, BC.lo); - PC += 1; - addCycles(8); - break; - - case 0x8A: - res(1, DE.hi); - PC += 1; - addCycles(8); - break; - - case 0x8B: - res(1, DE.lo); - PC += 1; - addCycles(8); - break; - - case 0x8C: - res(1, HL.hi); - PC += 1; - addCycles(8); - break; - - case 0x8D: - res(1, HL.lo); - PC += 1; - addCycles(8); - break; - - case 0x8E: - res(1, addressSpace[HL.reg]); - PC += 1; - addCycles(16); - break; - - case 0x8F: - res(1, AF.hi); - PC += 1; - addCycles(8); - break; - - case 0x90: - res(2, BC.hi); - PC += 1; - addCycles(8); - break; - - case 0x91: - res(2, BC.lo); - PC += 1; - addCycles(8); - break; - - case 0x92: - res(2, DE.hi); - PC += 1; - addCycles(8); - break; - - case 0x93: - res(2, DE.lo); - PC += 1; - addCycles(8); - break; - - case 0x94: - res(2, HL.hi); - PC += 1; - addCycles(8); - break; - - case 0x95: - res(2, HL.lo); - PC += 1; - addCycles(8); - break; - - case 0x96: - res(2, addressSpace[HL.reg]); - PC += 1; - addCycles(16); - break; - - case 0x97: - res(2, AF.hi); - PC += 1; - addCycles(8); - break; - - case 0x98: - res(3, BC.hi); - PC += 1; - addCycles(8); - break; - - case 0x99: - res(3, BC.lo); - PC += 1; - addCycles(8); - break; - - case 0x9A: - res(3, DE.hi); - PC += 1; - addCycles(8); - break; - - case 0x9B: - res(3, DE.lo); - PC += 1; - addCycles(8); - break; - - case 0x9C: - res(3, HL.hi); - PC += 1; - addCycles(8); - break; - - case 0x9D: - res(3, HL.lo); - PC += 1; - addCycles(8); - break; - - case 0x9E: - res(3, addressSpace[HL.reg]); - PC += 1; - addCycles(16); - break; - - case 0x9F: - res(3, AF.hi); - PC += 1; - addCycles(8); - break; - - case 0xA0: - res(4, BC.hi); - PC += 1; - addCycles(8); - break; - - case 0xA1: - res(4, BC.lo); - PC += 1; - addCycles(8); - break; - - case 0xA2: - res(4, DE.hi); - PC += 1; - addCycles(8); - break; - - case 0xA3: - res(4, DE.lo); - PC += 1; - addCycles(8); - break; - - case 0xA4: - res(4, HL.hi); - PC += 1; - addCycles(8); - break; - - case 0xA5: - res(4, HL.lo); - PC += 1; - addCycles(8); - break; - - case 0xA6: - res(4, addressSpace[HL.reg]); - PC += 1; - addCycles(16); - break; - - case 0xA7: - res(4, AF.hi); - PC += 1; - addCycles(8); - break; - - case 0xA8: - res(5, BC.hi); - PC += 1; - addCycles(8); - break; - - case 0xA9: - res(5, BC.lo); - PC += 1; - addCycles(8); - break; - - case 0xAA: - res(5, DE.hi); - PC += 1; - addCycles(8); - break; - - case 0xAB: - res(5, DE.lo); - PC += 1; - addCycles(8); - break; - - case 0xAC: - res(5, HL.hi); - PC += 1; - addCycles(8); - break; - - case 0xAD: - res(5, HL.lo); - PC += 1; - addCycles(8); - break; - - case 0xAE: - res(5, addressSpace[HL.reg]); - PC += 1; - addCycles(16); - break; - - case 0xAF: - res(5, AF.hi); - PC += 1; - addCycles(8); - break; - - case 0xB0: - res(6, BC.hi); - PC += 1; - addCycles(8); - break; - - case 0xB1: - res(6, BC.lo); - PC += 1; - addCycles(8); - break; - - case 0xB2: - res(6, DE.hi); - PC += 1; - addCycles(8); - break; - - case 0xB3: - res(6, DE.lo); - PC += 1; - addCycles(8); - break; - - case 0xB4: - res(6, HL.hi); - PC += 1; - addCycles(8); - break; - - case 0xB5: - res(6, HL.lo); - PC += 1; - addCycles(8); - break; - - case 0xB6: - res(6, addressSpace[HL.reg]); - PC += 1; - addCycles(16); - break; - - case 0xB7: - res(6, AF.hi); - PC += 1; - addCycles(8); - break; - - case 0xB8: - res(7, BC.hi); - PC += 1; - addCycles(8); - break; - - case 0xB9: - res(7, BC.lo); - PC += 1; - addCycles(8); - break; - - case 0xBA: - res(7, DE.hi); - PC += 1; - addCycles(8); - break; - - case 0xBB: - res(7, DE.lo); - PC += 1; - addCycles(8); - break; - - case 0xBC: - res(7, HL.hi); - PC += 1; - addCycles(8); - break; - - case 0xBD: - res(7, HL.lo); - PC += 1; - addCycles(8); - break; - - case 0xBE: - res(7, addressSpace[HL.reg]); - PC += 1; - addCycles(16); - break; - - case 0xBF: - res(7, AF.hi); - PC += 1; - addCycles(8); - break; - - case 0xC0: - set(0, BC.hi); - PC += 1; - addCycles(8); - break; - - case 0xC1: - set(0, BC.lo); - PC += 1; - addCycles(8); - break; - - case 0xC2: - set(0, DE.hi); - PC += 1; - addCycles(8); - break; - - case 0xC3: - set(0, DE.lo); - PC += 1; - addCycles(8); - break; - - case 0xC4: - set(0, HL.hi); - PC += 1; - addCycles(8); - break; - - case 0xC5: - set(0, HL.lo); - PC += 1; - addCycles(8); - break; - - case 0xC6: - set(0, addressSpace[HL.reg]); - PC += 1; - addCycles(16); - break; - - case 0xC7: - set(0, AF.hi); - PC += 1; - addCycles(8); - break; - - case 0xC8: - set(1, BC.hi); - PC += 1; - addCycles(8); - break; - - case 0xC9: - set(1, BC.lo); - PC += 1; - addCycles(8); - break; - - case 0xCA: - set(1, DE.hi); - PC += 1; - addCycles(8); - break; - - case 0xCB: - set(1, DE.lo); - PC += 1; - addCycles(8); - break; - - case 0xCC: - set(1, HL.hi); - PC += 1; - addCycles(8); - break; - - case 0xCD: - set(1, HL.lo); - PC += 1; - addCycles(8); - break; - - case 0xCE: - set(1, addressSpace[HL.reg]); - PC += 1; - addCycles(16); - break; - - case 0xCF: - set(1, AF.hi); - PC += 1; - addCycles(8); - break; - - case 0xD0: - set(2, BC.hi); - PC += 1; - addCycles(8); - break; - - case 0xD1: - set(2, BC.lo); - PC += 1; - addCycles(8); - break; - - case 0xD2: - set(2, DE.hi); - PC += 1; - addCycles(8); - break; - - case 0xD3: - set(2, DE.lo); - PC += 1; - addCycles(8); - break; - - case 0xD4: - set(2, HL.hi); - PC += 1; - addCycles(8); - break; - - case 0xD5: - set(2, HL.lo); - PC += 1; - addCycles(8); - break; - - case 0xD6: - set(2, addressSpace[HL.reg]); - PC += 1; - addCycles(16); - break; - - case 0xD7: - set(2, AF.hi); - PC += 1; - addCycles(8); - break; - - case 0xD8: - set(3, BC.hi); - PC += 1; - addCycles(8); - break; - - case 0xD9: - set(3, BC.lo); - PC += 1; - addCycles(8); - break; - - case 0xDA: - set(3, DE.hi); - PC += 1; - addCycles(8); - break; - - case 0xDB: - set(3, DE.lo); - PC += 1; - addCycles(8); - break; - - case 0xDC: - set(3, HL.hi); - PC += 1; - addCycles(8); - break; - - case 0xDD: - set(3, HL.lo); - PC += 1; - addCycles(8); - break; - - case 0xDE: - set(3, addressSpace[HL.reg]); - PC += 1; - addCycles(16); - break; - - case 0xDF: - set(3, AF.hi); - PC += 1; - addCycles(8); - break; - - case 0xE0: - set(4, BC.hi); - PC += 1; - addCycles(8); - break; - - case 0xE1: - set(4, BC.lo); - PC += 1; - addCycles(8); - break; - - case 0xE2: - set(4, DE.hi); - PC += 1; - addCycles(8); - break; - - case 0xE3: - set(4, DE.lo); - PC += 1; - addCycles(8); - break; - - case 0xE4: - set(4, HL.hi); - PC += 1; - addCycles(8); - break; - - case 0xE5: - set(4, HL.lo); - PC += 1; - addCycles(8); - break; - - case 0xE6: - set(4, addressSpace[HL.reg]); - PC += 1; - addCycles(16); - break; - - case 0xE7: - set(4, AF.hi); - PC += 1; - addCycles(8); - break; - - case 0xE8: - set(5, BC.hi); - PC += 1; - addCycles(8); - break; - - case 0xE9: - set(5, BC.lo); - PC += 1; - addCycles(8); - break; - - case 0xEA: - set(5, DE.hi); - PC += 1; - addCycles(8); - break; - - case 0xEB: - set(5, DE.lo); - PC += 1; - addCycles(8); - break; - - case 0xEC: - set(5, HL.hi); - PC += 1; - addCycles(8); - break; - - case 0xED: - set(5, HL.lo); - PC += 1; - addCycles(8); - break; - - case 0xEE: - set(5, addressSpace[HL.reg]); - PC += 1; - addCycles(16); - break; - - case 0xEF: - set(5, AF.hi); - PC += 1; - addCycles(8); - break; - - case 0xF0: - set(6, BC.hi); - PC += 1; - addCycles(8); - break; - - case 0xF1: - set(6, BC.lo); - PC += 1; - addCycles(8); - break; - - case 0xF2: - set(6, DE.hi); - PC += 1; - addCycles(8); - break; - - case 0xF3: - set(6, DE.lo); - PC += 1; - addCycles(8); - break; - - case 0xF4: - set(6, HL.hi); - PC += 1; - addCycles(8); - break; - - case 0xF5: - set(6, HL.lo); - PC += 1; - addCycles(8); - break; - - case 0xF6: - set(6, addressSpace[HL.reg]); - PC += 1; - addCycles(16); - break; - - case 0xF7: - set(6, AF.hi); - PC += 1; - addCycles(8); - break; - - case 0xF8: - set(7, BC.hi); - PC += 1; - addCycles(8); - break; - - case 0xF9: - set(7, BC.lo); - PC += 1; - addCycles(8); - break; - - case 0xFA: - set(7, DE.hi); - PC += 1; - addCycles(8); - break; - - case 0xFB: - set(7, DE.lo); - PC += 1; - addCycles(8); - break; - - case 0xFC: - set(7, HL.hi); - PC += 1; - addCycles(8); - break; - - case 0xFD: - set(7, HL.lo); - PC += 1; - addCycles(8); - break; - - case 0xFE: - set(7, addressSpace[HL.reg]); - PC += 1; - addCycles(16); - break; - - case 0xFF: - set(7, AF.hi); - PC += 1; - addCycles(8); - break; - - default: - printf("Unsupported extended opcode found: PC:0x%.2x, Opcode:0xcb%.2x\n", PC, addressSpace[PC]); - exit(1); - } + PC += 1; + + switch (readOnlyAddressSpace[PC]) { + case 0x00: + rlc(BC.hi); + PC += 1; + addCycles(8); + break; + + case 0x01: + rlc(BC.lo); + PC += 1; + addCycles(8); + break; + + case 0x02: + rlc(DE.hi); + PC += 1; + addCycles(8); + break; + + case 0x03: + rlc(DE.lo); + PC += 1; + addCycles(8); + break; + + case 0x04: + rlc(HL.hi); + PC += 1; + addCycles(8); + break; + + case 0x05: + rlc(HL.lo); + PC += 1; + addCycles(8); + break; + + case 0x06: + rlc(addressSpace[HL.reg]); + PC += 1; + addCycles(16); + break; + + case 0x07: + rlc(AF.hi); + PC += 1; + addCycles(8); + break; + + case 0x08: + rrc(BC.hi); + PC += 1; + addCycles(8); + break; + + case 0x09: + rrc(BC.lo); + PC += 1; + addCycles(8); + break; + + case 0x0A: + rrc(DE.hi); + PC += 1; + addCycles(8); + break; + + case 0x0B: + rrc(DE.lo); + PC += 1; + addCycles(8); + break; + + case 0x0C: + rrc(HL.hi); + PC += 1; + addCycles(8); + break; + + case 0x0D: + rrc(HL.lo); + PC += 1; + addCycles(8); + break; + + case 0x0E: + rrc(addressSpace[HL.reg]); + PC += 1; + addCycles(16); + break; + + case 0x0F: + rrc(AF.hi); + PC += 1; + addCycles(8); + break; + + case 0x10: + rl(BC.hi); + PC += 1; + addCycles(8); + break; + + case 0x11: + rl(BC.lo); + PC += 1; + addCycles(8); + break; + + case 0x12: + rl(DE.hi); + PC += 1; + addCycles(8); + break; + + case 0x13: + rl(DE.lo); + PC += 1; + addCycles(8); + break; + + case 0x14: + rl(HL.hi); + PC += 1; + addCycles(8); + break; + + case 0x15: + rl(HL.lo); + PC += 1; + addCycles(8); + break; + + case 0x16: + rl(addressSpace[HL.reg]); + PC += 1; + addCycles(16); + break; + + case 0x17: + rl(AF.hi); + PC += 1; + addCycles(8); + break; + + case 0x18: + rr(BC.hi); + PC += 1; + addCycles(8); + break; + + case 0x19: + rr(BC.lo); + PC += 1; + addCycles(8); + break; + + case 0x1A: + rr(DE.hi); + PC += 1; + addCycles(8); + break; + + case 0x1B: + rr(DE.lo); + PC += 1; + addCycles(8); + break; + + case 0x1C: + rr(HL.hi); + PC += 1; + addCycles(8); + break; + + case 0x1D: + rr(HL.lo); + PC += 1; + addCycles(8); + break; + + case 0x1E: + rr(addressSpace[HL.reg]); + PC += 1; + addCycles(16); + break; + + case 0x1F: + rr(AF.hi); + PC += 1; + addCycles(8); + break; + + case 0x20: + sla(BC.hi); + PC += 1; + addCycles(8); + break; + + case 0x21: + sla(BC.lo); + PC += 1; + addCycles(8); + break; + + case 0x22: + sla(DE.hi); + PC += 1; + addCycles(8); + break; + + case 0x23: + sla(DE.lo); + PC += 1; + addCycles(8); + break; + + case 0x24: + sla(HL.hi); + PC += 1; + addCycles(8); + break; + + case 0x25: + sla(HL.lo); + PC += 1; + addCycles(8); + break; + + case 0x26: + sla(addressSpace[HL.reg]); + PC += 1; + addCycles(16); + break; + + case 0x27: + sla(AF.hi); + PC += 1; + addCycles(8); + break; + + case 0x28: + sra(BC.hi); + PC += 1; + addCycles(8); + break; + + case 0x29: + sra(BC.lo); + PC += 1; + addCycles(8); + break; + + case 0x2A: + sra(DE.hi); + PC += 1; + addCycles(8); + break; + + case 0x2B: + sra(DE.lo); + PC += 1; + addCycles(8); + break; + + case 0x2C: + sra(HL.hi); + PC += 1; + addCycles(8); + break; + + case 0x2D: + sra(HL.lo); + PC += 1; + addCycles(8); + break; + + case 0x2E: + sra(addressSpace[HL.reg]); + PC += 1; + addCycles(16); + break; + + case 0x2F: + sra(AF.hi); + PC += 1; + addCycles(8); + break; + + case 0x30: + swap(BC.hi); + PC += 1; + addCycles(8); + break; + + case 0x31: + swap(BC.lo); + PC += 1; + addCycles(8); + break; + + case 0x32: + swap(DE.hi); + PC += 1; + addCycles(8); + break; + + case 0x33: + swap(DE.lo); + PC += 1; + addCycles(8); + break; + + case 0x34: + swap(HL.hi); + PC += 1; + addCycles(8); + break; + + case 0x35: + swap(HL.lo); + PC += 1; + addCycles(8); + break; + + case 0x36: + swap(addressSpace[HL.reg]); + PC += 1; + addCycles(16); + break; + + case 0x37: + swap(AF.hi); + PC += 1; + addCycles(8); + break; + + case 0x38: + srl(BC.hi); + PC += 1; + addCycles(8); + break; + + case 0x39: + srl(BC.lo); + PC += 1; + addCycles(8); + break; + + case 0x3A: + srl(DE.hi); + PC += 1; + addCycles(8); + break; + + case 0x3B: + srl(DE.lo); + PC += 1; + addCycles(8); + break; + + case 0x3C: + srl(HL.hi); + PC += 1; + addCycles(8); + break; + + case 0x3D: + srl(HL.lo); + PC += 1; + addCycles(8); + break; + + case 0x3E: + srl(addressSpace[HL.reg]); + PC += 1; + addCycles(16); + break; + + case 0x3F: + srl(AF.hi); + PC += 1; + addCycles(8); + break; + + case 0x40: + bit(0, BC.hi); + PC += 1; + addCycles(8); + break; + + case 0x41: + bit(0, BC.lo); + PC += 1; + addCycles(8); + break; + + case 0x42: + bit(0, DE.hi); + PC += 1; + addCycles(8); + break; + + case 0x43: + bit(0, DE.lo); + PC += 1; + addCycles(8); + break; + + case 0x44: + bit(0, HL.hi); + PC += 1; + addCycles(8); + break; + + case 0x45: + bit(0, HL.lo); + PC += 1; + addCycles(8); + break; + + case 0x46: + bit(0, readOnlyAddressSpace[HL.reg]); + PC += 1; + addCycles(12); + break; + + case 0x47: + bit(0, AF.hi); + PC += 1; + addCycles(8); + break; + + case 0x48: + bit(1, BC.hi); + PC += 1; + addCycles(8); + break; + + case 0x49: + bit(1, BC.lo); + PC += 1; + addCycles(8); + break; + + case 0x4A: + bit(1, DE.hi); + PC += 1; + addCycles(8); + break; + + case 0x4B: + bit(1, DE.lo); + PC += 1; + addCycles(8); + break; + + case 0x4C: + bit(1, HL.hi); + PC += 1; + addCycles(8); + break; + + case 0x4D: + bit(1, HL.lo); + PC += 1; + addCycles(8); + break; + + case 0x4E: + bit(1, readOnlyAddressSpace[HL.reg]); + PC += 1; + addCycles(12); + break; + + case 0x4F: + bit(1, AF.hi); + PC += 1; + addCycles(8); + break; + + case 0x50: + bit(2, BC.hi); + PC += 1; + addCycles(8); + break; + + case 0x51: + bit(2, BC.lo); + PC += 1; + addCycles(8); + break; + + case 0x52: + bit(2, DE.hi); + PC += 1; + addCycles(8); + break; + + case 0x53: + bit(2, DE.lo); + PC += 1; + addCycles(8); + break; + + case 0x54: + bit(2, HL.hi); + PC += 1; + addCycles(8); + break; + + case 0x55: + bit(2, HL.lo); + PC += 1; + addCycles(8); + break; + + case 0x56: + bit(2, readOnlyAddressSpace[HL.reg]); + PC += 1; + addCycles(12); + break; + + case 0x57: + bit(2, AF.hi); + PC += 1; + addCycles(8); + break; + + case 0x58: + bit(3, BC.hi); + PC += 1; + addCycles(8); + break; + + case 0x59: + bit(3, BC.lo); + PC += 1; + addCycles(8); + break; + + case 0x5A: + bit(3, DE.hi); + PC += 1; + addCycles(8); + break; + + case 0x5B: + bit(3, DE.lo); + PC += 1; + addCycles(8); + break; + + case 0x5C: + bit(3, HL.hi); + PC += 1; + addCycles(8); + break; + + case 0x5D: + bit(3, HL.lo); + PC += 1; + addCycles(8); + break; + + case 0x5E: + bit(3, readOnlyAddressSpace[HL.reg]); + PC += 1; + addCycles(12); + break; + + case 0x5F: + bit(3, AF.hi); + PC += 1; + addCycles(8); + break; + + case 0x60: + bit(4, BC.hi); + PC += 1; + addCycles(8); + break; + + case 0x61: + bit(4, BC.lo); + PC += 1; + addCycles(8); + break; + + case 0x62: + bit(4, DE.hi); + PC += 1; + addCycles(8); + break; + + case 0x63: + bit(4, DE.lo); + PC += 1; + addCycles(8); + break; + + case 0x64: + bit(4, HL.hi); + PC += 1; + addCycles(8); + break; + + case 0x65: + bit(4, HL.lo); + PC += 1; + addCycles(8); + break; + + case 0x66: + bit(4, readOnlyAddressSpace[HL.reg]); + PC += 1; + addCycles(12); + break; + + case 0x67: + bit(4, AF.hi); + PC += 1; + addCycles(8); + break; + + case 0x68: + bit(5, BC.hi); + PC += 1; + addCycles(8); + break; + + case 0x69: + bit(5, BC.lo); + PC += 1; + addCycles(8); + break; + + case 0x6A: + bit(5, DE.hi); + PC += 1; + addCycles(8); + break; + + case 0x6B: + bit(5, DE.lo); + PC += 1; + addCycles(8); + break; + + case 0x6C: + bit(5, HL.hi); + PC += 1; + addCycles(8); + break; + + case 0x6D: + bit(5, HL.lo); + PC += 1; + addCycles(8); + break; + + case 0x6E: + bit(5, readOnlyAddressSpace[HL.reg]); + PC += 1; + addCycles(12); + break; + + case 0x6F: + bit(5, AF.hi); + PC += 1; + addCycles(8); + break; + + case 0x70: + bit(6, BC.hi); + PC += 1; + addCycles(8); + break; + + case 0x71: + bit(6, BC.lo); + PC += 1; + addCycles(8); + break; + + case 0x72: + bit(6, DE.hi); + PC += 1; + addCycles(8); + break; + + case 0x73: + bit(6, DE.lo); + PC += 1; + addCycles(8); + break; + + case 0x74: + bit(6, HL.hi); + PC += 1; + addCycles(8); + break; + + case 0x75: + bit(6, HL.lo); + PC += 1; + addCycles(8); + break; + + case 0x76: + bit(6, readOnlyAddressSpace[HL.reg]); + PC += 1; + addCycles(12); + break; + + case 0x77: + bit(6, AF.hi); + PC += 1; + addCycles(8); + break; + + case 0x78: + bit(7, BC.hi); + PC += 1; + addCycles(8); + break; + + case 0x79: + bit(7, BC.lo); + PC += 1; + addCycles(8); + break; + + case 0x7A: + bit(7, DE.hi); + PC += 1; + addCycles(8); + break; + + case 0x7B: + bit(7, DE.lo); + PC += 1; + addCycles(8); + break; + + case 0x7C: + bit(7, HL.hi); + PC += 1; + addCycles(8); + break; + + case 0x7D: + bit(7, HL.lo); + PC += 1; + addCycles(8); + break; + + case 0x7E: + bit(7, readOnlyAddressSpace[HL.reg]); + PC += 1; + addCycles(12); + break; + + case 0x7F: + bit(7, AF.hi); + PC += 1; + addCycles(8); + break; + + case 0x80: + res(0, BC.hi); + PC += 1; + addCycles(8); + break; + + case 0x81: + res(0, BC.lo); + PC += 1; + addCycles(8); + break; + + case 0x82: + res(0, DE.hi); + PC += 1; + addCycles(8); + break; + + case 0x83: + res(0, DE.lo); + PC += 1; + addCycles(8); + break; + + case 0x84: + res(0, HL.hi); + PC += 1; + addCycles(8); + break; + + case 0x85: + res(0, HL.lo); + PC += 1; + addCycles(8); + break; + + case 0x86: + res(0, addressSpace[HL.reg]); + PC += 1; + addCycles(16); + break; + + case 0x87: + res(0, AF.hi); + PC += 1; + addCycles(8); + break; + + case 0x88: + res(1, BC.hi); + PC += 1; + addCycles(8); + break; + + case 0x89: + res(1, BC.lo); + PC += 1; + addCycles(8); + break; + + case 0x8A: + res(1, DE.hi); + PC += 1; + addCycles(8); + break; + + case 0x8B: + res(1, DE.lo); + PC += 1; + addCycles(8); + break; + + case 0x8C: + res(1, HL.hi); + PC += 1; + addCycles(8); + break; + + case 0x8D: + res(1, HL.lo); + PC += 1; + addCycles(8); + break; + + case 0x8E: + res(1, addressSpace[HL.reg]); + PC += 1; + addCycles(16); + break; + + case 0x8F: + res(1, AF.hi); + PC += 1; + addCycles(8); + break; + + case 0x90: + res(2, BC.hi); + PC += 1; + addCycles(8); + break; + + case 0x91: + res(2, BC.lo); + PC += 1; + addCycles(8); + break; + + case 0x92: + res(2, DE.hi); + PC += 1; + addCycles(8); + break; + + case 0x93: + res(2, DE.lo); + PC += 1; + addCycles(8); + break; + + case 0x94: + res(2, HL.hi); + PC += 1; + addCycles(8); + break; + + case 0x95: + res(2, HL.lo); + PC += 1; + addCycles(8); + break; + + case 0x96: + res(2, addressSpace[HL.reg]); + PC += 1; + addCycles(16); + break; + + case 0x97: + res(2, AF.hi); + PC += 1; + addCycles(8); + break; + + case 0x98: + res(3, BC.hi); + PC += 1; + addCycles(8); + break; + + case 0x99: + res(3, BC.lo); + PC += 1; + addCycles(8); + break; + + case 0x9A: + res(3, DE.hi); + PC += 1; + addCycles(8); + break; + + case 0x9B: + res(3, DE.lo); + PC += 1; + addCycles(8); + break; + + case 0x9C: + res(3, HL.hi); + PC += 1; + addCycles(8); + break; + + case 0x9D: + res(3, HL.lo); + PC += 1; + addCycles(8); + break; + + case 0x9E: + res(3, addressSpace[HL.reg]); + PC += 1; + addCycles(16); + break; + + case 0x9F: + res(3, AF.hi); + PC += 1; + addCycles(8); + break; + + case 0xA0: + res(4, BC.hi); + PC += 1; + addCycles(8); + break; + + case 0xA1: + res(4, BC.lo); + PC += 1; + addCycles(8); + break; + + case 0xA2: + res(4, DE.hi); + PC += 1; + addCycles(8); + break; + + case 0xA3: + res(4, DE.lo); + PC += 1; + addCycles(8); + break; + + case 0xA4: + res(4, HL.hi); + PC += 1; + addCycles(8); + break; + + case 0xA5: + res(4, HL.lo); + PC += 1; + addCycles(8); + break; + + case 0xA6: + res(4, addressSpace[HL.reg]); + PC += 1; + addCycles(16); + break; + + case 0xA7: + res(4, AF.hi); + PC += 1; + addCycles(8); + break; + + case 0xA8: + res(5, BC.hi); + PC += 1; + addCycles(8); + break; + + case 0xA9: + res(5, BC.lo); + PC += 1; + addCycles(8); + break; + + case 0xAA: + res(5, DE.hi); + PC += 1; + addCycles(8); + break; + + case 0xAB: + res(5, DE.lo); + PC += 1; + addCycles(8); + break; + + case 0xAC: + res(5, HL.hi); + PC += 1; + addCycles(8); + break; + + case 0xAD: + res(5, HL.lo); + PC += 1; + addCycles(8); + break; + + case 0xAE: + res(5, addressSpace[HL.reg]); + PC += 1; + addCycles(16); + break; + + case 0xAF: + res(5, AF.hi); + PC += 1; + addCycles(8); + break; + + case 0xB0: + res(6, BC.hi); + PC += 1; + addCycles(8); + break; + + case 0xB1: + res(6, BC.lo); + PC += 1; + addCycles(8); + break; + + case 0xB2: + res(6, DE.hi); + PC += 1; + addCycles(8); + break; + + case 0xB3: + res(6, DE.lo); + PC += 1; + addCycles(8); + break; + + case 0xB4: + res(6, HL.hi); + PC += 1; + addCycles(8); + break; + + case 0xB5: + res(6, HL.lo); + PC += 1; + addCycles(8); + break; + + case 0xB6: + res(6, addressSpace[HL.reg]); + PC += 1; + addCycles(16); + break; + + case 0xB7: + res(6, AF.hi); + PC += 1; + addCycles(8); + break; + + case 0xB8: + res(7, BC.hi); + PC += 1; + addCycles(8); + break; + + case 0xB9: + res(7, BC.lo); + PC += 1; + addCycles(8); + break; + + case 0xBA: + res(7, DE.hi); + PC += 1; + addCycles(8); + break; + + case 0xBB: + res(7, DE.lo); + PC += 1; + addCycles(8); + break; + + case 0xBC: + res(7, HL.hi); + PC += 1; + addCycles(8); + break; + + case 0xBD: + res(7, HL.lo); + PC += 1; + addCycles(8); + break; + + case 0xBE: + res(7, addressSpace[HL.reg]); + PC += 1; + addCycles(16); + break; + + case 0xBF: + res(7, AF.hi); + PC += 1; + addCycles(8); + break; + + case 0xC0: + set(0, BC.hi); + PC += 1; + addCycles(8); + break; + + case 0xC1: + set(0, BC.lo); + PC += 1; + addCycles(8); + break; + + case 0xC2: + set(0, DE.hi); + PC += 1; + addCycles(8); + break; + + case 0xC3: + set(0, DE.lo); + PC += 1; + addCycles(8); + break; + + case 0xC4: + set(0, HL.hi); + PC += 1; + addCycles(8); + break; + + case 0xC5: + set(0, HL.lo); + PC += 1; + addCycles(8); + break; + + case 0xC6: + set(0, addressSpace[HL.reg]); + PC += 1; + addCycles(16); + break; + + case 0xC7: + set(0, AF.hi); + PC += 1; + addCycles(8); + break; + + case 0xC8: + set(1, BC.hi); + PC += 1; + addCycles(8); + break; + + case 0xC9: + set(1, BC.lo); + PC += 1; + addCycles(8); + break; + + case 0xCA: + set(1, DE.hi); + PC += 1; + addCycles(8); + break; + + case 0xCB: + set(1, DE.lo); + PC += 1; + addCycles(8); + break; + + case 0xCC: + set(1, HL.hi); + PC += 1; + addCycles(8); + break; + + case 0xCD: + set(1, HL.lo); + PC += 1; + addCycles(8); + break; + + case 0xCE: + set(1, addressSpace[HL.reg]); + PC += 1; + addCycles(16); + break; + + case 0xCF: + set(1, AF.hi); + PC += 1; + addCycles(8); + break; + + case 0xD0: + set(2, BC.hi); + PC += 1; + addCycles(8); + break; + + case 0xD1: + set(2, BC.lo); + PC += 1; + addCycles(8); + break; + + case 0xD2: + set(2, DE.hi); + PC += 1; + addCycles(8); + break; + + case 0xD3: + set(2, DE.lo); + PC += 1; + addCycles(8); + break; + + case 0xD4: + set(2, HL.hi); + PC += 1; + addCycles(8); + break; + + case 0xD5: + set(2, HL.lo); + PC += 1; + addCycles(8); + break; + + case 0xD6: + set(2, addressSpace[HL.reg]); + PC += 1; + addCycles(16); + break; + + case 0xD7: + set(2, AF.hi); + PC += 1; + addCycles(8); + break; + + case 0xD8: + set(3, BC.hi); + PC += 1; + addCycles(8); + break; + + case 0xD9: + set(3, BC.lo); + PC += 1; + addCycles(8); + break; + + case 0xDA: + set(3, DE.hi); + PC += 1; + addCycles(8); + break; + + case 0xDB: + set(3, DE.lo); + PC += 1; + addCycles(8); + break; + + case 0xDC: + set(3, HL.hi); + PC += 1; + addCycles(8); + break; + + case 0xDD: + set(3, HL.lo); + PC += 1; + addCycles(8); + break; + + case 0xDE: + set(3, addressSpace[HL.reg]); + PC += 1; + addCycles(16); + break; + + case 0xDF: + set(3, AF.hi); + PC += 1; + addCycles(8); + break; + + case 0xE0: + set(4, BC.hi); + PC += 1; + addCycles(8); + break; + + case 0xE1: + set(4, BC.lo); + PC += 1; + addCycles(8); + break; + + case 0xE2: + set(4, DE.hi); + PC += 1; + addCycles(8); + break; + + case 0xE3: + set(4, DE.lo); + PC += 1; + addCycles(8); + break; + + case 0xE4: + set(4, HL.hi); + PC += 1; + addCycles(8); + break; + + case 0xE5: + set(4, HL.lo); + PC += 1; + addCycles(8); + break; + + case 0xE6: + set(4, addressSpace[HL.reg]); + PC += 1; + addCycles(16); + break; + + case 0xE7: + set(4, AF.hi); + PC += 1; + addCycles(8); + break; + + case 0xE8: + set(5, BC.hi); + PC += 1; + addCycles(8); + break; + + case 0xE9: + set(5, BC.lo); + PC += 1; + addCycles(8); + break; + + case 0xEA: + set(5, DE.hi); + PC += 1; + addCycles(8); + break; + + case 0xEB: + set(5, DE.lo); + PC += 1; + addCycles(8); + break; + + case 0xEC: + set(5, HL.hi); + PC += 1; + addCycles(8); + break; + + case 0xED: + set(5, HL.lo); + PC += 1; + addCycles(8); + break; + + case 0xEE: + set(5, addressSpace[HL.reg]); + PC += 1; + addCycles(16); + break; + + case 0xEF: + set(5, AF.hi); + PC += 1; + addCycles(8); + break; + + case 0xF0: + set(6, BC.hi); + PC += 1; + addCycles(8); + break; + + case 0xF1: + set(6, BC.lo); + PC += 1; + addCycles(8); + break; + + case 0xF2: + set(6, DE.hi); + PC += 1; + addCycles(8); + break; + + case 0xF3: + set(6, DE.lo); + PC += 1; + addCycles(8); + break; + + case 0xF4: + set(6, HL.hi); + PC += 1; + addCycles(8); + break; + + case 0xF5: + set(6, HL.lo); + PC += 1; + addCycles(8); + break; + + case 0xF6: + set(6, addressSpace[HL.reg]); + PC += 1; + addCycles(16); + break; + + case 0xF7: + set(6, AF.hi); + PC += 1; + addCycles(8); + break; + + case 0xF8: + set(7, BC.hi); + PC += 1; + addCycles(8); + break; + + case 0xF9: + set(7, BC.lo); + PC += 1; + addCycles(8); + break; + + case 0xFA: + set(7, DE.hi); + PC += 1; + addCycles(8); + break; + + case 0xFB: + set(7, DE.lo); + PC += 1; + addCycles(8); + break; + + case 0xFC: + set(7, HL.hi); + PC += 1; + addCycles(8); + break; + + case 0xFD: + set(7, HL.lo); + PC += 1; + addCycles(8); + break; + + case 0xFE: + set(7, addressSpace[HL.reg]); + PC += 1; + addCycles(16); + break; + + case 0xFF: + set(7, AF.hi); + PC += 1; + addCycles(8); + break; + + default: + printf("Unsupported extended opcode found: PC:0x%.2x, Opcode:0xcb%.2x\n", + PC, addressSpace[PC]); + exit(1); + } } diff --git a/src/gameboy.cpp b/src/gameboy.cpp index d900dfa..8383ece 100644 --- a/src/gameboy.cpp +++ b/src/gameboy.cpp @@ -1,202 +1,194 @@ -#include #include "gameboy.hpp" +#include void GameBoy::addCycles(const uint8_t ticks) { - cycles += ticks; - if (ppuEnabled) { - ppuCycles += ticks; - } - lastOpTicks = ticks; + cycles += ticks; + if (ppuEnabled) { + ppuCycles += ticks; + } + lastOpTicks = ticks; } GameboyTestState GameBoy::runTest(GameboyTestState initial) { - addressSpace.setTesting(true); + addressSpace.setTesting(true); - PC = initial.PC; - SP = initial.SP; - AF.hi = initial.A; - AF.lo = initial.F; - BC.hi = initial.B; - BC.lo = initial.C; - DE.hi = initial.D; - DE.lo = initial.E; - HL.hi = initial.H; - HL.lo = initial.L; - addressSpace.memoryLayout.IE = 1; + PC = initial.PC; + SP = initial.SP; + AF.hi = initial.A; + AF.lo = initial.F; + BC.hi = initial.B; + BC.lo = initial.C; + DE.hi = initial.D; + DE.lo = initial.E; + HL.hi = initial.H; + HL.lo = initial.L; + addressSpace.memoryLayout.IE = 1; - for (const auto& [addr, val] : initial.RAM) { - addressSpace[addr] = val; - } + for (const auto &[addr, val] : initial.RAM) { + addressSpace[addr] = val; + } - opcodeResolver(); + opcodeResolver(); - std::vector> returnRAM; - for (const auto& [addr, val] : initial.RAM) { - returnRAM.emplace_back(addr, addressSpace[addr]); - } - return { - PC, SP, - AF.hi, AF.lo, - BC.hi, BC.lo, - DE.hi, DE.lo, - HL.hi, HL.lo, - returnRAM - }; + std::vector> returnRAM; + for (const auto &[addr, val] : initial.RAM) { + returnRAM.emplace_back(addr, addressSpace[addr]); + } + return {PC, SP, AF.hi, AF.lo, BC.hi, BC.lo, + DE.hi, DE.lo, HL.hi, HL.lo, returnRAM}; } +void GameBoy::start(const std::string &bootrom, const std::string &game) { + addressSpace.loadBootrom(bootrom); + addressSpace.loadGame(game); + addressSpace.determineMBCInfo(); + addressSpace.createRamBank(); -void GameBoy::start(const std::string& bootrom, const std::string& game) { - addressSpace.loadBootrom(bootrom); - addressSpace.loadGame(game); - addressSpace.determineMBCInfo(); - addressSpace.createRamBank(); + bool quit = false; + bool setIME = false; + bool debug = false; + bool step = false; - bool quit = false; - bool setIME = false; - bool debug = false; - bool step = false; + while (!quit) { + // Event loop + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_QUIT: + quit = true; + break; + case SDL_KEYDOWN: + switch (event.key.keysym.sym) { + case SDLK_a: + joypadInput.LEFT = true; + break; + case SDLK_d: + joypadInput.RIGHT = true; + break; + case SDLK_w: + joypadInput.UP = true; + break; + case SDLK_s: + joypadInput.DOWN = true; + break; + case SDLK_k: + joypadInput.A = true; + break; + case SDLK_l: + joypadInput.B = true; + break; + case SDLK_o: + joypadInput.SELECT = true; + break; + case SDLK_p: + joypadInput.START = true; + break; + case SDLK_h: + debug = !debug; + break; + case SDLK_n: + step = true; + break; + default: + break; + } + break; + case SDL_KEYUP: + switch (event.key.keysym.sym) { + case SDLK_a: + joypadInput.LEFT = false; + break; + case SDLK_d: + joypadInput.RIGHT = false; + break; + case SDLK_w: + joypadInput.UP = false; + break; + case SDLK_s: + joypadInput.DOWN = false; + break; + case SDLK_k: + joypadInput.A = false; + break; + case SDLK_l: + joypadInput.B = false; + break; + case SDLK_o: + joypadInput.SELECT = false; + break; + case SDLK_p: + joypadInput.START = false; + break; + default: + break; + } + break; + default: + break; + } + } - while (!quit) { - // Event loop - while (SDL_PollEvent(&event)) { - switch (event.type) { - case SDL_QUIT: - quit = true; - break; - case SDL_KEYDOWN: - switch (event.key.keysym.sym) { - case SDLK_a: - joypadInput.LEFT = true; - break; - case SDLK_d: - joypadInput.RIGHT = true; - break; - case SDLK_w: - joypadInput.UP = true; - break; - case SDLK_s: - joypadInput.DOWN = true; - break; - case SDLK_k: - joypadInput.A = true; - break; - case SDLK_l: - joypadInput.B = true; - break; - case SDLK_o: - joypadInput.SELECT = true; - break; - case SDLK_p: - joypadInput.START = true; - break; - case SDLK_h: - debug = !debug; - break; - case SDLK_n: - step = true; - break; - default: - break; - } - break; - case SDL_KEYUP: - switch (event.key.keysym.sym) { - case SDLK_a: - joypadInput.LEFT = false; - break; - case SDLK_d: - joypadInput.RIGHT = false; - break; - case SDLK_w: - joypadInput.UP = false; - break; - case SDLK_s: - joypadInput.DOWN = false; - break; - case SDLK_k: - joypadInput.A = false; - break; - case SDLK_l: - joypadInput.B = false; - break; - case SDLK_o: - joypadInput.SELECT = false; - break; - case SDLK_p: - joypadInput.START = false; - break; - default: - break; - } - break; - default: - break; - } - } + while (!rendered) { + if (debug == true && step == false) + break; + step = false; + joypadHandler(); + if (PC > 0xFF && addressSpace.getBootromState()) { + addressSpace.unmapBootrom(); + } + ppuEnabled = addressSpace.memoryLayout.LCDC & 0x80; + prevTMA = addressSpace.memoryLayout.TMA; - while (!rendered) { - if (debug == true && step == false) - break; - step = false; - joypadHandler(); - if (PC > 0xFF && addressSpace.getBootromState()) { - addressSpace.unmapBootrom(); - } - ppuEnabled = addressSpace.memoryLayout.LCDC & 0x80; - prevTMA = addressSpace.memoryLayout.TMA; + if (debug) { + printf("A: %.2X F: %.2X B: %.2X C: %.2X D: %.2X E: %.2X H: %.2X L: " + "%.2X SP: %.4X PC: 00:%.4X (%.2X %.2X %.2X %.2X)\n", + AF.hi, AF.lo, BC.hi, BC.lo, DE.hi, DE.lo, HL.hi, HL.lo, SP, PC, + readOnlyAddressSpace[PC], readOnlyAddressSpace[PC + 1], + readOnlyAddressSpace[PC + 2], readOnlyAddressSpace[PC + 3]); - if (debug) { - printf( - "A: %.2X F: %.2X B: %.2X C: %.2X D: %.2X E: %.2X H: %.2X L: %.2X SP: %.4X PC: 00:%.4X (%.2X %.2X %.2X %.2X)\n", - AF.hi, AF.lo, BC.hi, BC.lo, DE.hi, DE.lo, HL.hi, HL.lo, SP, PC, readOnlyAddressSpace[PC], - readOnlyAddressSpace[PC + 1], readOnlyAddressSpace[PC + 2], readOnlyAddressSpace[PC + 3]); + // printf("Cycles: %lu, Opcode: 0x%.2x PPU cycles: %lu, PPMode: %d\n", + // cycles, readOnlyAddressSpace[PC], + // cyclesSinceLastScanline(), currentMode); + // printf("AF:0x%.4x, BC:0x%.4x\n", AF.reg, BC.reg); + // printf("DE:0x%.4x, HL:0x%.4x\n", DE.reg, HL.reg); + // printf("IME:%d IF:0x%.2x IE:0x%.2x\n", IME, (*IF), (*IE)); + // printf("PC:0x%.4x, SP:0x%.4x\n", PC, SP); + // printf("LCDC:%.2x STAT:0x%.2x LY:%d LYC:%d\n", (*LCDC), (*STAT), + // (*LY), (*LYC)); printf("\n"); + } - - // printf("Cycles: %lu, Opcode: 0x%.2x PPU cycles: %lu, PPMode: %d\n", cycles, readOnlyAddressSpace[PC], - // cyclesSinceLastScanline(), currentMode); - // printf("AF:0x%.4x, BC:0x%.4x\n", AF.reg, BC.reg); - // printf("DE:0x%.4x, HL:0x%.4x\n", DE.reg, HL.reg); - // printf("IME:%d IF:0x%.2x IE:0x%.2x\n", IME, (*IF), (*IE)); - // printf("PC:0x%.4x, SP:0x%.4x\n", PC, SP); - // printf("LCDC:%.2x STAT:0x%.2x LY:%d LYC:%d\n", (*LCDC), (*STAT), (*LY), (*LYC)); - // printf("\n"); - } - - if (!halted) { - opcodeResolver(); - addressSpace.MBCUpdate(); - } - else { - addCycles(4); - } - timingHandler(); - interruptHandler(); - if (ppuEnabled) { - ppuUpdate(); - } - else { - ppuCycles = 2; - lastScanline = 0; - lastRefresh = 0; - addressSpace.memoryLayout.LY = 0x00; - addressSpace.memoryLayout.STAT &= 0xfc; - } - if (setIME) { - IME = 1; - setIME = false; - } - if (IME_togge) { - setIME = true; - IME_togge = false; - } - if (addressSpace.dmaTransferRequested) { - cyclesUntilDMATransfer -= lastOpTicks; - if (cyclesUntilDMATransfer <= 0) { - cyclesUntilDMATransfer = 160; - addressSpace.dmaTransfer(); - } - } - } - rendered = false; - } + if (!halted) { + opcodeResolver(); + addressSpace.MBCUpdate(); + } else { + addCycles(4); + } + timingHandler(); + interruptHandler(); + if (ppuEnabled) { + ppuUpdate(); + } else { + ppuCycles = 2; + lastScanline = 0; + lastRefresh = 0; + addressSpace.memoryLayout.LY = 0x00; + addressSpace.memoryLayout.STAT &= 0xfc; + } + if (setIME) { + IME = 1; + setIME = false; + } + if (IME_togge) { + setIME = true; + IME_togge = false; + } + if (addressSpace.dmaTransferRequested) { + cyclesUntilDMATransfer -= lastOpTicks; + if (cyclesUntilDMATransfer <= 0) { + cyclesUntilDMATransfer = 160; + addressSpace.dmaTransfer(); + } + } + } + rendered = false; + } } diff --git a/src/gameboy.hpp b/src/gameboy.hpp index 30fa4fc..2c81ab5 100644 --- a/src/gameboy.hpp +++ b/src/gameboy.hpp @@ -1,186 +1,172 @@ #ifndef GBPP_SRC_GAMEBOY_HPP_ #define GBPP_SRC_GAMEBOY_HPP_ -#include -#include -#include -#include -#include "defines.hpp" #include "addressSpace.hpp" +#include "defines.hpp" #include "testing.hpp" +#include +#include +#include +#include union RegisterPair { - Word reg; //register.reg == (hi << 8) + lo. (hi is more significant than lo) + Word reg; // register.reg == (hi << 8) + lo. (hi is more significant than lo) - struct { - Byte lo; - Byte hi; - }; + struct { + Byte lo; + Byte hi; + }; }; class GameBoy { - //T-cycles not M-cycles (4 T-cycles = 1 M-cycle) - uint64_t cycles = 0; - //Start at 2 T-cycles https://github.com/Gekkio/mooneye-test-suite/blob/main/acceptance/ppu/lcdon_timing-GS.s - uint64_t ppuCycles = 2; - bool ppuEnabled = false; - uint16_t lastOpTicks = 0; - uint64_t lastRefresh = 0; - uint64_t lastScanline = 0; - uint64_t cyclesToStayInHblank = -1; - uint64_t lastDivUpdate = 0; - bool rendered = false; + // T-cycles not M-cycles (4 T-cycles = 1 M-cycle) + uint64_t cycles = 0; + // Start at 2 T-cycles + // https://github.com/Gekkio/mooneye-test-suite/blob/main/acceptance/ppu/lcdon_timing-GS.s + uint64_t ppuCycles = 2; + bool ppuEnabled = false; + uint16_t lastOpTicks = 0; + uint64_t lastRefresh = 0; + uint64_t lastScanline = 0; + uint64_t cyclesToStayInHblank = -1; + uint64_t lastDivUpdate = 0; + bool rendered = false; - uint8_t IME = 0; //enables interupts - // EI is actually "disable interrupts for one instruction, then enable them" - // This keeps track of that - bool IME_togge = false; + uint8_t IME = 0; // enables interupts + // EI is actually "disable interrupts for one instruction, then enable them" + // This keeps track of that + bool IME_togge = false; - //Accumulator and flags - RegisterPair AF = {0}; - //General purpose CPU registers - RegisterPair BC = {0}; - RegisterPair DE = {0}; - RegisterPair HL = {0}; + // Accumulator and flags + RegisterPair AF = {0}; + // General purpose CPU registers + RegisterPair BC = {0}; + RegisterPair DE = {0}; + RegisterPair HL = {0}; - Word SP = 0xFFFE; //stack pointer - Word PC = 0x0000; //program counter + Word SP = 0xFFFE; // stack pointer + Word PC = 0x0000; // program counter - AddressSpace addressSpace; - const AddressSpace& readOnlyAddressSpace = addressSpace; + AddressSpace addressSpace; + const AddressSpace &readOnlyAddressSpace = addressSpace; - PPUMode currentMode = PPUMode::mode0; - Byte windowLineCounter = 0; - int16_t cyclesUntilDMATransfer = 160; + PPUMode currentMode = PPUMode::mode0; + Byte windowLineCounter = 0; + int16_t cyclesUntilDMATransfer = 160; - Byte prevTMA = 0; - uint64_t lastTIMAUpdate = 0; - bool halted = false; - bool haltBug = true; - bool stopped = false; + Byte prevTMA = 0; + uint64_t lastTIMAUpdate = 0; + bool halted = false; + bool haltBug = true; + bool stopped = false; - //3 colour channels - uint32_t* framebuffer = new uint32_t[RESOLUTION_X * RESOLUTION_Y * SCREEN_BPP]; - SDL_Window* screen = nullptr; - SDL_Renderer* renderer = nullptr; - SDL_Texture* texture = nullptr; - SDL_Event event = {0}; - uint32_t frameStart = 0; - uint32_t frameTime = 0; - const int frameDelay = 1000 / V_SYNC; + // 3 colour channels + uint32_t *framebuffer = + new uint32_t[RESOLUTION_X * RESOLUTION_Y * SCREEN_BPP]; + SDL_Window *screen = nullptr; + SDL_Renderer *renderer = nullptr; + SDL_Texture *texture = nullptr; + SDL_Event event = {0}; + uint32_t frameStart = 0; + uint32_t frameTime = 0; + const int frameDelay = 1000 / V_SYNC; - Input joypadInput; - void joypadHandler(); + Input joypadInput; + void joypadHandler(); - void opcodeResolver(); + void opcodeResolver(); - bool statInteruptLine = false; - bool LCDCBitEnabled(Byte bit) const; - void incLY(); - void ppuUpdate(); - void drawLine(); - static bool oamBitEnabled(Byte oamAttributeByte, Byte bit); - static unsigned int getColourFromPalette(Byte palette); - void SDL2present(); + bool statInteruptLine = false; + bool LCDCBitEnabled(Byte bit) const; + void incLY(); + void ppuUpdate(); + void drawLine(); + static bool oamBitEnabled(Byte oamAttributeByte, Byte bit); + static unsigned int getColourFromPalette(Byte palette); + void SDL2present(); - void checkPPUMode(); - void setPPUMode(PPUMode mode); - uint64_t cyclesSinceLastScanline() const; - uint64_t cyclesSinceLastRefresh() const; + void checkPPUMode(); + void setPPUMode(PPUMode mode); + uint64_t cyclesSinceLastScanline() const; + uint64_t cyclesSinceLastRefresh() const; - void timingHandler(); + void timingHandler(); - void interruptHandler(); - bool testInterruptEnabled(Byte interrupt) const; - void setInterrupt(Byte interrupt); - void resetInterrupt(Byte interrupt); + void interruptHandler(); + bool testInterruptEnabled(Byte interrupt) const; + void setInterrupt(Byte interrupt); + void resetInterrupt(Byte interrupt); - void VBlankHandle(); - void LCDStatHandle(); - void timerHandle(); - void serialHandle(); - void joypadHandle(); + void VBlankHandle(); + void LCDStatHandle(); + void timerHandle(); + void serialHandle(); + void joypadHandle(); - void setFlag(Byte bit); - void resetFlag(Byte bit); - bool getFlag(Byte bit) const; + void setFlag(Byte bit); + void resetFlag(Byte bit); + bool getFlag(Byte bit) const; - Word getWordPC(); - Byte getBytePC(); - Word getWordSP(); - Byte getByteSP(); + Word getWordPC(); + Byte getBytePC(); + Word getWordSP(); + Byte getByteSP(); - void addCycles(Byte ticks); + void addCycles(Byte ticks); - //OPCODE FUNCTIONS - template - void ld(T& dest, T src); - void ldW(Word destAddr, Word src); - template - void orBitwise(T& dest, T src); - template - void andBitwise(T& dest, T src); - template - void xorBitwise(T& dest, T src); - void bit(Byte testBit, Byte reg); - void extendedOpcodeResolver(); - static void set(uint8_t testBit, uint8_t& reg); - static void res(uint8_t testBit, uint8_t& reg); - template - void jp(T address); - template - bool jrNZ(T offset); - template - bool jrNC(T offset); - template - bool jrC(T offset); - template - void inc(T& reg); - template - void call(T address); - void halt(); - void daa(); - void stop(); - void cp(Byte value); - template - void dec(T& reg); - template - bool jrZ(T offset); - void sub(Byte value); - void sbc(Byte value); - template - void jr(T OFFSET); - void push(Word reg); - void rl(Byte& reg); - void sla(Byte& reg); - void sra(uint8_t& reg); - void srl(uint8_t& reg); - void rrc(Byte& reg); - void rrca(); - void rra(); - void rr(Byte& reg); - void rlc(Byte& reg); - void rlca(); - void rla(); - template - void pop(T& reg); - template - void rst(T address); - void ret(); - template - void add(T& reg, T value); - void adc(Byte value); - void cpl(); - void scf(); - void ccf(); - void swap(Byte& value); + // OPCODE FUNCTIONS + template void ld(T &dest, T src); + void ldW(Word destAddr, Word src); + template void orBitwise(T &dest, T src); + template void andBitwise(T &dest, T src); + template void xorBitwise(T &dest, T src); + void bit(Byte testBit, Byte reg); + void extendedOpcodeResolver(); + static void set(uint8_t testBit, uint8_t ®); + static void res(uint8_t testBit, uint8_t ®); + template void jp(T address); + template bool jrNZ(T offset); + template bool jrNC(T offset); + template bool jrC(T offset); + template void inc(T ®); + template void call(T address); + void halt(); + void daa(); + void stop(); + void cp(Byte value); + template void dec(T ®); + template bool jrZ(T offset); + void sub(Byte value); + void sbc(Byte value); + template void jr(T OFFSET); + void push(Word reg); + void rl(Byte ®); + void sla(Byte ®); + void sra(uint8_t ®); + void srl(uint8_t ®); + void rrc(Byte ®); + void rrca(); + void rra(); + void rr(Byte ®); + void rlc(Byte ®); + void rlca(); + void rla(); + template void pop(T ®); + template void rst(T address); + void ret(); + template void add(T ®, T value); + void adc(Byte value); + void cpl(); + void scf(); + void ccf(); + void swap(Byte &value); public: - void start(const std::string& bootrom, const std::string& game); - void SDL2setup(); - void SDL2destroy() const; + void start(const std::string &bootrom, const std::string &game); + void SDL2setup(); + void SDL2destroy() const; - GameboyTestState runTest(GameboyTestState initial); + GameboyTestState runTest(GameboyTestState initial); }; -#endif //GBPP_SRC_GAMEBOY_HPP_ +#endif // GBPP_SRC_GAMEBOY_HPP_ diff --git a/src/interupts.cpp b/src/interupts.cpp index 38c68af..0f9e238 100644 --- a/src/interupts.cpp +++ b/src/interupts.cpp @@ -2,88 +2,94 @@ #include "gameboy.hpp" bool GameBoy::testInterruptEnabled(const Byte interrupt) const { - return readOnlyAddressSpace.memoryLayout.IE & static_cast(1 << interrupt); + return readOnlyAddressSpace.memoryLayout.IE & + static_cast(1 << interrupt); } void GameBoy::setInterrupt(const Byte interrupt) { - addressSpace.memoryLayout.IF |= 1 << interrupt; - addressSpace.memoryLayout.IF |= 0xE0; + addressSpace.memoryLayout.IF |= 1 << interrupt; + addressSpace.memoryLayout.IF |= 0xE0; } void GameBoy::resetInterrupt(const Byte interrupt) { - addressSpace.memoryLayout.IF &= ~(1 << interrupt); - addressSpace.memoryLayout.IF |= 0xE0; + addressSpace.memoryLayout.IF &= ~(1 << interrupt); + addressSpace.memoryLayout.IF |= 0xE0; } void GameBoy::interruptHandler() { - if (readOnlyAddressSpace.memoryLayout.IF & static_cast(1 << VBLANK_INTERRUPT) && testInterruptEnabled( - VBLANK_INTERRUPT)) { - if (IME) - VBlankHandle(); - halted = false; - } - if (readOnlyAddressSpace.memoryLayout.IF & static_cast(1 << LCD_STAT_INTERRUPT) && testInterruptEnabled( - LCD_STAT_INTERRUPT)) { - if (IME) - LCDStatHandle(); - halted = false; - } - if (readOnlyAddressSpace.memoryLayout.IF & static_cast(1 << TIMER_INTERRUPT) && testInterruptEnabled( - TIMER_INTERRUPT)) { - if (IME) - timerHandle(); - halted = false; - } - if (readOnlyAddressSpace.memoryLayout.IF & static_cast(1 << SERIAL_INTERRUPT) && testInterruptEnabled( - SERIAL_INTERRUPT)) { - if (IME) - serialHandle(); - halted = false; - } - if (readOnlyAddressSpace.memoryLayout.IF & static_cast(1 << JOYPAD_INTERRUPT) && testInterruptEnabled( - JOYPAD_INTERRUPT)) { - if (IME) - joypadHandle(); - halted = false; - } + if (readOnlyAddressSpace.memoryLayout.IF & + static_cast(1 << VBLANK_INTERRUPT) && + testInterruptEnabled(VBLANK_INTERRUPT)) { + if (IME) + VBlankHandle(); + halted = false; + } + if (readOnlyAddressSpace.memoryLayout.IF & + static_cast(1 << LCD_STAT_INTERRUPT) && + testInterruptEnabled(LCD_STAT_INTERRUPT)) { + if (IME) + LCDStatHandle(); + halted = false; + } + if (readOnlyAddressSpace.memoryLayout.IF & + static_cast(1 << TIMER_INTERRUPT) && + testInterruptEnabled(TIMER_INTERRUPT)) { + if (IME) + timerHandle(); + halted = false; + } + if (readOnlyAddressSpace.memoryLayout.IF & + static_cast(1 << SERIAL_INTERRUPT) && + testInterruptEnabled(SERIAL_INTERRUPT)) { + if (IME) + serialHandle(); + halted = false; + } + if (readOnlyAddressSpace.memoryLayout.IF & + static_cast(1 << JOYPAD_INTERRUPT) && + testInterruptEnabled(JOYPAD_INTERRUPT)) { + if (IME) + joypadHandle(); + halted = false; + } } void GameBoy::VBlankHandle() { - IME = 0; - push(PC); - addCycles(20); - PC = 0x40; - resetInterrupt(VBLANK_INTERRUPT); + IME = 0; + push(PC); + addCycles(20); + PC = 0x40; + resetInterrupt(VBLANK_INTERRUPT); } void GameBoy::LCDStatHandle() { - IME = 0; - push(PC); - addCycles(20); - PC = 0x48; - resetInterrupt(LCD_STAT_INTERRUPT); + IME = 0; + push(PC); + addCycles(20); + PC = 0x48; + resetInterrupt(LCD_STAT_INTERRUPT); } void GameBoy::timerHandle() { - IME = 0; - push(PC); - addCycles(20); - PC = 0x50; - resetInterrupt(TIMER_INTERRUPT); + IME = 0; + push(PC); + addCycles(20); + PC = 0x50; + resetInterrupt(TIMER_INTERRUPT); } void GameBoy::serialHandle() { - IME = 0; - push(PC); - addCycles(20); - PC = 0x58; - resetInterrupt(SERIAL_INTERRUPT); + IME = 0; + push(PC); + addCycles(20); + PC = 0x58; + resetInterrupt(SERIAL_INTERRUPT); } void GameBoy::joypadHandle() { - IME = 0; - push(PC); - addCycles(20); - PC = 0x60; - resetInterrupt(JOYPAD_INTERRUPT); + IME = 0; + push(PC); + addCycles(20); + PC = 0x60; + resetInterrupt(JOYPAD_INTERRUPT); } diff --git a/src/joypad.cpp b/src/joypad.cpp index 9f4a26a..5b6335c 100644 --- a/src/joypad.cpp +++ b/src/joypad.cpp @@ -1,44 +1,44 @@ -#include "gameboy.hpp" #include "defines.hpp" +#include "gameboy.hpp" void GameBoy::joypadHandler() { - const Byte joyP = addressSpace.memoryLayout.JOYP; - const bool buttons = (joyP & 0x20) == 0; - const bool dpad = (joyP & 0x10) == 0; + const Byte joyP = addressSpace.memoryLayout.JOYP; + const bool buttons = (joyP & 0x20) == 0; + const bool dpad = (joyP & 0x10) == 0; - addressSpace.memoryLayout.JOYP |= 0xCF; + addressSpace.memoryLayout.JOYP |= 0xCF; - if (buttons && !dpad) { - if (joypadInput.A) - addressSpace.memoryLayout.JOYP &= ~0x1; - if (joypadInput.B) - addressSpace.memoryLayout.JOYP &= ~0x2; - if (joypadInput.SELECT) - addressSpace.memoryLayout.JOYP &= ~0x4; - if (joypadInput.START) - addressSpace.memoryLayout.JOYP &= ~0x8; - } - if (!buttons && dpad) { - if (joypadInput.RIGHT) - addressSpace.memoryLayout.JOYP &= ~0x1; - if (joypadInput.LEFT) - addressSpace.memoryLayout.JOYP &= ~0x2; - if (joypadInput.UP) - addressSpace.memoryLayout.JOYP &= ~0x4; - if (joypadInput.DOWN) - addressSpace.memoryLayout.JOYP &= ~0x8; - } + if (buttons && !dpad) { + if (joypadInput.A) + addressSpace.memoryLayout.JOYP &= ~0x1; + if (joypadInput.B) + addressSpace.memoryLayout.JOYP &= ~0x2; + if (joypadInput.SELECT) + addressSpace.memoryLayout.JOYP &= ~0x4; + if (joypadInput.START) + addressSpace.memoryLayout.JOYP &= ~0x8; + } + if (!buttons && dpad) { + if (joypadInput.RIGHT) + addressSpace.memoryLayout.JOYP &= ~0x1; + if (joypadInput.LEFT) + addressSpace.memoryLayout.JOYP &= ~0x2; + if (joypadInput.UP) + addressSpace.memoryLayout.JOYP &= ~0x4; + if (joypadInput.DOWN) + addressSpace.memoryLayout.JOYP &= ~0x8; + } - if (buttons && dpad) { - addressSpace.memoryLayout.JOYP |= 0xCF; + if (buttons && dpad) { + addressSpace.memoryLayout.JOYP |= 0xCF; - if (joypadInput.RIGHT && joypadInput.A) - addressSpace.memoryLayout.JOYP &= ~0x1; - if (joypadInput.LEFT && joypadInput.B) - addressSpace.memoryLayout.JOYP &= ~0x2; - if (joypadInput.UP && joypadInput.SELECT) - addressSpace.memoryLayout.JOYP &= ~0x4; - if (joypadInput.DOWN && joypadInput.START) - addressSpace.memoryLayout.JOYP &= ~0x8; - } + if (joypadInput.RIGHT && joypadInput.A) + addressSpace.memoryLayout.JOYP &= ~0x1; + if (joypadInput.LEFT && joypadInput.B) + addressSpace.memoryLayout.JOYP &= ~0x2; + if (joypadInput.UP && joypadInput.SELECT) + addressSpace.memoryLayout.JOYP &= ~0x4; + if (joypadInput.DOWN && joypadInput.START) + addressSpace.memoryLayout.JOYP &= ~0x8; + } } diff --git a/src/main.cpp b/src/main.cpp index c61ce20..73770d1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,94 +1,91 @@ -#include -#include -#include #include "3rdParty/json.hpp" #include "gameboy.hpp" +#include +#include +#include namespace fs = std::filesystem; using json = nlohmann::json; -void runJSONTests(GameBoy* gb); +void runJSONTests(GameBoy *gb); -int main(int argc, char** argv) { - if (argc != 3) { - std::cerr << "Usage: " << argv[0] << " \n" << std::endl; - return 1; - } +int main(int argc, char **argv) { + if (argc != 3) { + std::cerr << "Usage: " << argv[0] << " \n" << std::endl; + return 1; + } - auto* gb = new GameBoy(); - gb->SDL2setup(); - //runJSONTests(gb); - gb->start(argv[1], argv[2]); - gb->SDL2destroy(); - delete gb; + auto *gb = new GameBoy(); + gb->SDL2setup(); + // runJSONTests(gb); + gb->start(argv[1], argv[2]); + gb->SDL2destroy(); + delete gb; - return 0; + return 0; } -void runJSONTests(GameBoy* gb) { - std::string path = "../tests/sm83/v1"; - std::vector testFiles; - int failed = 0; - for (const auto& entry : fs::directory_iterator(path)) - testFiles.emplace_back(entry.path()); +void runJSONTests(GameBoy *gb) { + std::string path = "../tests/sm83/v1"; + std::vector testFiles; + int failed = 0; + for (const auto &entry : fs::directory_iterator(path)) + testFiles.emplace_back(entry.path()); + for (const auto &testFile : testFiles) { + std::ifstream file(testFile); + std::cout << "Running test: " << testFile << std::endl; + const json tests = json::parse(file); - for (const auto& testFile : testFiles) { - std::ifstream file(testFile); - std::cout << "Running test: " << testFile << std::endl; - const json tests = json::parse(file); + for (auto &test : tests) { + // create state + std::vector> initialRAM; + for (int i = 0; i < test["initial"]["ram"].size(); i++) + initialRAM.emplace_back(test["initial"]["ram"][i][0], + test["initial"]["ram"][i][1]); - for (auto& test : tests) { - //create state - std::vector> initialRAM; - for (int i = 0; i < test["initial"]["ram"].size(); i++) - initialRAM.emplace_back(test["initial"]["ram"][i][0], test["initial"]["ram"][i][1]); + GameboyTestState initialState = {test["initial"]["pc"], + test["initial"]["sp"], + test["initial"]["a"], + test["initial"]["f"], + test["initial"]["b"], + test["initial"]["c"], + test["initial"]["d"], + test["initial"]["e"], + test["initial"]["h"], + test["initial"]["l"], + initialRAM}; - GameboyTestState initialState = { - test["initial"]["pc"], - test["initial"]["sp"], - test["initial"]["a"], - test["initial"]["f"], - test["initial"]["b"], - test["initial"]["c"], - test["initial"]["d"], - test["initial"]["e"], - test["initial"]["h"], - test["initial"]["l"], - initialRAM - }; + // run + GameboyTestState result = gb->runTest(initialState); - //run - GameboyTestState result = gb->runTest(initialState); + // compare new state to expected + std::vector> finalRAM; + for (int i = 0; i < test["final"]["ram"].size(); i++) + finalRAM.emplace_back(test["final"]["ram"][i][0], + test["final"]["ram"][i][1]); - //compare new state to expected - std::vector> finalRAM; - for (int i = 0; i < test["final"]["ram"].size(); i++) - finalRAM.emplace_back(test["final"]["ram"][i][0], test["final"]["ram"][i][1]); + GameboyTestState finalState = {test["final"]["pc"], + test["final"]["sp"], + test["final"]["a"], + test["final"]["f"], + test["final"]["b"], + test["final"]["c"], + test["final"]["d"], + test["final"]["e"], + test["final"]["h"], + test["final"]["l"], + finalRAM}; - GameboyTestState finalState = { - test["final"]["pc"], - test["final"]["sp"], - test["final"]["a"], - test["final"]["f"], - test["final"]["b"], - test["final"]["c"], - test["final"]["d"], - test["final"]["e"], - test["final"]["h"], - test["final"]["l"], - finalRAM - }; - - if (finalState != result) { - std::cout << "Test " << testFile << " failed!" << std::endl; - failed += 1; - break; - } - } - } - if (!failed) - std::cout << "Success!" << std::endl; - else - std::cout << failed << "/" << testFiles.size() << " failed!" << std::endl; + if (finalState != result) { + std::cout << "Test " << testFile << " failed!" << std::endl; + failed += 1; + break; + } + } + } + if (!failed) + std::cout << "Success!" << std::endl; + else + std::cout << failed << "/" << testFiles.size() << " failed!" << std::endl; } diff --git a/src/opcodeResolver.cpp b/src/opcodeResolver.cpp index 1448797..56e155a 100644 --- a/src/opcodeResolver.cpp +++ b/src/opcodeResolver.cpp @@ -1,2249 +1,2195 @@ #include "gameboy.hpp" -void GameBoy::setFlag(const Byte bit) { - AF.lo |= (1 << bit); -} +void GameBoy::setFlag(const Byte bit) { AF.lo |= (1 << bit); } -void GameBoy::resetFlag(const Byte bit) { - AF.lo &= ~(1 << bit); -} +void GameBoy::resetFlag(const Byte bit) { AF.lo &= ~(1 << bit); } -bool GameBoy::getFlag(const Byte bit) const { - return (AF.lo >> bit) & 1; -} +bool GameBoy::getFlag(const Byte bit) const { return (AF.lo >> bit) & 1; } Word GameBoy::getWordPC() { - RegisterPair word = {0}; + RegisterPair word = {0}; - //remember little endianness - word.lo = readOnlyAddressSpace[PC + 1]; - word.hi = readOnlyAddressSpace[PC + 2]; + // remember little endianness + word.lo = readOnlyAddressSpace[PC + 1]; + word.hi = readOnlyAddressSpace[PC + 2]; - return word.reg; + return word.reg; } -Byte GameBoy::getBytePC() { - return readOnlyAddressSpace[PC + 1]; -} +Byte GameBoy::getBytePC() { return readOnlyAddressSpace[PC + 1]; } Word GameBoy::getWordSP() { - RegisterPair word = {0}; + RegisterPair word = {0}; - //remember little endianness - word.lo = readOnlyAddressSpace[SP++]; - word.hi = readOnlyAddressSpace[SP++]; + // remember little endianness + word.lo = readOnlyAddressSpace[SP++]; + word.hi = readOnlyAddressSpace[SP++]; - return word.reg; + return word.reg; } -Byte GameBoy::getByteSP() { - return readOnlyAddressSpace[SP++]; -} +Byte GameBoy::getByteSP() { return readOnlyAddressSpace[SP++]; } void GameBoy::ret() { - PC = readOnlyAddressSpace[SP++]; - PC |= readOnlyAddressSpace[SP++] << 8; + PC = readOnlyAddressSpace[SP++]; + PC |= readOnlyAddressSpace[SP++] << 8; } -template -void GameBoy::ld(T& dest, T src) { - if constexpr (std::is_same_v) { - if (&dest == &addressSpace.memoryLayout.DIV) { - addressSpace.memoryLayout.DIV = 0x00; - lastDivUpdate = cycles; - } - else { - dest = src; - } - } - else { - //16-bit register pair write - dest = src; - } +template void GameBoy::ld(T &dest, T src) { + if constexpr (std::is_same_v) { + if (&dest == &addressSpace.memoryLayout.DIV) { + addressSpace.memoryLayout.DIV = 0x00; + lastDivUpdate = cycles; + } else { + dest = src; + } + } else { + // 16-bit register pair write + dest = src; + } } void GameBoy::ldW(const Word destAddr, const Word src) { - addressSpace[destAddr] = static_cast(src & 0xFF); - addressSpace[destAddr + 1] = static_cast((src & 0xFF00) >> 8); + addressSpace[destAddr] = static_cast(src & 0xFF); + addressSpace[destAddr + 1] = static_cast((src & 0xFF00) >> 8); } -template -void GameBoy::add(T& reg, T value) { - if (sizeof(reg) == sizeof(Byte)) { - if ((((value & 0xF) + (reg & 0xF)) & 0x10) == 0x10) - setFlag(HALFCARRY_FLAG); - else - resetFlag(HALFCARRY_FLAG); - if ((((value & 0xFF) + (reg & 0xFF)) & 0x100) == 0x100) - setFlag(CARRY_FLAG); - else - resetFlag(CARRY_FLAG); - } +template void GameBoy::add(T ®, T value) { + if (sizeof(reg) == sizeof(Byte)) { + if ((((value & 0xF) + (reg & 0xF)) & 0x10) == 0x10) + setFlag(HALFCARRY_FLAG); + else + resetFlag(HALFCARRY_FLAG); + if ((((value & 0xFF) + (reg & 0xFF)) & 0x100) == 0x100) + setFlag(CARRY_FLAG); + else + resetFlag(CARRY_FLAG); + } - if (sizeof(reg) == sizeof(Word)) { - if (((value & 0xFFF) + (reg & 0xFFF)) & 0x1000) - setFlag(HALFCARRY_FLAG); - else - resetFlag(HALFCARRY_FLAG); - if ((static_cast(value) + static_cast(reg)) & 0x10000) - setFlag(CARRY_FLAG); - else - resetFlag(CARRY_FLAG); - } + if (sizeof(reg) == sizeof(Word)) { + if (((value & 0xFFF) + (reg & 0xFFF)) & 0x1000) + setFlag(HALFCARRY_FLAG); + else + resetFlag(HALFCARRY_FLAG); + if ((static_cast(value) + static_cast(reg)) & 0x10000) + setFlag(CARRY_FLAG); + else + resetFlag(CARRY_FLAG); + } - reg += value; + reg += value; - if (sizeof(reg) == sizeof(Byte)) { - if (reg == 0) - setFlag(ZERO_FLAG); - else - resetFlag(ZERO_FLAG); - } + if (sizeof(reg) == sizeof(Byte)) { + if (reg == 0) + setFlag(ZERO_FLAG); + else + resetFlag(ZERO_FLAG); + } - resetFlag(SUBTRACT_FLAG); + resetFlag(SUBTRACT_FLAG); } void GameBoy::adc(const Byte value) { - Byte carry = getFlag(CARRY_FLAG) ? 1 : 0; + Byte carry = getFlag(CARRY_FLAG) ? 1 : 0; - if ((AF.hi & 0xF) + (value & 0xF) + carry > 0xF) - setFlag(HALFCARRY_FLAG); - else - resetFlag(HALFCARRY_FLAG); - if ((value & 0xFF) + (AF.hi & 0xFF) + carry > 0xFF) - setFlag(CARRY_FLAG); - else - resetFlag(CARRY_FLAG); + if ((AF.hi & 0xF) + (value & 0xF) + carry > 0xF) + setFlag(HALFCARRY_FLAG); + else + resetFlag(HALFCARRY_FLAG); + if ((value & 0xFF) + (AF.hi & 0xFF) + carry > 0xFF) + setFlag(CARRY_FLAG); + else + resetFlag(CARRY_FLAG); + AF.hi += value + carry; - AF.hi += value + carry; + if (AF.hi == 0) + setFlag(ZERO_FLAG); + else + resetFlag(ZERO_FLAG); - if (AF.hi == 0) - setFlag(ZERO_FLAG); - else - resetFlag(ZERO_FLAG); - - resetFlag(SUBTRACT_FLAG); + resetFlag(SUBTRACT_FLAG); } void GameBoy::sub(const Byte value) { - if (AF.hi < value) - setFlag(CARRY_FLAG); - else - resetFlag(CARRY_FLAG); - if (AF.hi == value) - setFlag(ZERO_FLAG); - else - resetFlag(ZERO_FLAG); - if ((AF.hi & 0xf) < (value & 0xf)) - setFlag(HALFCARRY_FLAG); - else - resetFlag(HALFCARRY_FLAG); + if (AF.hi < value) + setFlag(CARRY_FLAG); + else + resetFlag(CARRY_FLAG); + if (AF.hi == value) + setFlag(ZERO_FLAG); + else + resetFlag(ZERO_FLAG); + if ((AF.hi & 0xf) < (value & 0xf)) + setFlag(HALFCARRY_FLAG); + else + resetFlag(HALFCARRY_FLAG); - AF.hi -= value; + AF.hi -= value; - setFlag(SUBTRACT_FLAG); + setFlag(SUBTRACT_FLAG); } void GameBoy::sbc(const Byte value) { - const Byte carry = getFlag(CARRY_FLAG) ? 1 : 0; - const Byte result = AF.hi - value - carry; + const Byte carry = getFlag(CARRY_FLAG) ? 1 : 0; + const Byte result = AF.hi - value - carry; - if ((static_cast(AF.hi) - static_cast(value) - carry) > 0xFF) - setFlag(CARRY_FLAG); - else - resetFlag(CARRY_FLAG); + if ((static_cast(AF.hi) - static_cast(value) - carry) > + 0xFF) + setFlag(CARRY_FLAG); + else + resetFlag(CARRY_FLAG); - if (result == 0) - setFlag(ZERO_FLAG); - else - resetFlag(ZERO_FLAG); + if (result == 0) + setFlag(ZERO_FLAG); + else + resetFlag(ZERO_FLAG); - if ((AF.hi & 0xF) < (value & 0xF) + carry) - setFlag(HALFCARRY_FLAG); - else - resetFlag(HALFCARRY_FLAG); + if ((AF.hi & 0xF) < (value & 0xF) + carry) + setFlag(HALFCARRY_FLAG); + else + resetFlag(HALFCARRY_FLAG); - AF.hi = result; + AF.hi = result; - setFlag(SUBTRACT_FLAG); + setFlag(SUBTRACT_FLAG); } -//https://gbdev.gg8.se/wiki/articles/DAA +// https://gbdev.gg8.se/wiki/articles/DAA void GameBoy::daa() { - if (getFlag(SUBTRACT_FLAG)) { - if (getFlag(CARRY_FLAG)) { - AF.hi -= 0x60; - } - if (getFlag(HALFCARRY_FLAG)) { - AF.hi -= 0x06; - } - } - else { - if (getFlag(CARRY_FLAG) || (AF.hi & 0xFF) > 0x99) { - AF.hi += 0x60; - setFlag(CARRY_FLAG); - } - if (getFlag(HALFCARRY_FLAG) || (AF.hi & 0x0F) > 0x09) { - AF.hi += 0x06; - } - } + if (getFlag(SUBTRACT_FLAG)) { + if (getFlag(CARRY_FLAG)) { + AF.hi -= 0x60; + } + if (getFlag(HALFCARRY_FLAG)) { + AF.hi -= 0x06; + } + } else { + if (getFlag(CARRY_FLAG) || (AF.hi & 0xFF) > 0x99) { + AF.hi += 0x60; + setFlag(CARRY_FLAG); + } + if (getFlag(HALFCARRY_FLAG) || (AF.hi & 0x0F) > 0x09) { + AF.hi += 0x06; + } + } - if (AF.hi == 0) - setFlag(ZERO_FLAG); - else - resetFlag(ZERO_FLAG); - resetFlag(HALFCARRY_FLAG); + if (AF.hi == 0) + setFlag(ZERO_FLAG); + else + resetFlag(ZERO_FLAG); + resetFlag(HALFCARRY_FLAG); } -template -void GameBoy::orBitwise(T& dest, T src) { - dest |= src; +template void GameBoy::orBitwise(T &dest, T src) { + dest |= src; - if (dest == 0) - setFlag(ZERO_FLAG); - else - resetFlag(ZERO_FLAG); + if (dest == 0) + setFlag(ZERO_FLAG); + else + resetFlag(ZERO_FLAG); - resetFlag(SUBTRACT_FLAG); - resetFlag(HALFCARRY_FLAG); - resetFlag(CARRY_FLAG); + resetFlag(SUBTRACT_FLAG); + resetFlag(HALFCARRY_FLAG); + resetFlag(CARRY_FLAG); } -template -void GameBoy::andBitwise(T& dest, T src) { - dest &= src; +template void GameBoy::andBitwise(T &dest, T src) { + dest &= src; - if (dest == 0) - setFlag(ZERO_FLAG); - else - resetFlag(ZERO_FLAG); + if (dest == 0) + setFlag(ZERO_FLAG); + else + resetFlag(ZERO_FLAG); - resetFlag(SUBTRACT_FLAG); - setFlag(HALFCARRY_FLAG); - resetFlag(CARRY_FLAG); + resetFlag(SUBTRACT_FLAG); + setFlag(HALFCARRY_FLAG); + resetFlag(CARRY_FLAG); } -template -void GameBoy::xorBitwise(T& dest, T src) { - dest ^= src; +template void GameBoy::xorBitwise(T &dest, T src) { + dest ^= src; - if (dest == 0) - setFlag(ZERO_FLAG); - else - resetFlag(ZERO_FLAG); + if (dest == 0) + setFlag(ZERO_FLAG); + else + resetFlag(ZERO_FLAG); - resetFlag(SUBTRACT_FLAG); - resetFlag(CARRY_FLAG); - resetFlag(HALFCARRY_FLAG); + resetFlag(SUBTRACT_FLAG); + resetFlag(CARRY_FLAG); + resetFlag(HALFCARRY_FLAG); } void GameBoy::bit(Byte testBit, Byte reg) { - if (const Byte result = reg & (1 << testBit); result == 0) - setFlag(ZERO_FLAG); - else - resetFlag(ZERO_FLAG); + if (const Byte result = reg & (1 << testBit); result == 0) + setFlag(ZERO_FLAG); + else + resetFlag(ZERO_FLAG); - resetFlag(SUBTRACT_FLAG); - setFlag(HALFCARRY_FLAG); + resetFlag(SUBTRACT_FLAG); + setFlag(HALFCARRY_FLAG); } -void GameBoy::set(const Byte testBit, Byte& reg) { - reg |= (1 << testBit); +void GameBoy::set(const Byte testBit, Byte ®) { reg |= (1 << testBit); } + +void GameBoy::res(const Byte testBit, Byte ®) { reg &= ~(1 << testBit); } + +template void GameBoy::jr(T offset) { + PC += static_cast(offset) + 2; // PC moves 2 from original instruction } -void GameBoy::res(const Byte testBit, Byte& reg) { - reg &= ~(1 << testBit); +template bool GameBoy::jrNZ(T offset) { + bool jumped = false; + if (!getFlag(ZERO_FLAG)) // if not set + { + PC += static_cast(offset) + + 2; // PC moves 2 from the original instruction + jumped = true; + } + + return jumped; } +template bool GameBoy::jrZ(T offset) { + bool jumped = false; + if (getFlag(ZERO_FLAG)) // if not set + { + PC += static_cast(offset) + + 2; // PC moves 2 from the original instruction + jumped = true; + } -template -void GameBoy::jr(T offset) { - PC += static_cast(offset) + 2; //PC moves 2 from original instruction + return jumped; } -template -bool GameBoy::jrNZ(T offset) { - bool jumped = false; - if (!getFlag(ZERO_FLAG)) //if not set - { - PC += static_cast(offset) + 2; //PC moves 2 from the original instruction - jumped = true; - } +template bool GameBoy::jrNC(T offset) { + bool jumped = false; + if (!getFlag(CARRY_FLAG)) // if not set + { + PC += static_cast(offset) + + 2; // PC moves 2 from the original instruction + jumped = true; + } - return jumped; + return jumped; } -template -bool GameBoy::jrZ(T offset) { - bool jumped = false; - if (getFlag(ZERO_FLAG)) //if not set - { - PC += static_cast(offset) + 2; //PC moves 2 from the original instruction - jumped = true; - } +template bool GameBoy::jrC(T offset) { + bool jumped = false; + if (getFlag(CARRY_FLAG)) // if not set + { + PC += static_cast(offset) + + 2; // PC moves 2 from the original instruction + jumped = true; + } - return jumped; + return jumped; } -template -bool GameBoy::jrNC(T offset) { - bool jumped = false; - if (!getFlag(CARRY_FLAG)) //if not set - { - PC += static_cast(offset) + 2; //PC moves 2 from the original instruction - jumped = true; - } +template void GameBoy::inc(T ®) { + reg += 1; - return jumped; + if (sizeof(reg) == sizeof(Byte)) { + if (reg == 0) + setFlag(ZERO_FLAG); + else + resetFlag(ZERO_FLAG); + + resetFlag(SUBTRACT_FLAG); + + // halfcarry test + // https://robdor.com/2016/08/10/gameboy-emulator-half-carry-flag/ + if ((reg & 0x0F) == 0) + setFlag(HALFCARRY_FLAG); + else + resetFlag(HALFCARRY_FLAG); + } } -template -bool GameBoy::jrC(T offset) { - bool jumped = false; - if (getFlag(CARRY_FLAG)) //if not set - { - PC += static_cast(offset) + 2; //PC moves 2 from the original instruction - jumped = true; - } - - return jumped; +template void GameBoy::call(T address) { + push(PC + 3); + PC = address; } -template -void GameBoy::inc(T& reg) { - reg += 1; - - if (sizeof(reg) == sizeof(Byte)) { - if (reg == 0) - setFlag(ZERO_FLAG); - else - resetFlag(ZERO_FLAG); - - resetFlag(SUBTRACT_FLAG); - - //halfcarry test https://robdor.com/2016/08/10/gameboy-emulator-half-carry-flag/ - if ((reg & 0x0F) == 0) - setFlag(HALFCARRY_FLAG); - else - resetFlag(HALFCARRY_FLAG); - } -} - -template -void GameBoy::call(T address) { - push(PC + 3); - PC = address; -} - -void GameBoy::cp(const Byte value) //compare +void GameBoy::cp(const Byte value) // compare { - resetFlag(ZERO_FLAG); - resetFlag(CARRY_FLAG); - resetFlag(HALFCARRY_FLAG); + resetFlag(ZERO_FLAG); + resetFlag(CARRY_FLAG); + resetFlag(HALFCARRY_FLAG); - if (AF.hi == value) { - setFlag(ZERO_FLAG); - } - if ((AF.hi & 0xF) < (value & 0xF)) { - setFlag(HALFCARRY_FLAG); - } - if (AF.hi < value) { - setFlag(CARRY_FLAG); - } + if (AF.hi == value) { + setFlag(ZERO_FLAG); + } + if ((AF.hi & 0xF) < (value & 0xF)) { + setFlag(HALFCARRY_FLAG); + } + if (AF.hi < value) { + setFlag(CARRY_FLAG); + } - setFlag(SUBTRACT_FLAG); + setFlag(SUBTRACT_FLAG); } -template -void GameBoy::dec(T& reg) { - reg -= 1; +template void GameBoy::dec(T ®) { + reg -= 1; - if (sizeof(reg) == sizeof(Byte)) { - if (reg == 0) - setFlag(ZERO_FLAG); - else - resetFlag(ZERO_FLAG); + if (sizeof(reg) == sizeof(Byte)) { + if (reg == 0) + setFlag(ZERO_FLAG); + else + resetFlag(ZERO_FLAG); - setFlag(SUBTRACT_FLAG); + setFlag(SUBTRACT_FLAG); - //halfcarry test https://www.reddit.com/r/EmuDev/comments/4clh23/trouble_with_halfcarrycarry_flag/ - if (0 > (((reg + 1) & 0xf) - (reg & 0xf))) - setFlag(HALFCARRY_FLAG); - else - resetFlag(HALFCARRY_FLAG); - } + // halfcarry test + // https://www.reddit.com/r/EmuDev/comments/4clh23/trouble_with_halfcarrycarry_flag/ + if (0 > (((reg + 1) & 0xf) - (reg & 0xf))) + setFlag(HALFCARRY_FLAG); + else + resetFlag(HALFCARRY_FLAG); + } } -void GameBoy::swap(Byte& value) { - const Byte lowerNibble = value & 0x0F; - const Byte upperNibble = (value >> 4) & 0x0F; +void GameBoy::swap(Byte &value) { + const Byte lowerNibble = value & 0x0F; + const Byte upperNibble = (value >> 4) & 0x0F; - // Swap the lower and upper nibbles - value = (lowerNibble << 4) | upperNibble; - if (value == 0) - setFlag(ZERO_FLAG); - else - resetFlag(ZERO_FLAG); + // Swap the lower and upper nibbles + value = (lowerNibble << 4) | upperNibble; + if (value == 0) + setFlag(ZERO_FLAG); + else + resetFlag(ZERO_FLAG); - resetFlag(SUBTRACT_FLAG); - resetFlag(HALFCARRY_FLAG); - resetFlag(CARRY_FLAG); + resetFlag(SUBTRACT_FLAG); + resetFlag(HALFCARRY_FLAG); + resetFlag(CARRY_FLAG); } void GameBoy::halt() { - halted = true; - if (!IME && addressSpace.memoryLayout.IE & addressSpace.memoryLayout.IF) - haltBug = true; + halted = true; + if (!IME && addressSpace.memoryLayout.IE & addressSpace.memoryLayout.IF) + haltBug = true; } -void GameBoy::rrc(Byte& reg) { - const Byte lsb = reg & 0x01; - reg >>= 1; +void GameBoy::rrc(Byte ®) { + const Byte lsb = reg & 0x01; + reg >>= 1; - if (lsb) - reg |= 0x80; + if (lsb) + reg |= 0x80; - if (lsb) - setFlag(CARRY_FLAG); - else - resetFlag(CARRY_FLAG); + if (lsb) + setFlag(CARRY_FLAG); + else + resetFlag(CARRY_FLAG); - if (reg) - resetFlag(ZERO_FLAG); - else - setFlag(ZERO_FLAG); + if (reg) + resetFlag(ZERO_FLAG); + else + setFlag(ZERO_FLAG); - resetFlag(SUBTRACT_FLAG); - resetFlag(HALFCARRY_FLAG); + resetFlag(SUBTRACT_FLAG); + resetFlag(HALFCARRY_FLAG); } void GameBoy::rrca() { - const Byte lsb = AF.hi & 0x01; - AF.hi >>= 1; + const Byte lsb = AF.hi & 0x01; + AF.hi >>= 1; - if (lsb) - AF.hi |= 0x80; + if (lsb) + AF.hi |= 0x80; - if (lsb) - setFlag(CARRY_FLAG); - else - resetFlag(CARRY_FLAG); + if (lsb) + setFlag(CARRY_FLAG); + else + resetFlag(CARRY_FLAG); - resetFlag(ZERO_FLAG); - resetFlag(SUBTRACT_FLAG); - resetFlag(HALFCARRY_FLAG); + resetFlag(ZERO_FLAG); + resetFlag(SUBTRACT_FLAG); + resetFlag(HALFCARRY_FLAG); } void GameBoy::rra() { - const Byte lsb = AF.hi & 0x01; - AF.hi >>= 1; + const Byte lsb = AF.hi & 0x01; + AF.hi >>= 1; - if (getFlag(CARRY_FLAG)) - AF.hi |= 0x80; + if (getFlag(CARRY_FLAG)) + AF.hi |= 0x80; - if (lsb) - setFlag(CARRY_FLAG); - else - resetFlag(CARRY_FLAG); + if (lsb) + setFlag(CARRY_FLAG); + else + resetFlag(CARRY_FLAG); - resetFlag(ZERO_FLAG); - resetFlag(SUBTRACT_FLAG); - resetFlag(HALFCARRY_FLAG); + resetFlag(ZERO_FLAG); + resetFlag(SUBTRACT_FLAG); + resetFlag(HALFCARRY_FLAG); } -void GameBoy::rr(Byte& reg) { - const Byte lsb = reg & 0x01; +void GameBoy::rr(Byte ®) { + const Byte lsb = reg & 0x01; - reg >>= 1; + reg >>= 1; - if (getFlag(CARRY_FLAG)) - reg |= 0x80; + if (getFlag(CARRY_FLAG)) + reg |= 0x80; - if (lsb) - setFlag(CARRY_FLAG); - else - resetFlag(CARRY_FLAG); + if (lsb) + setFlag(CARRY_FLAG); + else + resetFlag(CARRY_FLAG); - if (reg) - resetFlag(ZERO_FLAG); - else - setFlag(ZERO_FLAG); + if (reg) + resetFlag(ZERO_FLAG); + else + setFlag(ZERO_FLAG); - resetFlag(SUBTRACT_FLAG); - resetFlag(HALFCARRY_FLAG); + resetFlag(SUBTRACT_FLAG); + resetFlag(HALFCARRY_FLAG); } -void GameBoy::rlc(Byte& reg) { - const Byte msb = (reg & 0x80) >> 7; - reg <<= 1; +void GameBoy::rlc(Byte ®) { + const Byte msb = (reg & 0x80) >> 7; + reg <<= 1; - reg |= msb; + reg |= msb; - if (msb) - setFlag(CARRY_FLAG); - else - resetFlag(CARRY_FLAG); + if (msb) + setFlag(CARRY_FLAG); + else + resetFlag(CARRY_FLAG); - if (reg) - resetFlag(ZERO_FLAG); - else - setFlag(ZERO_FLAG); + if (reg) + resetFlag(ZERO_FLAG); + else + setFlag(ZERO_FLAG); - resetFlag(SUBTRACT_FLAG); - resetFlag(HALFCARRY_FLAG); + resetFlag(SUBTRACT_FLAG); + resetFlag(HALFCARRY_FLAG); } void GameBoy::rlca() { - const Byte msb = (AF.hi & 0x80) >> 7; - AF.hi <<= 1; + const Byte msb = (AF.hi & 0x80) >> 7; + AF.hi <<= 1; - AF.hi |= msb; + AF.hi |= msb; - if (msb) - setFlag(CARRY_FLAG); - else - resetFlag(CARRY_FLAG); + if (msb) + setFlag(CARRY_FLAG); + else + resetFlag(CARRY_FLAG); - resetFlag(ZERO_FLAG); - resetFlag(SUBTRACT_FLAG); - resetFlag(HALFCARRY_FLAG); + resetFlag(ZERO_FLAG); + resetFlag(SUBTRACT_FLAG); + resetFlag(HALFCARRY_FLAG); } void GameBoy::rla() { - const Byte msb = (AF.hi & 0x80) >> 7; - AF.hi <<= 1; + const Byte msb = (AF.hi & 0x80) >> 7; + AF.hi <<= 1; - if (getFlag(CARRY_FLAG)) - AF.hi |= 0x01; + if (getFlag(CARRY_FLAG)) + AF.hi |= 0x01; - if (msb) - setFlag(CARRY_FLAG); - else - resetFlag(CARRY_FLAG); + if (msb) + setFlag(CARRY_FLAG); + else + resetFlag(CARRY_FLAG); - resetFlag(ZERO_FLAG); - resetFlag(SUBTRACT_FLAG); - resetFlag(HALFCARRY_FLAG); + resetFlag(ZERO_FLAG); + resetFlag(SUBTRACT_FLAG); + resetFlag(HALFCARRY_FLAG); } -void GameBoy::rl(Byte& reg) { - const Byte msb = (reg & 0x80) >> 7; +void GameBoy::rl(Byte ®) { + const Byte msb = (reg & 0x80) >> 7; - reg <<= 1; + reg <<= 1; - if (getFlag(CARRY_FLAG)) - reg |= 1; + if (getFlag(CARRY_FLAG)) + reg |= 1; - if (msb) - setFlag(CARRY_FLAG); - else - resetFlag(CARRY_FLAG); + if (msb) + setFlag(CARRY_FLAG); + else + resetFlag(CARRY_FLAG); - if (reg) - resetFlag(ZERO_FLAG); - else - setFlag(ZERO_FLAG); + if (reg) + resetFlag(ZERO_FLAG); + else + setFlag(ZERO_FLAG); - resetFlag(SUBTRACT_FLAG); - resetFlag(HALFCARRY_FLAG); + resetFlag(SUBTRACT_FLAG); + resetFlag(HALFCARRY_FLAG); } -void GameBoy::sla(Byte& reg) { - const Byte msb = (reg & 0x80) >> 7; +void GameBoy::sla(Byte ®) { + const Byte msb = (reg & 0x80) >> 7; - reg <<= 1; + reg <<= 1; - if (msb) - setFlag(CARRY_FLAG); - else - resetFlag(CARRY_FLAG); + if (msb) + setFlag(CARRY_FLAG); + else + resetFlag(CARRY_FLAG); - if (reg) - resetFlag(ZERO_FLAG); - else - setFlag(ZERO_FLAG); + if (reg) + resetFlag(ZERO_FLAG); + else + setFlag(ZERO_FLAG); - resetFlag(SUBTRACT_FLAG); - resetFlag(HALFCARRY_FLAG); + resetFlag(SUBTRACT_FLAG); + resetFlag(HALFCARRY_FLAG); } -void GameBoy::sra(Byte& reg) { - const Byte msb = (reg & 0x80) >> 7; - const Byte lsb = reg & 0x1; +void GameBoy::sra(Byte ®) { + const Byte msb = (reg & 0x80) >> 7; + const Byte lsb = reg & 0x1; - reg >>= 1; + reg >>= 1; - if (msb) - reg |= 0x80; + if (msb) + reg |= 0x80; - if (lsb) - setFlag(CARRY_FLAG); - else - resetFlag(CARRY_FLAG); + if (lsb) + setFlag(CARRY_FLAG); + else + resetFlag(CARRY_FLAG); - if (reg) - resetFlag(ZERO_FLAG); - else - setFlag(ZERO_FLAG); + if (reg) + resetFlag(ZERO_FLAG); + else + setFlag(ZERO_FLAG); - resetFlag(SUBTRACT_FLAG); - resetFlag(HALFCARRY_FLAG); + resetFlag(SUBTRACT_FLAG); + resetFlag(HALFCARRY_FLAG); } -void GameBoy::srl(Byte& reg) { - const Byte lsb = reg & 0x1; +void GameBoy::srl(Byte ®) { + const Byte lsb = reg & 0x1; - reg >>= 1; + reg >>= 1; - if (lsb) - setFlag(CARRY_FLAG); - else - resetFlag(CARRY_FLAG); + if (lsb) + setFlag(CARRY_FLAG); + else + resetFlag(CARRY_FLAG); - if (reg) - resetFlag(ZERO_FLAG); - else - setFlag(ZERO_FLAG); + if (reg) + resetFlag(ZERO_FLAG); + else + setFlag(ZERO_FLAG); - resetFlag(SUBTRACT_FLAG); - resetFlag(HALFCARRY_FLAG); + resetFlag(SUBTRACT_FLAG); + resetFlag(HALFCARRY_FLAG); } -template -void GameBoy::pop(T& reg) { - reg = getWordSP(); - AF.reg &= 0xFFF0; +template void GameBoy::pop(T ®) { + reg = getWordSP(); + AF.reg &= 0xFFF0; } void GameBoy::push(const Word reg) { - //little endian - addressSpace[--SP] = reg >> 8; - addressSpace[--SP] = reg & 0xFF; + // little endian + addressSpace[--SP] = reg >> 8; + addressSpace[--SP] = reg & 0xFF; } -template -void GameBoy::jp(T address) { - PC = address; -} +template void GameBoy::jp(T address) { PC = address; } -template -void GameBoy::rst(T address) { - PC += 1; - push(PC); - PC = address; +template void GameBoy::rst(T address) { + PC += 1; + push(PC); + PC = address; } void GameBoy::cpl() { - AF.hi = ~AF.hi; - setFlag(SUBTRACT_FLAG); - setFlag(HALFCARRY_FLAG); + AF.hi = ~AF.hi; + setFlag(SUBTRACT_FLAG); + setFlag(HALFCARRY_FLAG); } void GameBoy::scf() { - resetFlag(SUBTRACT_FLAG); - resetFlag(HALFCARRY_FLAG); - setFlag(CARRY_FLAG); + resetFlag(SUBTRACT_FLAG); + resetFlag(HALFCARRY_FLAG); + setFlag(CARRY_FLAG); } void GameBoy::ccf() { - if (getFlag(CARRY_FLAG)) - resetFlag(CARRY_FLAG); - else - setFlag(CARRY_FLAG); + if (getFlag(CARRY_FLAG)) + resetFlag(CARRY_FLAG); + else + setFlag(CARRY_FLAG); - resetFlag(SUBTRACT_FLAG); - resetFlag(HALFCARRY_FLAG); + resetFlag(SUBTRACT_FLAG); + resetFlag(HALFCARRY_FLAG); } -void GameBoy::stop() { - stopped = true; -} +void GameBoy::stop() { stopped = true; } void GameBoy::opcodeResolver() { - if (readOnlyAddressSpace[PC] != 0xCB) { - bool jumped; - switch (readOnlyAddressSpace[PC]) { - case 0x00: - //NOP - PC += 1; - addCycles(4); - break; - - case 0x01: - ld(BC.reg, getWordPC()); - PC += 3; - addCycles(12); - break; - - case 0x02: - ld(addressSpace[BC.reg], AF.hi); - PC += 1; - addCycles(8); - break; - - case 0x03: - BC.reg += 1; - PC += 1; - addCycles(8); - break; - - case 0x04: - inc(BC.hi); - PC += 1; - addCycles(4); - break; - - case 0x05: - dec(BC.hi); - PC += 1; - addCycles(4); - break; - - case 0x06: - ld(BC.hi, getBytePC()); - PC += 2; - addCycles(8); - break; - - case 0x07: - rlca(); - PC += 1; - addCycles(4); - break; - - case 0x08: - ldW(getWordPC(), SP); - PC += 3; - addCycles(20); - break; - - case 0x09: - add(HL.reg, BC.reg); - PC += 1; - addCycles(8); - break; - - case 0x0A: - ld(AF.hi, readOnlyAddressSpace[BC.reg]); - PC += 1; - addCycles(8); - break; - - case 0x0B: - BC.reg -= 1; - PC += 1; - addCycles(8); - break; - - case 0x0C: - inc(BC.lo); - PC += 1; - addCycles(4); - break; - - case 0x0D: - dec(BC.lo); - PC += 1; - addCycles(4); - break; - - case 0x0E: - ld(BC.lo, getBytePC()); - PC += 2; - addCycles(8); - break; - - case 0x0F: - rrca(); - PC += 1; - addCycles(4); - break; - - case 0x10: - stop(); - PC += 2; - addCycles(4); - break; - - case 0x11: - ld(DE.reg, getWordPC()); - PC += 3; - addCycles(12); - break; - - case 0x12: - ld(addressSpace[DE.reg], AF.hi); - PC += 1; - addCycles(8); - break; - - case 0x13: - DE.reg += 1; //no flags change no just inc it manually - PC += 1; - addCycles(8); - break; - - case 0x14: - inc(DE.hi); - PC += 1; - addCycles(4); - break; - - case 0x15: - dec(DE.hi); - PC += 1; - addCycles(4); - break; - - case 0x16: - ld(DE.hi, getBytePC()); - PC += 2; - addCycles(8); - break; - - case 0x17: - rla(); - PC += 1; - addCycles(4); - break; - - case 0x18: - jr(getBytePC()); - addCycles(12); - break; - - case 0x19: - add(HL.reg, DE.reg); - PC += 1; - addCycles(8); - break; - - case 0x1A: - ld(AF.hi, readOnlyAddressSpace[DE.reg]); - PC += 1; - addCycles(8); - break; - - case 0x1B: - DE.reg -= 1; - PC += 1; - addCycles(8); - break; - - case 0x1C: - inc(DE.lo); - PC += 1; - addCycles(4); - break; - - case 0x1D: - dec(DE.lo); - PC += 1; - addCycles(4); - break; - - case 0x1E: - ld(DE.lo, getBytePC()); - PC += 2; - addCycles(8); - break; - - case 0x1F: - rra(); - PC += 1; - addCycles(4); - break; - - case 0x20: - jumped = jrNZ(getBytePC()); - if (jumped) { - addCycles(12); - } - else { - PC += 2; - addCycles(8); - } - break; - - case 0x21: - ld(HL.reg, getWordPC()); - PC += 3; - addCycles(12); - break; - - case 0x22: - ld(addressSpace[HL.reg], AF.hi); - HL.reg += 1; - PC += 1; - addCycles(8); - break; - - case 0x23: - inc(HL.reg); - PC += 1; - addCycles(8); - break; - - case 0x24: - inc(HL.hi); - PC += 1; - addCycles(4); - break; - - case 0x25: - dec(HL.hi); - PC += 1; - addCycles(4); - break; - - case 0x26: - ld(HL.hi, getBytePC()); - PC += 2; - addCycles(8); - break; - - case 0x27: - daa(); - PC += 1; - addCycles(4); - break; - - case 0x28: - jumped = jrZ(getBytePC()); - if (jumped) { - addCycles(12); - } - else { - PC += 2; - addCycles(8); - } - break; - - case 0x29: - add(HL.reg, HL.reg); - PC += 1; - addCycles(8); - break; - - case 0x2A: - ld(AF.hi, readOnlyAddressSpace[HL.reg]); - HL.reg += 1; - PC += 1; - addCycles(8); - break; - - case 0x2B: - dec(HL.reg); - PC += 1; - addCycles(8); - break; - - case 0x2C: - inc(HL.lo); - PC += 1; - addCycles(4); - break; - - case 0x2D: - dec(HL.lo); - PC += 1; - addCycles(4); - break; - - case 0x2E: - ld(HL.lo, getBytePC()); - PC += 2; - addCycles(8); - break; - - case 0x2F: - cpl(); - PC += 1; - addCycles(4); - break; - - case 0x30: - jumped = jrNC(getBytePC()); - if (jumped) { - addCycles(12); - } - else { - PC += 2; - addCycles(8); - } - break; - - case 0x31: - ld(SP, getWordPC()); - PC += 3; - addCycles(12); - break; - - case 0x32: - ld(addressSpace[HL.reg], AF.hi); - HL.reg -= 1; - PC += 1; - addCycles(8); - break; - - case 0x33: - SP += 1; - PC += 1; - addCycles(8); - break; - - case 0x34: - inc(addressSpace[HL.reg]); - PC += 1; - addCycles(12); - break; - - case 0x35: - dec(addressSpace[HL.reg]); - PC += 1; - addCycles(12); - break; - - case 0x36: - ld(addressSpace[HL.reg], getBytePC()); - PC += 2; - addCycles(12); - break; - - case 0x37: - scf(); - PC += 1; - addCycles(4); - break; - - case 0x38: - jumped = jrC(getBytePC()); - if (jumped) { - addCycles(12); - } - else { - PC += 2; - addCycles(8); - } - break; - - case 0x39: - add(HL.reg, SP); - PC += 1; - addCycles(8); - break; - - case 0x3A: - ld(AF.hi, readOnlyAddressSpace[HL.reg]); - HL.reg -= 1; - PC += 1; - addCycles(8); - break; - - case 0x3B: - SP -= 1; - PC += 1; - addCycles(8); - break; - - case 0x3C: - inc(AF.hi); - PC += 1; - addCycles(4); - break; - - case 0x3D: - dec(AF.hi); - PC += 1; - addCycles(4); - break; - - case 0x3E: - ld(AF.hi, getBytePC()); - PC += 2; - addCycles(8); - break; - - case 0x3F: - ccf(); - PC += 1; - addCycles(4); - break; - - case 0x40: - ld(BC.hi, BC.hi); - PC += 1; - addCycles(4); - break; - - case 0x41: - ld(BC.hi, BC.lo); - PC += 1; - addCycles(4); - break; - - case 0x42: - ld(BC.hi, DE.hi); - PC += 1; - addCycles(4); - break; - - case 0x43: - ld(BC.hi, DE.lo); - PC += 1; - addCycles(4); - break; - - case 0x44: - ld(BC.hi, HL.hi); - PC += 1; - addCycles(4); - break; - - case 0x45: - ld(BC.hi, HL.lo); - PC += 1; - addCycles(4); - break; - - case 0x46: - ld(BC.hi, readOnlyAddressSpace[HL.reg]); - PC += 1; - addCycles(8); - break; - - case 0x47: - ld(BC.hi, AF.hi); - PC += 1; - addCycles(4); - break; - - case 0x48: - ld(BC.lo, BC.hi); - PC += 1; - addCycles(4); - break; - - case 0x49: - ld(BC.lo, BC.lo); - PC += 1; - addCycles(4); - break; - - case 0x4A: - ld(BC.lo, DE.hi); - PC += 1; - addCycles(4); - break; - - case 0x4B: - ld(BC.lo, DE.lo); - PC += 1; - addCycles(4); - break; - - case 0x4C: - ld(BC.lo, HL.hi); - PC += 1; - addCycles(4); - break; - - case 0x4D: - ld(BC.lo, HL.lo); - PC += 1; - addCycles(4); - break; - - case 0x4E: - ld(BC.lo, readOnlyAddressSpace[HL.reg]); - PC += 1; - addCycles(8); - break; - - case 0x4F: - ld(BC.lo, AF.hi); - PC += 1; - addCycles(4); - break; - - case 0x50: - ld(DE.hi, BC.hi); - PC += 1; - addCycles(4); - break; - - case 0x51: - ld(DE.hi, BC.lo); - PC += 1; - addCycles(4); - break; - - case 0x52: - ld(DE.hi, DE.hi); - PC += 1; - addCycles(4); - break; - - case 0x53: - ld(DE.hi, DE.lo); - PC += 1; - addCycles(4); - break; - - case 0x54: - ld(DE.hi, HL.hi); - PC += 1; - addCycles(4); - break; - - case 0x55: - ld(DE.hi, HL.lo); - PC += 1; - addCycles(4); - break; - - case 0x56: - ld(DE.hi, readOnlyAddressSpace[HL.reg]); - PC += 1; - addCycles(8); - break; - - case 0x57: - ld(DE.hi, AF.hi); - PC += 1; - addCycles(4); - break; - - case 0x58: - ld(DE.lo, BC.hi); - PC += 1; - addCycles(4); - break; - - case 0x59: - ld(DE.lo, BC.lo); - PC += 1; - addCycles(4); - break; - - case 0x5A: - ld(DE.lo, DE.hi); - PC += 1; - addCycles(4); - break; - - case 0x5B: - ld(DE.lo, DE.lo); - PC += 1; - addCycles(4); - break; - - case 0x5C: - ld(DE.lo, HL.hi); - PC += 1; - addCycles(4); - break; - - case 0x5D: - ld(DE.lo, HL.lo); - PC += 1; - addCycles(4); - break; - - case 0x5E: - ld(DE.lo, readOnlyAddressSpace[HL.reg]); - PC += 1; - addCycles(8); - break; - - case 0x5F: - ld(DE.lo, AF.hi); - PC += 1; - addCycles(4); - break; - - case 0x60: - ld(HL.hi, BC.hi); - PC += 1; - addCycles(4); - break; - - case 0x61: - ld(HL.hi, BC.lo); - PC += 1; - addCycles(4); - break; - - case 0x62: - ld(HL.hi, DE.hi); - PC += 1; - addCycles(4); - break; - - case 0x63: - ld(HL.hi, DE.lo); - PC += 1; - addCycles(4); - break; - - case 0x64: - ld(HL.hi, HL.hi); - PC += 1; - addCycles(4); - break; - - case 0x65: - ld(HL.hi, HL.lo); - PC += 1; - addCycles(4); - break; - - case 0x66: - ld(HL.hi, readOnlyAddressSpace[HL.reg]); - PC += 1; - addCycles(8); - break; - - case 0x67: - ld(HL.hi, AF.hi); - PC += 1; - addCycles(4); - break; - - case 0x68: - ld(HL.lo, BC.hi); - PC += 1; - addCycles(4); - break; - - case 0x69: - ld(HL.lo, BC.lo); - PC += 1; - addCycles(4); - break; - - case 0x6A: - ld(HL.lo, DE.hi); - PC += 1; - addCycles(4); - break; - - case 0x6B: - ld(HL.lo, DE.lo); - PC += 1; - addCycles(4); - break; - - case 0x6C: - ld(HL.lo, HL.hi); - PC += 1; - addCycles(4); - break; - - case 0x6D: - ld(HL.lo, HL.lo); - PC += 1; - addCycles(4); - break; - - case 0x6E: - ld(HL.lo, readOnlyAddressSpace[HL.reg]); - PC += 1; - addCycles(8); - break; - - case 0x6F: - ld(HL.lo, AF.hi); - PC += 1; - addCycles(4); - break; - - case 0x70: - ld(addressSpace[HL.reg], BC.hi); - PC += 1; - addCycles(8); - break; - - case 0x71: - ld(addressSpace[HL.reg], BC.lo); - PC += 1; - addCycles(8); - break; - - case 0x72: - ld(addressSpace[HL.reg], DE.hi); - PC += 1; - addCycles(8); - break; - - case 0x73: - ld(addressSpace[HL.reg], DE.lo); - PC += 1; - addCycles(8); - break; - - case 0x74: - ld(addressSpace[HL.reg], HL.hi); - PC += 1; - addCycles(8); - break; - - case 0x75: - ld(addressSpace[HL.reg], HL.lo); - PC += 1; - addCycles(8); - break; - - case 0x76: - halt(); - PC += 1; - addCycles(4); - break; - - case 0x77: - ld(addressSpace[HL.reg], AF.hi); - PC += 1; - addCycles(8); - break; - - case 0x78: - ld(AF.hi, BC.hi); - PC += 1; - addCycles(4); - break; - - case 0x79: - ld(AF.hi, BC.lo); - PC += 1; - addCycles(4); - break; - - case 0x7A: - ld(AF.hi, DE.hi); - PC += 1; - addCycles(4); - break; - - case 0x7B: - ld(AF.hi, DE.lo); - PC += 1; - addCycles(4); - break; - - case 0x7C: - ld(AF.hi, HL.hi); - PC += 1; - addCycles(4); - break; - - case 0x7D: - ld(AF.hi, HL.lo); - PC += 1; - addCycles(4); - break; - - case 0x7E: - ld(AF.hi, readOnlyAddressSpace[HL.reg]); - PC += 1; - addCycles(8); - break; - - case 0x7F: - ld(AF.hi, AF.hi); - PC += 1; - addCycles(4); - break; - - case 0x80: - add(AF.hi, BC.hi); - PC += 1; - addCycles(4); - break; - - case 0x81: - add(AF.hi, BC.lo); - PC += 1; - addCycles(4); - break; - - case 0x82: - add(AF.hi, DE.hi); - PC += 1; - addCycles(4); - break; - - case 0x83: - add(AF.hi, DE.lo); - PC += 1; - addCycles(4); - break; - - case 0x84: - add(AF.hi, HL.hi); - PC += 1; - addCycles(4); - break; - - case 0x85: - add(AF.hi, HL.lo); - PC += 1; - addCycles(4); - break; - - case 0x86: - add(AF.hi, readOnlyAddressSpace[HL.reg]); - PC += 1; - addCycles(8); - break; - - case 0x87: - add(AF.hi, AF.hi); - PC += 1; - addCycles(4); - break; - - case 0x88: - adc(BC.hi); - PC += 1; - addCycles(4); - break; - - case 0x89: - adc(BC.lo); - PC += 1; - addCycles(4); - break; - - case 0x8A: - adc(DE.hi); - PC += 1; - addCycles(4); - break; - - case 0x8B: - adc(DE.lo); - PC += 1; - addCycles(4); - break; - - case 0x8C: - adc(HL.hi); - PC += 1; - addCycles(4); - break; - - case 0x8D: - adc(HL.lo); - PC += 1; - addCycles(4); - break; - - case 0x8E: - adc(readOnlyAddressSpace[HL.reg]); - PC += 1; - addCycles(8); - break; - - case 0x8F: - adc(AF.hi); - PC += 1; - addCycles(4); - break; - - case 0x90: - sub(BC.hi); - PC += 1; - addCycles(4); - break; - - case 0x91: - sub(BC.lo); - PC += 1; - addCycles(4); - break; - - case 0x92: - sub(DE.hi); - PC += 1; - addCycles(4); - break; - - case 0x93: - sub(DE.lo); - PC += 1; - addCycles(4); - break; - - case 0x94: - sub(HL.hi); - PC += 1; - addCycles(4); - break; - - case 0x95: - sub(HL.lo); - PC += 1; - addCycles(4); - break; - - case 0x96: - sub(readOnlyAddressSpace[HL.reg]); - PC += 1; - addCycles(8); - break; - - case 0x97: - sub(AF.hi); - PC += 1; - addCycles(4); - break; - - case 0x98: - sbc(BC.hi); - PC += 1; - addCycles(4); - break; - - case 0x99: - sbc(BC.lo); - PC += 1; - addCycles(4); - break; - - case 0x9A: - sbc(DE.hi); - PC += 1; - addCycles(4); - break; - - case 0x9B: - sbc(DE.lo); - PC += 1; - addCycles(4); - break; - - case 0x9C: - sbc(HL.hi); - PC += 1; - addCycles(4); - break; - - case 0x9D: - sbc(HL.lo); - PC += 1; - addCycles(4); - break; - - case 0x9E: - sbc(readOnlyAddressSpace[HL.reg]); - PC += 1; - addCycles(8); - break; - - case 0x9F: - sbc(AF.hi); - PC += 1; - addCycles(4); - break; - - case 0xA0: - andBitwise(AF.hi, BC.hi); - PC += 1; - addCycles(4); - break; - - case 0xA1: - andBitwise(AF.hi, BC.lo); - PC += 1; - addCycles(4); - break; - - case 0xA2: - andBitwise(AF.hi, DE.hi); - PC += 1; - addCycles(4); - break; - - case 0xA3: - andBitwise(AF.hi, DE.lo); - PC += 1; - addCycles(4); - break; - - case 0xA4: - andBitwise(AF.hi, HL.hi); - PC += 1; - addCycles(4); - break; - - case 0xA5: - andBitwise(AF.hi, HL.lo); - PC += 1; - addCycles(4); - break; - - case 0xA6: - andBitwise(AF.hi, readOnlyAddressSpace[HL.reg]); - PC += 1; - addCycles(8); - break; - - case 0xA7: - andBitwise(AF.hi, AF.hi); - PC += 1; - addCycles(4); - break; - - case 0xA8: - xorBitwise(AF.hi, BC.hi); - PC += 1; - addCycles(4); - break; - - case 0xA9: - xorBitwise(AF.hi, BC.lo); - PC += 1; - addCycles(4); - break; - - case 0xAA: - xorBitwise(AF.hi, DE.hi); - PC += 1; - addCycles(4); - break; - - case 0xAB: - xorBitwise(AF.hi, DE.lo); - PC += 1; - addCycles(4); - break; - - case 0xAC: - xorBitwise(AF.hi, HL.hi); - PC += 1; - addCycles(4); - break; - - case 0xAD: - xorBitwise(AF.hi, HL.lo); - PC += 1; - addCycles(4); - break; - - case 0xAE: - xorBitwise(AF.hi, readOnlyAddressSpace[HL.reg]); - PC += 1; - addCycles(8); - break; - - case 0xAF: - xorBitwise(AF.hi, AF.hi); - PC += 1; - addCycles(4); - break; - - case 0xB0: - orBitwise(AF.hi, BC.hi); - PC += 1; - addCycles(4); - break; - - case 0xB1: - orBitwise(AF.hi, BC.lo); - PC += 1; - addCycles(4); - break; - - case 0xB2: - orBitwise(AF.hi, DE.hi); - PC += 1; - addCycles(4); - break; - - case 0xB3: - orBitwise(AF.hi, DE.lo); - PC += 1; - addCycles(4); - break; - - case 0xB4: - orBitwise(AF.hi, HL.hi); - PC += 1; - addCycles(4); - break; - - case 0xB5: - orBitwise(AF.hi, HL.lo); - PC += 1; - addCycles(4); - break; - - case 0xB6: - orBitwise(AF.hi, readOnlyAddressSpace[HL.reg]); - PC += 1; - addCycles(8); - break; - - case 0xB7: - orBitwise(AF.hi, AF.hi); - PC += 1; - addCycles(4); - break; - - case 0xB8: - cp(BC.hi); - PC += 1; - addCycles(4); - break; - - case 0xB9: - cp(BC.lo); - PC += 1; - addCycles(4); - break; - - case 0xBA: - cp(DE.hi); - PC += 1; - addCycles(4); - break; - - case 0xBB: - cp(DE.lo); - PC += 1; - addCycles(4); - break; - - case 0xBC: - cp(HL.hi); - PC += 1; - addCycles(4); - break; - - case 0xBD: - cp(HL.lo); - PC += 1; - addCycles(4); - break; - - case 0xBE: - cp(readOnlyAddressSpace[HL.reg]); - PC += 1; - addCycles(8); - break; - - case 0xBF: - cp(AF.hi); - PC += 1; - addCycles(4); - break; - - case 0xC0: //RET NZ - if (!getFlag(ZERO_FLAG)) { - ret(); - addCycles(20); - } - else { - addCycles(8); - PC += 1; - } - break; - - case 0xC1: - pop(BC.reg); - PC += 1; - addCycles(12); - break; - - case 0xC2: - if (!getFlag(ZERO_FLAG)) { - jp(getWordPC()); - addCycles(16); - } - else { - addCycles(12); - PC += 3; - } - break; - - case 0xC3: - jp(getWordPC()); - addCycles(16); - break; - - case 0xC4: - if (!getFlag(ZERO_FLAG)) { - call(getWordPC()); - addCycles(24); - } - else { - addCycles(12); - PC += 3; - } - break; - - case 0xC5: - push(BC.reg); - PC += 1; - addCycles(16); - break; - - case 0xC6: - add(AF.hi, getBytePC()); - PC += 2; - addCycles(8); - break; - - case 0xC7: - rst(0x0000); - addCycles(16); - break; - - case 0xC8: - if (getFlag(ZERO_FLAG)) { - ret(); - addCycles(20); - } - else { - addCycles(8); - PC += 1; - } - break; - - case 0xC9: - ret(); - addCycles(16); - break; - - case 0xCA: - if (getFlag(ZERO_FLAG)) { - jp(getWordPC()); - addCycles(16); - } - else { - addCycles(12); - PC += 3; - } - break; - - case 0xCC: - if (getFlag(ZERO_FLAG)) { - call(getWordPC()); - addCycles(24); - } - else { - addCycles(12); - PC += 3; - } - break; - - case 0xCD: - call(getWordPC()); - addCycles(24); - break; - - case 0xCE: - adc(getBytePC()); - PC += 2; - addCycles(8); - break; - - case 0xCF: - rst(0x08); - addCycles(16); - break; - - case 0xD0: //RET NC - if (!getFlag(CARRY_FLAG)) { - ret(); - addCycles(20); - } - else { - addCycles(8); - PC += 1; - } - break; - - case 0xD1: - pop(DE.reg); - PC += 1; - addCycles(12); - break; - - case 0xD2: - if (!getFlag(CARRY_FLAG)) { - jp(getWordPC()); - addCycles(24); - } - else { - addCycles(12); - PC += 3; - } - break; - - case 0xD4: - if (!getFlag(CARRY_FLAG)) { - call(getWordPC()); - addCycles(24); - } - else { - addCycles(12); - PC += 3; - } - break; - - case 0xD5: - push(DE.reg); - PC += 1; - addCycles(16); - break; - - case 0xD6: - sub(getBytePC()); - PC += 2; - addCycles(8); - break; - - case 0xD7: - rst(0x0010); - addCycles(16); - break; - - case 0xD8: - if (getFlag(CARRY_FLAG)) { - ret(); - addCycles(20); - } - else { - addCycles(8); - PC += 1; - } - break; - - //reti - case 0xD9: - IME = 1; - ret(); - addCycles(16); - break; - - case 0xDA: - if (getFlag(CARRY_FLAG)) { - jp(getWordPC()); - addCycles(16); - } - else { - addCycles(12); - PC += 3; - } - break; - - case 0xDC: - if (getFlag(CARRY_FLAG)) { - call(getWordPC()); - addCycles(24); - } - else { - addCycles(12); - PC += 3; - } - break; - - case 0xDE: - sbc(getBytePC()); - PC += 2; - addCycles(8); - break; - - case 0xDF: - rst(0x18); - addCycles(16); - break; - - case 0xE0: - ld(addressSpace[0xFF00 + getBytePC()], AF.hi); - PC += 2; - addCycles(12); - break; - - case 0xE1: - pop(HL.reg); - PC += 1; - addCycles(12); - break; - - case 0xE2: - ld(addressSpace[0xFF00 + BC.lo], AF.hi); - PC += 1; - addCycles(8); - break; - - case 0xE5: - push(HL.reg); - PC += 1; - addCycles(16); - break; - - case 0xE6: - andBitwise(AF.hi, getBytePC()); - PC += 2; - addCycles(8); - break; - - case 0xE7: - rst(0x0020); - addCycles(16); - break; - - case 0xE8: - { - const int16_t immediate = static_cast(getBytePC()); - - if ((SP & 0xF) + (immediate & 0xF) > 0xF) - setFlag(HALFCARRY_FLAG); - else - resetFlag(HALFCARRY_FLAG); - - if ((SP & 0xFF) + (immediate & 0xFF) > 0xFF) - setFlag(CARRY_FLAG); - else - resetFlag(CARRY_FLAG); - - SP += immediate; - - resetFlag(ZERO_FLAG); - resetFlag(SUBTRACT_FLAG); - - PC += 2; - addCycles(16); - } - break; - - case 0xE9: - jp(HL.reg); - addCycles(16); - break; - - case 0xEA: - ld(addressSpace[getWordPC()], AF.hi); - PC += 3; - addCycles(16); - break; - - case 0xEE: - xorBitwise(AF.hi, getBytePC()); - PC += 2; - addCycles(8); - break; - - case 0xEF: - rst(0x28); - addCycles(16); - break; - - case 0xF0: - ld(AF.hi, readOnlyAddressSpace[0xFF00 + getBytePC()]); - PC += 2; - addCycles(12); - break; - - case 0xF1: - pop(AF.reg); - PC += 1; - addCycles(12); - break; - - case 0xF2: - ld(AF.hi, readOnlyAddressSpace[0xFF00 + BC.lo]); - PC += 1; - addCycles(12); - break; - - case 0xF3: - IME = 0; - PC += 1; - addCycles(4); - break; - - case 0xF5: - push(AF.reg); - PC += 1; - addCycles(16); - break; - - case 0xF6: - orBitwise(AF.hi, getBytePC()); - PC += 2; - addCycles(8); - break; - - case 0xF7: - rst(0x0030); - addCycles(16); - break; - - case 0xF8: - { - const int16_t immediate = static_cast(getBytePC()); - HL.reg = SP + immediate; - - if ((SP & 0xF) + (immediate & 0xF) > 0xF) - setFlag(HALFCARRY_FLAG); - else - resetFlag(HALFCARRY_FLAG); - - - if ((SP & 0xFF) + (immediate & 0xFF) > 0xFF) - setFlag(CARRY_FLAG); - else - resetFlag(CARRY_FLAG); - - - resetFlag(ZERO_FLAG); - resetFlag(SUBTRACT_FLAG); - - PC += 2; - addCycles(12); - } - break; - - case 0xF9: - ld(SP, HL.reg); - PC += 1; - addCycles(8); - break; - - case 0xFA: - ld(AF.hi, readOnlyAddressSpace[getWordPC()]); - PC += 3; - addCycles(16); - break; - - //EI (0xFB) then DI (0xF3) never allows interrupts to happen - case 0xFB: - IME = 0; - IME_togge = true; - PC += 1; - addCycles(4); - break; - - case 0xFE: - cp(getBytePC()); - PC += 2; - addCycles(8); - break; - - case 0xFF: - rst(0x38); - addCycles(16); - break; - - default: - printf("Unsupported opcode found: PC:0x%.2x, Opcode:0x%.2x\n", PC, addressSpace[PC]); - exit(1); - } - } - else - extendedOpcodeResolver(); + if (readOnlyAddressSpace[PC] != 0xCB) { + bool jumped; + switch (readOnlyAddressSpace[PC]) { + case 0x00: + // NOP + PC += 1; + addCycles(4); + break; + + case 0x01: + ld(BC.reg, getWordPC()); + PC += 3; + addCycles(12); + break; + + case 0x02: + ld(addressSpace[BC.reg], AF.hi); + PC += 1; + addCycles(8); + break; + + case 0x03: + BC.reg += 1; + PC += 1; + addCycles(8); + break; + + case 0x04: + inc(BC.hi); + PC += 1; + addCycles(4); + break; + + case 0x05: + dec(BC.hi); + PC += 1; + addCycles(4); + break; + + case 0x06: + ld(BC.hi, getBytePC()); + PC += 2; + addCycles(8); + break; + + case 0x07: + rlca(); + PC += 1; + addCycles(4); + break; + + case 0x08: + ldW(getWordPC(), SP); + PC += 3; + addCycles(20); + break; + + case 0x09: + add(HL.reg, BC.reg); + PC += 1; + addCycles(8); + break; + + case 0x0A: + ld(AF.hi, readOnlyAddressSpace[BC.reg]); + PC += 1; + addCycles(8); + break; + + case 0x0B: + BC.reg -= 1; + PC += 1; + addCycles(8); + break; + + case 0x0C: + inc(BC.lo); + PC += 1; + addCycles(4); + break; + + case 0x0D: + dec(BC.lo); + PC += 1; + addCycles(4); + break; + + case 0x0E: + ld(BC.lo, getBytePC()); + PC += 2; + addCycles(8); + break; + + case 0x0F: + rrca(); + PC += 1; + addCycles(4); + break; + + case 0x10: + stop(); + PC += 2; + addCycles(4); + break; + + case 0x11: + ld(DE.reg, getWordPC()); + PC += 3; + addCycles(12); + break; + + case 0x12: + ld(addressSpace[DE.reg], AF.hi); + PC += 1; + addCycles(8); + break; + + case 0x13: + DE.reg += 1; // no flags change no just inc it manually + PC += 1; + addCycles(8); + break; + + case 0x14: + inc(DE.hi); + PC += 1; + addCycles(4); + break; + + case 0x15: + dec(DE.hi); + PC += 1; + addCycles(4); + break; + + case 0x16: + ld(DE.hi, getBytePC()); + PC += 2; + addCycles(8); + break; + + case 0x17: + rla(); + PC += 1; + addCycles(4); + break; + + case 0x18: + jr(getBytePC()); + addCycles(12); + break; + + case 0x19: + add(HL.reg, DE.reg); + PC += 1; + addCycles(8); + break; + + case 0x1A: + ld(AF.hi, readOnlyAddressSpace[DE.reg]); + PC += 1; + addCycles(8); + break; + + case 0x1B: + DE.reg -= 1; + PC += 1; + addCycles(8); + break; + + case 0x1C: + inc(DE.lo); + PC += 1; + addCycles(4); + break; + + case 0x1D: + dec(DE.lo); + PC += 1; + addCycles(4); + break; + + case 0x1E: + ld(DE.lo, getBytePC()); + PC += 2; + addCycles(8); + break; + + case 0x1F: + rra(); + PC += 1; + addCycles(4); + break; + + case 0x20: + jumped = jrNZ(getBytePC()); + if (jumped) { + addCycles(12); + } else { + PC += 2; + addCycles(8); + } + break; + + case 0x21: + ld(HL.reg, getWordPC()); + PC += 3; + addCycles(12); + break; + + case 0x22: + ld(addressSpace[HL.reg], AF.hi); + HL.reg += 1; + PC += 1; + addCycles(8); + break; + + case 0x23: + inc(HL.reg); + PC += 1; + addCycles(8); + break; + + case 0x24: + inc(HL.hi); + PC += 1; + addCycles(4); + break; + + case 0x25: + dec(HL.hi); + PC += 1; + addCycles(4); + break; + + case 0x26: + ld(HL.hi, getBytePC()); + PC += 2; + addCycles(8); + break; + + case 0x27: + daa(); + PC += 1; + addCycles(4); + break; + + case 0x28: + jumped = jrZ(getBytePC()); + if (jumped) { + addCycles(12); + } else { + PC += 2; + addCycles(8); + } + break; + + case 0x29: + add(HL.reg, HL.reg); + PC += 1; + addCycles(8); + break; + + case 0x2A: + ld(AF.hi, readOnlyAddressSpace[HL.reg]); + HL.reg += 1; + PC += 1; + addCycles(8); + break; + + case 0x2B: + dec(HL.reg); + PC += 1; + addCycles(8); + break; + + case 0x2C: + inc(HL.lo); + PC += 1; + addCycles(4); + break; + + case 0x2D: + dec(HL.lo); + PC += 1; + addCycles(4); + break; + + case 0x2E: + ld(HL.lo, getBytePC()); + PC += 2; + addCycles(8); + break; + + case 0x2F: + cpl(); + PC += 1; + addCycles(4); + break; + + case 0x30: + jumped = jrNC(getBytePC()); + if (jumped) { + addCycles(12); + } else { + PC += 2; + addCycles(8); + } + break; + + case 0x31: + ld(SP, getWordPC()); + PC += 3; + addCycles(12); + break; + + case 0x32: + ld(addressSpace[HL.reg], AF.hi); + HL.reg -= 1; + PC += 1; + addCycles(8); + break; + + case 0x33: + SP += 1; + PC += 1; + addCycles(8); + break; + + case 0x34: + inc(addressSpace[HL.reg]); + PC += 1; + addCycles(12); + break; + + case 0x35: + dec(addressSpace[HL.reg]); + PC += 1; + addCycles(12); + break; + + case 0x36: + ld(addressSpace[HL.reg], getBytePC()); + PC += 2; + addCycles(12); + break; + + case 0x37: + scf(); + PC += 1; + addCycles(4); + break; + + case 0x38: + jumped = jrC(getBytePC()); + if (jumped) { + addCycles(12); + } else { + PC += 2; + addCycles(8); + } + break; + + case 0x39: + add(HL.reg, SP); + PC += 1; + addCycles(8); + break; + + case 0x3A: + ld(AF.hi, readOnlyAddressSpace[HL.reg]); + HL.reg -= 1; + PC += 1; + addCycles(8); + break; + + case 0x3B: + SP -= 1; + PC += 1; + addCycles(8); + break; + + case 0x3C: + inc(AF.hi); + PC += 1; + addCycles(4); + break; + + case 0x3D: + dec(AF.hi); + PC += 1; + addCycles(4); + break; + + case 0x3E: + ld(AF.hi, getBytePC()); + PC += 2; + addCycles(8); + break; + + case 0x3F: + ccf(); + PC += 1; + addCycles(4); + break; + + case 0x40: + ld(BC.hi, BC.hi); + PC += 1; + addCycles(4); + break; + + case 0x41: + ld(BC.hi, BC.lo); + PC += 1; + addCycles(4); + break; + + case 0x42: + ld(BC.hi, DE.hi); + PC += 1; + addCycles(4); + break; + + case 0x43: + ld(BC.hi, DE.lo); + PC += 1; + addCycles(4); + break; + + case 0x44: + ld(BC.hi, HL.hi); + PC += 1; + addCycles(4); + break; + + case 0x45: + ld(BC.hi, HL.lo); + PC += 1; + addCycles(4); + break; + + case 0x46: + ld(BC.hi, readOnlyAddressSpace[HL.reg]); + PC += 1; + addCycles(8); + break; + + case 0x47: + ld(BC.hi, AF.hi); + PC += 1; + addCycles(4); + break; + + case 0x48: + ld(BC.lo, BC.hi); + PC += 1; + addCycles(4); + break; + + case 0x49: + ld(BC.lo, BC.lo); + PC += 1; + addCycles(4); + break; + + case 0x4A: + ld(BC.lo, DE.hi); + PC += 1; + addCycles(4); + break; + + case 0x4B: + ld(BC.lo, DE.lo); + PC += 1; + addCycles(4); + break; + + case 0x4C: + ld(BC.lo, HL.hi); + PC += 1; + addCycles(4); + break; + + case 0x4D: + ld(BC.lo, HL.lo); + PC += 1; + addCycles(4); + break; + + case 0x4E: + ld(BC.lo, readOnlyAddressSpace[HL.reg]); + PC += 1; + addCycles(8); + break; + + case 0x4F: + ld(BC.lo, AF.hi); + PC += 1; + addCycles(4); + break; + + case 0x50: + ld(DE.hi, BC.hi); + PC += 1; + addCycles(4); + break; + + case 0x51: + ld(DE.hi, BC.lo); + PC += 1; + addCycles(4); + break; + + case 0x52: + ld(DE.hi, DE.hi); + PC += 1; + addCycles(4); + break; + + case 0x53: + ld(DE.hi, DE.lo); + PC += 1; + addCycles(4); + break; + + case 0x54: + ld(DE.hi, HL.hi); + PC += 1; + addCycles(4); + break; + + case 0x55: + ld(DE.hi, HL.lo); + PC += 1; + addCycles(4); + break; + + case 0x56: + ld(DE.hi, readOnlyAddressSpace[HL.reg]); + PC += 1; + addCycles(8); + break; + + case 0x57: + ld(DE.hi, AF.hi); + PC += 1; + addCycles(4); + break; + + case 0x58: + ld(DE.lo, BC.hi); + PC += 1; + addCycles(4); + break; + + case 0x59: + ld(DE.lo, BC.lo); + PC += 1; + addCycles(4); + break; + + case 0x5A: + ld(DE.lo, DE.hi); + PC += 1; + addCycles(4); + break; + + case 0x5B: + ld(DE.lo, DE.lo); + PC += 1; + addCycles(4); + break; + + case 0x5C: + ld(DE.lo, HL.hi); + PC += 1; + addCycles(4); + break; + + case 0x5D: + ld(DE.lo, HL.lo); + PC += 1; + addCycles(4); + break; + + case 0x5E: + ld(DE.lo, readOnlyAddressSpace[HL.reg]); + PC += 1; + addCycles(8); + break; + + case 0x5F: + ld(DE.lo, AF.hi); + PC += 1; + addCycles(4); + break; + + case 0x60: + ld(HL.hi, BC.hi); + PC += 1; + addCycles(4); + break; + + case 0x61: + ld(HL.hi, BC.lo); + PC += 1; + addCycles(4); + break; + + case 0x62: + ld(HL.hi, DE.hi); + PC += 1; + addCycles(4); + break; + + case 0x63: + ld(HL.hi, DE.lo); + PC += 1; + addCycles(4); + break; + + case 0x64: + ld(HL.hi, HL.hi); + PC += 1; + addCycles(4); + break; + + case 0x65: + ld(HL.hi, HL.lo); + PC += 1; + addCycles(4); + break; + + case 0x66: + ld(HL.hi, readOnlyAddressSpace[HL.reg]); + PC += 1; + addCycles(8); + break; + + case 0x67: + ld(HL.hi, AF.hi); + PC += 1; + addCycles(4); + break; + + case 0x68: + ld(HL.lo, BC.hi); + PC += 1; + addCycles(4); + break; + + case 0x69: + ld(HL.lo, BC.lo); + PC += 1; + addCycles(4); + break; + + case 0x6A: + ld(HL.lo, DE.hi); + PC += 1; + addCycles(4); + break; + + case 0x6B: + ld(HL.lo, DE.lo); + PC += 1; + addCycles(4); + break; + + case 0x6C: + ld(HL.lo, HL.hi); + PC += 1; + addCycles(4); + break; + + case 0x6D: + ld(HL.lo, HL.lo); + PC += 1; + addCycles(4); + break; + + case 0x6E: + ld(HL.lo, readOnlyAddressSpace[HL.reg]); + PC += 1; + addCycles(8); + break; + + case 0x6F: + ld(HL.lo, AF.hi); + PC += 1; + addCycles(4); + break; + + case 0x70: + ld(addressSpace[HL.reg], BC.hi); + PC += 1; + addCycles(8); + break; + + case 0x71: + ld(addressSpace[HL.reg], BC.lo); + PC += 1; + addCycles(8); + break; + + case 0x72: + ld(addressSpace[HL.reg], DE.hi); + PC += 1; + addCycles(8); + break; + + case 0x73: + ld(addressSpace[HL.reg], DE.lo); + PC += 1; + addCycles(8); + break; + + case 0x74: + ld(addressSpace[HL.reg], HL.hi); + PC += 1; + addCycles(8); + break; + + case 0x75: + ld(addressSpace[HL.reg], HL.lo); + PC += 1; + addCycles(8); + break; + + case 0x76: + halt(); + PC += 1; + addCycles(4); + break; + + case 0x77: + ld(addressSpace[HL.reg], AF.hi); + PC += 1; + addCycles(8); + break; + + case 0x78: + ld(AF.hi, BC.hi); + PC += 1; + addCycles(4); + break; + + case 0x79: + ld(AF.hi, BC.lo); + PC += 1; + addCycles(4); + break; + + case 0x7A: + ld(AF.hi, DE.hi); + PC += 1; + addCycles(4); + break; + + case 0x7B: + ld(AF.hi, DE.lo); + PC += 1; + addCycles(4); + break; + + case 0x7C: + ld(AF.hi, HL.hi); + PC += 1; + addCycles(4); + break; + + case 0x7D: + ld(AF.hi, HL.lo); + PC += 1; + addCycles(4); + break; + + case 0x7E: + ld(AF.hi, readOnlyAddressSpace[HL.reg]); + PC += 1; + addCycles(8); + break; + + case 0x7F: + ld(AF.hi, AF.hi); + PC += 1; + addCycles(4); + break; + + case 0x80: + add(AF.hi, BC.hi); + PC += 1; + addCycles(4); + break; + + case 0x81: + add(AF.hi, BC.lo); + PC += 1; + addCycles(4); + break; + + case 0x82: + add(AF.hi, DE.hi); + PC += 1; + addCycles(4); + break; + + case 0x83: + add(AF.hi, DE.lo); + PC += 1; + addCycles(4); + break; + + case 0x84: + add(AF.hi, HL.hi); + PC += 1; + addCycles(4); + break; + + case 0x85: + add(AF.hi, HL.lo); + PC += 1; + addCycles(4); + break; + + case 0x86: + add(AF.hi, readOnlyAddressSpace[HL.reg]); + PC += 1; + addCycles(8); + break; + + case 0x87: + add(AF.hi, AF.hi); + PC += 1; + addCycles(4); + break; + + case 0x88: + adc(BC.hi); + PC += 1; + addCycles(4); + break; + + case 0x89: + adc(BC.lo); + PC += 1; + addCycles(4); + break; + + case 0x8A: + adc(DE.hi); + PC += 1; + addCycles(4); + break; + + case 0x8B: + adc(DE.lo); + PC += 1; + addCycles(4); + break; + + case 0x8C: + adc(HL.hi); + PC += 1; + addCycles(4); + break; + + case 0x8D: + adc(HL.lo); + PC += 1; + addCycles(4); + break; + + case 0x8E: + adc(readOnlyAddressSpace[HL.reg]); + PC += 1; + addCycles(8); + break; + + case 0x8F: + adc(AF.hi); + PC += 1; + addCycles(4); + break; + + case 0x90: + sub(BC.hi); + PC += 1; + addCycles(4); + break; + + case 0x91: + sub(BC.lo); + PC += 1; + addCycles(4); + break; + + case 0x92: + sub(DE.hi); + PC += 1; + addCycles(4); + break; + + case 0x93: + sub(DE.lo); + PC += 1; + addCycles(4); + break; + + case 0x94: + sub(HL.hi); + PC += 1; + addCycles(4); + break; + + case 0x95: + sub(HL.lo); + PC += 1; + addCycles(4); + break; + + case 0x96: + sub(readOnlyAddressSpace[HL.reg]); + PC += 1; + addCycles(8); + break; + + case 0x97: + sub(AF.hi); + PC += 1; + addCycles(4); + break; + + case 0x98: + sbc(BC.hi); + PC += 1; + addCycles(4); + break; + + case 0x99: + sbc(BC.lo); + PC += 1; + addCycles(4); + break; + + case 0x9A: + sbc(DE.hi); + PC += 1; + addCycles(4); + break; + + case 0x9B: + sbc(DE.lo); + PC += 1; + addCycles(4); + break; + + case 0x9C: + sbc(HL.hi); + PC += 1; + addCycles(4); + break; + + case 0x9D: + sbc(HL.lo); + PC += 1; + addCycles(4); + break; + + case 0x9E: + sbc(readOnlyAddressSpace[HL.reg]); + PC += 1; + addCycles(8); + break; + + case 0x9F: + sbc(AF.hi); + PC += 1; + addCycles(4); + break; + + case 0xA0: + andBitwise(AF.hi, BC.hi); + PC += 1; + addCycles(4); + break; + + case 0xA1: + andBitwise(AF.hi, BC.lo); + PC += 1; + addCycles(4); + break; + + case 0xA2: + andBitwise(AF.hi, DE.hi); + PC += 1; + addCycles(4); + break; + + case 0xA3: + andBitwise(AF.hi, DE.lo); + PC += 1; + addCycles(4); + break; + + case 0xA4: + andBitwise(AF.hi, HL.hi); + PC += 1; + addCycles(4); + break; + + case 0xA5: + andBitwise(AF.hi, HL.lo); + PC += 1; + addCycles(4); + break; + + case 0xA6: + andBitwise(AF.hi, readOnlyAddressSpace[HL.reg]); + PC += 1; + addCycles(8); + break; + + case 0xA7: + andBitwise(AF.hi, AF.hi); + PC += 1; + addCycles(4); + break; + + case 0xA8: + xorBitwise(AF.hi, BC.hi); + PC += 1; + addCycles(4); + break; + + case 0xA9: + xorBitwise(AF.hi, BC.lo); + PC += 1; + addCycles(4); + break; + + case 0xAA: + xorBitwise(AF.hi, DE.hi); + PC += 1; + addCycles(4); + break; + + case 0xAB: + xorBitwise(AF.hi, DE.lo); + PC += 1; + addCycles(4); + break; + + case 0xAC: + xorBitwise(AF.hi, HL.hi); + PC += 1; + addCycles(4); + break; + + case 0xAD: + xorBitwise(AF.hi, HL.lo); + PC += 1; + addCycles(4); + break; + + case 0xAE: + xorBitwise(AF.hi, readOnlyAddressSpace[HL.reg]); + PC += 1; + addCycles(8); + break; + + case 0xAF: + xorBitwise(AF.hi, AF.hi); + PC += 1; + addCycles(4); + break; + + case 0xB0: + orBitwise(AF.hi, BC.hi); + PC += 1; + addCycles(4); + break; + + case 0xB1: + orBitwise(AF.hi, BC.lo); + PC += 1; + addCycles(4); + break; + + case 0xB2: + orBitwise(AF.hi, DE.hi); + PC += 1; + addCycles(4); + break; + + case 0xB3: + orBitwise(AF.hi, DE.lo); + PC += 1; + addCycles(4); + break; + + case 0xB4: + orBitwise(AF.hi, HL.hi); + PC += 1; + addCycles(4); + break; + + case 0xB5: + orBitwise(AF.hi, HL.lo); + PC += 1; + addCycles(4); + break; + + case 0xB6: + orBitwise(AF.hi, readOnlyAddressSpace[HL.reg]); + PC += 1; + addCycles(8); + break; + + case 0xB7: + orBitwise(AF.hi, AF.hi); + PC += 1; + addCycles(4); + break; + + case 0xB8: + cp(BC.hi); + PC += 1; + addCycles(4); + break; + + case 0xB9: + cp(BC.lo); + PC += 1; + addCycles(4); + break; + + case 0xBA: + cp(DE.hi); + PC += 1; + addCycles(4); + break; + + case 0xBB: + cp(DE.lo); + PC += 1; + addCycles(4); + break; + + case 0xBC: + cp(HL.hi); + PC += 1; + addCycles(4); + break; + + case 0xBD: + cp(HL.lo); + PC += 1; + addCycles(4); + break; + + case 0xBE: + cp(readOnlyAddressSpace[HL.reg]); + PC += 1; + addCycles(8); + break; + + case 0xBF: + cp(AF.hi); + PC += 1; + addCycles(4); + break; + + case 0xC0: // RET NZ + if (!getFlag(ZERO_FLAG)) { + ret(); + addCycles(20); + } else { + addCycles(8); + PC += 1; + } + break; + + case 0xC1: + pop(BC.reg); + PC += 1; + addCycles(12); + break; + + case 0xC2: + if (!getFlag(ZERO_FLAG)) { + jp(getWordPC()); + addCycles(16); + } else { + addCycles(12); + PC += 3; + } + break; + + case 0xC3: + jp(getWordPC()); + addCycles(16); + break; + + case 0xC4: + if (!getFlag(ZERO_FLAG)) { + call(getWordPC()); + addCycles(24); + } else { + addCycles(12); + PC += 3; + } + break; + + case 0xC5: + push(BC.reg); + PC += 1; + addCycles(16); + break; + + case 0xC6: + add(AF.hi, getBytePC()); + PC += 2; + addCycles(8); + break; + + case 0xC7: + rst(0x0000); + addCycles(16); + break; + + case 0xC8: + if (getFlag(ZERO_FLAG)) { + ret(); + addCycles(20); + } else { + addCycles(8); + PC += 1; + } + break; + + case 0xC9: + ret(); + addCycles(16); + break; + + case 0xCA: + if (getFlag(ZERO_FLAG)) { + jp(getWordPC()); + addCycles(16); + } else { + addCycles(12); + PC += 3; + } + break; + + case 0xCC: + if (getFlag(ZERO_FLAG)) { + call(getWordPC()); + addCycles(24); + } else { + addCycles(12); + PC += 3; + } + break; + + case 0xCD: + call(getWordPC()); + addCycles(24); + break; + + case 0xCE: + adc(getBytePC()); + PC += 2; + addCycles(8); + break; + + case 0xCF: + rst(0x08); + addCycles(16); + break; + + case 0xD0: // RET NC + if (!getFlag(CARRY_FLAG)) { + ret(); + addCycles(20); + } else { + addCycles(8); + PC += 1; + } + break; + + case 0xD1: + pop(DE.reg); + PC += 1; + addCycles(12); + break; + + case 0xD2: + if (!getFlag(CARRY_FLAG)) { + jp(getWordPC()); + addCycles(24); + } else { + addCycles(12); + PC += 3; + } + break; + + case 0xD4: + if (!getFlag(CARRY_FLAG)) { + call(getWordPC()); + addCycles(24); + } else { + addCycles(12); + PC += 3; + } + break; + + case 0xD5: + push(DE.reg); + PC += 1; + addCycles(16); + break; + + case 0xD6: + sub(getBytePC()); + PC += 2; + addCycles(8); + break; + + case 0xD7: + rst(0x0010); + addCycles(16); + break; + + case 0xD8: + if (getFlag(CARRY_FLAG)) { + ret(); + addCycles(20); + } else { + addCycles(8); + PC += 1; + } + break; + + // reti + case 0xD9: + IME = 1; + ret(); + addCycles(16); + break; + + case 0xDA: + if (getFlag(CARRY_FLAG)) { + jp(getWordPC()); + addCycles(16); + } else { + addCycles(12); + PC += 3; + } + break; + + case 0xDC: + if (getFlag(CARRY_FLAG)) { + call(getWordPC()); + addCycles(24); + } else { + addCycles(12); + PC += 3; + } + break; + + case 0xDE: + sbc(getBytePC()); + PC += 2; + addCycles(8); + break; + + case 0xDF: + rst(0x18); + addCycles(16); + break; + + case 0xE0: + ld(addressSpace[0xFF00 + getBytePC()], AF.hi); + PC += 2; + addCycles(12); + break; + + case 0xE1: + pop(HL.reg); + PC += 1; + addCycles(12); + break; + + case 0xE2: + ld(addressSpace[0xFF00 + BC.lo], AF.hi); + PC += 1; + addCycles(8); + break; + + case 0xE5: + push(HL.reg); + PC += 1; + addCycles(16); + break; + + case 0xE6: + andBitwise(AF.hi, getBytePC()); + PC += 2; + addCycles(8); + break; + + case 0xE7: + rst(0x0020); + addCycles(16); + break; + + case 0xE8: { + const int16_t immediate = static_cast(getBytePC()); + + if ((SP & 0xF) + (immediate & 0xF) > 0xF) + setFlag(HALFCARRY_FLAG); + else + resetFlag(HALFCARRY_FLAG); + + if ((SP & 0xFF) + (immediate & 0xFF) > 0xFF) + setFlag(CARRY_FLAG); + else + resetFlag(CARRY_FLAG); + + SP += immediate; + + resetFlag(ZERO_FLAG); + resetFlag(SUBTRACT_FLAG); + + PC += 2; + addCycles(16); + } break; + + case 0xE9: + jp(HL.reg); + addCycles(16); + break; + + case 0xEA: + ld(addressSpace[getWordPC()], AF.hi); + PC += 3; + addCycles(16); + break; + + case 0xEE: + xorBitwise(AF.hi, getBytePC()); + PC += 2; + addCycles(8); + break; + + case 0xEF: + rst(0x28); + addCycles(16); + break; + + case 0xF0: + ld(AF.hi, readOnlyAddressSpace[0xFF00 + getBytePC()]); + PC += 2; + addCycles(12); + break; + + case 0xF1: + pop(AF.reg); + PC += 1; + addCycles(12); + break; + + case 0xF2: + ld(AF.hi, readOnlyAddressSpace[0xFF00 + BC.lo]); + PC += 1; + addCycles(12); + break; + + case 0xF3: + IME = 0; + PC += 1; + addCycles(4); + break; + + case 0xF5: + push(AF.reg); + PC += 1; + addCycles(16); + break; + + case 0xF6: + orBitwise(AF.hi, getBytePC()); + PC += 2; + addCycles(8); + break; + + case 0xF7: + rst(0x0030); + addCycles(16); + break; + + case 0xF8: { + const int16_t immediate = static_cast(getBytePC()); + HL.reg = SP + immediate; + + if ((SP & 0xF) + (immediate & 0xF) > 0xF) + setFlag(HALFCARRY_FLAG); + else + resetFlag(HALFCARRY_FLAG); + + if ((SP & 0xFF) + (immediate & 0xFF) > 0xFF) + setFlag(CARRY_FLAG); + else + resetFlag(CARRY_FLAG); + + resetFlag(ZERO_FLAG); + resetFlag(SUBTRACT_FLAG); + + PC += 2; + addCycles(12); + } break; + + case 0xF9: + ld(SP, HL.reg); + PC += 1; + addCycles(8); + break; + + case 0xFA: + ld(AF.hi, readOnlyAddressSpace[getWordPC()]); + PC += 3; + addCycles(16); + break; + + // EI (0xFB) then DI (0xF3) never allows interrupts to happen + case 0xFB: + IME = 0; + IME_togge = true; + PC += 1; + addCycles(4); + break; + + case 0xFE: + cp(getBytePC()); + PC += 2; + addCycles(8); + break; + + case 0xFF: + rst(0x38); + addCycles(16); + break; + + default: + printf("Unsupported opcode found: PC:0x%.2x, Opcode:0x%.2x\n", PC, + addressSpace[PC]); + exit(1); + } + } else + extendedOpcodeResolver(); } diff --git a/src/ppu.cpp b/src/ppu.cpp index 7fbccda..0853911 100644 --- a/src/ppu.cpp +++ b/src/ppu.cpp @@ -1,390 +1,408 @@ -#include "gameboy.hpp" #include "defines.hpp" +#include "gameboy.hpp" #include #include #include #include bool GameBoy::LCDCBitEnabled(const Byte bit) const { - return readOnlyAddressSpace.memoryLayout.LCDC & static_cast(1 << bit); + return readOnlyAddressSpace.memoryLayout.LCDC & static_cast(1 << bit); } bool GameBoy::oamBitEnabled(const Byte oamAttributeByte, const Byte bit) { - return oamAttributeByte & static_cast(1 << bit); + return oamAttributeByte & static_cast(1 << bit); } unsigned int GameBoy::getColourFromPalette(const Byte palette) { - switch (palette & 0x3) { - case 0: - return WHITE; - case 1: - return LIGHT_GRAY; - case 2: - return DARK_GRAY; - case 3: - return BLACK; - default: - std::unreachable(); - } + switch (palette & 0x3) { + case 0: + return WHITE; + case 1: + return LIGHT_GRAY; + case 2: + return DARK_GRAY; + case 3: + return BLACK; + default: + std::unreachable(); + } } void GameBoy::ppuUpdate() { - //test for HBlank - checkPPUMode(); + // test for HBlank + checkPPUMode(); - // TODO: - // bug on DMG models triggers a STAT interrupt anytime the STAT register is written - // Road Rage and Zerd no Denetsu rely on this + // TODO: + // bug on DMG models triggers a STAT interrupt anytime the STAT register is + // written Road Rage and Zerd no Denetsu rely on this - // Check for STAT interrupts and request if needed (e.g., when entering specific modes) - const bool hBlankInterruptEnabled = readOnlyAddressSpace.memoryLayout.STAT & (1 << 3); - const bool drawingInterruptEnabled = readOnlyAddressSpace.memoryLayout.STAT & (1 << 4); - const bool oamInterruptEnabled = readOnlyAddressSpace.memoryLayout.STAT & (1 << 5); - const bool previousInterruptLine = statInteruptLine; + // Check for STAT interrupts and request if needed (e.g., when entering + // specific modes) + const bool hBlankInterruptEnabled = + readOnlyAddressSpace.memoryLayout.STAT & (1 << 3); + const bool drawingInterruptEnabled = + readOnlyAddressSpace.memoryLayout.STAT & (1 << 4); + const bool oamInterruptEnabled = + readOnlyAddressSpace.memoryLayout.STAT & (1 << 5); + const bool previousInterruptLine = statInteruptLine; - if (currentMode == PPUMode::mode0 && hBlankInterruptEnabled || - currentMode == PPUMode::mode3 && drawingInterruptEnabled || - currentMode == PPUMode::mode2 && oamInterruptEnabled) { - statInteruptLine = true; - } - else { - statInteruptLine = false; - } + if (currentMode == PPUMode::mode0 && hBlankInterruptEnabled || + currentMode == PPUMode::mode3 && drawingInterruptEnabled || + currentMode == PPUMode::mode2 && oamInterruptEnabled) { + statInteruptLine = true; + } else { + statInteruptLine = false; + } - const bool lyLycInterruptEnabled = readOnlyAddressSpace.memoryLayout.STAT & (1 << 6); + const bool lyLycInterruptEnabled = + readOnlyAddressSpace.memoryLayout.STAT & (1 << 6); - if (readOnlyAddressSpace.memoryLayout.LY == readOnlyAddressSpace.memoryLayout.LYC) { - addressSpace.memoryLayout.STAT |= (1 << 2); - if (lyLycInterruptEnabled) - statInteruptLine = true; - } - else { - addressSpace.memoryLayout.STAT &= ~(1 << 2); - } - if (statInteruptLine && !previousInterruptLine) - addressSpace.memoryLayout.IF |= 1 << LCD_STAT_INTERRUPT; + if (readOnlyAddressSpace.memoryLayout.LY == + readOnlyAddressSpace.memoryLayout.LYC) { + addressSpace.memoryLayout.STAT |= (1 << 2); + if (lyLycInterruptEnabled) + statInteruptLine = true; + } else { + addressSpace.memoryLayout.STAT &= ~(1 << 2); + } + if (statInteruptLine && !previousInterruptLine) + addressSpace.memoryLayout.IF |= 1 << LCD_STAT_INTERRUPT; } void GameBoy::checkPPUMode() { - // Check the PPU mode (HBlank, VBlank, OAM Search, or Pixel Transfer) - const uint64_t cyclesSinceScanline = cyclesSinceLastScanline(); + // Check the PPU mode (HBlank, VBlank, OAM Search, or Pixel Transfer) + const uint64_t cyclesSinceScanline = cyclesSinceLastScanline(); - switch (currentMode) { - //hblank AND vblank - case 0: - case 1: - if (cyclesSinceScanline > SCANLINE_DURATION) { - lastScanline = ppuCycles - (cyclesSinceScanline - SCANLINE_DURATION); - incLY(); - } - break; - case 2: - if (cyclesSinceScanline > MODE2_DURATION) { - setPPUMode(PPUMode::mode3); - } - break; - case 3: - if (cyclesSinceScanline > MODE2_DURATION + MODE3_MIN_DURATION) { - drawLine(); - setPPUMode(PPUMode::mode0); - } - break; - } + switch (currentMode) { + // hblank AND vblank + case 0: + case 1: + if (cyclesSinceScanline > SCANLINE_DURATION) { + lastScanline = ppuCycles - (cyclesSinceScanline - SCANLINE_DURATION); + incLY(); + } + break; + case 2: + if (cyclesSinceScanline > MODE2_DURATION) { + setPPUMode(PPUMode::mode3); + } + break; + case 3: + if (cyclesSinceScanline > MODE2_DURATION + MODE3_MIN_DURATION) { + drawLine(); + setPPUMode(PPUMode::mode0); + } + break; + } } void GameBoy::incLY() { - addressSpace.memoryLayout.LY += 1; - setPPUMode(PPUMode::mode2); - if (addressSpace.memoryLayout.LY > SCANLINES_PER_FRAME - 1) { - addressSpace.memoryLayout.LY = 0; - windowLineCounter = 0; - } - else if (addressSpace.memoryLayout.LY == 144) { - // VBlank Period - SDL2present(); - setPPUMode(PPUMode::mode1); - addressSpace.memoryLayout.IF |= 0x1; - } + addressSpace.memoryLayout.LY += 1; + setPPUMode(PPUMode::mode2); + if (addressSpace.memoryLayout.LY > SCANLINES_PER_FRAME - 1) { + addressSpace.memoryLayout.LY = 0; + windowLineCounter = 0; + } else if (addressSpace.memoryLayout.LY == 144) { + // VBlank Period + SDL2present(); + setPPUMode(PPUMode::mode1); + addressSpace.memoryLayout.IF |= 0x1; + } } uint64_t GameBoy::cyclesSinceLastScanline() const { - const uint64_t difference = ppuCycles - lastScanline; - return difference; + const uint64_t difference = ppuCycles - lastScanline; + return difference; } uint64_t GameBoy::cyclesSinceLastRefresh() const { - const uint64_t difference = ppuCycles - lastRefresh; - return difference; + const uint64_t difference = ppuCycles - lastRefresh; + return difference; } void GameBoy::setPPUMode(const PPUMode mode) { - switch (mode) { - case mode0: - addressSpace.memoryLayout.STAT &= ~0x03; - currentMode = mode0; - break; - case mode1: - addressSpace.memoryLayout.STAT &= ~0x03; - addressSpace.memoryLayout.STAT |= 0x01; - currentMode = mode1; - break; - case mode2: - addressSpace.memoryLayout.STAT &= ~0x03; - addressSpace.memoryLayout.STAT |= 0x02; - currentMode = mode2; - break; - case mode3: - addressSpace.memoryLayout.STAT &= ~0x03; - addressSpace.memoryLayout.STAT |= 0x03; - currentMode = mode3; - break; - } - //7th bit is unused but always set - addressSpace.memoryLayout.STAT |= 0x80; + switch (mode) { + case mode0: + addressSpace.memoryLayout.STAT &= ~0x03; + currentMode = mode0; + break; + case mode1: + addressSpace.memoryLayout.STAT &= ~0x03; + addressSpace.memoryLayout.STAT |= 0x01; + currentMode = mode1; + break; + case mode2: + addressSpace.memoryLayout.STAT &= ~0x03; + addressSpace.memoryLayout.STAT |= 0x02; + currentMode = mode2; + break; + case mode3: + addressSpace.memoryLayout.STAT &= ~0x03; + addressSpace.memoryLayout.STAT |= 0x03; + currentMode = mode3; + break; + } + // 7th bit is unused but always set + addressSpace.memoryLayout.STAT |= 0x80; } void GameBoy::drawLine() { - const uint8_t line = readOnlyAddressSpace.memoryLayout.LY; + const uint8_t line = readOnlyAddressSpace.memoryLayout.LY; - // Calculate the starting index of the current scanline in the framebuffer - const uint32_t lineStartIndex = line * RESOLUTION_X; + // Calculate the starting index of the current scanline in the framebuffer + const uint32_t lineStartIndex = line * RESOLUTION_X; - // Pointer to the current line's pixel data in the framebuffer - uint32_t* currentLinePixels = framebuffer + lineStartIndex; - std::fill_n(currentLinePixels, RESOLUTION_X, 0xFFFFFFFF); + // Pointer to the current line's pixel data in the framebuffer + uint32_t *currentLinePixels = framebuffer + lineStartIndex; + std::fill_n(currentLinePixels, RESOLUTION_X, 0xFFFFFFFF); + const uint16_t backgroundMapAddr = + LCDCBitEnabled(BG_TILE_MAP_AREA) ? 0x9C00 : 0x9800; + const uint16_t windowMapAddr = + LCDCBitEnabled(WINDOW_TILE_MAP_AREA) ? 0x9C00 : 0x9800; + const uint16_t tileDataTableAddr = + LCDCBitEnabled(BG_WINDOW_TILE_DATA_AREA) ? 0x8000 : 0x8800; + const bool signedIndex = !LCDCBitEnabled(BG_WINDOW_TILE_DATA_AREA); - const uint16_t backgroundMapAddr = LCDCBitEnabled(BG_TILE_MAP_AREA) ? 0x9C00 : 0x9800; - const uint16_t windowMapAddr = LCDCBitEnabled(WINDOW_TILE_MAP_AREA) ? 0x9C00 : 0x9800; - const uint16_t tileDataTableAddr = LCDCBitEnabled(BG_WINDOW_TILE_DATA_AREA) ? 0x8000 : 0x8800; - const bool signedIndex = !LCDCBitEnabled(BG_WINDOW_TILE_DATA_AREA); + // BG + if (LCDCBitEnabled(BG_WINDOW_ENABLE)) { + for (int pixel = 0; pixel < RESOLUTION_X; pixel++) { + const uint16_t xIndex = + (pixel + readOnlyAddressSpace.memoryLayout.SCX) % 256; + // 256 pixels in total BG width + const uint16_t yIndex = + (line + readOnlyAddressSpace.memoryLayout.SCY) % 256; + // 256 pixels in total BG height - //BG - if (LCDCBitEnabled(BG_WINDOW_ENABLE)) { - for (int pixel = 0; pixel < RESOLUTION_X; pixel++) { - const uint16_t xIndex = (pixel + readOnlyAddressSpace.memoryLayout.SCX) % 256; - // 256 pixels in total BG width - const uint16_t yIndex = (line + readOnlyAddressSpace.memoryLayout.SCY) % 256; - // 256 pixels in total BG height + const uint16_t tileUpper = (yIndex / 8) << 5; + const uint16_t tileLower = xIndex / 8 & 0x1F; + const uint16_t tileIndex = tileUpper + tileLower; - const uint16_t tileUpper = (yIndex / 8) << 5; - const uint16_t tileLower = xIndex / 8 & 0x1F; - const uint16_t tileIndex = tileUpper + tileLower; + const uint16_t tileAddr = backgroundMapAddr + tileIndex; + const int16_t tileID = + signedIndex ? static_cast(readOnlyAddressSpace[tileAddr]) + : readOnlyAddressSpace[tileAddr]; - const uint16_t tileAddr = backgroundMapAddr + tileIndex; - const int16_t tileID = signedIndex - ? static_cast(readOnlyAddressSpace[tileAddr]) - : readOnlyAddressSpace[tileAddr]; + uint16_t tileDataAddr; + if (signedIndex) + tileDataAddr = tileDataTableAddr + + (((tileID + 128) % 256) << 4); // For signed, wrap around + else + tileDataAddr = tileDataTableAddr + (tileID * 16); - uint16_t tileDataAddr; - if (signedIndex) - tileDataAddr = tileDataTableAddr + (((tileID + 128) % 256) << 4); // For signed, wrap around - else - tileDataAddr = tileDataTableAddr + (tileID * 16); + const uint8_t lineOffset = yIndex % 8; + const uint8_t tileRowData1 = + readOnlyAddressSpace[tileDataAddr + (lineOffset * 2)]; + const uint8_t tileRowData2 = + readOnlyAddressSpace[tileDataAddr + (lineOffset * 2) + 1]; + // get pixel data (2 bits) + const uint8_t colourBit = 7 - (xIndex % 8); + const uint8_t colourNum = ((tileRowData2 >> colourBit) & 0x1) << 1 | + ((tileRowData1 >> colourBit) & 0x1); - const uint8_t lineOffset = yIndex % 8; - const uint8_t tileRowData1 = readOnlyAddressSpace[tileDataAddr + (lineOffset * 2)]; - const uint8_t tileRowData2 = readOnlyAddressSpace[tileDataAddr + (lineOffset * 2) + 1]; + // Apply the BGP register for palette mapping + const uint8_t palette = + (readOnlyAddressSpace.memoryLayout.BGP >> (colourNum * 2)) & 0x3; - //get pixel data (2 bits) - const uint8_t colourBit = 7 - (xIndex % 8); - const uint8_t colourNum = ((tileRowData2 >> colourBit) & 0x1) << 1 | ((tileRowData1 >> colourBit) & 0x1); + currentLinePixels[pixel] = getColourFromPalette(palette); + } - // Apply the BGP register for palette mapping - const uint8_t palette = (readOnlyAddressSpace.memoryLayout.BGP >> (colourNum * 2)) & 0x3; + // For the window to be displayed on a scanline, the following conditions + // must be met: WY condition was triggered: i.e. at some point in this frame + // the value of WY was equal to LY (checked at the start of Mode 2 only) WX + // condition was triggered: i.e. the current X coordinate being rendered + 7 + // was equal to WX Window enable bit in LCDC is set + // Window + const uint8_t windowY = readOnlyAddressSpace.memoryLayout.WY; + const int16_t windowX = + static_cast(readOnlyAddressSpace.memoryLayout.WX - 7); + if (LCDCBitEnabled(WINDOW_ENABLE) && windowX >= 0 && + windowX < RESOLUTION_X && line >= windowY) { + for (int pixel = windowX; pixel < RESOLUTION_X; pixel++) { + const uint16_t yIndex = windowLineCounter; + const uint16_t windowTileUpper = (yIndex / 8) << 5; - currentLinePixels[pixel] = getColourFromPalette(palette); - } + const uint16_t xIndex = pixel - windowX; + const uint16_t windowTileLower = (xIndex / 8) & 0x1F; - // For the window to be displayed on a scanline, the following conditions must be met: - // WY condition was triggered: i.e. at some point in this frame the value of WY was equal to LY (checked at the start of Mode 2 only) - // WX condition was triggered: i.e. the current X coordinate being rendered + 7 was equal to WX - // Window enable bit in LCDC is set - //Window - const uint8_t windowY = readOnlyAddressSpace.memoryLayout.WY; - const int16_t windowX = static_cast(readOnlyAddressSpace.memoryLayout.WX - 7); - if (LCDCBitEnabled(WINDOW_ENABLE) && windowX >= 0 && windowX < RESOLUTION_X && line >= windowY) { - for (int pixel = windowX; pixel < RESOLUTION_X; pixel++) { - const uint16_t yIndex = windowLineCounter; - const uint16_t windowTileUpper = (yIndex / 8) << 5; + const uint16_t tileIndex = windowTileUpper + windowTileLower; + const uint16_t tileAddr = windowMapAddr + tileIndex; - const uint16_t xIndex = pixel - windowX; - const uint16_t windowTileLower = (xIndex / 8) & 0x1F; + const int16_t tileID = + signedIndex ? static_cast(readOnlyAddressSpace[tileAddr]) + : readOnlyAddressSpace[tileAddr]; - const uint16_t tileIndex = windowTileUpper + windowTileLower; - const uint16_t tileAddr = windowMapAddr + tileIndex; + uint16_t tileDataAddr; + if (signedIndex) + tileDataAddr = tileDataTableAddr + (((tileID + 128) % 256) * + 16); // For signed, wrap around + else + tileDataAddr = tileDataTableAddr + (tileID * 16); - const int16_t tileID = signedIndex - ? static_cast(readOnlyAddressSpace[tileAddr]) - : readOnlyAddressSpace[tileAddr]; + const uint8_t lineOffset = yIndex % 8; + const uint8_t tileRowData1 = + readOnlyAddressSpace[tileDataAddr + (lineOffset * 2)]; + const uint8_t tileRowData2 = + readOnlyAddressSpace[tileDataAddr + (lineOffset * 2) + 1]; - uint16_t tileDataAddr; - if (signedIndex) - tileDataAddr = tileDataTableAddr + (((tileID + 128) % 256) * 16); // For signed, wrap around - else - tileDataAddr = tileDataTableAddr + (tileID * 16); + // get pixel data (2 bits) + const uint8_t colourBit = 7 - (xIndex % 8); + const uint8_t colourNum = ((tileRowData2 >> colourBit) & 0x1) << 1 | + ((tileRowData1 >> colourBit) & 0x1); + // Apply the BGP register for palette mapping + const uint8_t palette = + (readOnlyAddressSpace.memoryLayout.BGP >> (colourNum * 2)) & 0x3; - const uint8_t lineOffset = yIndex % 8; - const uint8_t tileRowData1 = readOnlyAddressSpace[tileDataAddr + (lineOffset * 2)]; - const uint8_t tileRowData2 = readOnlyAddressSpace[tileDataAddr + (lineOffset * 2) + 1]; + currentLinePixels[pixel] = getColourFromPalette(palette); + } + windowLineCounter += 1; + } + } + // oam/sprites + if (LCDCBitEnabled(OBJ_ENABLE)) { + uint32_t oamPixels[RESOLUTION_X]; + std::fill_n(oamPixels, RESOLUTION_X, 0); - //get pixel data (2 bits) - const uint8_t colourBit = 7 - (xIndex % 8); - const uint8_t colourNum = ((tileRowData2 >> colourBit) & 0x1) << 1 | ((tileRowData1 >> colourBit) & - 0x1); + constexpr Word oamAddrStart = 0xFE00; + const int spriteHeight = LCDCBitEnabled(OBJ_SIZE) ? 16 : 8; - // Apply the BGP register for palette mapping - const uint8_t palette = (readOnlyAddressSpace.memoryLayout.BGP >> (colourNum * 2)) & 0x3; + int objects[10] = {0}; + int found = 0; - currentLinePixels[pixel] = getColourFromPalette(palette); - } - windowLineCounter += 1; - } - } - // oam/sprites - if (LCDCBitEnabled(OBJ_ENABLE)) { - uint32_t oamPixels[RESOLUTION_X]; - std::fill_n(oamPixels, RESOLUTION_X, 0); + // oam hold 40 objects + // find first 10 + for (int i = 0; i < 40 && found < 10; i++) { + const int offset = i * 4; + const int yPos = readOnlyAddressSpace[oamAddrStart + offset] - 16; - constexpr - Word oamAddrStart = 0xFE00; - const int spriteHeight = LCDCBitEnabled(OBJ_SIZE) ? 16 : 8; + if (line >= yPos && line <= yPos + spriteHeight - 1) { + objects[found] = oamAddrStart + offset; + found += 1; + } + } - int objects[10] = {0}; - int found = 0; + // sort by xPos (lower has higher priority when rendering) and then earlier + // objects + for (int i = 0; i < found; i++) { + for (int j = 0; j < found - i - 1; j++) { + const int xPos1 = readOnlyAddressSpace[objects[j] + 1]; + const int xPos2 = readOnlyAddressSpace[objects[j + 1] + 1]; - //oam hold 40 objects - //find first 10 - for (int i = 0; i < 40 && found < 10; i++) { - const int offset = i * 4; - const int yPos = readOnlyAddressSpace[oamAddrStart + offset] - 16; + if (xPos1 > xPos2) { + const int tmp = objects[j]; + objects[j] = objects[j + 1]; + objects[j + 1] = tmp; + } + } + } - if (line >= yPos && line <= yPos + spriteHeight - 1) { - objects[found] = oamAddrStart + offset; - found += 1; - } - } + for (int objectIndex = found - 1; objectIndex >= 0; objectIndex--) { + const int yPos = readOnlyAddressSpace[objects[objectIndex]] - 16; + const int xPos = readOnlyAddressSpace[objects[objectIndex] + 1] - 8; + const int tileIndex = readOnlyAddressSpace[objects[objectIndex] + 2]; + const Byte attributes = readOnlyAddressSpace[objects[objectIndex] + 3]; - //sort by xPos (lower has higher priority when rendering) and then earlier objects - for (int i = 0; i < found; i++) { - for (int j = 0; j < found - i - 1; j++) { - const int xPos1 = readOnlyAddressSpace[objects[j] + 1]; - const int xPos2 = readOnlyAddressSpace[objects[j + 1] + 1]; + const bool priority = oamBitEnabled(attributes, PRIORITY); + const bool yFlip = oamBitEnabled(attributes, Y_FLIP); + const bool xFlip = oamBitEnabled(attributes, X_FLIP); + // get obp0 or obj1 + const Byte objPalette = oamBitEnabled(attributes, OBJ_PALETTE) + ? addressSpace.memoryLayout.OBP1 + : addressSpace.memoryLayout.OBP0; - if (xPos1 > xPos2) { - const int tmp = objects[j]; - objects[j] = objects[j + 1]; - objects[j + 1] = tmp; - } - } - } + for (int pixel = xPos; pixel < RESOLUTION_X && pixel < xPos + 8; + pixel++) { + constexpr Word objectTileAddr = 0x8000; + if (pixel < 0) + continue; + const uint32_t colour = currentLinePixels[pixel]; + const Byte BGP = readOnlyAddressSpace.memoryLayout.BGP; + if (priority && (colour == getColourFromPalette((BGP >> 2) & 0x3) || + colour == getColourFromPalette((BGP >> 4) & 0x3) || + colour == getColourFromPalette((BGP >> 6) & 0x3))) { + oamPixels[pixel] = colour; + continue; + } - for (int objectIndex = found - 1; objectIndex >= 0; objectIndex--) { - const int yPos = readOnlyAddressSpace[objects[objectIndex]] - 16; - const int xPos = readOnlyAddressSpace[objects[objectIndex] + 1] - 8; - const int tileIndex = readOnlyAddressSpace[objects[objectIndex] + 2]; - const Byte attributes = readOnlyAddressSpace[objects[objectIndex] + 3]; + Byte objectX = pixel - xPos; + Byte objectY = line - yPos; + if (xFlip) + objectX = 7 - objectX; + if (yFlip) + objectY = (spriteHeight - 1) - objectY; - const bool priority = oamBitEnabled(attributes, PRIORITY); - const bool yFlip = oamBitEnabled(attributes, Y_FLIP); - const bool xFlip = oamBitEnabled(attributes, X_FLIP); - //get obp0 or obj1 - const Byte objPalette = oamBitEnabled(attributes, OBJ_PALETTE) - ? addressSpace.memoryLayout.OBP1 - : addressSpace.memoryLayout.OBP0; + const Word objTileDataAddr = + spriteHeight == 8 ? objectTileAddr + (tileIndex * 16) + : objectTileAddr + ((tileIndex & 0xFE) * 16); - for (int pixel = xPos; pixel < RESOLUTION_X && pixel < xPos + 8; pixel++) { - constexpr - Word objectTileAddr = 0x8000; - if (pixel < 0) - continue; + const Byte tileRow = objectY * 2; + const Byte tileRowData1 = + readOnlyAddressSpace[objTileDataAddr + tileRow]; + const Byte tileRowData2 = + readOnlyAddressSpace[objTileDataAddr + tileRow + 1]; - const uint32_t colour = currentLinePixels[pixel]; - const Byte BGP = readOnlyAddressSpace.memoryLayout.BGP; - if (priority && (colour == getColourFromPalette((BGP >> 2) & 0x3) || - colour == getColourFromPalette((BGP >> 4) & 0x3) || - colour == getColourFromPalette((BGP >> 6) & 0x3) - )) { - oamPixels[pixel] = colour; - continue; - } + const int bit = 7 - objectX; + const int colorIndex = + ((tileRowData2 >> bit) & 1) << 1 | ((tileRowData1 >> bit) & 1); - Byte objectX = pixel - xPos; - Byte objectY = line - yPos; - if (xFlip) - objectX = 7 - objectX; - if (yFlip) - objectY = (spriteHeight - 1) - objectY; + // 0 is always transparent + if (colorIndex != 0) { + const uint8_t paletteColor = (objPalette >> (colorIndex * 2)) & 0x3; + const uint32_t finalColor = getColourFromPalette(paletteColor); + oamPixels[pixel] = finalColor; + } else if (oamPixels[pixel] == 0) { + oamPixels[pixel] = currentLinePixels[pixel]; + } + } + } - const Word objTileDataAddr = spriteHeight == 8 - ? objectTileAddr + (tileIndex * 16) - : objectTileAddr + ((tileIndex & 0xFE) * 16); - - const Byte tileRow = objectY * 2; - const Byte tileRowData1 = readOnlyAddressSpace[objTileDataAddr + tileRow]; - const Byte tileRowData2 = readOnlyAddressSpace[objTileDataAddr + tileRow + 1]; - - const int bit = 7 - objectX; - const int colorIndex = ((tileRowData2 >> bit) & 1) << 1 | ((tileRowData1 >> bit) & 1); - - // 0 is always transparent - if (colorIndex != 0) { - const uint8_t paletteColor = (objPalette >> (colorIndex * 2)) & 0x3; - const uint32_t finalColor = getColourFromPalette(paletteColor); - oamPixels[pixel] = finalColor; - } - else if (oamPixels[pixel] == 0) { - oamPixels[pixel] = currentLinePixels[pixel]; - } - } - } - - //help ensure correct interaction with "BG OVER OBJ" flag - for (int i = 0; i < RESOLUTION_X; i++) { - if (oamPixels[i] != currentLinePixels[i] && oamPixels[i] != 0) - currentLinePixels[i] = oamPixels[i]; - } - } + // help ensure correct interaction with "BG OVER OBJ" flag + for (int i = 0; i < RESOLUTION_X; i++) { + if (oamPixels[i] != currentLinePixels[i] && oamPixels[i] != 0) + currentLinePixels[i] = oamPixels[i]; + } + } } void GameBoy::SDL2setup() { - SDL_Init(SDL_INIT_EVERYTHING); - screen = SDL_CreateWindow("GameBoy++", - SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - RESOLUTION_X, RESOLUTION_Y, - 0); + SDL_Init(SDL_INIT_EVERYTHING); + screen = + SDL_CreateWindow("GameBoy++", SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, RESOLUTION_X, RESOLUTION_Y, 0); - // Create an SDL renderer to draw on the window - renderer = SDL_CreateRenderer(screen, -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED); + // Create an SDL renderer to draw on the window + renderer = SDL_CreateRenderer( + screen, -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED); - // Create an SDL texture to hold the framebuffer data - texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, - SDL_TEXTUREACCESS_STREAMING, RESOLUTION_X, RESOLUTION_Y); + // Create an SDL texture to hold the framebuffer data + texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STREAMING, RESOLUTION_X, + RESOLUTION_Y); } void GameBoy::SDL2destroy() const { - SDL_DestroyTexture(texture); - SDL_DestroyRenderer(renderer); - SDL_DestroyWindow(screen); - SDL_Quit(); + SDL_DestroyTexture(texture); + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(screen); + SDL_Quit(); } void GameBoy::SDL2present() { - SDL_UpdateTexture(texture, nullptr, framebuffer, RESOLUTION_X * sizeof(uint32_t)); - SDL_RenderClear(renderer); - SDL_RenderCopy(renderer, texture, nullptr, nullptr); + SDL_UpdateTexture(texture, nullptr, framebuffer, + RESOLUTION_X * sizeof(uint32_t)); + SDL_RenderClear(renderer); + SDL_RenderCopy(renderer, texture, nullptr, nullptr); + frameTime = SDL_GetTicks() - frameStart; - frameTime = SDL_GetTicks() - frameStart; + if (frameDelay > frameTime) { + SDL_Delay(frameDelay - frameTime); + } - if (frameDelay > frameTime) { - SDL_Delay(frameDelay - frameTime); - } - - SDL_RenderPresent(renderer); - frameStart = SDL_GetTicks(); - rendered = true; + SDL_RenderPresent(renderer); + frameStart = SDL_GetTicks(); + rendered = true; } diff --git a/src/testing.hpp b/src/testing.hpp index ff45a1c..8733793 100644 --- a/src/testing.hpp +++ b/src/testing.hpp @@ -1,43 +1,39 @@ #ifndef TESTING_HPP #define TESTING_HPP +#include "defines.hpp" #include -#include -#include #include #include #include -#include "defines.hpp" +#include +#include struct GameboyTestState { - Word PC; - Word SP; - Byte A; - Byte F; - Byte B; - Byte C; - Byte D; - Byte E; - Byte H; - Byte L; - //Byte IME; - //Byte IE; - std::vector> RAM; + Word PC; + Word SP; + Byte A; + Byte F; + Byte B; + Byte C; + Byte D; + Byte E; + Byte H; + Byte L; + // Byte IME; + // Byte IE; + std::vector> RAM; }; -inline bool operator==(const GameboyTestState& lhs, const GameboyTestState& rhs) { - for (int i = 0; i < lhs.RAM.size(); i++) { - if (std::get<1>(lhs.RAM[i]) != std::get<1>(rhs.RAM[i])) - return false; - } - return (lhs.A == rhs.A && - lhs.F == rhs.F && - lhs.B == rhs.B && - lhs.C == rhs.C && - lhs.D == rhs.D && - lhs.E == rhs.E && - lhs.H == rhs.H && - lhs.L == rhs.L); +inline bool operator==(const GameboyTestState &lhs, + const GameboyTestState &rhs) { + for (int i = 0; i < lhs.RAM.size(); i++) { + if (std::get<1>(lhs.RAM[i]) != std::get<1>(rhs.RAM[i])) + return false; + } + return (lhs.A == rhs.A && lhs.F == rhs.F && lhs.B == rhs.B && + lhs.C == rhs.C && lhs.D == rhs.D && lhs.E == rhs.E && + lhs.H == rhs.H && lhs.L == rhs.L); } -#endif //TESTING_HPP +#endif // TESTING_HPP diff --git a/src/timing.cpp b/src/timing.cpp index 0837f26..3aa4e7c 100644 --- a/src/timing.cpp +++ b/src/timing.cpp @@ -1,43 +1,45 @@ #include "gameboy.hpp" -//handles most of the behavoir as described here: https://gbdev.io/pandocs/Timer_and_Divider_Registers.html#ff04--div-divider-register +// handles most of the behavoir as described here: +// https://gbdev.io/pandocs/Timer_and_Divider_Registers.html#ff04--div-divider-register void GameBoy::timingHandler() { - //can't do this as we use cycles for PPU timing but this is what should happen - //addressSpace.memoryLayout.DIV = ((cycles / 4) >> 6) & 0xFF; + // can't do this as we use cycles for PPU timing but this is what should + // happen addressSpace.memoryLayout.DIV = ((cycles / 4) >> 6) & 0xFF; - if (cycles - lastDivUpdate >= DIVIDER_REGISTER_FREQ) { - const uint8_t increments = (cycles - lastDivUpdate) / DIVIDER_REGISTER_FREQ; - addressSpace.memoryLayout.DIV += increments; - lastDivUpdate += increments * DIVIDER_REGISTER_FREQ; - } + if (cycles - lastDivUpdate >= DIVIDER_REGISTER_FREQ) { + const uint8_t increments = (cycles - lastDivUpdate) / DIVIDER_REGISTER_FREQ; + addressSpace.memoryLayout.DIV += increments; + lastDivUpdate += increments * DIVIDER_REGISTER_FREQ; + } - //if enabled - uint64_t TIMAFrequency = 0; - if (addressSpace.memoryLayout.TAC & 0x04) { - switch (addressSpace.memoryLayout.TAC & 0x03) { - case 0: - TIMAFrequency = 1024; - break; - case 1: - TIMAFrequency = 16; - break; - case 2: - TIMAFrequency = 64; - break; - case 3: - TIMAFrequency = 256; - break; - } - //if TIMA overflowed and prevTMA != current TMA, use prevTMA (ie use prevTMA regardless) - const int increments = (cycles - lastTIMAUpdate) / TIMAFrequency; - if (cycles - lastTIMAUpdate >= TIMAFrequency) { - if (static_cast(addressSpace.memoryLayout.TIMA) + increments > 255) { - addressSpace.memoryLayout.TIMA = prevTMA + ((addressSpace.memoryLayout.TIMA + increments) % 256); - setInterrupt(TIMER_INTERRUPT); - } - else - addressSpace.memoryLayout.TIMA += increments; - lastTIMAUpdate += increments * TIMAFrequency; - } - } + // if enabled + uint64_t TIMAFrequency = 0; + if (addressSpace.memoryLayout.TAC & 0x04) { + switch (addressSpace.memoryLayout.TAC & 0x03) { + case 0: + TIMAFrequency = 1024; + break; + case 1: + TIMAFrequency = 16; + break; + case 2: + TIMAFrequency = 64; + break; + case 3: + TIMAFrequency = 256; + break; + } + // if TIMA overflowed and prevTMA != current TMA, use prevTMA (ie use + // prevTMA regardless) + const int increments = (cycles - lastTIMAUpdate) / TIMAFrequency; + if (cycles - lastTIMAUpdate >= TIMAFrequency) { + if (static_cast(addressSpace.memoryLayout.TIMA) + increments > 255) { + addressSpace.memoryLayout.TIMA = + prevTMA + ((addressSpace.memoryLayout.TIMA + increments) % 256); + setInterrupt(TIMER_INTERRUPT); + } else + addressSpace.memoryLayout.TIMA += increments; + lastTIMAUpdate += increments * TIMAFrequency; + } + } }