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.
This commit is contained in:
byuu 2019-10-14 23:04:38 +09:00
parent 95addddc46
commit 2de906ea46
17 changed files with 115 additions and 67 deletions

View File

@ -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";

View File

@ -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

View File

@ -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 {

View File

@ -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;

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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;

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -4,7 +4,6 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#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;

View File

@ -1,5 +1,5 @@
/*
libco v19 (2019-02-18)
libco v20 (2019-10-14)
author: byuu
license: ISC
*/

View File

@ -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;