Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c242fb7574 | |||
| 80e23312de | |||
| 037ba0c76d |
@@ -19,7 +19,11 @@ add_executable(GameBoy++ src/main.cpp
|
||||
src/testing.hpp
|
||||
src/joypad.cpp
|
||||
)
|
||||
target_compile_options(GameBoy++ PRIVATE -O2)
|
||||
target_link_libraries(GameBoy++ ${SDL2_LIBRARIES})
|
||||
target_compile_options(GameBoy++ PRIVATE
|
||||
$<$<CONFIG:Release>:-O2>
|
||||
)
|
||||
|
||||
if(CMAKE_EXPORT_COMPILE_COMMANDS)
|
||||
add_custom_target(copy_compile_commands ALL
|
||||
|
||||
@@ -43,7 +43,6 @@ public:
|
||||
Byte TAC = 0xF8;
|
||||
// interrupt flag and enable
|
||||
Byte IF = 0xE1;
|
||||
;
|
||||
// Sound registers
|
||||
Byte NR10;
|
||||
Byte NR11;
|
||||
@@ -93,8 +92,7 @@ public:
|
||||
void loadGame(const std::string &filename);
|
||||
|
||||
void determineMBCInfo();
|
||||
bool MBCWrite(Word address);
|
||||
Byte *MBCRead(Word address);
|
||||
Byte *MBCWrite(Word address);
|
||||
// prevents seg faults when programs with no MBC try to write to ROM
|
||||
Byte dummyVal = 0;
|
||||
|
||||
@@ -104,7 +102,7 @@ public:
|
||||
void loadRomBank();
|
||||
void createRamBank();
|
||||
void loadRamBank();
|
||||
MBCType MBC = {};
|
||||
MBCType_enum MBC = {};
|
||||
uint32_t romSize = 0;
|
||||
uint32_t romBanks = 0;
|
||||
uint32_t externalRamSize = 0;
|
||||
@@ -114,10 +112,11 @@ public:
|
||||
void dmaTransfer();
|
||||
|
||||
// MBC registers
|
||||
// Selected ROM Bank = (Secondary Bank << 5) + ROM Bank
|
||||
// Selected ROM Bank in MBC1 = (Secondary Bank << 5) + ROM Bank
|
||||
Byte selectedRomBank = 0;
|
||||
Byte romBankRegister = 0x00;
|
||||
// 2 bit register acts as secondary rom bank register or ram bank number
|
||||
// 2 bit register acts as secondary rom bank register or ram bank number in
|
||||
// MBC1
|
||||
Byte twoBitBankRegister = 0x0;
|
||||
Byte selectedExternalRamBank = 0;
|
||||
Byte romRamSelect = 0x00;
|
||||
@@ -129,6 +128,13 @@ public:
|
||||
// MBC3
|
||||
Byte latchClockData = 0x00;
|
||||
Byte ramBankRTCRegister = 0x00;
|
||||
// RTC registers
|
||||
enabledRTCRegister_enum enabledRTCRegister = NONE;
|
||||
Byte RTCSeconds = 0x0;
|
||||
Byte RTCMinutes = 0x0;
|
||||
Byte RTCHours = 0x0;
|
||||
Byte RTCDayLower = 0x0;
|
||||
Byte RTCDayHigher = 0x0;
|
||||
|
||||
void setTesting(bool state);
|
||||
|
||||
@@ -138,34 +144,47 @@ public:
|
||||
return testRam[address];
|
||||
if (address < 0x0100 && bootromLoaded)
|
||||
return bootrom[address];
|
||||
if (address < 0x4000)
|
||||
else if (address < 0x4000)
|
||||
return memoryLayout.romBank0[address];
|
||||
if (address < 0x8000)
|
||||
else if (address < 0x8000)
|
||||
return memoryLayout.romBankSwitch[address - 0x4000];
|
||||
if (address < 0xA000)
|
||||
else if (address < 0xA000)
|
||||
return memoryLayout.vram[address - 0x8000];
|
||||
if (address < 0xC000) {
|
||||
else if (address < 0xC000) {
|
||||
if (enabledRTCRegister != NONE) {
|
||||
switch (enabledRTCRegister) {
|
||||
case RTCS:
|
||||
return RTCSeconds;
|
||||
case RTCM:
|
||||
return RTCMinutes;
|
||||
case RTCH:
|
||||
return RTCHours;
|
||||
case RTCDL:
|
||||
return RTCDayLower;
|
||||
case RTCDH:
|
||||
return RTCDayHigher;
|
||||
}
|
||||
}
|
||||
if (externalRamSize == 0)
|
||||
return 0xFF;
|
||||
// MBC2 echos 15 times and only stores lower 4 bits
|
||||
if (MBC == MBC2 || MBC == MBC2Battery)
|
||||
else if (MBC == MBC2 || MBC == MBC2Battery)
|
||||
return memoryLayout.externalRam[(address - 0xA000) & 0x01FF] | 0xF0;
|
||||
return memoryLayout.externalRam[address - 0xA000];
|
||||
}
|
||||
if (address < 0xD000)
|
||||
else
|
||||
return memoryLayout.externalRam[address - 0xA000];
|
||||
} else if (address < 0xD000)
|
||||
return memoryLayout.memoryBank1[address - 0xC000];
|
||||
if (address < 0xE000)
|
||||
else if (address < 0xE000)
|
||||
return memoryLayout.memoryBank2[address - 0xD000];
|
||||
if (address < 0xFE00)
|
||||
else if (address < 0xFE00)
|
||||
return memoryLayout.memoryBank1[address - 0xE000];
|
||||
if (address < 0xFEA0)
|
||||
else if (address < 0xFEA0)
|
||||
return memoryLayout.oam[address - 0xFE00];
|
||||
if (address < 0xFF00) {
|
||||
else if (address < 0xFF00) {
|
||||
if ((memoryLayout.STAT & 0x03) == 2 || (memoryLayout.STAT & 0x03) == 3)
|
||||
return 0xFF;
|
||||
return 0x00;
|
||||
}
|
||||
if (address < 0xFF80)
|
||||
} else if (address < 0xFF80)
|
||||
switch (address) {
|
||||
case 0xFF00:
|
||||
return memoryLayout.JOYP;
|
||||
@@ -235,8 +254,6 @@ public:
|
||||
case 0xFF43:
|
||||
return memoryLayout.SCX;
|
||||
case 0xFF44:
|
||||
// for debugging only
|
||||
// return 0x90;
|
||||
return memoryLayout.LY;
|
||||
case 0xFF45:
|
||||
return memoryLayout.LYC;
|
||||
@@ -258,7 +275,7 @@ public:
|
||||
}
|
||||
return 0xFF;
|
||||
}
|
||||
if (address < 0xFFFF)
|
||||
else if (address < 0xFFFF)
|
||||
return memoryLayout.specialRam[address - 0xFF80];
|
||||
// 0xFFFF
|
||||
return memoryLayout.IE;
|
||||
@@ -269,28 +286,27 @@ public:
|
||||
dummyVal = 0xFF;
|
||||
if (testing)
|
||||
return testRam[address];
|
||||
if (address < 0x0100 && bootromLoaded)
|
||||
else if (address < 0x0100 && bootromLoaded)
|
||||
return bootrom[address];
|
||||
if (address < 0x8000)
|
||||
return (*MBCRead(address));
|
||||
if (address < 0xA000)
|
||||
else if (address < 0x8000)
|
||||
return (*MBCWrite(address));
|
||||
else if (address < 0xA000)
|
||||
return memoryLayout.vram[address - 0x8000];
|
||||
if (address < 0xC000) {
|
||||
else if (address < 0xC000) {
|
||||
if (externalRamSize == 0)
|
||||
return dummyVal;
|
||||
return memoryLayout.externalRam[address - 0xA000];
|
||||
}
|
||||
if (address < 0xD000)
|
||||
} else if (address < 0xD000)
|
||||
return memoryLayout.memoryBank1[address - 0xC000];
|
||||
if (address < 0xE000)
|
||||
else if (address < 0xE000)
|
||||
return memoryLayout.memoryBank2[address - 0xD000];
|
||||
if (address < 0xFE00)
|
||||
else if (address < 0xFE00)
|
||||
return memoryLayout.memoryBank1[address - 0xE000];
|
||||
if (address < 0xFEA0)
|
||||
else if (address < 0xFEA0)
|
||||
return memoryLayout.oam[address - 0xFE00];
|
||||
if (address < 0xFF00)
|
||||
else if (address < 0xFF00)
|
||||
return memoryLayout.notUsable[address - 0xFEA0];
|
||||
if (address < 0xFF80)
|
||||
else if (address < 0xFF80)
|
||||
switch (address) {
|
||||
case 0xFF00:
|
||||
return memoryLayout.JOYP;
|
||||
@@ -384,7 +400,7 @@ public:
|
||||
}
|
||||
return dummyVal;
|
||||
}
|
||||
if (address < 0xFFFF)
|
||||
else if (address < 0xFFFF)
|
||||
return memoryLayout.specialRam[address - 0xFF80];
|
||||
// 0xFFFF
|
||||
return memoryLayout.IE;
|
||||
|
||||
@@ -79,7 +79,7 @@ struct Input {
|
||||
bool SELECT = false;
|
||||
};
|
||||
|
||||
enum MBCType {
|
||||
enum MBCType_enum {
|
||||
romOnly = 0x00,
|
||||
MBC1 = 0x01,
|
||||
MBC1Ram = 0x02,
|
||||
@@ -111,7 +111,7 @@ enum MBCType {
|
||||
HuC1RamBattery = 0xFF
|
||||
};
|
||||
|
||||
enum PPUMode {
|
||||
enum PPUMode_enum {
|
||||
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
|
||||
@@ -122,4 +122,12 @@ enum PPUMode {
|
||||
// pixel transfer to the screen.
|
||||
};
|
||||
|
||||
enum enabledRTCRegister_enum {
|
||||
NONE = 0x00,
|
||||
RTCS = 0x08,
|
||||
RTCM = 0x09,
|
||||
RTCH = 0x0A,
|
||||
RTCDL = 0x0B,
|
||||
RTCDH = 0x0C
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -50,7 +50,7 @@ class GameBoy {
|
||||
AddressSpace addressSpace;
|
||||
const AddressSpace &readOnlyAddressSpace = addressSpace;
|
||||
|
||||
PPUMode currentMode = PPUMode::mode0;
|
||||
PPUMode_enum currentMode = PPUMode_enum::mode0;
|
||||
Byte windowLineCounter = 0;
|
||||
int16_t cyclesUntilDMATransfer = 160;
|
||||
|
||||
@@ -86,7 +86,7 @@ class GameBoy {
|
||||
void SDL2present();
|
||||
|
||||
void checkPPUMode();
|
||||
void setPPUMode(PPUMode mode);
|
||||
void setPPUMode(PPUMode_enum mode);
|
||||
uint64_t cyclesSinceLastScanline() const;
|
||||
uint64_t cyclesSinceLastRefresh() const;
|
||||
|
||||
|
||||
70
src/mbc.cpp
70
src/mbc.cpp
@@ -1,7 +1,8 @@
|
||||
#include "addressSpace.hpp"
|
||||
#include "defines.hpp"
|
||||
|
||||
void AddressSpace::determineMBCInfo() {
|
||||
MBC = static_cast<MBCType>(memoryLayout.romBank0[0x147]);
|
||||
MBC = static_cast<MBCType_enum>(memoryLayout.romBank0[0x147]);
|
||||
romSize = 32768 * (1 << memoryLayout.romBank0[0x147]);
|
||||
romBanks = 1 << (memoryLayout.romBank0[0x147] + 1);
|
||||
|
||||
@@ -35,13 +36,7 @@ void AddressSpace::determineMBCInfo() {
|
||||
}
|
||||
}
|
||||
|
||||
bool AddressSpace::MBCWrite(const Word address) {
|
||||
if (address <= 0x7FFF)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
Byte *AddressSpace::MBCRead(const Word address) {
|
||||
Byte *AddressSpace::MBCWrite(const Word address) {
|
||||
if (MBC == MBC1) {
|
||||
if (address <= 0x1FFF)
|
||||
return &ramEnable;
|
||||
@@ -51,8 +46,7 @@ Byte *AddressSpace::MBCRead(const Word address) {
|
||||
return &twoBitBankRegister;
|
||||
if (address <= 0x7FFF)
|
||||
return &romRamSelect;
|
||||
}
|
||||
if (MBC == MBC1Ram || MBC == MBC1RamBattery) {
|
||||
} else if (MBC == MBC1Ram || MBC == MBC1RamBattery) {
|
||||
if (address <= 0x1FFF)
|
||||
return &ramEnable;
|
||||
// bits 0-4
|
||||
@@ -63,14 +57,24 @@ Byte *AddressSpace::MBCRead(const Word address) {
|
||||
}
|
||||
if (address <= 0x7FFF)
|
||||
return &romRamSelect;
|
||||
}
|
||||
if (MBC == MBC2 || MBC == MBC2Battery) {
|
||||
} else if (MBC == MBC2 || MBC == MBC2Battery) {
|
||||
if (address <= 0x3FFF) {
|
||||
if (address & 0x0100)
|
||||
return &romBankRegister;
|
||||
else
|
||||
return &ramEnable;
|
||||
}
|
||||
} else if (MBC == MBC3 || MBC == MBC3TimerBattery) {
|
||||
if (address <= 0x1FFF)
|
||||
return &ramEnable;
|
||||
} else if (MBC == MBC3Ram || MBC == MBC3RamBattery ||
|
||||
MBC == MBC3TimerRamBattery) {
|
||||
if (address <= 0x1FFF)
|
||||
return &ramEnable;
|
||||
if (address <= 0x3FFF)
|
||||
return &romBankRegister;
|
||||
if (address <= 0x5FFF)
|
||||
return &ramBankRTCRegister;
|
||||
}
|
||||
return &dummyVal;
|
||||
}
|
||||
@@ -127,41 +131,35 @@ void AddressSpace::MBCUpdate() {
|
||||
loadRamBank();
|
||||
} else if (MBC == MBC2 || MBC == MBC2Battery) {
|
||||
selectedRomBank = romBankRegister & 0x0F;
|
||||
selectedExternalRamBank = 0;
|
||||
|
||||
loadRomBank();
|
||||
loadRamBank();
|
||||
} else if (MBC == MBC3 || MBC == MBC3TimerBattery) {
|
||||
romBankRegister &= 0b11111;
|
||||
twoBitBankRegister &= 0b11;
|
||||
selectedRomBank = romBankRegister & 0x7F;
|
||||
selectedExternalRamBank = 0;
|
||||
|
||||
// 512 KiB can only have 8KiB of ram
|
||||
if (romSize >= 524288) {
|
||||
if (romBankRegister == 0)
|
||||
selectedRomBank = (twoBitBankRegister << 5) + 1;
|
||||
selectedRomBank = (twoBitBankRegister << 5) + romBankRegister;
|
||||
} else {
|
||||
if (romBankRegister == 0)
|
||||
selectedRomBank = 1;
|
||||
if (MBC == MBC3TimerBattery) {
|
||||
if(ramBankRTCRegister >= 0x8 && ramBankRTCRegister <= 0xC)
|
||||
enabledRTCRegister = static_cast<enabledRTCRegister_enum>(ramBankRTCRegister);
|
||||
else
|
||||
selectedRomBank = romBankRegister;
|
||||
enabledRTCRegister = NONE;
|
||||
}
|
||||
loadRomBank();
|
||||
loadRamBank();
|
||||
} else if (MBC == MBC3Ram || MBC == MBC3RamBattery ||
|
||||
MBC == MBC3TimerRamBattery) {
|
||||
romBankRegister &= 0b11111;
|
||||
twoBitBankRegister &= 0b11;
|
||||
selectedRomBank = romBankRegister & 0x7F;
|
||||
selectedExternalRamBank = ramBankRTCRegister & 0b11;
|
||||
|
||||
// 512 KiB can only have 8KiB of ram
|
||||
if (romSize >= 524288) {
|
||||
if (romBankRegister == 0)
|
||||
selectedRomBank = (twoBitBankRegister << 5) + 1;
|
||||
selectedRomBank = (twoBitBankRegister << 5) + romBankRegister;
|
||||
selectedExternalRamBank = 0;
|
||||
} else {
|
||||
if (romBankRegister == 0)
|
||||
selectedRomBank = 1;
|
||||
if (MBC == MBC3TimerRamBattery) {
|
||||
if(ramBankRTCRegister >= 0x8 && ramBankRTCRegister <= 0xC)
|
||||
enabledRTCRegister = static_cast<enabledRTCRegister_enum>(ramBankRTCRegister);
|
||||
else
|
||||
selectedRomBank = romBankRegister;
|
||||
selectedExternalRamBank = twoBitBankRegister;
|
||||
enabledRTCRegister = NONE;
|
||||
}
|
||||
loadRomBank();
|
||||
loadRamBank();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
16
src/ppu.cpp
16
src/ppu.cpp
@@ -46,9 +46,9 @@ void GameBoy::ppuUpdate() {
|
||||
readOnlyAddressSpace.memoryLayout.STAT & (1 << 5);
|
||||
const bool previousInterruptLine = statInteruptLine;
|
||||
|
||||
if (currentMode == PPUMode::mode0 && hBlankInterruptEnabled ||
|
||||
currentMode == PPUMode::mode3 && drawingInterruptEnabled ||
|
||||
currentMode == PPUMode::mode2 && oamInterruptEnabled) {
|
||||
if (currentMode == PPUMode_enum::mode0 && hBlankInterruptEnabled ||
|
||||
currentMode == PPUMode_enum::mode3 && drawingInterruptEnabled ||
|
||||
currentMode == PPUMode_enum::mode2 && oamInterruptEnabled) {
|
||||
statInteruptLine = true;
|
||||
} else {
|
||||
statInteruptLine = false;
|
||||
@@ -84,13 +84,13 @@ void GameBoy::checkPPUMode() {
|
||||
break;
|
||||
case 2:
|
||||
if (cyclesSinceScanline > MODE2_DURATION) {
|
||||
setPPUMode(PPUMode::mode3);
|
||||
setPPUMode(PPUMode_enum::mode3);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (cyclesSinceScanline > MODE2_DURATION + MODE3_MIN_DURATION) {
|
||||
drawLine();
|
||||
setPPUMode(PPUMode::mode0);
|
||||
setPPUMode(PPUMode_enum::mode0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -98,14 +98,14 @@ void GameBoy::checkPPUMode() {
|
||||
|
||||
void GameBoy::incLY() {
|
||||
addressSpace.memoryLayout.LY += 1;
|
||||
setPPUMode(PPUMode::mode2);
|
||||
setPPUMode(PPUMode_enum::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);
|
||||
setPPUMode(PPUMode_enum::mode1);
|
||||
addressSpace.memoryLayout.IF |= 0x1;
|
||||
}
|
||||
}
|
||||
@@ -120,7 +120,7 @@ uint64_t GameBoy::cyclesSinceLastRefresh() const {
|
||||
return difference;
|
||||
}
|
||||
|
||||
void GameBoy::setPPUMode(const PPUMode mode) {
|
||||
void GameBoy::setPPUMode(const PPUMode_enum mode) {
|
||||
switch (mode) {
|
||||
case mode0:
|
||||
addressSpace.memoryLayout.STAT &= ~0x03;
|
||||
|
||||
Reference in New Issue
Block a user