diff --git a/Core/gb.c b/Core/gb.c index bad1910..2712da9 100644 --- a/Core/gb.c +++ b/Core/gb.c @@ -95,7 +95,7 @@ void GB_init(GB_gameboy_t *gb, GB_model_t model) memset(gb, 0, sizeof(*gb)); gb->model = model; if (GB_is_cgb(gb)) { - gb->ram = malloc(gb->ram_size = 0x2000 * 8); + gb->ram = malloc(gb->ram_size = 0x1000 * 8); gb->vram = malloc(gb->vram_size = 0x2000 * 2); } else { @@ -632,7 +632,7 @@ void GB_reset(GB_gameboy_t *gb) gb->io_registers[GB_IO_JOYP] = 0xF; gb->mbc_ram_size = mbc_ram_size; if (GB_is_cgb(gb)) { - gb->ram_size = 0x2000 * 8; + gb->ram_size = 0x1000 * 8; gb->vram_size = 0x2000 * 2; memset(gb->vram, 0, gb->vram_size); gb->cgb_mode = true; @@ -703,7 +703,7 @@ void GB_switch_model_and_reset(GB_gameboy_t *gb, GB_model_t model) { gb->model = model; if (GB_is_cgb(gb)) { - gb->ram = realloc(gb->ram, gb->ram_size = 0x2000 * 8); + gb->ram = realloc(gb->ram, gb->ram_size = 0x1000 * 8); gb->vram = realloc(gb->vram, gb->vram_size = 0x2000 * 2); } else { diff --git a/Core/gb.h b/Core/gb.h index b798a04..5385710 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -333,6 +333,7 @@ struct GB_gameboy_internal_s { bool infrared_input; GB_printer_t printer; uint8_t extra_oam[0xff00 - 0xfea0]; + uint32_t ram_size; // Different between CGB and DMG ); /* DMA and HDMA */ @@ -593,7 +594,6 @@ struct GB_gameboy_internal_s { bool turbo; bool turbo_dont_skip; bool disable_rendering; - uint32_t ram_size; // Different between CGB and DMG uint8_t boot_rom[0x900]; bool vblank_just_occured; // For slow operations involving syscalls; these should only run once per vblank uint8_t cycles_since_run; // How many cycles have passed since the last call to GB_run(), in 8MHz units diff --git a/Core/save_state.c b/Core/save_state.c index 26c9b52..1cd3458 100644 --- a/Core/save_state.c +++ b/Core/save_state.c @@ -156,11 +156,6 @@ static bool verify_state_compatibility(GB_gameboy_t *gb, GB_gameboy_t *save) return false; } - if (gb->ram_size != save->ram_size) { - GB_log(gb, "The save state has non-matching RAM size. Try changing the emulated model.\n"); - return false; - } - if (gb->vram_size != save->vram_size) { GB_log(gb, "The save state has non-matching VRAM size. Try changing the emulated model.\n"); return false; @@ -171,6 +166,17 @@ static bool verify_state_compatibility(GB_gameboy_t *gb, GB_gameboy_t *save) return false; } + if (gb->ram_size != save->ram_size) { + if (gb->ram_size == 0x1000 * 8 && save->ram_size == 0x2000 * 8) { + /* A bug in versions prior to 0.12 made CGB instances allocate twice the ammount of RAM. + Ignore this issue to retain compatibility with older, 0.11, save states. */ + } + else { + GB_log(gb, "The save state has non-matching RAM size. Try changing the emulated model.\n"); + return false; + } + } + return true; } @@ -182,6 +188,8 @@ int GB_load_state(GB_gameboy_t *gb, const char *path) /* Every unread value should be kept the same. */ memcpy(&save, gb, sizeof(save)); + /* ...Except ram size, we use it to detect old saves with incorrect ram sizes */ + save.ram_size = 0; FILE *f = fopen(path, "rb"); if (!f) { @@ -199,6 +207,17 @@ int GB_load_state(GB_gameboy_t *gb, const char *path) if (!READ_SECTION(&save, f, rtc )) goto error; if (!READ_SECTION(&save, f, video )) goto error; + if (save.ram_size == 0) { + /* Save doesn't have ram size specified, it's a pre 0.12 save state with potentially + incorrect RAM amount if it's a CGB instance */ + if (GB_is_cgb(&save)) { + save.ram_size = 0x2000 * 8; // Incorrect RAM size + } + else { + save.ram_size = gb->ram_size; + } + } + if (!verify_state_compatibility(gb, &save)) { errno = -1; goto error; @@ -218,13 +237,19 @@ int GB_load_state(GB_gameboy_t *gb, const char *path) fclose(f); return EIO; } + + /* Fix for 0.11 save states that allocate twice the amount of RAM in CGB instances */ + fseek(f, save.ram_size - gb->ram_size, SEEK_CUR); if (fread(gb->vram, 1, gb->vram_size, f) != gb->vram_size) { fclose(f); return EIO; } + size_t orig_ram_size = gb->ram_size; memcpy(gb, &save, sizeof(save)); + gb->ram_size = orig_ram_size; + errno = 0; if (gb->cartridge_type->has_rumble && gb->rumble_callback) { @@ -324,6 +349,10 @@ int GB_load_state_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t le return -1; } + /* Fix for 0.11 save states that allocate twice the amount of RAM in CGB instances */ + buffer += save.ram_size - gb->ram_size; + length -= save.ram_size - gb->ram_size; + memcpy(gb, &save, sizeof(save)); if (gb->cartridge_type->has_rumble && gb->rumble_callback) {