Sanitize allocations in the Game Boy emulator (#1105)

This adds checks for every allocation failure in the core Game Boy
emulator. In addition, this replaces some magic values defined
constant expressions and removes an unused function.
This also removes asserts for failed allocations in GB.cpp, they now
report a failure to the caller.
This commit is contained in:
Fabrice de Gans 2023-04-03 12:47:55 -07:00 committed by GitHub
parent e91e4dcf17
commit 7005b92840
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 205 additions and 146 deletions

View File

@ -21,4 +21,33 @@ constexpr size_t k2MiB = 2 * k1MiB;
constexpr size_t k4MiB = 2 * k2MiB;
constexpr size_t k8MiB = 2 * k4MiB;
// Game Boy BIOS Sizes.
constexpr size_t kGBBiosSize = k256B;
constexpr size_t kCGBBiosSize = k2KiB + k256B;
// Size of the buffer containing the BIOS, we alawys use the larger size.
constexpr size_t kGBBiosBufferSize = kCGBBiosSize;
// Game Boy-related screen sizes.
constexpr size_t kGBWidth = 160;
constexpr size_t kGBHeight = 144;
constexpr size_t kSGBWidth = 256;
constexpr size_t kSGBHeight = 224;
#ifdef __LIBRETRO__
constexpr size_t kGBPixSize = 4 * kSGBWidth * kSGBHeight;
#else
// Some of the filters and interframe blenders write beyond the end of the line
// or the screen, so we allocate extra space here.
constexpr size_t kGBPixSize = 4 * (kSGBWidth + 1) * (kSGBHeight + 2);
#endif
// Game Boy VRAM is 16 KiB.
constexpr size_t kGBVRamSize = k16KiB;
// Game Boy WRAM is 32 KiB.
constexpr size_t kGBWRamSize = k32KiB;
// A Game Boy line buffer size is the width of the screen at 2 bytes per pizel.
constexpr size_t kGBLineBufferSize = kGBWidth * 2;
#endif // VBAM_COMMON_SIZES_H_

View File

@ -114,6 +114,7 @@ bool gbInitializeRom(size_t romSize) {
switch (g_gbCartData.validity()) {
case gbCartData::Validity::kValid:
case gbCartData::Validity::kUninitialized:
// Unreachable.
assert(false);
break;
case gbCartData::Validity::kSizeTooSmall:
@ -157,7 +158,6 @@ bool gbInitializeRom(size_t romSize) {
if (romSize < romHeaderSize) {
uint8_t* gbRomNew = (uint8_t*)realloc(gbRom, romHeaderSize);
if (!gbRomNew) {
assert(false);
return false;
};
gbRom = gbRomNew;
@ -227,9 +227,12 @@ bool gbInitializeRom(size_t romSize) {
}
gbRamFill = 0x00;
if (gbTAMA5ram == nullptr)
gbTAMA5ram = (uint8_t*)malloc(kTama5RamSize);
memset(gbTAMA5ram, 0x0, kTama5RamSize);
if (gbTAMA5ram == nullptr) {
gbTAMA5ram = (uint8_t*)calloc(1, kTama5RamSize);
if (gbTAMA5ram == nullptr) {
return false;
}
}
g_mapperRAM = mapperTAMA5RAM;
g_mapperReadRAM = mapperTAMA5ReadRAM;
@ -253,6 +256,9 @@ bool gbInitializeRom(size_t romSize) {
const size_t ramSize = g_gbCartData.ram_size();
if (ramSize > 0) {
gbRam = (uint8_t*)malloc(ramSize);
if (gbRam == nullptr) {
return false;
}
memset(gbRam, gbRamFill, ramSize);
}
@ -261,14 +267,19 @@ bool gbInitializeRom(size_t romSize) {
setColorizerHack(false);
gbMemory = (uint8_t*)malloc(65536);
if (gbMemory == nullptr) {
return false;
}
#ifdef __LIBRETRO__
pix = (uint8_t*)calloc(1, 4 * 256 * 224);
#else
pix = (uint8_t*)calloc(1, 4 * 257 * 226);
#endif
pix = (uint8_t*)calloc(1, kGBPixSize);
if (pix == nullptr) {
return false;
}
gbLineBuffer = (uint16_t*)malloc(160 * sizeof(uint16_t));
gbLineBuffer = (uint16_t*)malloc(kGBLineBufferSize);
if (gbLineBuffer == nullptr) {
return false;
}
return true;
}
@ -281,7 +292,7 @@ bool inBios = false;
bool memorydebug = false;
char gbBuffer[2048];
extern uint16_t gbLineMix[160];
extern uint16_t gbLineMix[kGBWidth];
// registers
gbRegister PC;
@ -1436,7 +1447,7 @@ void gbWriteMemory(uint16_t address, uint8_t value)
// systemDrawScreen();
gbRegisterLYLCDCOffOn = (register_LY + 144) % 154;
gbRegisterLYLCDCOffOn = (register_LY + kGBHeight) % 154;
gbLcdTicks = GBLCD_MODE_2_CLOCK_TICKS - (gbSpeed ? 2 : 1);
gbLcdTicksDelayed = GBLCD_MODE_2_CLOCK_TICKS - (gbSpeed ? 1 : 0);
@ -1683,7 +1694,7 @@ void gbWriteMemory(uint16_t address, uint8_t value)
// WY
case 0x4a:
gbMemory[0xff4a] = register_WY = value;
if ((register_LY <= register_WY) && ((gbWindowLine < 0) || (gbWindowLine >= 144))) {
if ((register_LY <= register_WY) && ((gbWindowLine < 0) || (gbWindowLine >= (int)kGBHeight))) {
gbWindowLine = -1;
oldRegister_WY = register_WY;
}
@ -2356,7 +2367,7 @@ void gbCPUInit(const char* biosFileName, bool useBiosFile)
coreOptions.useBios = false;
if (useBiosFile) {
int expectedSize = (gbHardware & 2) ? 0x900 : 0x100;
int expectedSize = (gbHardware & 2) ? kCGBBiosSize : kGBBiosSize;
int size = expectedSize;
if (utilLoad(biosFileName,
CPUIsGBBios,
@ -2494,21 +2505,28 @@ void gbReset()
oldRegister_WY = 146;
gbInterruptLaunched = 0;
if (gbCgbMode == 1) {
if (gbVram == NULL)
gbVram = (uint8_t*)malloc(0x4000);
if (gbWram == NULL)
gbWram = (uint8_t*)malloc(0x8000);
memset(gbVram, 0, 0x4000);
memset(gbPalette, 0, 2 * 128);
} else {
if (gbVram != NULL) {
free(gbVram);
gbVram = NULL;
if (gbCgbMode) {
if (gbVram == nullptr) {
gbVram = (uint8_t*)calloc(1, kGBVRamSize);
if (gbVram == nullptr) {
return;
}
}
if (gbWram != NULL) {
if (gbWram == nullptr) {
gbWram = (uint8_t*)malloc(kGBWRamSize);
if (gbWram == nullptr) {
return;
}
}
memset(gbPalette, 0, sizeof(gbPalette));
} else {
if (gbVram != nullptr) {
free(gbVram);
gbVram = nullptr;
}
if (gbWram != nullptr) {
free(gbWram);
gbWram = NULL;
gbWram = nullptr;
}
}
@ -2526,7 +2544,7 @@ void gbReset()
// In all cases, most of the 2nd bank is filled with 00s.
// The starting data are important for some 'buggy' games, like Buster Brothers or
// Karamuchou ha Oosawagi!.
if (gbMemory != NULL) {
if (gbMemory != nullptr) {
memset(gbMemory, 0xff, 65536);
for (int temp = 0xC000; temp < 0xE000; temp++)
if ((temp & 0x8) ^ ((temp & 0x800) >> 8)) {
@ -2552,14 +2570,17 @@ void gbReset()
}
// clean LineBuffer
if (gbLineBuffer != NULL)
memset(gbLineBuffer, 0, sizeof(*gbLineBuffer));
if (gbLineBuffer != nullptr) {
memset(gbLineBuffer, 0, kGBLineBufferSize);
}
// clean Pix
if (pix != NULL)
memset(pix, 0, sizeof(*pix));
if (pix != nullptr) {
memset(pix, 0, kGBPixSize);
}
// clean Vram
if (gbVram != NULL)
memset(gbVram, 0, 0x4000);
if (gbVram != nullptr) {
memset(gbVram, 0, kGBVRamSize);
}
// clean Wram 2
// This kinda emulates the startup state of Wram on GBC (not very accurate,
// but way closer to the reality than filling it with 00es or FFes).
@ -2567,7 +2588,7 @@ void gbReset()
// In all cases, most of the 2nd bank is filled with 00s.
// The starting data are important for some 'buggy' games, like Buster Brothers or
// Karamuchou ha Oosawagi!
if (gbWram != NULL) {
if (gbWram != nullptr) {
for (int i = 0; i < 8; i++)
if (i != 2)
memcpy((uint16_t*)(gbWram + i * 0x1000), (uint16_t*)(gbMemory + 0xC000), 0x1000);
@ -2732,9 +2753,9 @@ void gbReset()
if ((gbHardware & 7) && (bios != NULL) && coreOptions.useBios && !coreOptions.skipBios) {
if (gbHardware & 5) {
memcpy((uint8_t*)(gbMemory), (uint8_t*)(gbRom), 0x1000);
memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), 0x100);
memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), kGBBiosSize);
} else {
memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), 0x900);
memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), kCGBBiosSize);
memcpy((uint8_t*)(gbMemory + 0x100), (uint8_t*)(gbRom + 0x100), 0x100);
}
gbWhiteScreen = 0;
@ -3541,26 +3562,7 @@ bool gbReadSaveMMM01(const char* name)
} else
return false;
}
#endif // !__LIBRETRO__
void gbInit()
{
gbGenFilter();
gbSgbInit();
setColorizerHack(false);
gbMemory = (uint8_t*)malloc(65536);
#ifdef __LIBRETRO__
pix = (uint8_t*)calloc(1, 4 * 256 * 224);
#else
pix = (uint8_t*)calloc(1, 4 * 257 * 226);
#endif
gbLineBuffer = (uint16_t*)malloc(160 * sizeof(uint16_t));
}
#ifndef __LIBRETRO__
bool gbWriteBatteryFile(const char* file, bool extendedSave)
{
if (gbBattery) {
@ -3870,7 +3872,7 @@ static bool gbWriteSaveState(gzFile gzFile)
utilGzWrite(gzFile, gbTAMA5ram, kTama5RamSize);
utilGzWrite(gzFile, &gbDataMMM01, sizeof(gbDataMMM01));
utilGzWrite(gzFile, gbPalette, 128 * sizeof(uint16_t));
utilGzWrite(gzFile, gbPalette, sizeof(gbPalette));
utilGzWrite(gzFile, &gbMemory[0x8000], 0x8000);
@ -3880,8 +3882,8 @@ static bool gbWriteSaveState(gzFile gzFile)
}
if (gbCgbMode) {
utilGzWrite(gzFile, gbVram, 0x4000);
utilGzWrite(gzFile, gbWram, 0x8000);
utilGzWrite(gzFile, gbVram, kGBVRamSize);
utilGzWrite(gzFile, gbWram, kGBWRamSize);
}
gbSoundSaveGame(gzFile);
@ -3983,22 +3985,29 @@ static bool gbReadSaveState(gzFile gzFile)
utilReadData(gzFile, gbSaveGameStruct);
// Correct crash when loading color gameboy save in regular gameboy type.
if (!gbCgbMode) {
if (gbVram != NULL) {
free(gbVram);
gbVram = NULL;
if (gbCgbMode) {
if (gbVram == nullptr) {
gbVram = (uint8_t*)calloc(1, kGBVRamSize);
if (gbVram == nullptr) {
return false;
}
}
if (gbWram != NULL) {
free(gbWram);
gbWram = NULL;
if (gbWram == nullptr) {
gbWram = (uint8_t*)malloc(kGBWRamSize);
if (gbWram == nullptr) {
return false;
}
}
memset(gbPalette, 0, sizeof(gbPalette));
} else {
if (gbVram == NULL)
gbVram = (uint8_t*)malloc(0x4000);
if (gbWram == NULL)
gbWram = (uint8_t*)malloc(0x8000);
memset(gbVram, 0, 0x4000);
memset(gbPalette, 0, 2 * 128);
if (gbVram != nullptr) {
free(gbVram);
gbVram = nullptr;
}
if (gbWram != nullptr) {
free(gbWram);
gbWram = nullptr;
}
}
if (version >= GBSAVE_GAME_VERSION_7) {
@ -4034,7 +4043,7 @@ static bool gbReadSaveState(gzFile gzFile)
if (version < GBSAVE_GAME_VERSION_5) {
utilGzRead(gzFile, pix, 256 * 224 * sizeof(uint16_t));
}
memset(pix, 0, 257 * 226 * sizeof(uint32_t));
memset(pix, 0, kGBPixSize);
if (version < GBSAVE_GAME_VERSION_6) {
utilGzRead(gzFile, gbPalette, 64 * sizeof(uint16_t));
@ -4080,9 +4089,9 @@ static bool gbReadSaveState(gzFile gzFile)
gbMemoryMap[0x00] = &gbMemory[0x0000];
if (gbHardware & 5) {
memcpy((uint8_t*)(gbMemory), (uint8_t*)(gbRom), 0x1000);
memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), 0x100);
memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), kGBBiosSize);
} else if (gbHardware & 2) {
memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), 0x900);
memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), kCGBBiosSize);
memcpy((uint8_t*)(gbMemory + 0x100), (uint8_t*)(gbRom + 0x100), 0x100);
}
@ -4166,8 +4175,8 @@ static bool gbReadSaveState(gzFile gzFile)
}
if (gbCgbMode) {
utilGzRead(gzFile, gbVram, 0x4000);
utilGzRead(gzFile, gbWram, 0x8000);
utilGzRead(gzFile, gbVram, kGBVRamSize);
utilGzRead(gzFile, gbWram, kGBWRamSize);
int value = register_SVBK;
if (value == 0)
@ -4275,8 +4284,10 @@ static bool gbReadSaveState(gzFile gzFile)
systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
if (version >= 12 && utilReadInt(gzFile) != 0x12345678)
assert(false); // fails if something read too much/little from file
if (version >= 12 && utilReadInt(gzFile) != 0x12345678) {
// fails if something read too much/little from file
return false;
}
return true;
}
@ -4310,65 +4321,65 @@ bool gbReadSaveState(const char* name)
bool gbWritePNGFile(const char* fileName)
{
if (gbBorderOn)
return utilWritePNGFile(fileName, 256, 224, pix);
return utilWritePNGFile(fileName, 160, 144, pix);
return utilWritePNGFile(fileName, kSGBWidth, kSGBHeight, pix);
return utilWritePNGFile(fileName, kGBWidth, kGBHeight, pix);
}
bool gbWriteBMPFile(const char* fileName)
{
if (gbBorderOn)
return utilWriteBMPFile(fileName, 256, 224, pix);
return utilWriteBMPFile(fileName, 160, 144, pix);
return utilWriteBMPFile(fileName, kSGBWidth, kSGBHeight, pix);
return utilWriteBMPFile(fileName, kGBWidth, kGBHeight, pix);
}
#endif // !__LIBRETRO__
void gbCleanUp()
{
if (gbRam != NULL) {
if (gbRam != nullptr) {
free(gbRam);
gbRam = NULL;
gbRam = nullptr;
}
if (gbRom != NULL) {
if (gbRom != nullptr) {
free(gbRom);
gbRom = NULL;
gbRom = nullptr;
}
if (bios != NULL) {
if (bios != nullptr) {
free(bios);
bios = NULL;
bios = nullptr;
}
if (gbMemory != NULL) {
if (gbMemory != nullptr) {
free(gbMemory);
gbMemory = NULL;
gbMemory = nullptr;
}
if (gbLineBuffer != NULL) {
if (gbLineBuffer != nullptr) {
free(gbLineBuffer);
gbLineBuffer = NULL;
gbLineBuffer = nullptr;
}
if (pix != NULL) {
if (pix != nullptr) {
free(pix);
pix = NULL;
pix = nullptr;
}
gbSgbShutdown();
if (gbVram != NULL) {
if (gbVram != nullptr) {
free(gbVram);
gbVram = NULL;
gbVram = nullptr;
}
if (gbWram != NULL) {
if (gbWram != nullptr) {
free(gbWram);
gbWram = NULL;
gbWram = nullptr;
}
if (gbTAMA5ram != NULL) {
if (gbTAMA5ram != nullptr) {
free(gbTAMA5ram);
gbTAMA5ram = NULL;
gbTAMA5ram = nullptr;
}
g_gbCartData = gbCartData();
@ -4398,7 +4409,10 @@ bool gbLoadRom(const char* filename) {
free(bios);
bios = nullptr;
}
bios = (uint8_t*)calloc(1, 0x900);
bios = (uint8_t*)calloc(1, kGBBiosBufferSize);
if (bios == nullptr) {
return false;
}
return gbInitializeRom(romSize);
}
@ -4445,7 +4459,7 @@ void gbDrawLine()
uint16_t* dest = (uint16_t*)pix + (gbBorderLineSkip + 2) * (register_LY + gbBorderRowSkip + 1)
+ gbBorderColumnSkip;
#endif
for (int x = 0; x < 160;) {
for (size_t x = 0; x < kGBWidth;) {
*dest++ = systemColorMap16[gbLineMix[x++]];
*dest++ = systemColorMap16[gbLineMix[x++]];
*dest++ = systemColorMap16[gbLineMix[x++]];
@ -4475,7 +4489,7 @@ void gbDrawLine()
case 24: {
uint8_t* dest = (uint8_t*)pix + 3 * (gbBorderLineSkip * (register_LY + gbBorderRowSkip) + gbBorderColumnSkip);
for (int x = 0; x < 160;) {
for (size_t x = 0; x < kGBWidth;) {
*((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]];
dest += 3;
*((uint32_t*)dest) = systemColorMap32[gbLineMix[x++]];
@ -4522,7 +4536,7 @@ void gbDrawLine()
uint32_t* dest = (uint32_t*)pix + (gbBorderLineSkip + 1) * (register_LY + gbBorderRowSkip + 1)
+ gbBorderColumnSkip;
#endif
for (int x = 0; x < 160;) {
for (size_t x = 0; x < kGBWidth;) {
*dest++ = systemColorMap32[gbLineMix[x++]];
*dest++ = systemColorMap32[gbLineMix[x++]];
*dest++ = systemColorMap32[gbLineMix[x++]];
@ -4770,7 +4784,7 @@ void gbEmulate(int ticksToStop)
case 0: {
// H-Blank
// check if we reached the V-Blank period
if (register_LY == 144) {
if (register_LY == kGBHeight) {
// Yes, V-Blank
// set the LY increment counter
if (gbHardware & 0x5) {
@ -4845,7 +4859,7 @@ void gbEmulate(int ticksToStop)
int tempinUseRegister_WY = inUseRegister_WY;
int tempgbWindowLine = gbWindowLine;
if ((tempgbWindowLine == -1) || (tempgbWindowLine > 144)) {
if ((tempgbWindowLine == -1) || (tempgbWindowLine > (int)kGBHeight)) {
tempinUseRegister_WY = oldRegister_WY;
if (register_LY > oldRegister_WY)
tempgbWindowLine = 146;
@ -4952,7 +4966,7 @@ void gbEmulate(int ticksToStop)
if (gbWindowLine < 0)
oldRegister_WY = register_WY;
// check if we reached the V-Blank period
if (register_LY == 144) {
if (register_LY == kGBHeight) {
// Yes, V-Blank
// set the LY increment counter
@ -5054,7 +5068,7 @@ void gbEmulate(int ticksToStop)
// OAM and VRAM in use
// next mode is H-Blank
if ((register_LY < 144) && (register_LCDC & 0x80) && gbScreenOn) {
if ((register_LY < kGBHeight) && (register_LCDC & 0x80) && gbScreenOn) {
if (!gbSgbMask) {
if (gbFrameSkipCount >= framesToSkip) {
if (!gbBlackScreen) {
@ -5064,7 +5078,7 @@ void gbEmulate(int ticksToStop)
uint16_t color = gbColorOption ? gbColorFilter[0] : 0;
if (!gbCgbMode)
color = gbColorOption ? gbColorFilter[gbPalette[3] & 0x7FFF] : gbPalette[3] & 0x7FFF;
for (int i = 0; i < 160; i++) {
for (size_t i = 0; i < kGBWidth; i++) {
gbLineMix[i] = color;
gbLineBuffer[i] = 0;
}
@ -5129,7 +5143,7 @@ void gbEmulate(int ticksToStop)
uint16_t color = gbColorOption ? gbColorFilter[0x7FFF] : 0x7FFF;
if (!gbCgbMode)
color = gbColorOption ? gbColorFilter[gbPalette[0] & 0x7FFF] : gbPalette[0] & 0x7FFF;
for (int i = 0; i < 160; i++) {
for (size_t i = 0; i < kGBWidth; i++) {
gbLineMix[i] = color;
gbLineBuffer[i] = 0;
}
@ -5145,17 +5159,17 @@ void gbEmulate(int ticksToStop)
while (gbLcdLYIncrementTicks <= 0) {
register_LY = ((register_LY + 1) % 154);
gbLcdLYIncrementTicks += GBLY_INCREMENT_CLOCK_TICKS;
if (register_LY < 144) {
if (register_LY < kGBHeight) {
uint16_t color = gbColorOption ? gbColorFilter[0x7FFF] : 0x7FFF;
if (!gbCgbMode)
color = gbColorOption ? gbColorFilter[gbPalette[0] & 0x7FFF] : gbPalette[0] & 0x7FFF;
for (int i = 0; i < 160; i++) {
for (size_t i = 0; i < kGBWidth; i++) {
gbLineMix[i] = color;
gbLineBuffer[i] = 0;
}
gbDrawLine();
} else if ((register_LY == 144) && (!systemFrameSkip)) {
} else if ((register_LY == kGBHeight) && (!systemFrameSkip)) {
int framesToSkip = systemFrameSkip;
//if (coreOptions.speedup)
// framesToSkip = 9; // try 6 FPS during speedup
@ -5457,7 +5471,7 @@ bool gbLoadRomData(const char* data, size_t size) {
gbRom = (uint8_t*)calloc(1, size);
if (gbRom == nullptr) {
return 0;
return false;
}
memcpy(gbRom, data, size);
@ -5469,7 +5483,10 @@ bool gbLoadRomData(const char* data, size_t size) {
bios = nullptr;
}
bios = (uint8_t*)calloc(1, 0x900);
bios = (uint8_t*)calloc(1, kGBBiosBufferSize);
if (bios == nullptr) {
return false;
}
return gbInitializeRom(size);
}
@ -5524,7 +5541,7 @@ unsigned int gbWriteSaveState(uint8_t* data)
utilWriteMem(data, gbTAMA5ram, kTama5RamSize);
utilWriteMem(data, &gbDataMMM01, sizeof(gbDataMMM01));
utilWriteMem(data, gbPalette, 128 * sizeof(uint16_t));
utilWriteMem(data, gbPalette, sizeof(gbPalette));
utilWriteMem(data, &gbMemory[0x8000], 0x8000);
@ -5534,8 +5551,8 @@ unsigned int gbWriteSaveState(uint8_t* data)
}
if (gbCgbMode) {
utilWriteMem(data, gbVram, 0x4000);
utilWriteMem(data, gbWram, 0x8000);
utilWriteMem(data, gbVram, kGBVRamSize);
utilWriteMem(data, gbWram, kGBWRamSize);
}
gbSoundSaveGame(data);
@ -5604,22 +5621,29 @@ bool gbReadSaveState(const uint8_t* data)
utilReadDataMem(data, gbSaveGameStruct);
// Correct crash when loading color gameboy save in regular gameboy type.
if (!gbCgbMode) {
if (gbVram != NULL) {
free(gbVram);
gbVram = NULL;
if (gbCgbMode) {
if (gbVram == nullptr) {
gbVram = (uint8_t*)calloc(1, kGBVRamSize);
if (gbVram == nullptr) {
return false;
}
}
if (gbWram != NULL) {
free(gbWram);
gbWram = NULL;
if (gbWram == nullptr) {
gbWram = (uint8_t*)malloc(kGBWRamSize);
if (gbWram == nullptr) {
return false;
}
}
memset(gbPalette, 0, sizeof(gbPalette));
} else {
if (gbVram == NULL)
gbVram = (uint8_t*)malloc(0x4000);
if (gbWram == NULL)
gbWram = (uint8_t*)malloc(0x8000);
memset(gbVram, 0, 0x4000);
memset(gbPalette, 0, 2 * 128);
if (gbVram != nullptr) {
free(gbVram);
gbVram = nullptr;
}
if (gbWram != nullptr) {
free(gbWram);
gbWram = nullptr;
}
}
utilReadMem(&IFF, data, 2);
@ -5644,7 +5668,7 @@ bool gbReadSaveState(const uint8_t* data)
}
utilReadMem(&gbDataMMM01, data, sizeof(gbDataMMM01));
utilReadMem(gbPalette, data, 128 * sizeof(uint16_t));
utilReadMem(gbPalette, data, sizeof(gbPalette));
utilReadMem(&gbMemory[0x8000], data, 0x8000);
@ -5666,9 +5690,9 @@ bool gbReadSaveState(const uint8_t* data)
gbMemoryMap[0x00] = &gbMemory[0x0000];
if (gbHardware & 5) {
memcpy((uint8_t*)(gbMemory), (uint8_t*)(gbRom), 0x1000);
memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), 0x100);
memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), kGBBiosSize);
} else if (gbHardware & 2) {
memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), 0x900);
memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), kCGBBiosSize);
memcpy((uint8_t*)(gbMemory + 0x100), (uint8_t*)(gbRom + 0x100), 0x100);
}
@ -5754,8 +5778,8 @@ bool gbReadSaveState(const uint8_t* data)
}
if (gbCgbMode) {
utilReadMem(gbVram, data, 0x4000);
utilReadMem(gbWram, data, 0x8000);
utilReadMem(gbVram, data, kGBVRamSize);
utilReadMem(gbWram, data, kGBWRamSize);
int value = register_SVBK;
if (value == 0)
@ -5795,8 +5819,10 @@ bool gbReadSaveState(const uint8_t* data)
systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
if (version >= 12 && utilReadIntMem(data) != 0x12345678)
assert(false); // fails if something read too much/little from file
if (version >= 12 && utilReadIntMem(data) != 0x12345678) {
// fails if something read too much/little from file
return false;
}
return true;
}

View File

@ -391,6 +391,10 @@ gbCartData::gbCartData(const uint8_t* romData, size_t romDataSize) {
ram_size_ = k128KiB;
break;
case 0x05:
// Technically, this refers to a 1 Mbit (128 KiB) RAM chip, but
// this is only used in Pocket Monsters Crystal JP, which has a
// mapper chip referred as "MBC30". This mapper can only address
// half of the RAM chip. So, we set the size to 64 KiB.
ram_size_ = k64KiB;
break;
default:

View File

@ -8,13 +8,13 @@ int gbRomSize = 0;
int gbRamSizeMask = 0;
int gbRamSize = 0;
uint8_t* gbMemory = NULL;
uint8_t* gbVram = NULL;
uint8_t* gbRom = NULL;
uint8_t* gbRam = NULL;
uint8_t* gbWram = NULL;
uint16_t* gbLineBuffer = NULL;
uint8_t* gbTAMA5ram = NULL;
uint8_t* gbMemory = nullptr;
uint8_t* gbVram = nullptr;
uint8_t* gbRom = nullptr;
uint8_t* gbRam = nullptr;
uint8_t* gbWram = nullptr;
uint16_t* gbLineBuffer = nullptr;
uint8_t* gbTAMA5ram = nullptr;
uint16_t gbPalette[128];
uint8_t gbBgp[4] = { 0, 1, 2, 3 };