reformatting
This commit is contained in:
@@ -9,7 +9,7 @@
|
|||||||
// 6 n - - Add/Sub-Flag (BCD)
|
// 6 n - - Add/Sub-Flag (BCD)
|
||||||
// 5 h - - Half Carry Flag (BCD)
|
// 5 h - - Half Carry Flag (BCD)
|
||||||
// 4 cy C NC Carry Flag
|
// 4 cy C NC Carry Flag
|
||||||
// 3-0 - - - Not used (always zero)
|
// 3-0 - - - Not used
|
||||||
#define CARRY_FLAG 4 //'C'
|
#define CARRY_FLAG 4 //'C'
|
||||||
#define HALFCARRY_FLAG 5 //'H'
|
#define HALFCARRY_FLAG 5 //'H'
|
||||||
#define SUBTRACT_FLAG 6 //'N'
|
#define SUBTRACT_FLAG 6 //'N'
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
#define SERIAL_INTERRUPT 3
|
#define SERIAL_INTERRUPT 3
|
||||||
#define JOYPAD_INTERRUPT 4
|
#define JOYPAD_INTERRUPT 4
|
||||||
|
|
||||||
#define T_CLOCK_FREQ 4194304
|
#define T_CLOCK_FREQ 4194304 //2^22
|
||||||
|
|
||||||
#define DIVIDER_REGISTER_FREQ 16384
|
#define DIVIDER_REGISTER_FREQ 16384
|
||||||
|
|
||||||
@@ -39,13 +39,13 @@
|
|||||||
#define MODE2_DURATION 80
|
#define MODE2_DURATION 80
|
||||||
#define MODE3_MIN_DURATION 172
|
#define MODE3_MIN_DURATION 172
|
||||||
#define MODE0_3_DURATION 376 //mode3 is 172 to 289, mode0 87 to 204
|
#define MODE0_3_DURATION 376 //mode3 is 172 to 289, mode0 87 to 204
|
||||||
#define MODE1_DURATION 4560
|
|
||||||
|
|
||||||
#define H_SYNC 9198
|
#define H_SYNC 9198
|
||||||
#define V_SYNC 59.73
|
#define V_SYNC 59.73
|
||||||
#define HBlank_DURATION 204 //GPU_MODE 0
|
#define HBLANK_DURATION 204 //PPU_MODE 0
|
||||||
#define SCANLINE_OAM_FREQ 80 //GPU_MODE 2
|
#define VBLANK_DURATION 4560
|
||||||
#define SCANLINE_VRAM_FREQ 80 //GPU_MODE 3
|
#define SCANLINE_OAM_FREQ 80 //PPU_MODE 2
|
||||||
|
#define SCANLINE_VRAM_FREQ 80 //PPU_MODE 3
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,27 +1,22 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "gameboy.hpp"
|
#include "gameboy.hpp"
|
||||||
|
|
||||||
bool AddressSpace::getBootromState()
|
bool AddressSpace::getBootromState() {
|
||||||
{
|
|
||||||
return bootromLoaded;
|
return bootromLoaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddressSpace::unmapBootrom()
|
void AddressSpace::unmapBootrom() {
|
||||||
{
|
|
||||||
bootromLoaded = false;
|
bootromLoaded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddressSpace::mapBootrom()
|
void AddressSpace::mapBootrom() {
|
||||||
{
|
|
||||||
bootromLoaded = true;
|
bootromLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddressSpace::loadBootrom(std::string filename)
|
void AddressSpace::loadBootrom(std::string filename) {
|
||||||
{
|
|
||||||
std::ifstream file;
|
std::ifstream file;
|
||||||
int size = std::filesystem::file_size(filename);
|
int size = std::filesystem::file_size(filename);
|
||||||
if(size != 256)
|
if (size != 256) {
|
||||||
{
|
|
||||||
std::cerr << "Bootrom was an unexpected size!\nQuitting!\n" << std::endl;
|
std::cerr << "Bootrom was an unexpected size!\nQuitting!\n" << std::endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@@ -29,32 +24,27 @@ void AddressSpace::loadBootrom(std::string filename)
|
|||||||
file.read(reinterpret_cast<char*>(bootrom), BOOTROM_SIZE);
|
file.read(reinterpret_cast<char*>(bootrom), BOOTROM_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddressSpace::loadGame(std::string filename)
|
void AddressSpace::loadGame(std::string filename) {
|
||||||
{
|
|
||||||
game.open(filename, std::ios::binary);
|
game.open(filename, std::ios::binary);
|
||||||
|
|
||||||
if(!game.is_open())
|
if (!game.is_open()) {
|
||||||
{
|
|
||||||
std::cerr << "Game was not found!\nQuitting!\n" << std::endl;
|
std::cerr << "Game was not found!\nQuitting!\n" << std::endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
game.read(reinterpret_cast<char*>(memoryLayout.romBank1), ROM_BANK_SIZE * 2);
|
game.read(reinterpret_cast<char*>(memoryLayout.romBank1), ROM_BANK_SIZE * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameBoy::addCycles(uint8_t ticks)
|
void GameBoy::addCycles(uint8_t ticks) {
|
||||||
{
|
|
||||||
cycles = (cycles + ticks) % T_CLOCK_FREQ;
|
cycles = (cycles + ticks) % T_CLOCK_FREQ;
|
||||||
lastOpTicks = ticks;
|
lastOpTicks = ticks;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameBoy::start(std::string bootrom, std::string game)
|
void GameBoy::start(std::string bootrom, std::string game) {
|
||||||
{
|
|
||||||
addressSpace.loadBootrom(bootrom);
|
addressSpace.loadBootrom(bootrom);
|
||||||
addressSpace.loadGame(game);
|
addressSpace.loadGame(game);
|
||||||
|
|
||||||
bool quit = false;
|
bool quit = false;
|
||||||
while(!quit)
|
while (!quit) {
|
||||||
{
|
|
||||||
// Event loop: Check and handle SDL events
|
// Event loop: Check and handle SDL events
|
||||||
// if(SDL_PollEvent(&event))
|
// if(SDL_PollEvent(&event))
|
||||||
// {
|
// {
|
||||||
@@ -68,16 +58,13 @@ void GameBoy::start(std::string bootrom, std::string game)
|
|||||||
interruptHandler();
|
interruptHandler();
|
||||||
//timing();
|
//timing();
|
||||||
ppuUpdate();
|
ppuUpdate();
|
||||||
if(PC > 0xFF && addressSpace.getBootromState())
|
if (PC > 0xFF && addressSpace.getBootromState()) {
|
||||||
{
|
|
||||||
addressSpace.unmapBootrom();
|
addressSpace.unmapBootrom();
|
||||||
}
|
}
|
||||||
int cyclesSince = cyclesSinceLastRefresh();
|
int cyclesSince = cyclesSinceLastRefresh();
|
||||||
if(cyclesSince > FRAME_DURATION)
|
if (cyclesSince > FRAME_DURATION) {
|
||||||
{
|
|
||||||
lastRefresh = cycles;
|
lastRefresh = cycles;
|
||||||
SDL2present();
|
SDL2present();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,54 +11,47 @@
|
|||||||
#include "defines.hpp"
|
#include "defines.hpp"
|
||||||
|
|
||||||
//two bits per colour
|
//two bits per colour
|
||||||
enum Colour
|
enum Colour {
|
||||||
{
|
|
||||||
black = 0b11,
|
black = 0b11,
|
||||||
darkGray = 0b10,
|
darkGray = 0b10,
|
||||||
lightGray = 0b01,
|
lightGray = 0b01,
|
||||||
white = 0b00
|
white = 0b00
|
||||||
};
|
};
|
||||||
|
|
||||||
enum PPUMode
|
enum PPUMode {
|
||||||
{
|
|
||||||
mode0, // Horizontal Blank (Mode 0): No access to video RAM, occurs during horizontal blanking period.
|
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.
|
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.
|
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)
|
Word reg; //register.reg == (hi << 8) + lo. (hi is more significant than lo)
|
||||||
|
|
||||||
struct
|
struct {
|
||||||
{
|
|
||||||
Byte lo;
|
Byte lo;
|
||||||
Byte hi;
|
Byte hi;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
class AddressSpace
|
class AddressSpace {
|
||||||
{
|
|
||||||
private:
|
private:
|
||||||
bool bootromLoaded = true;
|
bool bootromLoaded = true;
|
||||||
Byte bootrom[BOOTROM_SIZE];
|
Byte bootrom[BOOTROM_SIZE];
|
||||||
std::ifstream game;
|
std::ifstream game;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AddressSpace()
|
AddressSpace() {
|
||||||
{
|
|
||||||
// Initialize the memory to zero
|
// Initialize the memory to zero
|
||||||
memoryLayout = {};
|
memoryLayout = {};
|
||||||
std::memset(memoryLayout.memory, 0, sizeof(memoryLayout.memory));
|
std::memset(memoryLayout.memory, 0, sizeof(memoryLayout.memory));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nested union for the memory layout
|
// Nested union for the memory layout
|
||||||
union MemoryLayout
|
union MemoryLayout {
|
||||||
{
|
|
||||||
Byte memory[0x10000];
|
Byte memory[0x10000];
|
||||||
struct
|
|
||||||
{
|
struct {
|
||||||
Byte romBank1[ROM_BANK_SIZE]; // Mapped to 0x0000
|
Byte romBank1[ROM_BANK_SIZE]; // Mapped to 0x0000
|
||||||
Byte romBankSwitch[ROM_BANK_SIZE]; // Mapped to 0x4000
|
Byte romBankSwitch[ROM_BANK_SIZE]; // Mapped to 0x4000
|
||||||
Byte vram[0x2000]; // Mapped to 0x8000
|
Byte vram[0x2000]; // Mapped to 0x8000
|
||||||
@@ -81,8 +74,7 @@ class AddressSpace
|
|||||||
void loadGame(std::string filename);
|
void loadGame(std::string filename);
|
||||||
|
|
||||||
//overload [] for echo ram and bootrom support
|
//overload [] for echo ram and bootrom support
|
||||||
Byte operator[](uint32_t address) const
|
Byte operator[](uint32_t address) const {
|
||||||
{
|
|
||||||
if (address >= 0xE000 && address < 0xFE00)
|
if (address >= 0xE000 && address < 0xFE00)
|
||||||
return memoryLayout.echoRam[address - 0xE000];
|
return memoryLayout.echoRam[address - 0xE000];
|
||||||
if (address < 0x0100 && bootromLoaded)
|
if (address < 0x0100 && bootromLoaded)
|
||||||
@@ -90,8 +82,8 @@ class AddressSpace
|
|||||||
else
|
else
|
||||||
return memoryLayout.memory[address];
|
return memoryLayout.memory[address];
|
||||||
}
|
}
|
||||||
Byte& operator[](uint32_t address)
|
|
||||||
{
|
Byte& operator[](uint32_t address) {
|
||||||
if (address >= 0xE000 && address < 0xFE00)
|
if (address >= 0xE000 && address < 0xFE00)
|
||||||
return memoryLayout.echoRam[address - 0xE000];
|
return memoryLayout.echoRam[address - 0xE000];
|
||||||
if (address < 0x0100 && bootromLoaded)
|
if (address < 0x0100 && bootromLoaded)
|
||||||
|
|||||||
@@ -1,18 +1,15 @@
|
|||||||
#include "defines.hpp"
|
#include "defines.hpp"
|
||||||
#include "gameboy.hpp"
|
#include "gameboy.hpp"
|
||||||
|
|
||||||
bool GameBoy::testInterruptEnabled(Byte interrupt)
|
bool GameBoy::testInterruptEnabled(Byte interrupt) {
|
||||||
{
|
|
||||||
return (*IE) & (Byte)(1 << interrupt);
|
return (*IE) & (Byte)(1 << interrupt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameBoy::resetInterrupt(Byte interrupt)
|
void GameBoy::resetInterrupt(Byte interrupt) {
|
||||||
{
|
|
||||||
*IF &= ~(1 << interrupt);
|
*IF &= ~(1 << interrupt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameBoy::interruptHandler()
|
void GameBoy::interruptHandler() {
|
||||||
{
|
|
||||||
if (!IME)
|
if (!IME)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -28,8 +25,7 @@ void GameBoy::interruptHandler()
|
|||||||
joypadHandle();
|
joypadHandle();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameBoy::VBlankHandle()
|
void GameBoy::VBlankHandle() {
|
||||||
{
|
|
||||||
printf("VBlank interrupt");
|
printf("VBlank interrupt");
|
||||||
IME = 0;
|
IME = 0;
|
||||||
push(PC);
|
push(PC);
|
||||||
@@ -37,8 +33,7 @@ void GameBoy::VBlankHandle()
|
|||||||
resetInterrupt(VBLANK_INTERRUPT);
|
resetInterrupt(VBLANK_INTERRUPT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameBoy::LCDStatHandle()
|
void GameBoy::LCDStatHandle() {
|
||||||
{
|
|
||||||
printf("LCD stat interrupt");
|
printf("LCD stat interrupt");
|
||||||
IME = 0;
|
IME = 0;
|
||||||
push(PC);
|
push(PC);
|
||||||
@@ -47,8 +42,7 @@ void GameBoy::LCDStatHandle()
|
|||||||
resetInterrupt(LCD_STAT_INTERRUPT);
|
resetInterrupt(LCD_STAT_INTERRUPT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameBoy::timerHandle()
|
void GameBoy::timerHandle() {
|
||||||
{
|
|
||||||
printf("timer interrupt");
|
printf("timer interrupt");
|
||||||
IME = 0;
|
IME = 0;
|
||||||
push(PC);
|
push(PC);
|
||||||
@@ -57,8 +51,7 @@ void GameBoy::timerHandle()
|
|||||||
resetInterrupt(TIMER_INTERRUPT);
|
resetInterrupt(TIMER_INTERRUPT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameBoy::serialHandle()
|
void GameBoy::serialHandle() {
|
||||||
{
|
|
||||||
printf("serial interrupt");
|
printf("serial interrupt");
|
||||||
IME = 0;
|
IME = 0;
|
||||||
push(PC);
|
push(PC);
|
||||||
@@ -67,8 +60,7 @@ void GameBoy::serialHandle()
|
|||||||
resetInterrupt(SERIAL_INTERRUPT);
|
resetInterrupt(SERIAL_INTERRUPT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameBoy::joypadHandle()
|
void GameBoy::joypadHandle() {
|
||||||
{
|
|
||||||
printf("joypad interrupt");
|
printf("joypad interrupt");
|
||||||
IME = 0;
|
IME = 0;
|
||||||
push(PC);
|
push(PC);
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include "gameboy.hpp"
|
#include "gameboy.hpp"
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv) {
|
||||||
{
|
|
||||||
auto* gb = new GameBoy();
|
auto* gb = new GameBoy();
|
||||||
gb->SDL2setup();
|
gb->SDL2setup();
|
||||||
gb->start("../bootrom.bin", "../roms/DrMario.gb");
|
gb->start("../bootrom.bin", "../roms/DrMario.gb");
|
||||||
|
|||||||
240
src/opcode.cpp
240
src/opcode.cpp
@@ -1,22 +1,18 @@
|
|||||||
#include "gameboy.hpp"
|
#include "gameboy.hpp"
|
||||||
|
|
||||||
void GameBoy::setFlag(Byte bit)
|
void GameBoy::setFlag(Byte bit) {
|
||||||
{
|
|
||||||
AF.lo |= (1 << bit);
|
AF.lo |= (1 << bit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameBoy::resetFlag(Byte bit)
|
void GameBoy::resetFlag(Byte bit) {
|
||||||
{
|
|
||||||
AF.lo &= ~(1 << bit);
|
AF.lo &= ~(1 << bit);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameBoy::getFlag(Byte bit) const
|
bool GameBoy::getFlag(Byte bit) const {
|
||||||
{
|
|
||||||
return (AF.lo >> bit) & 1;
|
return (AF.lo >> bit) & 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Word GameBoy::getWordPC()
|
Word GameBoy::getWordPC() {
|
||||||
{
|
|
||||||
RegisterPair word;
|
RegisterPair word;
|
||||||
|
|
||||||
//remember little endianness
|
//remember little endianness
|
||||||
@@ -26,13 +22,11 @@ Word GameBoy::getWordPC()
|
|||||||
return word.reg;
|
return word.reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
Byte GameBoy::getBytePC()
|
Byte GameBoy::getBytePC() {
|
||||||
{
|
|
||||||
return addressSpace[PC + 1];
|
return addressSpace[PC + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
Word GameBoy::getWordSP()
|
Word GameBoy::getWordSP() {
|
||||||
{
|
|
||||||
RegisterPair word;
|
RegisterPair word;
|
||||||
|
|
||||||
//remember little endianness
|
//remember little endianness
|
||||||
@@ -42,35 +36,29 @@ Word GameBoy::getWordSP()
|
|||||||
return word.reg;
|
return word.reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
Byte GameBoy::getByteSP()
|
Byte GameBoy::getByteSP() {
|
||||||
{
|
|
||||||
return addressSpace[SP++];
|
return addressSpace[SP++];
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameBoy::ret()
|
void GameBoy::ret() {
|
||||||
{
|
|
||||||
pop(PC);
|
pop(PC);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void GameBoy::ld(T &dest, T src)
|
void GameBoy::ld(T& dest, T src) {
|
||||||
{
|
|
||||||
dest = src;
|
dest = src;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void GameBoy::ldW(T dest, T src)
|
void GameBoy::ldW(T dest, T src) {
|
||||||
{
|
if (sizeof(src) == sizeof(Word)) {
|
||||||
if(sizeof(src) == sizeof(Word))
|
|
||||||
{
|
|
||||||
addressSpace[dest] = (Byte)(src & 0xFF00) >> 8;
|
addressSpace[dest] = (Byte)(src & 0xFF00) >> 8;
|
||||||
addressSpace[dest + 1] = (Byte)(src & 0xFF);
|
addressSpace[dest + 1] = (Byte)(src & 0xFF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void GameBoy::rla(T ®)
|
void GameBoy::rla(T& reg) {
|
||||||
{
|
|
||||||
//printf("0x%.2x\n", REG);
|
//printf("0x%.2x\n", REG);
|
||||||
//printf("%d\n", GET_FLAG(CARRY_FLAG));
|
//printf("%d\n", GET_FLAG(CARRY_FLAG));
|
||||||
bool carry;
|
bool carry;
|
||||||
@@ -99,10 +87,8 @@ void GameBoy::rla(T ®)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void GameBoy::add(T ®, T value)
|
void GameBoy::add(T& reg, T value) {
|
||||||
{
|
if (sizeof(reg) == sizeof(Byte)) {
|
||||||
if(sizeof(reg) == sizeof(Byte))
|
|
||||||
{
|
|
||||||
//halfcarry test https://robdor.com/2016/08/10/gameboy-emulator-half-carry-flag/
|
//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);
|
setFlag(HALFCARRY_FLAG);
|
||||||
@@ -115,8 +101,7 @@ void GameBoy::add(T ®, T value)
|
|||||||
resetFlag(CARRY_FLAG);
|
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/
|
//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);
|
setFlag(HALFCARRY_FLAG);
|
||||||
@@ -137,12 +122,10 @@ void GameBoy::add(T ®, T value)
|
|||||||
resetFlag(ZERO_FLAG);
|
resetFlag(ZERO_FLAG);
|
||||||
|
|
||||||
resetFlag(SUBTRACT_FLAG);
|
resetFlag(SUBTRACT_FLAG);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void GameBoy::orBitwise(T &dest, T src)
|
void GameBoy::orBitwise(T& dest, T src) {
|
||||||
{
|
|
||||||
dest |= src;
|
dest |= src;
|
||||||
|
|
||||||
if (dest == 0)
|
if (dest == 0)
|
||||||
@@ -154,8 +137,7 @@ void GameBoy::orBitwise(T &dest, T src)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void GameBoy::andBitwise(T &dest, T src)
|
void GameBoy::andBitwise(T& dest, T src) {
|
||||||
{
|
|
||||||
dest &= src;
|
dest &= src;
|
||||||
|
|
||||||
if (dest == 0)
|
if (dest == 0)
|
||||||
@@ -167,8 +149,7 @@ void GameBoy::andBitwise(T &dest, T src)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void GameBoy::xorBitwise(T &dest, T src)
|
void GameBoy::xorBitwise(T& dest, T src) {
|
||||||
{
|
|
||||||
dest ^= src;
|
dest ^= src;
|
||||||
|
|
||||||
if (dest == 0)
|
if (dest == 0)
|
||||||
@@ -180,8 +161,7 @@ void GameBoy::xorBitwise(T &dest, T src)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void GameBoy::bit(T testBit, T reg)
|
void GameBoy::bit(T testBit, T reg) {
|
||||||
{
|
|
||||||
Byte result = reg & (T)(1 << testBit);
|
Byte result = reg & (T)(1 << testBit);
|
||||||
|
|
||||||
if (result == 0)
|
if (result == 0)
|
||||||
@@ -194,8 +174,7 @@ void GameBoy::bit(T testBit, T reg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool GameBoy::jrNZ(T offset)
|
bool GameBoy::jrNZ(T offset) {
|
||||||
{
|
|
||||||
bool jumped = false;
|
bool jumped = false;
|
||||||
if (!getFlag(ZERO_FLAG)) //if not set
|
if (!getFlag(ZERO_FLAG)) //if not set
|
||||||
{
|
{
|
||||||
@@ -207,12 +186,10 @@ bool GameBoy::jrNZ(T offset)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void GameBoy::inc(T ®)
|
void GameBoy::inc(T& reg) {
|
||||||
{
|
|
||||||
reg++;
|
reg++;
|
||||||
|
|
||||||
if(sizeof(reg) == sizeof(Byte))
|
if (sizeof(reg) == sizeof(Byte)) {
|
||||||
{
|
|
||||||
if (reg == 0)
|
if (reg == 0)
|
||||||
setFlag(ZERO_FLAG);
|
setFlag(ZERO_FLAG);
|
||||||
else
|
else
|
||||||
@@ -225,13 +202,11 @@ void GameBoy::inc(T ®)
|
|||||||
setFlag(HALFCARRY_FLAG);
|
setFlag(HALFCARRY_FLAG);
|
||||||
else
|
else
|
||||||
resetFlag(HALFCARRY_FLAG);
|
resetFlag(HALFCARRY_FLAG);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void GameBoy::call(T address)
|
void GameBoy::call(T address) {
|
||||||
{
|
|
||||||
push(PC + 3);
|
push(PC + 3);
|
||||||
PC = address;
|
PC = address;
|
||||||
}
|
}
|
||||||
@@ -239,13 +214,11 @@ void GameBoy::call(T address)
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
void GameBoy::cp(T value) //compare
|
void GameBoy::cp(T value) //compare
|
||||||
{
|
{
|
||||||
if(AF.hi < value)
|
if (AF.hi < value) {
|
||||||
{
|
|
||||||
setFlag(CARRY_FLAG);
|
setFlag(CARRY_FLAG);
|
||||||
resetFlag(ZERO_FLAG);
|
resetFlag(ZERO_FLAG);
|
||||||
}
|
}
|
||||||
else if(AF.hi == value)
|
else if (AF.hi == value) {
|
||||||
{
|
|
||||||
setFlag(ZERO_FLAG);
|
setFlag(ZERO_FLAG);
|
||||||
resetFlag(CARRY_FLAG);
|
resetFlag(CARRY_FLAG);
|
||||||
}
|
}
|
||||||
@@ -257,16 +230,13 @@ void GameBoy::cp(T value) //compare
|
|||||||
setFlag(HALFCARRY_FLAG);
|
setFlag(HALFCARRY_FLAG);
|
||||||
else
|
else
|
||||||
resetFlag(HALFCARRY_FLAG);
|
resetFlag(HALFCARRY_FLAG);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void GameBoy::dec(T ®)
|
void GameBoy::dec(T& reg) {
|
||||||
{
|
|
||||||
reg -= 1;
|
reg -= 1;
|
||||||
|
|
||||||
if(sizeof(reg) == sizeof(Byte))
|
if (sizeof(reg) == sizeof(Byte)) {
|
||||||
{
|
|
||||||
if (reg == 0)
|
if (reg == 0)
|
||||||
setFlag(ZERO_FLAG);
|
setFlag(ZERO_FLAG);
|
||||||
else
|
else
|
||||||
@@ -279,14 +249,11 @@ void GameBoy::dec(T ®)
|
|||||||
setFlag(HALFCARRY_FLAG);
|
setFlag(HALFCARRY_FLAG);
|
||||||
else
|
else
|
||||||
resetFlag(HALFCARRY_FLAG);
|
resetFlag(HALFCARRY_FLAG);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool GameBoy::jrZ(T offset)
|
bool GameBoy::jrZ(T offset) {
|
||||||
{
|
|
||||||
bool jumped = false;
|
bool jumped = false;
|
||||||
if (getFlag(ZERO_FLAG)) //if not set
|
if (getFlag(ZERO_FLAG)) //if not set
|
||||||
{
|
{
|
||||||
@@ -297,8 +264,7 @@ bool GameBoy::jrZ(T offset)
|
|||||||
return jumped;
|
return jumped;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameBoy::swap(Byte &value)
|
void GameBoy::swap(Byte& value) {
|
||||||
{
|
|
||||||
// Extract the lower and upper nibbles of the register
|
// Extract the lower and upper nibbles of the register
|
||||||
Byte lowerNibble = value & 0x0F;
|
Byte lowerNibble = value & 0x0F;
|
||||||
Byte upperNibble = (value >> 4) & 0x0F;
|
Byte upperNibble = (value >> 4) & 0x0F;
|
||||||
@@ -315,21 +281,15 @@ void GameBoy::swap(Byte &value)
|
|||||||
resetFlag(CARRY_FLAG);
|
resetFlag(CARRY_FLAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameBoy::halt()
|
void GameBoy::halt() {}
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void GameBoy::sub(T value)
|
void GameBoy::sub(T value) {
|
||||||
{
|
if (AF.hi < value) {
|
||||||
if(AF.hi < value)
|
|
||||||
{
|
|
||||||
setFlag(CARRY_FLAG);
|
setFlag(CARRY_FLAG);
|
||||||
resetFlag(ZERO_FLAG);
|
resetFlag(ZERO_FLAG);
|
||||||
}
|
}
|
||||||
else if(AF.hi == value)
|
else if (AF.hi == value) {
|
||||||
{
|
|
||||||
setFlag(ZERO_FLAG);
|
setFlag(ZERO_FLAG);
|
||||||
resetFlag(CARRY_FLAG);
|
resetFlag(CARRY_FLAG);
|
||||||
}
|
}
|
||||||
@@ -342,25 +302,17 @@ void GameBoy::sub(T value)
|
|||||||
setFlag(HALFCARRY_FLAG);
|
setFlag(HALFCARRY_FLAG);
|
||||||
else
|
else
|
||||||
resetFlag(HALFCARRY_FLAG);
|
resetFlag(HALFCARRY_FLAG);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void GameBoy::jr(T offset)
|
void GameBoy::jr(T offset) {
|
||||||
{
|
|
||||||
PC += (int8_t)offset + 2; //PC moves 2 from original instruction
|
PC += (int8_t)offset + 2; //PC moves 2 from original instruction
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void GameBoy::rl(T ®)
|
void GameBoy::rl(T& reg) {
|
||||||
{
|
|
||||||
//printf("0x%.2x\n", REG);
|
|
||||||
//printf("%d\n", GET_FLAG(CARRY_FLAG));
|
|
||||||
bool carry;
|
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;
|
carry = true;
|
||||||
else
|
else
|
||||||
@@ -385,14 +337,12 @@ void GameBoy::rl(T ®)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void GameBoy::pop(T ®)
|
void GameBoy::pop(T& reg) {
|
||||||
{
|
|
||||||
reg = getWordSP();
|
reg = getWordSP();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void GameBoy::push(T reg)
|
void GameBoy::push(T reg) {
|
||||||
{
|
|
||||||
//little endian
|
//little endian
|
||||||
RegisterPair temp;
|
RegisterPair temp;
|
||||||
temp.lo = reg & 0xFF;
|
temp.lo = reg & 0xFF;
|
||||||
@@ -404,27 +354,23 @@ void GameBoy::push(T reg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void GameBoy::jp(T address)
|
void GameBoy::jp(T address) {
|
||||||
{
|
|
||||||
PC = address;
|
PC = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void GameBoy::rst(T address)
|
void GameBoy::rst(T address) {
|
||||||
{
|
|
||||||
push(PC);
|
push(PC);
|
||||||
PC = address;
|
PC = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameBoy::cpl()
|
void GameBoy::cpl() {
|
||||||
{
|
|
||||||
AF.hi = ~AF.hi;
|
AF.hi = ~AF.hi;
|
||||||
setFlag(SUBTRACT_FLAG);
|
setFlag(SUBTRACT_FLAG);
|
||||||
setFlag(HALFCARRY_FLAG);
|
setFlag(HALFCARRY_FLAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameBoy::ccf()
|
void GameBoy::ccf() {
|
||||||
{
|
|
||||||
resetFlag(SUBTRACT_FLAG);
|
resetFlag(SUBTRACT_FLAG);
|
||||||
resetFlag(HALFCARRY_FLAG);
|
resetFlag(HALFCARRY_FLAG);
|
||||||
if (getFlag(CARRY_FLAG))
|
if (getFlag(CARRY_FLAG))
|
||||||
@@ -433,27 +379,21 @@ void GameBoy::ccf()
|
|||||||
setFlag(CARRY_FLAG);
|
setFlag(CARRY_FLAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameBoy::stop()
|
void GameBoy::stop() {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameBoy::opcodeHandler()
|
void GameBoy::opcodeHandler() {
|
||||||
{
|
|
||||||
bool jumped;
|
bool jumped;
|
||||||
|
|
||||||
if(addressSpace[PC] != 0xCB)
|
if (addressSpace[PC] != 0xCB) {
|
||||||
{
|
|
||||||
//printf("PC:0x%.2x, Opcode:0x%.2x\n", PC, addressSpace[PC]);
|
//printf("PC:0x%.2x, Opcode:0x%.2x\n", PC, addressSpace[PC]);
|
||||||
if(PC == 0x100)
|
if (PC == 0x100) {
|
||||||
{
|
|
||||||
printf("LY:0x%.2x\n", (*LY));
|
printf("LY:0x%.2x\n", (*LY));
|
||||||
// printf("PC:0x%.2x, Opcode:0x%.2x\n", PC, addressSpace[PC]);
|
// 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));
|
||||||
}
|
}
|
||||||
//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:
|
case 0x00:
|
||||||
//NOP
|
//NOP
|
||||||
PC += 1;
|
PC += 1;
|
||||||
@@ -630,12 +570,10 @@ void GameBoy::opcodeHandler()
|
|||||||
|
|
||||||
case 0x20:
|
case 0x20:
|
||||||
jumped = jrNZ(getBytePC());
|
jumped = jrNZ(getBytePC());
|
||||||
if(jumped)
|
if (jumped) {
|
||||||
{
|
|
||||||
addCycles(12);
|
addCycles(12);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
PC += 2;
|
PC += 2;
|
||||||
addCycles(8);
|
addCycles(8);
|
||||||
}
|
}
|
||||||
@@ -674,12 +612,10 @@ void GameBoy::opcodeHandler()
|
|||||||
|
|
||||||
case 0x28:
|
case 0x28:
|
||||||
jumped = jrZ(getBytePC());
|
jumped = jrZ(getBytePC());
|
||||||
if(jumped)
|
if (jumped) {
|
||||||
{
|
|
||||||
addCycles(12);
|
addCycles(12);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
PC += 2;
|
PC += 2;
|
||||||
addCycles(8);
|
addCycles(8);
|
||||||
}
|
}
|
||||||
@@ -1457,13 +1393,11 @@ void GameBoy::opcodeHandler()
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xC0: //RET NZ
|
case 0xC0: //RET NZ
|
||||||
if(!getFlag(ZERO_FLAG))
|
if (!getFlag(ZERO_FLAG)) {
|
||||||
{
|
|
||||||
ret();
|
ret();
|
||||||
addCycles(20);
|
addCycles(20);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
addCycles(8);
|
addCycles(8);
|
||||||
PC += 1;
|
PC += 1;
|
||||||
}
|
}
|
||||||
@@ -1476,13 +1410,11 @@ void GameBoy::opcodeHandler()
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xC2:
|
case 0xC2:
|
||||||
if(!getFlag(ZERO_FLAG))
|
if (!getFlag(ZERO_FLAG)) {
|
||||||
{
|
|
||||||
jp(getWordPC());
|
jp(getWordPC());
|
||||||
addCycles(16);
|
addCycles(16);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
addCycles(12);
|
addCycles(12);
|
||||||
PC += 3;
|
PC += 3;
|
||||||
}
|
}
|
||||||
@@ -1494,13 +1426,11 @@ void GameBoy::opcodeHandler()
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xC4:
|
case 0xC4:
|
||||||
if(!getFlag(ZERO_FLAG))
|
if (!getFlag(ZERO_FLAG)) {
|
||||||
{
|
|
||||||
call(getWordPC());
|
call(getWordPC());
|
||||||
addCycles(24);
|
addCycles(24);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
addCycles(12);
|
addCycles(12);
|
||||||
PC += 3;
|
PC += 3;
|
||||||
}
|
}
|
||||||
@@ -1513,13 +1443,11 @@ void GameBoy::opcodeHandler()
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xC8:
|
case 0xC8:
|
||||||
if(getFlag(ZERO_FLAG))
|
if (getFlag(ZERO_FLAG)) {
|
||||||
{
|
|
||||||
ret();
|
ret();
|
||||||
addCycles(20);
|
addCycles(20);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
addCycles(8);
|
addCycles(8);
|
||||||
PC += 1;
|
PC += 1;
|
||||||
}
|
}
|
||||||
@@ -1531,26 +1459,22 @@ void GameBoy::opcodeHandler()
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xCA:
|
case 0xCA:
|
||||||
if(getFlag(ZERO_FLAG))
|
if (getFlag(ZERO_FLAG)) {
|
||||||
{
|
|
||||||
jp(getWordPC());
|
jp(getWordPC());
|
||||||
addCycles(16);
|
addCycles(16);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
addCycles(12);
|
addCycles(12);
|
||||||
PC += 3;
|
PC += 3;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xCC:
|
case 0xCC:
|
||||||
if(getFlag(ZERO_FLAG))
|
if (getFlag(ZERO_FLAG)) {
|
||||||
{
|
|
||||||
call(getWordPC());
|
call(getWordPC());
|
||||||
addCycles(24);
|
addCycles(24);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
addCycles(12);
|
addCycles(12);
|
||||||
PC += 3;
|
PC += 3;
|
||||||
}
|
}
|
||||||
@@ -1567,13 +1491,11 @@ void GameBoy::opcodeHandler()
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xD0: //RET NC
|
case 0xD0: //RET NC
|
||||||
if(!getFlag(CARRY_FLAG))
|
if (!getFlag(CARRY_FLAG)) {
|
||||||
{
|
|
||||||
ret();
|
ret();
|
||||||
addCycles(20);
|
addCycles(20);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
addCycles(8);
|
addCycles(8);
|
||||||
PC += 3;
|
PC += 3;
|
||||||
}
|
}
|
||||||
@@ -1586,26 +1508,22 @@ void GameBoy::opcodeHandler()
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xD2:
|
case 0xD2:
|
||||||
if(!getFlag(CARRY_FLAG))
|
if (!getFlag(CARRY_FLAG)) {
|
||||||
{
|
|
||||||
jp(getWordPC());
|
jp(getWordPC());
|
||||||
addCycles(24);
|
addCycles(24);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
addCycles(12);
|
addCycles(12);
|
||||||
PC += 3;
|
PC += 3;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xD4:
|
case 0xD4:
|
||||||
if(!getFlag(CARRY_FLAG))
|
if (!getFlag(CARRY_FLAG)) {
|
||||||
{
|
|
||||||
call(getWordPC());
|
call(getWordPC());
|
||||||
addCycles(24);
|
addCycles(24);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
addCycles(12);
|
addCycles(12);
|
||||||
PC += 3;
|
PC += 3;
|
||||||
}
|
}
|
||||||
@@ -1618,13 +1536,11 @@ void GameBoy::opcodeHandler()
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xD8:
|
case 0xD8:
|
||||||
if(getFlag(CARRY_FLAG))
|
if (getFlag(CARRY_FLAG)) {
|
||||||
{
|
|
||||||
ret();
|
ret();
|
||||||
addCycles(20);
|
addCycles(20);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
addCycles(8);
|
addCycles(8);
|
||||||
PC += 1;
|
PC += 1;
|
||||||
}
|
}
|
||||||
@@ -1638,26 +1554,22 @@ void GameBoy::opcodeHandler()
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xDA:
|
case 0xDA:
|
||||||
if(getFlag(CARRY_FLAG))
|
if (getFlag(CARRY_FLAG)) {
|
||||||
{
|
|
||||||
jp(getWordPC());
|
jp(getWordPC());
|
||||||
addCycles(16);
|
addCycles(16);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
addCycles(12);
|
addCycles(12);
|
||||||
PC += 3;
|
PC += 3;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xDC:
|
case 0xDC:
|
||||||
if(getFlag(CARRY_FLAG))
|
if (getFlag(CARRY_FLAG)) {
|
||||||
{
|
|
||||||
call(getWordPC());
|
call(getWordPC());
|
||||||
addCycles(24);
|
addCycles(24);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
addCycles(12);
|
addCycles(12);
|
||||||
PC += 3;
|
PC += 3;
|
||||||
}
|
}
|
||||||
@@ -1773,7 +1685,6 @@ void GameBoy::opcodeHandler()
|
|||||||
printf("Unimplemented opcode found: PC:0x%.2x, Opcode:0x%.2x\n", PC, addressSpace[PC]);
|
printf("Unimplemented opcode found: PC:0x%.2x, Opcode:0x%.2x\n", PC, addressSpace[PC]);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else //extension
|
else //extension
|
||||||
{
|
{
|
||||||
@@ -1782,8 +1693,7 @@ void GameBoy::opcodeHandler()
|
|||||||
addCycles(4);
|
addCycles(4);
|
||||||
|
|
||||||
//extension handler
|
//extension handler
|
||||||
switch(addressSpace[PC])
|
switch (addressSpace[PC]) {
|
||||||
{
|
|
||||||
case 0x11:
|
case 0x11:
|
||||||
rl(BC.lo);
|
rl(BC.lo);
|
||||||
PC += 1;
|
PC += 1;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
void GameBoy::ppuUpdate() {
|
void GameBoy::ppuUpdate() {
|
||||||
//test HBlank
|
//test for HBlank
|
||||||
checkPPUMode();
|
checkPPUMode();
|
||||||
|
|
||||||
if (cyclesToStayInHblank != -1) {
|
if (cyclesToStayInHblank != -1) {
|
||||||
@@ -53,7 +53,8 @@ void GameBoy::ppuUpdate() {
|
|||||||
// bug on DMG models triggers a STAT interrupt anytime the STAT register is written
|
// bug on DMG models triggers a STAT interrupt anytime the STAT register is written
|
||||||
// Road Rage and Zerd no Denetsu rely on this
|
// Road Rage and Zerd no Denetsu rely on this
|
||||||
(*STAT) |= (1 << 2);
|
(*STAT) |= (1 << 2);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
(*STAT) &= ~(1 << 2);
|
(*STAT) &= ~(1 << 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +97,8 @@ void GameBoy::checkPPUMode() {
|
|||||||
setPPUMode(PPUMode::mode3);
|
setPPUMode(PPUMode::mode3);
|
||||||
else
|
else
|
||||||
setPPUMode(PPUMode::mode0);
|
setPPUMode(PPUMode::mode0);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// VBlank Period
|
// VBlank Period
|
||||||
setPPUMode(PPUMode::mode1);
|
setPPUMode(PPUMode::mode1);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user