From 2de906ea46b9fefe1bdd4c6cffc767bf988e1ff5 Mon Sep 17 00:00:00 2001 From: byuu <2107894+byuu@users.noreply.github.com> Date: Mon, 14 Oct 2019 23:04:38 +0900 Subject: [PATCH] v111.7 Added System/Serialization/Synchronize setting to settings.bml This option is for experimental deterministic rewind support. It does not currently work with SuperFX and SA-1 games, and as such is set to true (force synchronize) for now. --- bsnes/emulator/emulator.hpp | 2 +- bsnes/emulator/interface.hpp | 2 +- bsnes/sfc/interface/interface.cpp | 5 +-- bsnes/sfc/interface/interface.hpp | 2 +- bsnes/sfc/memory/protectable.hpp | 10 +++-- bsnes/sfc/memory/readable.hpp | 10 +++-- bsnes/sfc/memory/writable.hpp | 10 +++-- bsnes/sfc/sfc.hpp | 29 ++++++++++++- bsnes/sfc/system/serialization.cpp | 52 +++++++++++++++--------- bsnes/sfc/system/system.cpp | 3 +- bsnes/sfc/system/system.hpp | 10 ++--- bsnes/target-bsnes/program/rewind.cpp | 2 +- bsnes/target-bsnes/settings/settings.cpp | 1 + bsnes/target-bsnes/settings/settings.hpp | 1 + libco/amd64.c | 21 +++++----- libco/libco.h | 2 +- libco/x86.c | 20 ++++----- 17 files changed, 115 insertions(+), 67 deletions(-) diff --git a/bsnes/emulator/emulator.hpp b/bsnes/emulator/emulator.hpp index 5aa39daf..186587e9 100644 --- a/bsnes/emulator/emulator.hpp +++ b/bsnes/emulator/emulator.hpp @@ -29,7 +29,7 @@ using namespace nall; namespace Emulator { static const string Name = "bsnes"; - static const string Version = "111.6"; + static const string Version = "111.7"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "https://byuu.org"; diff --git a/bsnes/emulator/interface.hpp b/bsnes/emulator/interface.hpp index 9b89ff95..71284711 100644 --- a/bsnes/emulator/interface.hpp +++ b/bsnes/emulator/interface.hpp @@ -81,7 +81,7 @@ struct Interface { virtual auto synchronize(uint64 timestamp = 0) -> void {} //state functions - virtual auto serialize() -> serializer { return {}; } + virtual auto serialize(bool synchronize = true) -> serializer { return {}; } virtual auto unserialize(serializer&) -> bool { return false; } //cheat functions diff --git a/bsnes/sfc/interface/interface.cpp b/bsnes/sfc/interface/interface.cpp index 91ed0b85..ebeabdc2 100644 --- a/bsnes/sfc/interface/interface.cpp +++ b/bsnes/sfc/interface/interface.cpp @@ -239,9 +239,8 @@ auto Interface::synchronize(uint64 timestamp) -> void { if(cartridge.has.SharpRTC) sharprtc.synchronize(timestamp); } -auto Interface::serialize() -> serializer { - system.runToSave(); - return system.serialize(); +auto Interface::serialize(bool synchronize) -> serializer { + return system.serialize(synchronize); } auto Interface::unserialize(serializer& s) -> bool { diff --git a/bsnes/sfc/interface/interface.hpp b/bsnes/sfc/interface/interface.hpp index cfd46669..2af1e7bb 100644 --- a/bsnes/sfc/interface/interface.hpp +++ b/bsnes/sfc/interface/interface.hpp @@ -58,7 +58,7 @@ struct Interface : Emulator::Interface { auto rtc() -> bool override; auto synchronize(uint64 timestamp) -> void override; - auto serialize() -> serializer override; + auto serialize(bool synchronize = true) -> serializer override; auto unserialize(serializer&) -> bool override; auto read(uint24 address) -> uint8 override; diff --git a/bsnes/sfc/memory/protectable.hpp b/bsnes/sfc/memory/protectable.hpp index 4a028c17..a6f8a5b3 100644 --- a/bsnes/sfc/memory/protectable.hpp +++ b/bsnes/sfc/memory/protectable.hpp @@ -6,9 +6,13 @@ struct ProtectableMemory : Memory { } inline auto allocate(uint size, uint8 fill = 0xff) -> void override { - delete[] self.data; - self.data = new uint8[self.size = size]; - for(uint address : range(size)) self.data[address] = fill; + if(self.size != size) { + delete[] self.data; + self.data = new uint8[self.size = size]; + } + for(uint address : range(size)) { + self.data[address] = fill; + } } inline auto data() -> uint8* override { diff --git a/bsnes/sfc/memory/readable.hpp b/bsnes/sfc/memory/readable.hpp index 87c69e09..fcaf14b3 100644 --- a/bsnes/sfc/memory/readable.hpp +++ b/bsnes/sfc/memory/readable.hpp @@ -6,9 +6,13 @@ struct ReadableMemory : Memory { } inline auto allocate(uint size, uint8 fill = 0xff) -> void override { - delete[] self.data; - self.data = new uint8[self.size = size]; - for(uint address : range(size)) self.data[address] = fill; + if(self.size != size) { + delete[] self.data; + self.data = new uint8[self.size = size]; + } + for(uint address : range(size)) { + self.data[address] = fill; + } } inline auto data() -> uint8* override { diff --git a/bsnes/sfc/memory/writable.hpp b/bsnes/sfc/memory/writable.hpp index 7ea76737..7d51303f 100644 --- a/bsnes/sfc/memory/writable.hpp +++ b/bsnes/sfc/memory/writable.hpp @@ -6,9 +6,13 @@ struct WritableMemory : Memory { } inline auto allocate(uint size, uint8 fill = 0xff) -> void override { - delete[] self.data; - self.data = new uint8[self.size = size]; - for(uint address : range(size)) self.data[address] = fill; + if(self.size != size) { + delete[] self.data; + self.data = new uint8[self.size = size]; + } + for(uint address : range(size)) { + self.data[address] = fill; + } } inline auto data() -> uint8* override { diff --git a/bsnes/sfc/sfc.hpp b/bsnes/sfc/sfc.hpp index 7171b29b..b6d7dbbb 100644 --- a/bsnes/sfc/sfc.hpp +++ b/bsnes/sfc/sfc.hpp @@ -73,9 +73,14 @@ namespace SuperFamicom { extern Scheduler scheduler; struct Thread { + enum : uint { Size = 16_KiB * sizeof(void*) }; + auto create(auto (*entrypoint)() -> void, uint frequency_) -> void { - if(thread) co_delete(thread); - thread = co_create(65536 * sizeof(void*), entrypoint); + if(!thread) { + thread = co_create(Thread::Size, entrypoint); + } else { + co_derive(thread, Thread::Size, entrypoint); + } frequency = frequency_; clock = 0; } @@ -89,6 +94,26 @@ namespace SuperFamicom { s.integer(clock); } + auto serializeStack(serializer& s) -> void { + auto stack = new uint8_t[Thread::Size]; + + if(s.mode() == serializer::Size) { + s.array(stack, Thread::Size); + } + + if(s.mode() == serializer::Load) { + s.array(stack, Thread::Size); + memory::copy(thread, stack, Thread::Size); + } + + if(s.mode() == serializer::Save) { + memory::copy(stack, thread, Thread::Size); + s.array(stack, Thread::Size); + } + + delete[] stack; + } + cothread_t thread = nullptr; uint32_t frequency = 0; int64_t clock = 0; diff --git a/bsnes/sfc/system/serialization.cpp b/bsnes/sfc/system/serialization.cpp index 5dcf89a2..277fa04c 100644 --- a/bsnes/sfc/system/serialization.cpp +++ b/bsnes/sfc/system/serialization.cpp @@ -1,49 +1,51 @@ -auto System::serialize() -> serializer { - serializer s(serializeSize); +auto System::serialize(bool synchronize) -> serializer { + if(synchronize) runToSave(); uint signature = 0x31545342; + uint serializeSize = information.serializeSize[synchronize]; char version[16] = {}; char description[512] = {}; memory::copy(&version, (const char*)Emulator::SerializerVersion, Emulator::SerializerVersion.size()); + serializer s(serializeSize); s.integer(signature); + s.integer(serializeSize); s.array(version); s.array(description); - + s.boolean(synchronize); s.boolean(hacks.fastPPU); - - serializeAll(s); + serializeAll(s, synchronize); return s; } auto System::unserialize(serializer& s) -> bool { uint signature = 0; + uint serializeSize = 0; char version[16] = {}; char description[512] = {}; + bool synchronize = false; + bool fastPPU = false; s.integer(signature); + s.integer(serializeSize); s.array(version); s.array(description); + s.boolean(synchronize); + s.boolean(fastPPU); if(signature != 0x31545342) return false; + if(serializeSize != information.serializeSize[synchronize]) return false; if(string{version} != Emulator::SerializerVersion) return false; - - s.boolean(hacks.fastPPU); + if(fastPPU != hacks.fastPPU) return false; power(/* reset = */ false); - serializeAll(s); - serializeInit(); //hacks.fastPPU setting changes serializeSize - + serializeAll(s, synchronize); return true; } //internal -auto System::serialize(serializer& s) -> void { -} - -auto System::serializeAll(serializer& s) -> void { - system.serialize(s); +auto System::serializeAll(serializer& s, bool synchronize) -> void { random.serialize(s); cartridge.serialize(s); cpu.serialize(s); @@ -80,24 +82,34 @@ auto System::serializeAll(serializer& s) -> void { controllerPort1.serialize(s); controllerPort2.serialize(s); expansionPort.serialize(s); + + if(!synchronize) { + cpu.serializeStack(s); + smp.serializeStack(s); + ppu.serializeStack(s); + for(auto coprocessor : cpu.coprocessors) { + coprocessor->serializeStack(s); + } + } } //perform dry-run state save: //determines exactly how many bytes are needed to save state for this cartridge, //as amount varies per game (eg different RAM sizes, special chips, etc.) -auto System::serializeInit() -> void { +auto System::serializeInit(bool synchronize) -> uint { serializer s; uint signature = 0; + uint serializeSize = 0; char version[16] = {}; char description[512] = {}; s.integer(signature); + s.integer(serializeSize); s.array(version); s.array(description); - + s.boolean(synchronize); s.boolean(hacks.fastPPU); - - serializeAll(s); - serializeSize = s.size(); + serializeAll(s, synchronize); + return s.size(); } diff --git a/bsnes/sfc/system/system.cpp b/bsnes/sfc/system/system.cpp index 8a81f85b..3bee3330 100644 --- a/bsnes/sfc/system/system.cpp +++ b/bsnes/sfc/system/system.cpp @@ -97,7 +97,8 @@ auto System::load(Emulator::Interface* interface) -> bool { } if(cartridge.has.BSMemorySlot) bsmemory.load(); - serializeInit(); + information.serializeSize[0] = serializeInit(0); + information.serializeSize[1] = serializeInit(1); this->interface = interface; return information.loaded = true; } diff --git a/bsnes/sfc/system/system.hpp b/bsnes/sfc/system/system.hpp index 29241074..0d8fb444 100644 --- a/bsnes/sfc/system/system.hpp +++ b/bsnes/sfc/system/system.hpp @@ -18,7 +18,7 @@ struct System { auto power(bool reset) -> void; //serialization.cpp - auto serialize() -> serializer; + auto serialize(bool synchronize) -> serializer; auto unserialize(serializer&) -> bool; uint frameSkip = 0; @@ -32,17 +32,15 @@ private: Region region = Region::NTSC; double cpuFrequency = Emulator::Constants::Colorburst::NTSC * 6.0; double apuFrequency = 32040.0 * 768.0; + uint serializeSize[2] = {0, 0}; } information; struct Hacks { bool fastPPU = false; } hacks; - uint serializeSize = 0; - - auto serialize(serializer&) -> void; - auto serializeAll(serializer&) -> void; - auto serializeInit() -> void; + auto serializeAll(serializer&, bool synchronize) -> void; + auto serializeInit(bool synchronize) -> uint; friend class Cartridge; }; diff --git a/bsnes/target-bsnes/program/rewind.cpp b/bsnes/target-bsnes/program/rewind.cpp index 36dd6902..b148720e 100644 --- a/bsnes/target-bsnes/program/rewind.cpp +++ b/bsnes/target-bsnes/program/rewind.cpp @@ -35,7 +35,7 @@ auto Program::rewindRun() -> void { if(rewind.history.size() >= rewind.length) { rewind.history.takeFirst(); } - auto s = emulator->serialize(); + auto s = emulator->serialize(settings.emulator.serialization.synchronize); rewind.history.append(s); return; } diff --git a/bsnes/target-bsnes/settings/settings.cpp b/bsnes/target-bsnes/settings/settings.cpp index 95e46ca4..0b061686 100644 --- a/bsnes/target-bsnes/settings/settings.cpp +++ b/bsnes/target-bsnes/settings/settings.cpp @@ -115,6 +115,7 @@ auto Settings::process(bool load) -> void { bind(boolean, "Emulator/AutoSaveStateOnUnload", emulator.autoSaveStateOnUnload); bind(boolean, "Emulator/AutoLoadStateOnLoad", emulator.autoLoadStateOnLoad); bind(text, "Emulator/Serialization/Method", emulator.serialization.method); + bind(boolean, "Emulator/Serialization/Synchronize", emulator.serialization.synchronize); bind(boolean, "Emulator/Hack/Hotfixes", emulator.hack.hotfixes); bind(text, "Emulator/Hack/Entropy", emulator.hack.entropy); bind(natural, "Emulator/Hack/CPU/Overclock", emulator.hack.cpu.overclock); diff --git a/bsnes/target-bsnes/settings/settings.hpp b/bsnes/target-bsnes/settings/settings.hpp index 6bd7ae52..7e9dea71 100644 --- a/bsnes/target-bsnes/settings/settings.hpp +++ b/bsnes/target-bsnes/settings/settings.hpp @@ -96,6 +96,7 @@ struct Settings : Markup::Node { bool autoLoadStateOnLoad = false; struct Serialization { string method = "Fast"; + bool synchronize = true; } serialization; struct Hack { bool hotfixes = true; diff --git a/libco/amd64.c b/libco/amd64.c index e56924f3..664730a1 100755 --- a/libco/amd64.c +++ b/libco/amd64.c @@ -4,7 +4,6 @@ #include #include -#include #ifdef __cplusplus extern "C" { @@ -130,10 +129,11 @@ cothread_t co_derive(void* memory, unsigned int size, void (*entrypoint)(void)) if(!co_active_handle) co_active_handle = &co_active_buffer; if(handle = (cothread_t)memory) { - long long *p = (long long*)((char*)handle + size); /* seek to top of stack */ - *--p = (long long)crash; /* crash if entrypoint returns */ - *--p = (long long)entrypoint; /* start of function */ - *(long long*)handle = (long long)p; /* stack pointer */ + unsigned int offset = (size & ~15) - 32; + long long *p = (long long*)((char*)handle + offset); /* seek to top of stack */ + *--p = (long long)crash; /* crash if entrypoint returns */ + *--p = (long long)entrypoint; /* start of function */ + *(long long*)handle = (long long)p; /* stack pointer */ } return handle; @@ -146,14 +146,13 @@ cothread_t co_create(unsigned int size, void (*entrypoint)(void)) { co_swap = (void (*)(cothread_t, cothread_t))co_swap_function; } if(!co_active_handle) co_active_handle = &co_active_buffer; - size += 512; /* allocate additional space for storage */ - size &= ~15; /* align stack to 16-byte boundary */ if(handle = (cothread_t)malloc(size)) { - long long *p = (long long*)((char*)handle + size); /* seek to top of stack */ - *--p = (long long)crash; /* crash if entrypoint returns */ - *--p = (long long)entrypoint; /* start of function */ - *(long long*)handle = (long long)p; /* stack pointer */ + unsigned int offset = (size & ~15) - 32; + long long *p = (long long*)((char*)handle + offset); /* seek to top of stack */ + *--p = (long long)crash; /* crash if entrypoint returns */ + *--p = (long long)entrypoint; /* start of function */ + *(long long*)handle = (long long)p; /* stack pointer */ } return handle; diff --git a/libco/libco.h b/libco/libco.h index b7f60852..a436957c 100755 --- a/libco/libco.h +++ b/libco/libco.h @@ -1,5 +1,5 @@ /* - libco v19 (2019-02-18) + libco v20 (2019-10-14) author: byuu license: ISC */ diff --git a/libco/x86.c b/libco/x86.c index d79306c6..3eb2e21e 100755 --- a/libco/x86.c +++ b/libco/x86.c @@ -83,10 +83,11 @@ cothread_t co_derive(void* memory, unsigned int size, void (*entrypoint)(void)) if(!co_active_handle) co_active_handle = &co_active_buffer; if(handle = (cothread_t)memory) { - long *p = (long*)((char*)handle + size); /* seek to top of stack */ - *--p = (long)crash; /* crash if entrypoint returns */ - *--p = (long)entrypoint; /* start of function */ - *(long*)handle = (long)p; /* stack pointer */ + unsigned int offset = (size & ~15) - 32; + long *p = (long*)((char*)handle + offset); /* seek to top of stack */ + *--p = (long)crash; /* crash if entrypoint returns */ + *--p = (long)entrypoint; /* start of function */ + *(long*)handle = (long)p; /* stack pointer */ } return handle; @@ -99,14 +100,13 @@ cothread_t co_create(unsigned int size, void (*entrypoint)(void)) { co_swap = (void (fastcall*)(cothread_t, cothread_t))co_swap_function; } if(!co_active_handle) co_active_handle = &co_active_buffer; - size += 256; /* allocate additional space for storage */ - size &= ~15; /* align stack to 16-byte boundary */ if(handle = (cothread_t)malloc(size)) { - long *p = (long*)((char*)handle + size); /* seek to top of stack */ - *--p = (long)crash; /* crash if entrypoint returns */ - *--p = (long)entrypoint; /* start of function */ - *(long*)handle = (long)p; /* stack pointer */ + unsigned int offset = (size & ~15) - 32; + long *p = (long*)((char*)handle + offset); /* seek to top of stack */ + *--p = (long)crash; /* crash if entrypoint returns */ + *--p = (long)entrypoint; /* start of function */ + *(long*)handle = (long)p; /* stack pointer */ } return handle;