diff --git a/bsnes/emulator/emulator.cpp b/bsnes/emulator/emulator.cpp index 1b7d3658..ce4b7055 100644 --- a/bsnes/emulator/emulator.cpp +++ b/bsnes/emulator/emulator.cpp @@ -1,6 +1,5 @@ #include #include -#include namespace Emulator { diff --git a/bsnes/emulator/emulator.hpp b/bsnes/emulator/emulator.hpp index d7bc920d..eb4afc61 100644 --- a/bsnes/emulator/emulator.hpp +++ b/bsnes/emulator/emulator.hpp @@ -28,11 +28,10 @@ using namespace nall; #include #include #include -#include namespace Emulator { static const string Name = "bsnes"; - static const string Version = "107.14"; + static const string Version = "107.15"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "https://byuu.org"; diff --git a/bsnes/emulator/resource/GNUmakefile b/bsnes/emulator/resource/GNUmakefile deleted file mode 100644 index 8218cabb..00000000 --- a/bsnes/emulator/resource/GNUmakefile +++ /dev/null @@ -1,6 +0,0 @@ -all: - sourcery resource.bml resource.cpp resource.hpp - -clean: - rm resource.cpp - rm resource.hpp diff --git a/bsnes/emulator/resource/resource.bml b/bsnes/emulator/resource/resource.bml deleted file mode 100644 index 39d109a1..00000000 --- a/bsnes/emulator/resource/resource.bml +++ /dev/null @@ -1,5 +0,0 @@ -namespace name=Resource - namespace name=Sprite - binary name=CrosshairRed file=sprite/crosshair-red.png - binary name=CrosshairGreen file=sprite/crosshair-green.png - binary name=CrosshairBlue file=sprite/crosshair-blue.png diff --git a/bsnes/emulator/resource/resource.cpp b/bsnes/emulator/resource/resource.cpp deleted file mode 100644 index 2d675a8a..00000000 --- a/bsnes/emulator/resource/resource.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "resource.hpp" - -namespace Resource { -namespace Sprite { -const unsigned char CrosshairRed[342] = { - 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0,0,115,122,122, - 244,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,9,112,72,89,115,0,0,14,196,0,0,14, - 196,1,149,43,14,27,0,0,0,248,73,68,65,84,88,133,205,87,65,14,196,32,8,132,102,255,255,101,246,176,177,139, - 148,81,80,27,229,212,70,102,6,212,0,50,229,77,26,107,156,37,139,2,228,241,209,39,11,113,71,156,68,139,106,128, - 56,255,198,175,203,223,114,16,79,68,253,138,90,99,141,113,112,80,231,131,196,11,83,52,19,43,196,53,135,147,7,38, - 150,104,244,212,32,86,235,228,236,20,6,200,207,191,117,215,70,12,242,94,139,133,166,236,173,236,67,252,111,139,67,157, - 237,71,48,27,192,244,142,93,228,23,148,144,184,228,131,96,254,3,164,4,176,213,108,37,52,5,208,53,47,227,81,28, - 49,153,102,163,88,96,149,68,150,193,21,223,59,128,68,43,69,13,103,4,199,246,8,34,151,240,209,249,38,112,251,47, - 97,177,209,74,152,246,95,93,9,211,51,160,181,99,142,128,104,115,55,124,59,136,115,7,146,237,51,33,2,71,166,226, - 94,23,13,77,214,104,44,103,174,163,143,86,189,244,187,224,232,151,81,21,132,39,210,33,91,246,54,132,193,44,226,219, - 107,95,57,136,120,253,172,254,16,23,0,0,0,0,73,69,78,68,174,66,96,130, -}; -const unsigned char CrosshairGreen[329] = { - 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0,0,115,122,122, - 244,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,9,112,72,89,115,0,0,14,196,0,0,14, - 196,1,149,43,14,27,0,0,0,235,73,68,65,84,88,133,213,87,65,18,195,32,8,196,78,31,230,211,253,153,61,180, - 52,18,145,1,193,97,178,39,141,44,139,24,69,11,216,209,133,177,98,117,166,37,92,162,77,176,170,118,223,26,163,78, - 68,71,145,198,244,169,157,57,35,84,248,43,222,255,109,154,254,113,140,114,102,222,18,239,165,120,251,181,42,0,232,103, - 114,217,85,226,163,27,124,232,163,87,142,115,153,82,137,71,98,233,247,21,44,228,194,169,217,171,252,159,22,95,234,164, - 47,129,55,128,144,140,237,166,63,132,151,190,4,247,147,16,103,35,157,90,220,140,119,121,80,224,94,108,0,164,227,119, - 182,221,229,13,182,82,193,225,176,42,56,59,188,105,9,52,5,3,109,58,243,205,202,203,255,9,17,251,91,202,169,227, - 205,128,235,198,19,17,64,40,82,171,225,233,32,158,113,33,65,164,222,9,105,16,50,81,55,238,88,210,212,119,1,0, - 238,241,241,126,143,125,62,216,173,151,209,35,222,134,235,96,98,252,229,226,3,112,72,179,236,202,138,114,18,0,0,0, - 0,73,69,78,68,174,66,96,130, -}; -const unsigned char CrosshairBlue[332] = { - 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0,0,115,122,122, - 244,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,9,112,72,89,115,0,0,14,196,0,0,14, - 196,1,149,43,14,27,0,0,0,238,73,68,65,84,88,133,213,87,91,18,195,32,8,196,78,15,232,81,189,161,253,9, - 25,52,98,121,57,76,246,43,137,44,11,24,69,11,232,209,55,99,69,235,76,74,184,69,107,229,245,91,27,220,137,124, - 75,140,58,21,165,34,181,246,199,251,100,167,174,200,32,124,137,119,124,134,177,252,116,108,224,44,120,44,190,156,56,102, - 163,204,228,182,107,173,80,31,93,225,67,30,189,112,124,85,41,145,120,36,88,191,159,96,33,23,78,101,47,242,127,90, - 156,213,73,159,2,111,0,33,21,179,150,63,132,151,62,5,243,78,136,217,236,118,173,85,198,86,30,20,152,154,13,192, - 118,251,125,216,90,121,212,118,215,112,86,224,26,142,133,247,152,2,73,195,64,155,190,248,166,229,229,255,132,8,243,146, - 242,234,120,43,224,58,241,68,4,16,138,212,110,120,58,136,119,28,72,16,169,103,194,33,136,63,68,209,184,103,74,83, - 239,5,0,215,26,167,231,123,124,103,130,53,221,140,94,113,55,100,131,9,242,151,139,31,79,50,234,237,105,206,30,22, - 0,0,0,0,73,69,78,68,174,66,96,130, -}; -} -} diff --git a/bsnes/emulator/resource/resource.hpp b/bsnes/emulator/resource/resource.hpp deleted file mode 100644 index 5c888361..00000000 --- a/bsnes/emulator/resource/resource.hpp +++ /dev/null @@ -1,7 +0,0 @@ -namespace Resource { -namespace Sprite { -extern const unsigned char CrosshairRed[342]; -extern const unsigned char CrosshairGreen[329]; -extern const unsigned char CrosshairBlue[332]; -} -} diff --git a/bsnes/emulator/resource/sprite/crosshair-blue.png b/bsnes/emulator/resource/sprite/crosshair-blue.png deleted file mode 100644 index 56687d62..00000000 Binary files a/bsnes/emulator/resource/sprite/crosshair-blue.png and /dev/null differ diff --git a/bsnes/emulator/resource/sprite/crosshair-green.png b/bsnes/emulator/resource/sprite/crosshair-green.png deleted file mode 100644 index d0441b52..00000000 Binary files a/bsnes/emulator/resource/sprite/crosshair-green.png and /dev/null differ diff --git a/bsnes/emulator/resource/sprite/crosshair-red.png b/bsnes/emulator/resource/sprite/crosshair-red.png deleted file mode 100644 index 791e4af1..00000000 Binary files a/bsnes/emulator/resource/sprite/crosshair-red.png and /dev/null differ diff --git a/bsnes/gb/Core/gb.c b/bsnes/gb/Core/gb.c index 8c2330a4..b1f4ea41 100644 --- a/bsnes/gb/Core/gb.c +++ b/bsnes/gb/Core/gb.c @@ -250,6 +250,48 @@ typedef union { } vba64; } GB_rtc_save_t; +int GB_save_battery_size(GB_gameboy_t *gb) +{ + if (!gb->cartridge_type->has_battery) return 0; // Nothing to save. + if (gb->mbc_ram_size == 0 && !gb->cartridge_type->has_rtc) return 0; /* Claims to have battery, but has no RAM or RTC */ + + GB_rtc_save_t rtc_save_size; + return gb->mbc_ram_size + (gb->cartridge_type->has_rtc ? sizeof(rtc_save_size.vba64) : 0); +} + +int GB_save_battery_to_buffer(GB_gameboy_t *gb, uint8_t *buffer, size_t size) +{ + if (!gb->cartridge_type->has_battery) return 0; // Nothing to save. + if (gb->mbc_ram_size == 0 && !gb->cartridge_type->has_rtc) return 0; /* Claims to have battery, but has no RAM or RTC */ + + if (size < GB_save_battery_size(gb)) return EIO; + + memcpy(buffer, gb->mbc_ram, gb->mbc_ram_size); + + if (gb->cartridge_type->has_rtc) { + GB_rtc_save_t rtc_save = {{{{0,}},},}; + rtc_save.vba64.rtc_real.seconds = gb->rtc_real.seconds; + rtc_save.vba64.rtc_real.minutes = gb->rtc_real.minutes; + rtc_save.vba64.rtc_real.hours = gb->rtc_real.hours; + rtc_save.vba64.rtc_real.days = gb->rtc_real.days; + rtc_save.vba64.rtc_real.high = gb->rtc_real.high; + rtc_save.vba64.rtc_latched.seconds = gb->rtc_latched.seconds; + rtc_save.vba64.rtc_latched.minutes = gb->rtc_latched.minutes; + rtc_save.vba64.rtc_latched.hours = gb->rtc_latched.hours; + rtc_save.vba64.rtc_latched.days = gb->rtc_latched.days; + rtc_save.vba64.rtc_latched.high = gb->rtc_latched.high; +#ifdef GB_BIG_ENDIAN + rtc_save.vba64.last_rtc_second = __builtin_bswap64(gb->last_rtc_second); +#else + rtc_save.vba64.last_rtc_second = gb->last_rtc_second; +#endif + memcpy(buffer + gb->mbc_ram_size, &rtc_save.vba64, sizeof(rtc_save.vba64)); + } + + errno = 0; + return errno; +} + int GB_save_battery(GB_gameboy_t *gb, const char *path) { if (!gb->cartridge_type->has_battery) return 0; // Nothing to save. @@ -293,6 +335,79 @@ int GB_save_battery(GB_gameboy_t *gb, const char *path) return errno; } +void GB_load_battery_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t size) +{ + memcpy(gb->mbc_ram, buffer, MIN(gb->mbc_ram_size, size)); + if (size <= gb->mbc_ram_size) { + goto reset_rtc; + } + + GB_rtc_save_t rtc_save; + memcpy(&rtc_save, buffer + gb->mbc_ram_size, MIN(sizeof(rtc_save), size)); + switch (size - gb->mbc_ram_size) { + case sizeof(rtc_save.sameboy_legacy): + memcpy(&gb->rtc_real, &rtc_save.sameboy_legacy.rtc_real, sizeof(gb->rtc_real)); + memcpy(&gb->rtc_latched, &rtc_save.sameboy_legacy.rtc_real, sizeof(gb->rtc_real)); + gb->last_rtc_second = rtc_save.sameboy_legacy.last_rtc_second; + break; + + case sizeof(rtc_save.vba32): + gb->rtc_real.seconds = rtc_save.vba32.rtc_real.seconds; + gb->rtc_real.minutes = rtc_save.vba32.rtc_real.minutes; + gb->rtc_real.hours = rtc_save.vba32.rtc_real.hours; + gb->rtc_real.days = rtc_save.vba32.rtc_real.days; + gb->rtc_real.high = rtc_save.vba32.rtc_real.high; + gb->rtc_latched.seconds = rtc_save.vba32.rtc_latched.seconds; + gb->rtc_latched.minutes = rtc_save.vba32.rtc_latched.minutes; + gb->rtc_latched.hours = rtc_save.vba32.rtc_latched.hours; + gb->rtc_latched.days = rtc_save.vba32.rtc_latched.days; + gb->rtc_latched.high = rtc_save.vba32.rtc_latched.high; +#ifdef GB_BIG_ENDIAN + gb->last_rtc_second = __builtin_bswap32(rtc_save.vba32.last_rtc_second); +#else + gb->last_rtc_second = rtc_save.vba32.last_rtc_second; +#endif + break; + + case sizeof(rtc_save.vba64): + gb->rtc_real.seconds = rtc_save.vba64.rtc_real.seconds; + gb->rtc_real.minutes = rtc_save.vba64.rtc_real.minutes; + gb->rtc_real.hours = rtc_save.vba64.rtc_real.hours; + gb->rtc_real.days = rtc_save.vba64.rtc_real.days; + gb->rtc_real.high = rtc_save.vba64.rtc_real.high; + gb->rtc_latched.seconds = rtc_save.vba64.rtc_latched.seconds; + gb->rtc_latched.minutes = rtc_save.vba64.rtc_latched.minutes; + gb->rtc_latched.hours = rtc_save.vba64.rtc_latched.hours; + gb->rtc_latched.days = rtc_save.vba64.rtc_latched.days; + gb->rtc_latched.high = rtc_save.vba64.rtc_latched.high; +#ifdef GB_BIG_ENDIAN + gb->last_rtc_second = __builtin_bswap64(rtc_save.vba64.last_rtc_second); +#else + gb->last_rtc_second = rtc_save.vba64.last_rtc_second; +#endif + break; + + default: + goto reset_rtc; + } + if (gb->last_rtc_second > time(NULL)) { + /* We must reset RTC here, or it will not advance. */ + goto reset_rtc; + } + + if (gb->last_rtc_second < 852076800) { /* 1/1/97. There weren't any RTC games that time, + so if the value we read is lower it means it wasn't + really RTC data. */ + goto reset_rtc; + } + goto exit; +reset_rtc: + gb->last_rtc_second = time(NULL); + gb->rtc_real.high |= 0x80; /* This gives the game a hint that the clock should be reset. */ +exit: + return; +} + /* Loading will silently stop if the format is incomplete */ void GB_load_battery(GB_gameboy_t *gb, const char *path) { diff --git a/bsnes/gb/Core/gb.h b/bsnes/gb/Core/gb.h index 9c2dc8d3..c3e877c2 100644 --- a/bsnes/gb/Core/gb.h +++ b/bsnes/gb/Core/gb.h @@ -670,8 +670,12 @@ int GB_load_boot_rom(GB_gameboy_t *gb, const char *path); void GB_load_boot_rom_from_buffer(GB_gameboy_t *gb, const unsigned char *buffer, size_t size); int GB_load_rom(GB_gameboy_t *gb, const char *path); void GB_load_rom_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t size); - + +int GB_save_battery_size(GB_gameboy_t *gb); +int GB_save_battery_to_buffer(GB_gameboy_t *gb, uint8_t *buffer, size_t size); int GB_save_battery(GB_gameboy_t *gb, const char *path); + +void GB_load_battery_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t size); void GB_load_battery(GB_gameboy_t *gb, const char *path); void GB_set_turbo_mode(GB_gameboy_t *gb, bool on, bool no_frame_skip); diff --git a/bsnes/sfc/cartridge/cartridge.cpp b/bsnes/sfc/cartridge/cartridge.cpp index 3f574b38..2e939d1b 100644 --- a/bsnes/sfc/cartridge/cartridge.cpp +++ b/bsnes/sfc/cartridge/cartridge.cpp @@ -128,7 +128,7 @@ auto Cartridge::loadSufamiTurboB() -> bool { auto Cartridge::save() -> void { saveCartridge(game.document); if(has.GameBoySlot) { - saveCartridgeGameBoy(slotGameBoy.document); + icd.save(); } if(has.BSMemorySlot) { saveCartridgeBSMemory(slotBSMemory.document); diff --git a/bsnes/sfc/cartridge/cartridge.hpp b/bsnes/sfc/cartridge/cartridge.hpp index 867bafea..671f209b 100644 --- a/bsnes/sfc/cartridge/cartridge.hpp +++ b/bsnes/sfc/cartridge/cartridge.hpp @@ -98,7 +98,6 @@ private: //save.cpp auto saveCartridge(Markup::Node) -> void; - auto saveCartridgeGameBoy(Markup::Node) -> void; auto saveCartridgeBSMemory(Markup::Node) -> void; auto saveCartridgeSufamiTurboA(Markup::Node) -> void; auto saveCartridgeSufamiTurboB(Markup::Node) -> void; diff --git a/bsnes/sfc/cartridge/save.cpp b/bsnes/sfc/cartridge/save.cpp index bd547200..89ef7729 100644 --- a/bsnes/sfc/cartridge/save.cpp +++ b/bsnes/sfc/cartridge/save.cpp @@ -13,9 +13,6 @@ auto Cartridge::saveCartridge(Markup::Node node) -> void { if(auto node = board["processor(identifier=OBC1)"]) saveOBC1(node); } -auto Cartridge::saveCartridgeGameBoy(Markup::Node node) -> void { -} - auto Cartridge::saveCartridgeBSMemory(Markup::Node node) -> void { if(auto memory = Emulator::Game::Memory{node["game/board/memory(type=Flash,content=Program)"]}) { if(auto fp = platform->open(bsmemory.pathID, memory.name(), File::Write)) { diff --git a/bsnes/sfc/coprocessor/icd/icd.cpp b/bsnes/sfc/coprocessor/icd/icd.cpp index bab08593..f10cf859 100644 --- a/bsnes/sfc/coprocessor/icd/icd.cpp +++ b/bsnes/sfc/coprocessor/icd/icd.cpp @@ -101,11 +101,31 @@ auto ICD::load() -> bool { cartridge.information.sha256 = Hash::SHA256({data, (uint64_t)size}).digest(); fp->read(data, size); GB_load_rom_from_buffer(&sameboy, data, size); + free(data); } else return unload(), false; + if(auto fp = platform->open(pathID(), "save.ram", File::Read)) { + auto size = fp->size(); + auto data = (uint8_t*)malloc(size); + fp->read(data, size); + GB_load_battery_from_buffer(&sameboy, data, size); + free(data); + } return true; } +auto ICD::save() -> void { + if(auto size = GB_save_battery_size(&sameboy)) { + auto data = (uint8_t*)malloc(size); + GB_save_battery_to_buffer(&sameboy, data, size); + if(auto fp = platform->open(pathID(), "save.ram", File::Write)) { + fp->write(data, size); + } + free(data); + } +} + auto ICD::unload() -> void { + save(); GB_free(&sameboy); } diff --git a/bsnes/sfc/coprocessor/icd/icd.hpp b/bsnes/sfc/coprocessor/icd/icd.hpp index 12dac2ef..6e4840e8 100644 --- a/bsnes/sfc/coprocessor/icd/icd.hpp +++ b/bsnes/sfc/coprocessor/icd/icd.hpp @@ -8,6 +8,7 @@ struct ICD : Emulator::Platform, Thread { auto main() -> void; auto load() -> bool; + auto save() -> void; auto unload() -> void; auto power(bool reset = false) -> void;