From 0ee073b71b8377c2ccd4acd50d64cd627e9cc77b Mon Sep 17 00:00:00 2001 From: goyuken Date: Sat, 31 May 2014 05:57:18 +0000 Subject: [PATCH] bizswan: savestates --- .../Consoles/WonderSwan/BizSwan.cs | 12 +++ .../Consoles/WonderSwan/WonderSwan.cs | 63 ++++++++++- output/dll/bizswan.dll | Bin 81408 -> 91136 bytes wonderswan/bizswan/bizswan.vcxproj | 2 + wonderswan/bizswan/bizswan.vcxproj.filters | 6 ++ wonderswan/eeprom.cpp | 14 ++- wonderswan/eeprom.h | 1 + wonderswan/gfx.cpp | 69 +++++++++++- wonderswan/gfx.h | 12 +-- wonderswan/interrupt.cpp | 10 ++ wonderswan/interrupt.h | 1 + wonderswan/memory.cpp | 33 +++++- wonderswan/memory.h | 3 +- wonderswan/mingw/Makefile | 1 + wonderswan/newstate.cpp | 69 ++++++++++++ wonderswan/newstate.h | 102 ++++++++++++++++++ wonderswan/rtc.cpp | 10 ++ wonderswan/rtc.h | 1 + wonderswan/sound.cpp | 31 ++++++ wonderswan/sound.h | 1 + wonderswan/system.cpp | 45 ++++++++ wonderswan/system.h | 9 +- wonderswan/v30mz.cpp | 21 ++++ wonderswan/v30mz.h | 1 + wonderswan/wswan.h | 2 - 25 files changed, 495 insertions(+), 24 deletions(-) create mode 100644 wonderswan/newstate.cpp create mode 100644 wonderswan/newstate.h diff --git a/BizHawk.Emulation.Cores/Consoles/WonderSwan/BizSwan.cs b/BizHawk.Emulation.Cores/Consoles/WonderSwan/BizSwan.cs index 1b568e68f8..dd857c9f06 100644 --- a/BizHawk.Emulation.Cores/Consoles/WonderSwan/BizSwan.cs +++ b/BizHawk.Emulation.Cores/Consoles/WonderSwan/BizSwan.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; +using BizHawk.Common; namespace BizHawk.Emulation.Cores.WonderSwan { @@ -105,6 +106,17 @@ namespace BizHawk.Emulation.Cores.WonderSwan [DllImport(dd, CallingConvention = cc)] public static extern bool bizswan_getmemoryarea(IntPtr core, int index, out IntPtr name, out int size, out IntPtr data); + [DllImport(dd, CallingConvention = cc)] + public static extern int bizswan_binstatesize(IntPtr core); + [DllImport(dd, CallingConvention = cc)] + public static extern bool bizswan_binstatesave(IntPtr core, byte[] data, int length); + [DllImport(dd, CallingConvention = cc)] + public static extern bool bizswan_binstateload(IntPtr core, byte[] data, int length); + + [DllImport(dd, CallingConvention = cc)] + public static extern void bizswan_txtstatesave(IntPtr core, [In]ref TextStateFPtrs ff); + [DllImport(dd, CallingConvention = cc)] + public static extern void bizswan_txtstateload(IntPtr core, [In]ref TextStateFPtrs ff); /// /// return a CPU register diff --git a/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs b/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs index 6e96a33899..213e9c655d 100644 --- a/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs +++ b/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs @@ -56,6 +56,8 @@ namespace BizHawk.Emulation.Cores.WonderSwan try { var ss = _SyncSettings.GetNativeSettings(); + if (deterministicEmulation) + ss.userealtime = false; bool rotate = false; @@ -70,6 +72,9 @@ namespace BizHawk.Emulation.Cores.WonderSwan InitVideo(rotate); PutSettings(_Settings); SetMemoryDomains(); + + savebuff = new byte[BizSwan.bizswan_binstatesize(Core)]; + savebuff2 = new byte[savebuff.Length + 13]; } catch { @@ -157,25 +162,81 @@ namespace BizHawk.Emulation.Cores.WonderSwan #region Savestates + JsonSerializer ser = new JsonSerializer() { Formatting = Formatting.Indented }; + + class TextStateData + { + public int Frame; + public int LagCount; + public bool IsLagFrame; + } + public void SaveStateText(TextWriter writer) { + var s = new TextState(); + s.Prepare(); + var ff = s.GetFunctionPointers(); + BizSwan.bizswan_txtstatesave(Core, ref ff); + s.ExtraData.IsLagFrame = IsLagFrame; + s.ExtraData.LagCount = LagCount; + s.ExtraData.Frame = Frame; + + ser.Serialize(writer, s); + // write extra copy of stuff we don't use + writer.WriteLine(); + writer.WriteLine("Frame {0}", Frame); } public void LoadStateText(TextReader reader) { + var s = (TextState)ser.Deserialize(reader, typeof(TextState)); + s.Prepare(); + var ff = s.GetFunctionPointers(); + BizSwan.bizswan_txtstateload(Core, ref ff); + IsLagFrame = s.ExtraData.IsLagFrame; + LagCount = s.ExtraData.LagCount; + Frame = s.ExtraData.Frame; } + byte[] savebuff; + byte[] savebuff2; + public void SaveStateBinary(BinaryWriter writer) { + if (!BizSwan.bizswan_binstatesave(Core, savebuff, savebuff.Length)) + throw new InvalidOperationException("bizswan_binstatesave() returned false!"); + writer.Write(savebuff.Length); + writer.Write(savebuff); + + // other variables + writer.Write(IsLagFrame); + writer.Write(LagCount); + writer.Write(Frame); } public void LoadStateBinary(BinaryReader reader) { + int length = reader.ReadInt32(); + if (length != savebuff.Length) + throw new InvalidOperationException("Save buffer size mismatch!"); + reader.Read(savebuff, 0, length); + if (!BizSwan.bizswan_binstateload(Core, savebuff, savebuff.Length)) + throw new InvalidOperationException("bizswan_binstateload() returned false!"); + + // other variables + IsLagFrame = reader.ReadBoolean(); + LagCount = reader.ReadInt32(); + Frame = reader.ReadInt32(); } public byte[] SaveStateBinary() { - return new byte[0]; + var ms = new MemoryStream(savebuff2, true); + var bw = new BinaryWriter(ms); + SaveStateBinary(bw); + bw.Flush(); + ms.Close(); + return savebuff2; } public bool BinarySaveStatesPreferred diff --git a/output/dll/bizswan.dll b/output/dll/bizswan.dll index a067a401b956321ef8dbf2047829c1f2efb1d3d9..9ad84e4e81c9f5903a4ef9635837eec411db2289 100644 GIT binary patch delta 25761 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 + @@ -90,6 +91,7 @@ + diff --git a/wonderswan/bizswan/bizswan.vcxproj.filters b/wonderswan/bizswan/bizswan.vcxproj.filters index a021bd15b7..424754cf11 100644 --- a/wonderswan/bizswan/bizswan.vcxproj.filters +++ b/wonderswan/bizswan/bizswan.vcxproj.filters @@ -57,6 +57,9 @@ Source Files + + Source Files + @@ -101,6 +104,9 @@ Header Files + + Header Files + diff --git a/wonderswan/eeprom.cpp b/wonderswan/eeprom.cpp index 03925c47ab..6ebb7773c5 100644 --- a/wonderswan/eeprom.cpp +++ b/wonderswan/eeprom.cpp @@ -114,9 +114,6 @@ namespace MDFN_IEN_WSWAN 255,255,255,255 }; - //static uint8 iEEPROM_Command, EEPROM_Command; - //static uint16 iEEPROM_Address, EEPROM_Address; - uint8 EEPROM::Read(uint32 A) { switch(A) @@ -203,4 +200,15 @@ namespace MDFN_IEN_WSWAN iEEPROM[0x375] = Blood; } + SYNCFUNC(EEPROM) + { + NSS(iEEPROM_Command); + NSS(EEPROM_Command); + NSS(iEEPROM_Address); + NSS(EEPROM_Address); + + NSS(eeprom_size); + NSS(iEEPROM); + NSS(wsEEPROM); + } } diff --git a/wonderswan/eeprom.h b/wonderswan/eeprom.h index 2538e39990..c96aa6889b 100644 --- a/wonderswan/eeprom.h +++ b/wonderswan/eeprom.h @@ -27,6 +27,7 @@ public: public: System *sys; + templatevoid SyncState(NewState *ns); }; diff --git a/wonderswan/gfx.cpp b/wonderswan/gfx.cpp index 0b8fc5cc0a..ac51c557d9 100644 --- a/wonderswan/gfx.cpp +++ b/wonderswan/gfx.cpp @@ -19,8 +19,6 @@ */ #include "system.h" -//#include -//#include #include namespace MDFN_IEN_WSWAN @@ -602,4 +600,71 @@ namespace MDFN_IEN_WSWAN std::memset(wsCols, 0, sizeof(wsCols)); } + SYNCFUNC(GFX) + { + + // TCACHE stuff. we invalidate the cache instead of saving it + if (isReader) + { + std::memset(wsTCacheUpdate, 0, sizeof(wsTCacheUpdate)); + std::memset(wsTCacheUpdate2, 0, sizeof(wsTCacheUpdate2)); + } + /* + NSS(tiles); + NSS(wsTCache); + NSS(wsTCache2); + NSS(wsTCacheFlipped); + NSS(wsTCacheFlipped2); + NSS(wsTCacheUpdate); + NSS(wsTCacheUpdate2); + NSS(wsTileRow); + */ + + NSS(wsVMode); + + NSS(wsMonoPal); + NSS(wsColors); + NSS(wsCols); + + NSS(ColorMapG); + NSS(ColorMap); + NSS(LayerEnabled); + + NSS(wsLine); + + NSS(SpriteTable); + NSS(SpriteCountCache); + NSS(DispControl); + NSS(BGColor); + NSS(LineCompare); + NSS(SPRBase); + NSS(SpriteStart); + NSS(SpriteCount); + NSS(FGBGLoc); + NSS(FGx0); + NSS(FGy0); + NSS(FGx1); + NSS(FGy1); + NSS(SPRx0); + NSS(SPRy0); + NSS(SPRx1); + NSS(SPRy1); + + NSS(BGXScroll); + NSS(BGYScroll); + NSS(FGXScroll); + NSS(FGYScroll); + NSS(LCDControl); + NSS(LCDIcons); + + NSS(BTimerControl); + NSS(HBTimerPeriod); + NSS(VBTimerPeriod); + + NSS(HBCounter); + NSS(VBCounter); + NSS(VideoMode); + + NSS(wsc); // mono / color + } } diff --git a/wonderswan/gfx.h b/wonderswan/gfx.h index 9e020fd88a..0fbef1e471 100644 --- a/wonderswan/gfx.h +++ b/wonderswan/gfx.h @@ -40,8 +40,9 @@ private: uint8 wsTCacheUpdate[512]; uint8 wsTCacheUpdate2[512]; uint8 wsTileRow[8]; - int wsVMode; // doesn't belong here? // TCACHE/==================================== + int wsVMode; + uint32 wsMonoPal[16][4]; uint32 wsColors[8]; uint32 wsCols[16][16]; @@ -78,16 +79,9 @@ private: public: System *sys; + templatevoid SyncState(NewState *ns); }; - - -// ? -//extern uint32 dx_r,dx_g,dx_b,dx_sr,dx_sg,dx_sb; -//extern uint32 dx_bits,dx_pitch,cmov,dx_linewidth_blit,dx_buffer_line; - - - } #endif diff --git a/wonderswan/interrupt.cpp b/wonderswan/interrupt.cpp index bff9d854fc..d88dd53871 100644 --- a/wonderswan/interrupt.cpp +++ b/wonderswan/interrupt.cpp @@ -74,4 +74,14 @@ namespace MDFN_IEN_WSWAN Recalc(); } + SYNCFUNC(Interrupt) + { + NSS(IStatus); + NSS(IEnable); + NSS(IVectorBase); + + NSS(IOn_Cache); + NSS(IOn_Which); + NSS(IVector_Cache); + } } diff --git a/wonderswan/interrupt.h b/wonderswan/interrupt.h index 6c41e18205..429fa93df2 100644 --- a/wonderswan/interrupt.h +++ b/wonderswan/interrupt.h @@ -41,6 +41,7 @@ private: void Recalc(); public: System *sys; + templatevoid SyncState(NewState *ns); }; } diff --git a/wonderswan/memory.cpp b/wonderswan/memory.cpp index 30feaabf6d..133792891c 100644 --- a/wonderswan/memory.cpp +++ b/wonderswan/memory.cpp @@ -27,9 +27,6 @@ namespace MDFN_IEN_WSWAN { - - //extern uint16 WSButtonStatus; - void Memory::Write20(uint32 A, uint8 V) { uint32 offset, bank; @@ -336,4 +333,34 @@ namespace MDFN_IEN_WSWAN CommData = 0; } + SYNCFUNC(Memory) + { + NSS(wsRAM); + //NSS(rom_size); + //PSS(wsCartROM, rom_size); + NSS(sram_size); + PSS(wsSRAM, sram_size); + + NSS(WSButtonStatus); + NSS(Lagged); + + NSS(ButtonWhich); + NSS(ButtonReadLatch); + + NSS(DMASource); + NSS(DMADest); + NSS(DMALength); + NSS(DMAControl); + + NSS(SoundDMASource); + NSS(SoundDMALength); + NSS(SoundDMAControl); + + NSS(BankSelector); + + NSS(CommControl); + NSS(CommData); + + NSS(language); + } } diff --git a/wonderswan/memory.h b/wonderswan/memory.h index e9d938a316..3ccfcd5c2a 100644 --- a/wonderswan/memory.h +++ b/wonderswan/memory.h @@ -53,6 +53,7 @@ private: public: System *sys; + templatevoid SyncState(NewState *ns); private: void CheckDMA(); @@ -66,8 +67,6 @@ enum MEMORY_GSREG_BNK3SLCT, }; - - } #endif diff --git a/wonderswan/mingw/Makefile b/wonderswan/mingw/Makefile index d72ea3d600..90788da80a 100644 --- a/wonderswan/mingw/Makefile +++ b/wonderswan/mingw/Makefile @@ -16,6 +16,7 @@ SRCS = \ ../system.cpp \ ../tcache.cpp \ ../v30mz.cpp \ + ../newstate.cpp \ ../Blip/Blip_Buffer.cpp OBJS = $(SRCS:.cpp=.o) diff --git a/wonderswan/newstate.cpp b/wonderswan/newstate.cpp new file mode 100644 index 0000000000..95727b3cf8 --- /dev/null +++ b/wonderswan/newstate.cpp @@ -0,0 +1,69 @@ +#include "newstate.h" +#include +#include + +namespace MDFN_IEN_WSWAN { + +NewStateDummy::NewStateDummy() + :length(0) +{ +} +void NewStateDummy::Save(const void *ptr, size_t size, const char *name) +{ + length += size; +} +void NewStateDummy::Load(void *ptr, size_t size, const char *name) +{ +} + +NewStateExternalBuffer::NewStateExternalBuffer(char *buffer, long maxlength) + :buffer(buffer), length(0), maxlength(maxlength) +{ +} + +void NewStateExternalBuffer::Save(const void *ptr, size_t size, const char *name) +{ + if (maxlength - length >= (long)size) + { + std::memcpy(buffer + length, ptr, size); + } + length += size; +} + +void NewStateExternalBuffer::Load(void *ptr, size_t size, const char *name) +{ + char *dst = static_cast(ptr); + if (maxlength - length >= (long)size) + { + std::memcpy(dst, buffer + length, size); + } + length += size; +} + +NewStateExternalFunctions::NewStateExternalFunctions(const FPtrs *ff) + :Save_(ff->Save_), + Load_(ff->Load_), + EnterSection_(ff->EnterSection_), + ExitSection_(ff->ExitSection_) +{ +} + +void NewStateExternalFunctions::Save(const void *ptr, size_t size, const char *name) +{ + Save_(ptr, size, name); +} +void NewStateExternalFunctions::Load(void *ptr, size_t size, const char *name) +{ + Load_(ptr, size, name); +} +void NewStateExternalFunctions::EnterSection(const char *name) +{ + EnterSection_(name); +} +void NewStateExternalFunctions::ExitSection(const char *name) +{ + ExitSection_(name); +} + + +} diff --git a/wonderswan/newstate.h b/wonderswan/newstate.h new file mode 100644 index 0000000000..f7c95f7982 --- /dev/null +++ b/wonderswan/newstate.h @@ -0,0 +1,102 @@ +#ifndef NEWSTATE_H +#define NEWSTATE_H + +#include +#include + +namespace MDFN_IEN_WSWAN { + +class NewState +{ +public: + virtual void Save(const void *ptr, size_t size, const char *name) = 0; + virtual void Load(void *ptr, size_t size, const char *name) = 0; + virtual void EnterSection(const char *name) { } + virtual void ExitSection(const char *name) { } +}; + +class NewStateDummy : public NewState +{ +private: + long length; +public: + NewStateDummy(); + long GetLength() { return length; } + void Rewind() { length = 0; } + virtual void Save(const void *ptr, size_t size, const char *name); + virtual void Load(void *ptr, size_t size, const char *name); +}; + +class NewStateExternalBuffer : public NewState +{ +private: + char *const buffer; + long length; + const long maxlength; +public: + NewStateExternalBuffer(char *buffer, long maxlength); + long GetLength() { return length; } + void Rewind() { length = 0; } + bool Overflow() { return length > maxlength; } + virtual void Save(const void *ptr, size_t size, const char *name); + virtual void Load(void *ptr, size_t size, const char *name); +}; + +struct FPtrs +{ + void (*Save_)(const void *ptr, size_t size, const char *name); + void (*Load_)(void *ptr, size_t size, const char *name); + void (*EnterSection_)(const char *name); + void (*ExitSection_)(const char *name); +}; + +class NewStateExternalFunctions : public NewState +{ +private: + void (*Save_)(const void *ptr, size_t size, const char *name); + void (*Load_)(void *ptr, size_t size, const char *name); + void (*EnterSection_)(const char *name); + void (*ExitSection_)(const char *name); +public: + NewStateExternalFunctions(const FPtrs *ff); + virtual void Save(const void *ptr, size_t size, const char *name); + virtual void Load(void *ptr, size_t size, const char *name); + virtual void EnterSection(const char *name); + virtual void ExitSection(const char *name); +}; + +// defines and explicitly instantiates +#define SYNCFUNC(x)\ + template void x::SyncState(NewState *ns);\ + template void x::SyncState(NewState *ns);\ + templatevoid x::SyncState(NewState *ns) + +// N = normal variable +// P = pointer to fixed size data +// S = "sub object" +// T = "ptr to sub object" +// R = pointer, store its offset from some other pointer +// E = general purpose cased value "enum" + + +// first line is default value in converted enum; last line is default value in argument x +#define EBS(x,d) do { int _ttmp = (d); if (isReader) ns->Load(&_ttmp, sizeof(_ttmp), #x); if (0) +#define EVS(x,v,n) else if (!isReader && (x) == (v)) _ttmp = (n); else if (isReader && _ttmp == (n)) (x) = (v) +#define EES(x,d) else if (isReader) (x) = (d); if (!isReader) ns->Save(&_ttmp, sizeof(_ttmp), #x); } while (0) + +#define RSS(x,b) do { if (isReader)\ +{ ptrdiff_t _ttmp; ns->Load(&_ttmp, sizeof(_ttmp), #x); (x) = (_ttmp == (ptrdiff_t)0xdeadbeef ? 0 : (b) + _ttmp); }\ + else\ +{ ptrdiff_t _ttmp = (x) == 0 ? 0xdeadbeef : (x) - (b); ns->Save(&_ttmp, sizeof(_ttmp), #x); } } while (0) + +#define PSS(x,s) do { if (isReader) ns->Load((x), (s), #x); else ns->Save((x), (s), #x); } while (0) + +#define NSS(x) do { if (isReader) ns->Load(&(x), sizeof(x), #x); else ns->Save(&(x), sizeof(x), #x); } while (0) + +#define SSS(x) do { ns->EnterSection(#x); (x).SyncState(ns); ns->ExitSection(#x); } while (0) + +#define TSS(x) do { ns->EnterSection(#x); (x)->SyncState(ns); ns->ExitSection(#x); } while (0) + +} + +#endif diff --git a/wonderswan/rtc.cpp b/wonderswan/rtc.cpp index 4423bce87a..f3fd8c7755 100644 --- a/wonderswan/rtc.cpp +++ b/wonderswan/rtc.cpp @@ -112,4 +112,14 @@ namespace MDFN_IEN_WSWAN } } + SYNCFUNC(RTC) + { + NSS(CurrentTime); + NSS(userealtime); + + NSS(ClockCycleCounter); + NSS(wsCA15); + NSS(Command); + NSS(Data); + } } diff --git a/wonderswan/rtc.h b/wonderswan/rtc.h index cdead60466..331e003a2d 100644 --- a/wonderswan/rtc.h +++ b/wonderswan/rtc.h @@ -22,6 +22,7 @@ private: uint8 Command, Data; public: System *sys; + templatevoid SyncState(NewState *ns); }; diff --git a/wonderswan/sound.cpp b/wonderswan/sound.cpp index a94a63ee11..baf0e77ecd 100644 --- a/wonderswan/sound.cpp +++ b/wonderswan/sound.cpp @@ -379,4 +379,35 @@ namespace MDFN_IEN_WSWAN sbuf[y]->clear(); } + SYNCFUNC(Sound) + { + // don't need to save any of the blip stuff + + NSS(period[4]); + NSS(volume[4]); + NSS(voice_volume); + + NSS(sweep_step); + NSS(sweep_value); + NSS(noise_control); + NSS(control); + NSS(output_control); + + NSS(sweep_8192_divider); + NSS(sweep_counter); + NSS(SampleRAMPos); + + NSS(sample_cache); + + NSS(last_v_val); + + NSS(HyperVoice); + NSS(last_hv_val); + + NSS(period_counter); + NSS(last_val); + NSS(sample_pos); + NSS(nreg); + NSS(last_ts); + } } diff --git a/wonderswan/sound.h b/wonderswan/sound.h index 47fc9ae3e3..c4fcf7619b 100644 --- a/wonderswan/sound.h +++ b/wonderswan/sound.h @@ -61,6 +61,7 @@ private: public: System *sys; + templatevoid SyncState(NewState *ns); }; diff --git a/wonderswan/system.cpp b/wonderswan/system.cpp index 3cfb0e63bb..0d56e3406a 100644 --- a/wonderswan/system.cpp +++ b/wonderswan/system.cpp @@ -237,6 +237,7 @@ namespace MDFN_IEN_WSWAN { return eeprom.ieeprom_size + eeprom.eeprom_size + memory.sram_size; } + bool System::SaveRamLoad(const uint8 *data, int size) { if (size != SaveRamSize()) @@ -294,6 +295,18 @@ namespace MDFN_IEN_WSWAN return ret; } + SYNCFUNC(System) + { + SSS(gfx); + SSS(memory); + SSS(eeprom); + SSS(rtc); + SSS(sound); + SSS(cpu); + SSS(interrupt); + + NSS(rotate); + } EXPORT System *bizswan_new() { @@ -352,4 +365,36 @@ namespace MDFN_IEN_WSWAN return s->GetMemoryArea(index, *name, *size, *data); } + EXPORT int bizswan_binstatesize(System *s) + { + NewStateDummy dummy; + s->SyncState(&dummy); + return dummy.GetLength(); + } + + EXPORT int bizswan_binstatesave(System *s, char *data, int length) + { + NewStateExternalBuffer saver(data, length); + s->SyncState(&saver); + return !saver.Overflow() && saver.GetLength() == length; + } + + EXPORT int bizswan_binstateload(System *s, const char *data, int length) + { + NewStateExternalBuffer loader(const_cast(data), length); + s->SyncState(&loader); + return !loader.Overflow() && loader.GetLength() == length; + } + + EXPORT void bizswan_txtstatesave(System *s, FPtrs *ff) + { + NewStateExternalFunctions saver(ff); + s->SyncState(&saver); + } + + EXPORT void bizswan_txtstateload(System *s, FPtrs *ff) + { + NewStateExternalFunctions loader(ff); + s->SyncState(&loader); + } } diff --git a/wonderswan/system.h b/wonderswan/system.h index bbccb45c7f..1893a20239 100644 --- a/wonderswan/system.h +++ b/wonderswan/system.h @@ -7,8 +7,11 @@ class System; struct SyncSettings; struct Settings; } - + #include "wswan.h" + +#include "newstate.h" + #include "gfx.h" #include "memory.h" #include "eeprom.h" @@ -18,7 +21,7 @@ struct Settings; #include "interrupt.h" #include - + namespace MDFN_IEN_WSWAN { class System @@ -52,6 +55,8 @@ public: Interrupt interrupt; bool rotate; // rotate screen and controls left 90 + + templatevoid SyncState(NewState *ns); }; struct SyncSettings diff --git a/wonderswan/v30mz.cpp b/wonderswan/v30mz.cpp index 70e1f71e24..18e6f16398 100644 --- a/wonderswan/v30mz.cpp +++ b/wonderswan/v30mz.cpp @@ -1027,4 +1027,25 @@ namespace MDFN_IEN_WSWAN } + SYNCFUNC(V30MZ) + { + NSS(old_CS); + NSS(old_IP); + NSS(timestamp); + NSS(ICount); + + NSS(I); + NSS(InHLT); + + NSS(prefix_base); + NSS(seg_prefix); + + NSS(parity_table); + + NSS(EA); + NSS(EO); + NSS(E16); + + NSS(Mod_RM); + } } diff --git a/wonderswan/v30mz.h b/wonderswan/v30mz.h index 622257cc70..7ef1a5dbbc 100644 --- a/wonderswan/v30mz.h +++ b/wonderswan/v30mz.h @@ -141,6 +141,7 @@ private: public: System *sys; + templatevoid SyncState(NewState *ns); }; diff --git a/wonderswan/wswan.h b/wonderswan/wswan.h index 9e99ce8397..9e67fada37 100644 --- a/wonderswan/wswan.h +++ b/wonderswan/wswan.h @@ -3,8 +3,6 @@ #include -#include "interrupt.h" - namespace MDFN_IEN_WSWAN {