diff --git a/src/defines.hpp b/src/defines.hpp index 2ab5e4e..30e63c2 100644 --- a/src/defines.hpp +++ b/src/defines.hpp @@ -9,7 +9,7 @@ // 6 n - - Add/Sub-Flag (BCD) // 5 h - - Half Carry Flag (BCD) // 4 cy C NC Carry Flag -// 3-0 - - - Not used (always zero) +// 3-0 - - - Not used #define CARRY_FLAG 4 //'C' #define HALFCARRY_FLAG 5 //'H' #define SUBTRACT_FLAG 6 //'N' @@ -21,7 +21,7 @@ #define SERIAL_INTERRUPT 3 #define JOYPAD_INTERRUPT 4 -#define T_CLOCK_FREQ 4194304 +#define T_CLOCK_FREQ 4194304 //2^22 #define DIVIDER_REGISTER_FREQ 16384 @@ -39,13 +39,13 @@ #define MODE2_DURATION 80 #define MODE3_MIN_DURATION 172 #define MODE0_3_DURATION 376 //mode3 is 172 to 289, mode0 87 to 204 -#define MODE1_DURATION 4560 #define H_SYNC 9198 #define V_SYNC 59.73 -#define HBlank_DURATION 204 //GPU_MODE 0 -#define SCANLINE_OAM_FREQ 80 //GPU_MODE 2 -#define SCANLINE_VRAM_FREQ 80 //GPU_MODE 3 +#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 #endif diff --git a/src/gameboy.cpp b/src/gameboy.cpp index 20b5333..15190d3 100644 --- a/src/gameboy.cpp +++ b/src/gameboy.cpp @@ -1,60 +1,50 @@ #include #include "gameboy.hpp" -bool AddressSpace::getBootromState() -{ +bool AddressSpace::getBootromState() { return bootromLoaded; } -void AddressSpace::unmapBootrom() -{ +void AddressSpace::unmapBootrom() { bootromLoaded = false; } -void AddressSpace::mapBootrom() -{ +void AddressSpace::mapBootrom() { bootromLoaded = true; } -void AddressSpace::loadBootrom(std::string filename) -{ +void AddressSpace::loadBootrom(std::string filename) { std::ifstream file; int size = std::filesystem::file_size(filename); - if(size != 256) - { + if (size != 256) { std::cerr << "Bootrom was an unexpected size!\nQuitting!\n" << std::endl; exit(1); } file.open(filename, std::ios::binary); - file.read(reinterpret_cast(bootrom), BOOTROM_SIZE); + file.read(reinterpret_cast(bootrom), BOOTROM_SIZE); } -void AddressSpace::loadGame(std::string filename) -{ +void AddressSpace::loadGame(std::string filename) { game.open(filename, std::ios::binary); - if(!game.is_open()) - { + if (!game.is_open()) { std::cerr << "Game was not found!\nQuitting!\n" << std::endl; exit(1); } - game.read(reinterpret_cast(memoryLayout.romBank1), ROM_BANK_SIZE*2); + game.read(reinterpret_cast(memoryLayout.romBank1), ROM_BANK_SIZE * 2); } -void GameBoy::addCycles(uint8_t ticks) -{ - cycles = (cycles+ticks) % T_CLOCK_FREQ; +void GameBoy::addCycles(uint8_t ticks) { + cycles = (cycles + ticks) % T_CLOCK_FREQ; lastOpTicks = ticks; } -void GameBoy::start(std::string bootrom, std::string game) -{ +void GameBoy::start(std::string bootrom, std::string game) { addressSpace.loadBootrom(bootrom); addressSpace.loadGame(game); bool quit = false; - while(!quit) - { + while (!quit) { // Event loop: Check and handle SDL events // if(SDL_PollEvent(&event)) // { @@ -68,16 +58,13 @@ void GameBoy::start(std::string bootrom, std::string game) interruptHandler(); //timing(); ppuUpdate(); - if(PC > 0xFF && addressSpace.getBootromState()) - { + if (PC > 0xFF && addressSpace.getBootromState()) { addressSpace.unmapBootrom(); } int cyclesSince = cyclesSinceLastRefresh(); - if(cyclesSince > FRAME_DURATION) - { + if (cyclesSince > FRAME_DURATION) { lastRefresh = cycles; SDL2present(); } } } - diff --git a/src/gameboy.hpp b/src/gameboy.hpp index 6774e9a..2526394 100644 --- a/src/gameboy.hpp +++ b/src/gameboy.hpp @@ -11,66 +11,59 @@ #include "defines.hpp" //two bits per colour -enum Colour -{ +enum Colour { black = 0b11, darkGray = 0b10, lightGray = 0b01, white = 0b00 }; -enum PPUMode -{ +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. + mode3 // Pixel Transfer (Mode 3): Access to both OAM and video RAM, actual pixel transfer to the screen. }; -union RegisterPair -{ +union RegisterPair { Word reg; //register.reg == (hi << 8) + lo. (hi is more significant than lo) - struct - { + struct { Byte lo; Byte hi; }; }; -class AddressSpace -{ - private: +class AddressSpace { +private: bool bootromLoaded = true; Byte bootrom[BOOTROM_SIZE]; std::ifstream game; - public: - AddressSpace() - { +public: + AddressSpace() { // Initialize the memory to zero memoryLayout = {}; std::memset(memoryLayout.memory, 0, sizeof(memoryLayout.memory)); } // Nested union for the memory layout - union MemoryLayout - { + union MemoryLayout { Byte memory[0x10000]; - struct - { - Byte romBank1[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 echoRam[0x1E00]; // Mapped to 0xE000 (Echo RAM, mirrors 0xC000 to 0xDFFF) + + struct { + Byte romBank1[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 echoRam[0x1E00]; // Mapped to 0xE000 (Echo RAM, mirrors 0xC000 to 0xDFFF) Byte spriteAttributeTable[0xA0]; // Mapped to 0xFE00 - Byte notUsable[0x60]; // Mapped to 0xFEA0 - Byte io[0x80]; // Mapped to 0xFF00, 0xFF0F is interrupt flag - Byte specialRam[0x7F]; // Mapped to 0xFF80 - Byte interuptEnableReg; // Mapped to 0xFFFF + Byte notUsable[0x60]; // Mapped to 0xFEA0 + Byte io[0x80]; // Mapped to 0xFF00, 0xFF0F is interrupt flag + Byte specialRam[0x7F]; // Mapped to 0xFF80 + Byte interuptEnableReg; // Mapped to 0xFFFF }; } memoryLayout; @@ -81,20 +74,19 @@ class AddressSpace void loadGame(std::string filename); //overload [] for echo ram and bootrom support - Byte operator[](uint32_t address) const - { - if(address >= 0xE000 && address < 0xFE00) + Byte operator[](uint32_t address) const { + if (address >= 0xE000 && address < 0xFE00) return memoryLayout.echoRam[address - 0xE000]; - if(address < 0x0100 && bootromLoaded) + if (address < 0x0100 && bootromLoaded) return bootrom[address]; else return memoryLayout.memory[address]; } - Byte& operator[](uint32_t address) - { - if(address >= 0xE000 && address < 0xFE00) + + Byte& operator[](uint32_t address) { + if (address >= 0xE000 && address < 0xFE00) return memoryLayout.echoRam[address - 0xE000]; - if(address < 0x0100 && bootromLoaded) + if (address < 0x0100 && bootromLoaded) return bootrom[address]; else return memoryLayout.memory[address]; @@ -102,7 +94,7 @@ class AddressSpace }; class GameBoy { - private: +private: uint32_t cycles = 0; uint32_t lastOpTicks = 0; uint32_t lastRefresh = 0; @@ -181,10 +173,10 @@ class GameBoy { PPUMode currentMode; //3 colour channels - uint32_t* framebuffer = new uint32_t[RESOLUTION_X*RESOLUTION_Y*SCREEN_BPP]; - SDL_Window *screen; - SDL_Renderer *renderer; - SDL_Texture *texture; + uint32_t* framebuffer = new uint32_t[RESOLUTION_X * RESOLUTION_Y * SCREEN_BPP]; + SDL_Window* screen; + SDL_Renderer* renderer; + SDL_Texture* texture; SDL_Event event; void opcodeHandler(); @@ -220,56 +212,56 @@ class GameBoy { void addCycles(Byte ticks); //OPCODE FUNCTIONS - template + template void ld(T& dest, T src); - template - void orBitwise(T &dest, T src); - template - void andBitwise(T &dest, T src); - template + template + void orBitwise(T& dest, T src); + template + void andBitwise(T& dest, T src); + template void xorBitwise(T& dest, T src); - template + template void bit(T testBit, T reg); - template + template void jp(T address); - template + template bool jrNZ(T offset); - template + template void inc(T& reg); - template + template void call(T address); void halt(); void stop(); - template + template void ldW(T dest, T src); - template + template void cp(T value); - template + template void dec(T& reg); - template + template bool jrZ(T offset); - template + template void sub(T value); - template + template void jr(T OFFSET); - template + template void push(T reg); - template + template void rl(T& reg); - template + template void pop(T& reg); - template + template void rla(T& reg); - template + template void rst(T address); void ret(); - template + template void add(T& reg, T value); void cpl(); void ccf(); - void swap(Byte &value); + void swap(Byte& value); - public: +public: void start(std::string bootrom, std::string game); void SDL2setup(); void SDL2destroy(); diff --git a/src/interupts.cpp b/src/interupts.cpp index 6696afc..2b1a2f1 100644 --- a/src/interupts.cpp +++ b/src/interupts.cpp @@ -1,35 +1,31 @@ #include "defines.hpp" #include "gameboy.hpp" -bool GameBoy::testInterruptEnabled(Byte interrupt) -{ - return (*IE) & (Byte) (1 << interrupt); +bool GameBoy::testInterruptEnabled(Byte interrupt) { + return (*IE) & (Byte)(1 << interrupt); } -void GameBoy::resetInterrupt(Byte interrupt) -{ +void GameBoy::resetInterrupt(Byte interrupt) { *IF &= ~(1 << interrupt); } -void GameBoy::interruptHandler() -{ - if(!IME) +void GameBoy::interruptHandler() { + if (!IME) return; - if(*IF & (Byte) (1 << VBLANK_INTERRUPT) && testInterruptEnabled(VBLANK_INTERRUPT)) + if (*IF & (Byte)(1 << VBLANK_INTERRUPT) && testInterruptEnabled(VBLANK_INTERRUPT)) VBlankHandle(); - if(*IF & (Byte) (1 << LCD_STAT_INTERRUPT) && testInterruptEnabled(LCD_STAT_INTERRUPT)) + if (*IF & (Byte)(1 << LCD_STAT_INTERRUPT) && testInterruptEnabled(LCD_STAT_INTERRUPT)) LCDStatHandle(); - if(*IF & (Byte) (1 << TIMER_INTERRUPT) && testInterruptEnabled(TIMER_INTERRUPT)) + if (*IF & (Byte)(1 << TIMER_INTERRUPT) && testInterruptEnabled(TIMER_INTERRUPT)) timerHandle(); - if(*IF & (Byte) (1 << SERIAL_INTERRUPT) && testInterruptEnabled(SERIAL_INTERRUPT)) + if (*IF & (Byte)(1 << SERIAL_INTERRUPT) && testInterruptEnabled(SERIAL_INTERRUPT)) serialHandle(); - if(*IF & (Byte) (1 << JOYPAD_INTERRUPT) && testInterruptEnabled(JOYPAD_INTERRUPT)) + if (*IF & (Byte)(1 << JOYPAD_INTERRUPT) && testInterruptEnabled(JOYPAD_INTERRUPT)) joypadHandle(); } -void GameBoy::VBlankHandle() -{ +void GameBoy::VBlankHandle() { printf("VBlank interrupt"); IME = 0; push(PC); @@ -37,8 +33,7 @@ void GameBoy::VBlankHandle() resetInterrupt(VBLANK_INTERRUPT); } -void GameBoy::LCDStatHandle() -{ +void GameBoy::LCDStatHandle() { printf("LCD stat interrupt"); IME = 0; push(PC); @@ -47,8 +42,7 @@ void GameBoy::LCDStatHandle() resetInterrupt(LCD_STAT_INTERRUPT); } -void GameBoy::timerHandle() -{ +void GameBoy::timerHandle() { printf("timer interrupt"); IME = 0; push(PC); @@ -57,8 +51,7 @@ void GameBoy::timerHandle() resetInterrupt(TIMER_INTERRUPT); } -void GameBoy::serialHandle() -{ +void GameBoy::serialHandle() { printf("serial interrupt"); IME = 0; push(PC); @@ -67,12 +60,11 @@ void GameBoy::serialHandle() resetInterrupt(SERIAL_INTERRUPT); } -void GameBoy::joypadHandle() -{ +void GameBoy::joypadHandle() { printf("joypad interrupt"); IME = 0; push(PC); addCycles(16); PC = 0x60; resetInterrupt(JOYPAD_INTERRUPT); -} \ No newline at end of file +} diff --git a/src/main.cpp b/src/main.cpp index a2082c6..b1a90de 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,8 +1,7 @@ #include #include "gameboy.hpp" -int main(int argc, char** argv) -{ +int main(int argc, char** argv) { auto* gb = new GameBoy(); gb->SDL2setup(); gb->start("../bootrom.bin", "../roms/DrMario.gb"); diff --git a/src/opcode.cpp b/src/opcode.cpp index 6abf06e..d9397e3 100644 --- a/src/opcode.cpp +++ b/src/opcode.cpp @@ -1,22 +1,18 @@ #include "gameboy.hpp" -void GameBoy::setFlag(Byte bit) -{ +void GameBoy::setFlag(Byte bit) { AF.lo |= (1 << bit); } -void GameBoy::resetFlag(Byte bit) -{ +void GameBoy::resetFlag(Byte bit) { AF.lo &= ~(1 << bit); } -bool GameBoy::getFlag(Byte bit) const -{ +bool GameBoy::getFlag(Byte bit) const { return (AF.lo >> bit) & 1; } -Word GameBoy::getWordPC() -{ +Word GameBoy::getWordPC() { RegisterPair word; //remember little endianness @@ -26,13 +22,11 @@ Word GameBoy::getWordPC() return word.reg; } -Byte GameBoy::getBytePC() -{ +Byte GameBoy::getBytePC() { return addressSpace[PC + 1]; } -Word GameBoy::getWordSP() -{ +Word GameBoy::getWordSP() { RegisterPair word; //remember little endianness @@ -42,35 +36,29 @@ Word GameBoy::getWordSP() return word.reg; } -Byte GameBoy::getByteSP() -{ +Byte GameBoy::getByteSP() { return addressSpace[SP++]; } -void GameBoy::ret() -{ +void GameBoy::ret() { pop(PC); } -template -void GameBoy::ld(T &dest, T src) -{ +template +void GameBoy::ld(T& dest, T src) { dest = src; } -template -void GameBoy::ldW(T dest, T src) -{ - if(sizeof(src) == sizeof(Word)) - { - addressSpace[dest] = (Byte) (src & 0xFF00) >> 8; - addressSpace[dest + 1] = (Byte) (src & 0xFF); +template +void GameBoy::ldW(T dest, T src) { + if (sizeof(src) == sizeof(Word)) { + addressSpace[dest] = (Byte)(src & 0xFF00) >> 8; + addressSpace[dest + 1] = (Byte)(src & 0xFF); } } -template -void GameBoy::rla(T ®) -{ +template +void GameBoy::rla(T& reg) { //printf("0x%.2x\n", REG); //printf("%d\n", GET_FLAG(CARRY_FLAG)); bool carry; @@ -78,17 +66,17 @@ void GameBoy::rla(T ®) //printf("\n0x%x\n", REG); //printf("0x%x\n\n", REG & ((T)1 << 7)); - if(reg & (1 << 7)) + if (reg & (1 << 7)) carry = true; else carry = false; reg <<= 1; - if(getFlag(CARRY_FLAG)) + if (getFlag(CARRY_FLAG)) reg += 1; - if(carry) + if (carry) setFlag(CARRY_FLAG); else resetFlag(CARRY_FLAG); @@ -98,32 +86,29 @@ void GameBoy::rla(T ®) resetFlag(HALFCARRY_FLAG); } -template -void GameBoy::add(T ®, T value) -{ - if(sizeof(reg) == sizeof(Byte)) - { +template +void GameBoy::add(T& reg, T value) { + if (sizeof(reg) == sizeof(Byte)) { //halfcarry test https://robdor.com/2016/08/10/gameboy-emulator-half-carry-flag/ - if((((value & 0xF) + (reg & 0xF)) & 0x10) == 0x10) + if ((((value & 0xF) + (reg & 0xF)) & 0x10) == 0x10) setFlag(HALFCARRY_FLAG); else resetFlag(HALFCARRY_FLAG); //halfcarry test https://robdor.com/2016/08/10/gameboy-emulator-half-carry-flag/ - if((((value & 0xFF) + (reg & 0xFF)) & 0x100) == 0x100) + if ((((value & 0xFF) + (reg & 0xFF)) & 0x100) == 0x100) setFlag(CARRY_FLAG); else resetFlag(CARRY_FLAG); } - if(sizeof(reg) == sizeof(Word)) - { + if (sizeof(reg) == sizeof(Word)) { //halfcarry test https://robdor.com/2016/08/10/gameboy-emulator-half-carry-flag/ - if((((value & 0xFFF) + (reg & 0xFFF)) & 0x1000) == 0x1000) + if ((((value & 0xFFF) + (reg & 0xFFF)) & 0x1000) == 0x1000) setFlag(HALFCARRY_FLAG); else resetFlag(HALFCARRY_FLAG); //halfcarry test https://robdor.com/2016/08/10/gameboy-emulator-half-carry-flag/ - if((((value & 0xFFFF) + (reg & 0xFFFF)) & 0x10000) == 0x10000) + if ((((value & 0xFFFF) + (reg & 0xFFFF)) & 0x10000) == 0x10000) setFlag(CARRY_FLAG); else resetFlag(CARRY_FLAG); @@ -131,21 +116,19 @@ void GameBoy::add(T ®, T value) reg += value; - if(reg == 0) + if (reg == 0) setFlag(ZERO_FLAG); else resetFlag(ZERO_FLAG); resetFlag(SUBTRACT_FLAG); - } -template -void GameBoy::orBitwise(T &dest, T src) -{ +template +void GameBoy::orBitwise(T& dest, T src) { dest |= src; - if(dest == 0) + if (dest == 0) setFlag(ZERO_FLAG); resetFlag(SUBTRACT_FLAG); @@ -153,12 +136,11 @@ void GameBoy::orBitwise(T &dest, T src) resetFlag(CARRY_FLAG); } -template -void GameBoy::andBitwise(T &dest, T src) -{ +template +void GameBoy::andBitwise(T& dest, T src) { dest &= src; - if(dest == 0) + if (dest == 0) setFlag(ZERO_FLAG); resetFlag(SUBTRACT_FLAG); @@ -166,12 +148,11 @@ void GameBoy::andBitwise(T &dest, T src) resetFlag(CARRY_FLAG); } -template -void GameBoy::xorBitwise(T &dest, T src) -{ +template +void GameBoy::xorBitwise(T& dest, T src) { dest ^= src; - if(dest == 0) + if (dest == 0) setFlag(ZERO_FLAG); resetFlag(SUBTRACT_FLAG); @@ -179,12 +160,11 @@ void GameBoy::xorBitwise(T &dest, T src) resetFlag(HALFCARRY_FLAG); } -template -void GameBoy::bit(T testBit, T reg) -{ - Byte result = reg & (T) (1 << testBit); +template +void GameBoy::bit(T testBit, T reg) { + Byte result = reg & (T)(1 << testBit); - if(result == 0) + if (result == 0) setFlag(ZERO_FLAG); else resetFlag(ZERO_FLAG); @@ -193,27 +173,24 @@ void GameBoy::bit(T testBit, T reg) setFlag(HALFCARRY_FLAG); } -template -bool GameBoy::jrNZ(T offset) -{ +template +bool GameBoy::jrNZ(T offset) { bool jumped = false; - if(!getFlag(ZERO_FLAG)) //if not set + if (!getFlag(ZERO_FLAG)) //if not set { - PC += (int8_t) offset + 2; //PC moves 2 from the original instruction + PC += (int8_t)offset + 2; //PC moves 2 from the original instruction jumped = true; } return jumped; } -template -void GameBoy::inc(T ®) -{ +template +void GameBoy::inc(T& reg) { reg++; - if(sizeof(reg) == sizeof(Byte)) - { - if(reg == 0) + if (sizeof(reg) == sizeof(Byte)) { + if (reg == 0) setFlag(ZERO_FLAG); else resetFlag(ZERO_FLAG); @@ -221,31 +198,27 @@ void GameBoy::inc(T ®) resetFlag(SUBTRACT_FLAG); //halfcarry test https://robdor.com/2016/08/10/gameboy-emulator-half-carry-flag/ - if(((((reg - 1) & 0xf) + (reg & 0xf)) & 0x10) == 0x10) + if (((((reg - 1) & 0xf) + (reg & 0xf)) & 0x10) == 0x10) setFlag(HALFCARRY_FLAG); else resetFlag(HALFCARRY_FLAG); - } } -template -void GameBoy::call(T address) -{ +template +void GameBoy::call(T address) { push(PC + 3); PC = address; } -template +template void GameBoy::cp(T value) //compare { - if(AF.hi < value) - { + if (AF.hi < value) { setFlag(CARRY_FLAG); resetFlag(ZERO_FLAG); } - else if(AF.hi == value) - { + else if (AF.hi == value) { setFlag(ZERO_FLAG); resetFlag(CARRY_FLAG); } @@ -253,21 +226,18 @@ void GameBoy::cp(T value) //compare setFlag(SUBTRACT_FLAG); //halfcarry test https://www.reddit.com/r/EmuDev/comments/4clh23/trouble_with_halfcarrycarry_flag/ - if(0 > (((AF.hi) & 0xf) - (value & 0xf))) + if (0 > (((AF.hi) & 0xf) - (value & 0xf))) setFlag(HALFCARRY_FLAG); else resetFlag(HALFCARRY_FLAG); - } -template -void GameBoy::dec(T ®) -{ +template +void GameBoy::dec(T& reg) { reg -= 1; - if(sizeof(reg) == sizeof(Byte)) - { - if(reg == 0) + if (sizeof(reg) == sizeof(Byte)) { + if (reg == 0) setFlag(ZERO_FLAG); else resetFlag(ZERO_FLAG); @@ -275,37 +245,33 @@ void GameBoy::dec(T ®) setFlag(SUBTRACT_FLAG); //halfcarry test https://www.reddit.com/r/EmuDev/comments/4clh23/trouble_with_halfcarrycarry_flag/ - if(0 > (((reg + 1) & 0xf) - (reg & 0xf))) + if (0 > (((reg + 1) & 0xf) - (reg & 0xf))) setFlag(HALFCARRY_FLAG); else resetFlag(HALFCARRY_FLAG); - } - } -template -bool GameBoy::jrZ(T offset) -{ +template +bool GameBoy::jrZ(T offset) { bool jumped = false; - if(getFlag(ZERO_FLAG)) //if not set + if (getFlag(ZERO_FLAG)) //if not set { - PC += (int8_t) offset + 2; //PC moves 2 from the original instruction + PC += (int8_t)offset + 2; //PC moves 2 from the original instruction jumped = true; } return jumped; } -void GameBoy::swap(Byte &value) -{ +void GameBoy::swap(Byte& value) { // Extract the lower and upper nibbles of the register Byte lowerNibble = value & 0x0F; Byte upperNibble = (value >> 4) & 0x0F; // Swap the lower and upper nibbles value = (lowerNibble << 4) | upperNibble; - if(value == 0) + if (value == 0) setFlag(ZERO_FLAG); else resetFlag(ZERO_FLAG); @@ -315,21 +281,15 @@ void GameBoy::swap(Byte &value) resetFlag(CARRY_FLAG); } -void GameBoy::halt() -{ +void GameBoy::halt() {} -} - -template -void GameBoy::sub(T value) -{ - if(AF.hi < value) - { +template +void GameBoy::sub(T value) { + if (AF.hi < value) { setFlag(CARRY_FLAG); resetFlag(ZERO_FLAG); } - else if(AF.hi == value) - { + else if (AF.hi == value) { setFlag(ZERO_FLAG); resetFlag(CARRY_FLAG); } @@ -338,61 +298,51 @@ void GameBoy::sub(T value) setFlag(SUBTRACT_FLAG); //halfcarry test https://www.reddit.com/r/EmuDev/comments/4clh23/trouble_with_halfcarrycarry_flag/ - if(0 > (((AF.hi) & 0xf) - (value & 0xf))) + if (0 > (((AF.hi) & 0xf) - (value & 0xf))) setFlag(HALFCARRY_FLAG); else resetFlag(HALFCARRY_FLAG); - } -template -void GameBoy::jr(T offset) -{ - PC += (int8_t) offset + 2; //PC moves 2 from original instruction +template +void GameBoy::jr(T offset) { + PC += (int8_t)offset + 2; //PC moves 2 from original instruction } -template -void GameBoy::rl(T ®) -{ - //printf("0x%.2x\n", REG); - //printf("%d\n", GET_FLAG(CARRY_FLAG)); +template +void GameBoy::rl(T& reg) { bool carry; - //printf("\n0x%x\n", REG); - //printf("0x%x\n\n", REG & ((T)1 << 7)); - - if(reg & (1 << 7)) + if (reg & (1 << 7)) carry = true; else carry = false; reg <<= 1; - if(getFlag(CARRY_FLAG)) + if (getFlag(CARRY_FLAG)) reg += 1; - if(carry) + if (carry) setFlag(CARRY_FLAG); else resetFlag(CARRY_FLAG); - if(reg == 0) + if (reg == 0) setFlag(ZERO_FLAG); resetFlag(SUBTRACT_FLAG); resetFlag(HALFCARRY_FLAG); } -template -void GameBoy::pop(T ®) -{ +template +void GameBoy::pop(T& reg) { reg = getWordSP(); } -template -void GameBoy::push(T reg) -{ +template +void GameBoy::push(T reg) { //little endian RegisterPair temp; temp.lo = reg & 0xFF; @@ -403,57 +353,47 @@ void GameBoy::push(T reg) addressSpace[SP] = temp.lo; } -template -void GameBoy::jp(T address) -{ +template +void GameBoy::jp(T address) { PC = address; } -template -void GameBoy::rst(T address) -{ +template +void GameBoy::rst(T address) { push(PC); PC = address; } -void GameBoy::cpl() -{ +void GameBoy::cpl() { AF.hi = ~AF.hi; setFlag(SUBTRACT_FLAG); setFlag(HALFCARRY_FLAG); } -void GameBoy::ccf() -{ +void GameBoy::ccf() { resetFlag(SUBTRACT_FLAG); resetFlag(HALFCARRY_FLAG); - if(getFlag(CARRY_FLAG)) + if (getFlag(CARRY_FLAG)) resetFlag(CARRY_FLAG); else setFlag(CARRY_FLAG); } -void GameBoy::stop() -{ -} +void GameBoy::stop() {} -void GameBoy::opcodeHandler() -{ +void GameBoy::opcodeHandler() { bool jumped; - if(addressSpace[PC] != 0xCB) - { + if (addressSpace[PC] != 0xCB) { //printf("PC:0x%.2x, Opcode:0x%.2x\n", PC, addressSpace[PC]); - if(PC == 0x100) - { + if (PC == 0x100) { printf("LY:0x%.2x\n", (*LY)); // printf("PC:0x%.2x, Opcode:0x%.2x\n", PC, addressSpace[PC]); // printf("IME:%b IF:0x%.2x IE:0x%.2x\n", IME, (*IF), (*IE)); } //printf("IME:%b IF:0x%.2x IE:0x%.2x\n", IME, (*IF), (*IE)); - switch(addressSpace[PC]) - { + switch (addressSpace[PC]) { case 0x00: //NOP PC += 1; @@ -630,12 +570,10 @@ void GameBoy::opcodeHandler() case 0x20: jumped = jrNZ(getBytePC()); - if(jumped) - { + if (jumped) { addCycles(12); } - else - { + else { PC += 2; addCycles(8); } @@ -674,12 +612,10 @@ void GameBoy::opcodeHandler() case 0x28: jumped = jrZ(getBytePC()); - if(jumped) - { + if (jumped) { addCycles(12); } - else - { + else { PC += 2; addCycles(8); } @@ -1457,13 +1393,11 @@ void GameBoy::opcodeHandler() break; case 0xC0: //RET NZ - if(!getFlag(ZERO_FLAG)) - { + if (!getFlag(ZERO_FLAG)) { ret(); addCycles(20); } - else - { + else { addCycles(8); PC += 1; } @@ -1476,13 +1410,11 @@ void GameBoy::opcodeHandler() break; case 0xC2: - if(!getFlag(ZERO_FLAG)) - { + if (!getFlag(ZERO_FLAG)) { jp(getWordPC()); addCycles(16); } - else - { + else { addCycles(12); PC += 3; } @@ -1494,13 +1426,11 @@ void GameBoy::opcodeHandler() break; case 0xC4: - if(!getFlag(ZERO_FLAG)) - { + if (!getFlag(ZERO_FLAG)) { call(getWordPC()); addCycles(24); } - else - { + else { addCycles(12); PC += 3; } @@ -1513,17 +1443,15 @@ void GameBoy::opcodeHandler() break; case 0xC8: - if(getFlag(ZERO_FLAG)) - { + if (getFlag(ZERO_FLAG)) { ret(); addCycles(20); } - else - { + else { addCycles(8); PC += 1; } - break; + break; case 0xC9: ret(); @@ -1531,26 +1459,22 @@ void GameBoy::opcodeHandler() break; case 0xCA: - if(getFlag(ZERO_FLAG)) - { + if (getFlag(ZERO_FLAG)) { jp(getWordPC()); addCycles(16); } - else - { + else { addCycles(12); PC += 3; } break; case 0xCC: - if(getFlag(ZERO_FLAG)) - { + if (getFlag(ZERO_FLAG)) { call(getWordPC()); addCycles(24); } - else - { + else { addCycles(12); PC += 3; } @@ -1567,13 +1491,11 @@ void GameBoy::opcodeHandler() break; case 0xD0: //RET NC - if(!getFlag(CARRY_FLAG)) - { + if (!getFlag(CARRY_FLAG)) { ret(); addCycles(20); } - else - { + else { addCycles(8); PC += 3; } @@ -1586,26 +1508,22 @@ void GameBoy::opcodeHandler() break; case 0xD2: - if(!getFlag(CARRY_FLAG)) - { + if (!getFlag(CARRY_FLAG)) { jp(getWordPC()); addCycles(24); } - else - { + else { addCycles(12); PC += 3; } break; case 0xD4: - if(!getFlag(CARRY_FLAG)) - { + if (!getFlag(CARRY_FLAG)) { call(getWordPC()); addCycles(24); } - else - { + else { addCycles(12); PC += 3; } @@ -1618,13 +1536,11 @@ void GameBoy::opcodeHandler() break; case 0xD8: - if(getFlag(CARRY_FLAG)) - { + if (getFlag(CARRY_FLAG)) { ret(); addCycles(20); } - else - { + else { addCycles(8); PC += 1; } @@ -1638,26 +1554,22 @@ void GameBoy::opcodeHandler() break; case 0xDA: - if(getFlag(CARRY_FLAG)) - { + if (getFlag(CARRY_FLAG)) { jp(getWordPC()); addCycles(16); } - else - { + else { addCycles(12); PC += 3; } break; case 0xDC: - if(getFlag(CARRY_FLAG)) - { + if (getFlag(CARRY_FLAG)) { call(getWordPC()); addCycles(24); } - else - { + else { addCycles(12); PC += 3; } @@ -1698,11 +1610,11 @@ void GameBoy::opcodeHandler() addCycles(8); break; -// case 0xE8: -// SP += (int8_t)getByte(); -// PC += 2; -// addCycles(16); -// break; + // case 0xE8: + // SP += (int8_t)getByte(); + // PC += 2; + // addCycles(16); + // break; case 0xE9: jp(HL.reg); @@ -1773,7 +1685,6 @@ void GameBoy::opcodeHandler() printf("Unimplemented opcode found: PC:0x%.2x, Opcode:0x%.2x\n", PC, addressSpace[PC]); exit(1); } - } else //extension { @@ -1782,8 +1693,7 @@ void GameBoy::opcodeHandler() addCycles(4); //extension handler - switch(addressSpace[PC]) - { + switch (addressSpace[PC]) { case 0x11: rl(BC.lo); PC += 1; @@ -1839,7 +1749,7 @@ void GameBoy::opcodeHandler() break; case 0x7C: - bit((Byte) 7, HL.hi); + bit((Byte)7, HL.hi); PC += 1; addCycles(8); break; diff --git a/src/ppu.cpp b/src/ppu.cpp index 6bcd9f8..1622ddc 100644 --- a/src/ppu.cpp +++ b/src/ppu.cpp @@ -4,7 +4,7 @@ #include void GameBoy::ppuUpdate() { - //test HBlank + //test for HBlank checkPPUMode(); if (cyclesToStayInHblank != -1) { @@ -53,7 +53,8 @@ void GameBoy::ppuUpdate() { // bug on DMG models triggers a STAT interrupt anytime the STAT register is written // Road Rage and Zerd no Denetsu rely on this (*STAT) |= (1 << 2); - } else { + } + else { (*STAT) &= ~(1 << 2); } @@ -96,7 +97,8 @@ void GameBoy::checkPPUMode() { setPPUMode(PPUMode::mode3); else setPPUMode(PPUMode::mode0); - } else { + } + else { // VBlank Period setPPUMode(PPUMode::mode1); }