diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/LibVBANext.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/LibVBANext.cs index 0ba6a4626d..335e7f57cf 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/LibVBANext.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/LibVBANext.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; +using BizHawk.Emulation.Common; namespace BizHawk.Emulation.Cores.Nintendo.GBA { @@ -70,5 +71,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA /// true if lagged [DllImport(dllname, CallingConvention = cc)] public static extern bool FrameAdvance(IntPtr g, Buttons input, int[] videobuffer, short[] audiobuffer, out int numsamp); + + [DllImport(dllname, CallingConvention = cc)] + public static extern int BinStateSize(IntPtr g); + [DllImport(dllname, CallingConvention = cc)] + public static extern bool BinStateSave(IntPtr g, byte[] data, int length); + [DllImport(dllname, CallingConvention = cc)] + public static extern bool BinStateLoad(IntPtr g, byte[] data, int length); + [DllImport(dllname, CallingConvention = cc)] + public static extern void TxtStateSave(IntPtr g, [In]ref TextStateFPtrs ff); + [DllImport(dllname, CallingConvention = cc)] + public static extern void TxtStateLoad(IntPtr g, [In]ref TextStateFPtrs ff); } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs index 1c73b14bb7..5b3c858ed5 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs @@ -7,6 +7,7 @@ using System.IO; using BizHawk.Common.BufferExtensions; using BizHawk.Emulation.Common; +using Newtonsoft.Json; namespace BizHawk.Emulation.Cores.Nintendo.GBA { @@ -32,6 +33,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA { if (!LibVBANext.LoadRom(Core, romfile, (uint)romfile.Length, biosfile, (uint)biosfile.Length)) throw new InvalidOperationException("LoadRom() returned false!"); + + CoreComm.VsyncNum = 262144; + CoreComm.VsyncDen = 4389; + CoreComm.NominalWidth = 240; + CoreComm.NominalHeight = 160; + + savebuff = new byte[LibVBANext.BinStateSize(Core)]; + savebuff2 = new byte[savebuff.Length + 13]; } catch { @@ -118,25 +127,84 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA #region SaveStates + JsonSerializer ser = new JsonSerializer() { Formatting = Formatting.Indented }; + byte[] savebuff; + byte[] savebuff2; + + 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.GetFunctionPointersSave(); + LibVBANext.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); + + //Console.WriteLine(BizHawk.Common.BufferExtensions.BufferExtensions.HashSHA1(SaveStateBinary())); } public void LoadStateText(TextReader reader) { + var s = (TextState)ser.Deserialize(reader, typeof(TextState)); + s.Prepare(); + var ff = s.GetFunctionPointersLoad(); + LibVBANext.TxtStateLoad(Core, ref ff); + IsLagFrame = s.ExtraData.IsLagFrame; + LagCount = s.ExtraData.LagCount; + Frame = s.ExtraData.Frame; } public void SaveStateBinary(BinaryWriter writer) { + if (!LibVBANext.BinStateSave(Core, savebuff, savebuff.Length)) + throw new InvalidOperationException("Core's 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 (!LibVBANext.BinStateLoad(Core, savebuff, savebuff.Length)) + throw new InvalidOperationException("Core's BinStateLoad() returned false!"); + + // other variables + IsLagFrame = reader.ReadBoolean(); + LagCount = reader.ReadInt32(); + Frame = reader.ReadInt32(); } public byte[] SaveStateBinary() { - return new byte[16]; + var ms = new MemoryStream(savebuff2, true); + var bw = new BinaryWriter(ms); + SaveStateBinary(bw); + bw.Flush(); + if (ms.Position != savebuff2.Length) + throw new InvalidOperationException(); + ms.Close(); + return savebuff2; } public bool BinarySaveStatesPreferred diff --git a/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs b/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs index 154f285833..287f542a4c 100644 --- a/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs +++ b/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs @@ -237,9 +237,6 @@ namespace BizHawk.Emulation.Cores.WonderSwan // write extra copy of stuff we don't use writer.WriteLine(); writer.WriteLine("Frame {0}", Frame); - - // debug - //Console.WriteLine(Util.Hash_SHA1(SaveStateBinary())); } public void LoadStateText(TextReader reader) @@ -290,6 +287,8 @@ namespace BizHawk.Emulation.Cores.WonderSwan var bw = new BinaryWriter(ms); SaveStateBinary(bw); bw.Flush(); + if (ms.Position != savebuff2.Length) + throw new InvalidOperationException(); ms.Close(); return savebuff2; } diff --git a/output/dll/libvbanext.dll b/output/dll/libvbanext.dll index 4c70fc0587..24f2b01f65 100644 Binary files a/output/dll/libvbanext.dll and b/output/dll/libvbanext.dll differ diff --git a/vbanext/instance.cpp b/vbanext/instance.cpp index 15abdd09f0..4cf2918bab 100644 --- a/vbanext/instance.cpp +++ b/vbanext/instance.cpp @@ -21,6 +21,8 @@ #include "constarrays.h" +#include "newstate.h" + #define INLINE class Gigazoid @@ -430,10 +432,6 @@ typedef struct int bits; int state; u8 data[12]; - // reserved variables for future - u8 reserved[12]; - bool reserved2; - u32 reserved3; } RTCCLOCKDATA; RTCCLOCKDATA rtcClockData; @@ -527,40 +525,32 @@ bool rtcWrite(u32 address, u16 value) break; case 0x65: { - struct tm *newtime; - time_t long_time; - - time( &long_time ); /* Get time as long integer. */ - newtime = localtime( &long_time ); /* Convert to local time. */ - + tm newtime; + GetTime(newtime); rtcClockData.dataLen = 7; - rtcClockData.data[0] = toBCD(newtime->tm_year); - rtcClockData.data[1] = toBCD(newtime->tm_mon+1); - rtcClockData.data[2] = toBCD(newtime->tm_mday); - rtcClockData.data[3] = toBCD(newtime->tm_wday); - rtcClockData.data[4] = toBCD(newtime->tm_hour); - rtcClockData.data[5] = toBCD(newtime->tm_min); - rtcClockData.data[6] = toBCD(newtime->tm_sec); + rtcClockData.data[0] = toBCD(newtime.tm_year); + rtcClockData.data[1] = toBCD(newtime.tm_mon+1); + rtcClockData.data[2] = toBCD(newtime.tm_mday); + rtcClockData.data[3] = toBCD(newtime.tm_wday); + rtcClockData.data[4] = toBCD(newtime.tm_hour); + rtcClockData.data[5] = toBCD(newtime.tm_min); + rtcClockData.data[6] = toBCD(newtime.tm_sec); rtcClockData.state = DATA; } break; case 0x67: { - struct tm *newtime; - time_t long_time; - - time( &long_time ); /* Get time as long integer. */ - newtime = localtime( &long_time ); /* Convert to local time. */ - + tm newtime; + GetTime(newtime); rtcClockData.dataLen = 3; - rtcClockData.data[0] = toBCD(newtime->tm_hour); - rtcClockData.data[1] = toBCD(newtime->tm_min); - rtcClockData.data[2] = toBCD(newtime->tm_sec); + rtcClockData.data[0] = toBCD(newtime.tm_hour); + rtcClockData.data[1] = toBCD(newtime.tm_min); + rtcClockData.data[2] = toBCD(newtime.tm_sec); rtcClockData.state = DATA; } break; default: - systemMessage(0, "Unknown RTC command %02x", rtcClockData.command); + //systemMessage(0, "Unknown RTC command %02x", rtcClockData.command); rtcClockData.state = IDLE; break; } @@ -618,6 +608,33 @@ void rtcReset (void) rtcClockData.bits = 0; rtcClockData.state = IDLE; } + +void GetTime(tm ×) +{ + time_t t = RTCUseRealTime ? time(nullptr) : RTCTime; + #if defined _MSC_VER + gmtime_s(×, &t); + #elif defined __MINGW32__ + tm *tmp = gmtime(&t); + times = *tmp; + #elif defined __GNUC__ + gmtime_r(&t, ×); + #endif +} + +uint64_t RTCTime; +int RTCTicks; +bool RTCUseRealTime; + +void AdvanceRTC(int ticks) +{ + RTCTicks += ticks; + while (RTCTicks >= 16777216) + { + RTCTicks -= 16777216; + RTCTime++; + } +} //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // END MEMORY.CPP @@ -660,6 +677,19 @@ void rtcReset (void) class Blip_Buffer { public: + templatevoid SyncState(NewState *ns) + { + NSS(clock_rate_); + NSS(length_); + NSS(sample_rate_); + NSS(factor_); + NSS(offset_); + // int32_t *buffer_; shouldn't need to save + NSS(buffer_size_); + NSS(reader_accum_); + + } + Blip_Buffer::Blip_Buffer() { factor_ = INT_MAX; @@ -743,11 +773,11 @@ class Blip_Buffer class Blip_Synth { public: - Blip_Buffer* buf; int delta_factor; - Blip_Synth() + templatevoid SyncState(NewState *ns) { + NSS(delta_factor); } void volume( double v ) { delta_factor = int ((v * 1.0) * (1L << BLIP_SAMPLE_BITS) + 0.5); } @@ -778,9 +808,6 @@ class Blip_Synth void offset_inline( int32_t t, int delta, Blip_Buffer* buf ) const { offset_resampled( t * buf->factor_ + buf->offset_, delta, buf ); } - void offset_inline( int32_t t, int delta ) const { - offset_resampled( t * buf->factor_ + buf->offset_, delta, buf ); - } }; #define TRIGGER_MASK 0x80 @@ -813,6 +840,25 @@ class Gb_Osc unsigned phase; /* waveform phase (or equivalent)*/ bool enabled; /* internal enabled flag*/ + templatevoid SyncState(NewState *ns) + { + EBS(output, -1); + EVS(output, outputs[0], 0); + EVS(output, outputs[1], 1); + EVS(output, outputs[2], 2); + EVS(output, outputs[3], 3); + EES(output, nullptr); + + NSS(mode); + NSS(dac_off_amp); + NSS(last_amp); + + NSS(delay); + NSS(length_ctr); + NSS(phase); + NSS(enabled); + } + void Gb_Osc::clock_length() { if ( (regs [4] & LENGTH_ENABLED) && length_ctr ) @@ -874,6 +920,14 @@ class Gb_Env : public Gb_Osc int volume; bool env_enabled; + templatevoid SyncState(NewState *ns) + { + Gb_Osc::SyncState(ns); + NSS(env_delay); + NSS(volume); + NSS(env_enabled); + } + void Gb_Env::clock_envelope() { if ( env_enabled && --env_delay <= 0 && reload_env_timer() ) @@ -961,7 +1015,12 @@ class Gb_Env : public Gb_Osc class Gb_Square : public Gb_Env { - public: +public: + templatevoid SyncState(NewState *ns) + { + Gb_Env::SyncState(ns); + } + bool Gb_Square::write_register( int frame_phase, int reg, int old_data, int data ) { bool result = Gb_Env::write_register( frame_phase, reg, old_data, data ); @@ -1065,6 +1124,15 @@ class Gb_Sweep_Square : public Gb_Square bool sweep_enabled; bool sweep_neg; + templatevoid SyncState(NewState *ns) + { + Gb_Square::SyncState(ns); + NSS(sweep_freq); + NSS(sweep_delay); + NSS(sweep_enabled); + NSS(sweep_neg); + } + void Gb_Sweep_Square::clock_sweep() { if ( --sweep_delay <= 0 ) @@ -1128,6 +1196,12 @@ class Gb_Noise : public Gb_Env public: int divider; /* noise has more complex frequency divider setup*/ + templatevoid SyncState(NewState *ns) + { + Gb_Env::SyncState(ns); + NSS(divider); + } + /* Quickly runs LFSR for a large number of clocks. For use when noise is generating*/ /* no sound.*/ unsigned run_lfsr( unsigned s, unsigned mask, int count ) @@ -1314,6 +1388,13 @@ class Gb_Wave : public Gb_Osc int agb_mask; /* 0xFF if AGB features enabled, 0 otherwise*/ uint8_t* wave_ram; /* 32 bytes (64 nybbles), stored in APU*/ + templatevoid SyncState(NewState *ns) + { + Gb_Osc::SyncState(ns); + NSS(sample_buf); + NSS(agb_mask); + } + INLINE void Gb_Wave::write_register( int frame_phase, int reg, int old_data, int data ) { switch ( reg ) @@ -1505,15 +1586,29 @@ int soundTicksUp; // counts up from 0 being the last time the blips were emptied int soundEnableFlag; // = 0x3ff; /* emulator channels enabled*/ -typedef struct +struct gba_pcm_t { int last_amp; int last_time; int shift; Blip_Buffer* output; -} gba_pcm_t; -typedef struct + templatevoid SyncState(NewState *ns, Gigazoid *g) + { + NSS(last_amp); + NSS(last_time); + NSS(shift); + + // tricky + EBS(output, -1); + EVS(output, &g->bufs_buffer[0], 0); + EVS(output, &g->bufs_buffer[1], 1); + EVS(output, &g->bufs_buffer[2], 2); + EES(output, nullptr); + } +}; + +struct gba_pcm_fifo_t { bool enabled; uint8_t fifo [32]; @@ -1524,7 +1619,20 @@ typedef struct int which; int timer; gba_pcm_t pcm; -} gba_pcm_fifo_t; + + templatevoid SyncState(NewState *ns, Gigazoid *g) + { + NSS(enabled); + NSS(fifo); + NSS(count); + NSS(dac); + NSS(readIndex); + NSS(writeIndex); + NSS(which); + NSS(timer); + SSS_HACKY(pcm, g); + } +}; gba_pcm_fifo_t pcm [2]; @@ -1618,45 +1726,26 @@ struct gb_apu_t Gb_Noise noise; Blip_Synth good_synth; Blip_Synth med_synth; + + templatevoid SyncState(NewState *ns) + { + NSS(reduce_clicks_); + NSS(regs); + NSS(last_time); + NSS(frame_time); + NSS(frame_period); + NSS(frame_phase); + NSS(volume_); + SSS(square1); + SSS(square2); + SSS(wave); + SSS(noise); + + SSS(good_synth); + SSS(med_synth); + } } gb_apu; -// Format of save state. Should be stable across versions of the library, -// with earlier versions properly opening later save states. Includes some -// room for expansion so the state size shouldn't increase. -struct gb_apu_state_t -{ - // Values stored as plain int so your code can read/write them easily. - // Structure can NOT be written to disk, since format is not portable. - typedef int val_t; - - enum { format0 = 0x50414247 }; - - val_t format; // format of all following data - val_t version; // later versions just add fields to end - - unsigned char regs [0x40]; - val_t frame_time; - val_t frame_phase; - - val_t sweep_freq; - val_t sweep_delay; - val_t sweep_enabled; - val_t sweep_neg; - val_t noise_divider; - val_t wave_buf; - - val_t delay [4]; - val_t length_ctr [4]; - val_t phase [4]; - val_t enabled [4]; - - val_t env_delay [3]; - val_t env_volume [3]; - val_t env_enabled [3]; - - val_t unused [13]; // for future expansion -}; - #define VOL_REG 0xFF24 #define STEREO_REG 0xFF25 #define STATUS_REG 0xFF26 @@ -8956,9 +9045,6 @@ bool CPUReadBatteryFile(const char *fileName) return true; } */ -void CPUCleanUp (void) -{ -} int CPULoadRom(const u8 *romfile, const u32 romfilelen) { @@ -8986,9 +9072,6 @@ int CPULoadRom(const u8 *romfile, const u32 romfilelen) } - - - flashInit(); eepromInit(); @@ -12557,6 +12640,8 @@ updateLoop: soundTicksUp += clockTicks; + AdvanceRTC(clockTicks); + if(graphics.lcdTicks <= 0) { if(io_registers[REG_DISPSTAT] & 1) @@ -12997,10 +13082,6 @@ void systemDrawScreen (void) // TODO: fix up RTC so this is used //uint32_t systemGetClock (void) { return 0; } -void systemMessage(const char *, ...) -{ -} - // called at regular intervals on sound clock void systemOnWriteDataToSoundBuffer(int16_t * finalWave, int length) { @@ -13011,6 +13092,225 @@ void systemOnWriteDataToSoundBuffer(int16_t * finalWave, int length) } public: + +templatevoid SyncState(NewState *ns) +{ + NSS(flashSaveMemory); + NSS(flashState); + NSS(flashReadState); + NSS(flashSize); + NSS(flashDeviceID); + NSS(flashManufacturerID); + NSS(flashBank); + + NSS(eepromMode); + NSS(eepromByte); + NSS(eepromBits); + NSS(eepromAddress); + NSS(eepromData); + NSS(eepromBuffer); + NSS(eepromInUse); + NSS(eepromSize); + + NSS(rtcClockData); + NSS(rtcEnabled); + NSS(RTCTime); + NSS(RTCTicks); + NSS(RTCUseRealTime); + + NSS(soundTicksUp); + NSS(soundEnableFlag); + SSS_HACKY(pcm[0], this); + SSS_HACKY(pcm[1], this); + SSS(pcm_synth); + + SSS(bufs_buffer[0]); + SSS(bufs_buffer[1]); + SSS(bufs_buffer[2]); + NSS(mixer_samples_read); + + SSS(gb_apu); + + NSS(cpuNextEvent); + NSS(holdState); + NSS(cpuPrefetch); + NSS(cpuTotalTicks); + NSS(memoryWait); + NSS(memoryWaitSeq); + NSS(memoryWait32); + NSS(memoryWaitSeq32); + NSS(biosProtected); + NSS(cpuBitsSet); + + NSS(N_FLAG); + NSS(C_FLAG); + NSS(Z_FLAG); + NSS(V_FLAG); + NSS(armState); + NSS(armIrqEnable); + NSS(armMode); + + NSS(io_registers); + + NSS(MOSAIC); + + NSS(BG2X_L); + NSS(BG2X_H); + NSS(BG2Y_L); + NSS(BG2Y_H); + NSS(BG3X_L); + NSS(BG3X_H); + NSS(BG3Y_L); + NSS(BG3Y_H); + NSS(BLDMOD); + NSS(COLEV); + NSS(COLY); + NSS(DM0SAD_L); + NSS(DM0SAD_H); + NSS(DM0DAD_L); + NSS(DM0DAD_H); + NSS(DM0CNT_L); + NSS(DM0CNT_H); + NSS(DM1SAD_L); + NSS(DM1SAD_H); + NSS(DM1DAD_L); + NSS(DM1DAD_H); + NSS(DM1CNT_L); + NSS(DM1CNT_H); + NSS(DM2SAD_L); + NSS(DM2SAD_H); + NSS(DM2DAD_L); + NSS(DM2DAD_H); + NSS(DM2CNT_L); + NSS(DM2CNT_H); + NSS(DM3SAD_L); + NSS(DM3SAD_H); + NSS(DM3DAD_L); + NSS(DM3DAD_H); + NSS(DM3CNT_L); + NSS(DM3CNT_H); + + NSS(timerOnOffDelay); + NSS(timer0Value); + NSS(dma0Source); + NSS(dma0Dest); + NSS(dma1Source); + NSS(dma1Dest); + NSS(dma2Source); + NSS(dma2Dest); + NSS(dma3Source); + NSS(dma3Dest); + + EBS(cpuSaveGameFunc, 0); + EVS(cpuSaveGameFunc, &Gigazoid::flashWrite, 1); + EVS(cpuSaveGameFunc, &Gigazoid::sramWrite, 2); + EVS(cpuSaveGameFunc, &Gigazoid::flashSaveDecide, 3); + EVS(cpuSaveGameFunc, &Gigazoid::flashDelayedWrite, 4); + EVS(cpuSaveGameFunc, &Gigazoid::sramDelayedWrite, 5); + EES(cpuSaveGameFunc, nullptr); + + NSS(fxOn); + NSS(windowOn); + NSS(cpuDmaTicksToUpdate); + NSS(IRQTicks); + NSS(intState); + + NSS(bus); + NSS(graphics); + + // map; // values never change + + NSS(clockTicks); + + NSS(romSize); + NSS(line); + NSS(gfxInWin); + NSS(lineOBJpixleft); + NSS(joy); + + NSS(gfxBG2Changed); + NSS(gfxBG3Changed); + + NSS(gfxBG2X); + NSS(gfxBG2Y); + NSS(gfxBG3X); + NSS(gfxBG3Y); + + NSS(ioReadable); + NSS(gbaSaveType); + + NSS(stopState); + + NSS(timer0On); + NSS(timer0Ticks); + NSS(timer0Reload); + NSS(timer0ClockReload); + NSS(timer1Value); + NSS(timer1On); + NSS(timer1Ticks); + NSS(timer1Reload); + NSS(timer1ClockReload); + NSS(timer2Value); + NSS(timer2On); + NSS(timer2Ticks); + NSS(timer2Reload); + NSS(timer2ClockReload); + NSS(timer3Value); + NSS(timer3On); + NSS(timer3Ticks); + NSS(timer3Reload); + NSS(timer3ClockReload); + + NSS(saveType); + NSS(skipBios); + NSS(cpuIsMultiBoot); + NSS(cpuSaveType); + NSS(enableRtc); + NSS(mirroringEnable); + NSS(skipSaveGameBattery); + + NSS(cpuDmaCount); + + NSS(internalRAM); + NSS(workRAM); + NSS(vram); + NSS(pix); + NSS(oam); + NSS(ioMem); + + NSS(cpuSramEnabled); + NSS(cpuFlashEnabled); + NSS(cpuEEPROMEnabled); + NSS(cpuEEPROMSensorEnabled); + + EBS(renderLine, 0); + EVS(renderLine, &Gigazoid::mode0RenderLine, 0x01); + EVS(renderLine, &Gigazoid::mode0RenderLineNoWindow, 0x02); + EVS(renderLine, &Gigazoid::mode0RenderLineAll, 0x03); + EVS(renderLine, &Gigazoid::mode1RenderLine, 0x11); + EVS(renderLine, &Gigazoid::mode1RenderLineNoWindow, 0x12); + EVS(renderLine, &Gigazoid::mode1RenderLineAll, 0x13); + EVS(renderLine, &Gigazoid::mode2RenderLine, 0x21); + EVS(renderLine, &Gigazoid::mode2RenderLineNoWindow, 0x22); + EVS(renderLine, &Gigazoid::mode2RenderLineAll, 0x23); + EVS(renderLine, &Gigazoid::mode3RenderLine, 0x31); + EVS(renderLine, &Gigazoid::mode3RenderLineNoWindow, 0x32); + EVS(renderLine, &Gigazoid::mode3RenderLineAll, 0x33); + EVS(renderLine, &Gigazoid::mode4RenderLine, 0x41); + EVS(renderLine, &Gigazoid::mode4RenderLineNoWindow, 0x42); + EVS(renderLine, &Gigazoid::mode4RenderLineAll, 0x43); + EVS(renderLine, &Gigazoid::mode5RenderLine, 0x51); + EVS(renderLine, &Gigazoid::mode5RenderLineNoWindow, 0x52); + EVS(renderLine, &Gigazoid::mode5RenderLineAll, 0x53); + EES(renderLine, nullptr); + + NSS(render_line_all_enabled); + + // address_lut; // values never change + + NSS(lagged); +} + Gigazoid() { Gigazoid_Init(); @@ -13018,7 +13318,6 @@ public: ~Gigazoid() { - CPUCleanUp(); // todo: check me! } bool LoadRom(const u8 *romfile, const u32 romfilelen, const u8 *biosfile, const u32 biosfilelen) @@ -13044,7 +13343,9 @@ public: CPUInit(biosfile, biosfilelen); CPUReset(); - soundReset(); + + // CPUReset already calls this, but if that were to change + // soundReset(); return true; } @@ -13111,4 +13412,38 @@ EXPORT int FrameAdvance(Gigazoid *g, int input, u32 *videobuffer, s16 *audiobuff return g->FrameAdvance(input, videobuffer, audiobuffer, numsamp); } +EXPORT int BinStateSize(Gigazoid *g) +{ + NewStateDummy dummy; + g->SyncState(&dummy); + return dummy.GetLength(); +} + +EXPORT int BinStateSave(Gigazoid *g, char *data, int length) +{ + NewStateExternalBuffer saver(data, length); + g->SyncState(&saver); + return !saver.Overflow() && saver.GetLength() == length; +} + +EXPORT int BinStateLoad(Gigazoid *g, const char *data, int length) +{ + NewStateExternalBuffer loader(const_cast(data), length); + g->SyncState(&loader); + return !loader.Overflow() && loader.GetLength() == length; +} + +EXPORT void TxtStateSave(Gigazoid *g, FPtrs *ff) +{ + NewStateExternalFunctions saver(ff); + g->SyncState(&saver); +} + +EXPORT void TxtStateLoad(Gigazoid *g, FPtrs *ff) +{ + NewStateExternalFunctions loader(ff); + g->SyncState(&loader); +} + + #include "optable.inc" diff --git a/vbanext/mingw/Makefile b/vbanext/mingw/Makefile new file mode 100644 index 0000000000..75c5f60d7d --- /dev/null +++ b/vbanext/mingw/Makefile @@ -0,0 +1,27 @@ +CXX = g++ +CXXFLAGS = -Wall -O3 -fpermissive -Wno-unused-but-set-variable -Wno-strict-aliasing -Wzero-as-null-pointer-constant -Wno-unused-variable -Wno-parentheses -Wno-sign-compare -std=gnu++11 -fomit-frame-pointer -fno-exceptions +TARGET = libvbanext.dll +LDFLAGS = -shared -static-libgcc -static-libstdc++ $(CXXFLAGS) +RM = rm +CP = cp + +SRCS = \ + ../instance.cpp \ + ../newstate.cpp + +OBJS = $(SRCS:.cpp=.o) + +all: $(TARGET) + +%.o: %.cpp + $(CXX) -c -o $@ $< $(CXXFLAGS) + +$(TARGET) : $(OBJS) + $(CXX) -o $@ $(LDFLAGS) $(OBJS) + +clean: + $(RM) $(OBJS) + $(RM) $(TARGET) + +install: + $(CP) $(TARGET) ../../output/dll diff --git a/vbanext/msvs/libvbanext/libvbanext.vcxproj b/vbanext/msvs/libvbanext/libvbanext.vcxproj index 56cc5d8cb6..c2e55b1d9c 100644 --- a/vbanext/msvs/libvbanext/libvbanext.vcxproj +++ b/vbanext/msvs/libvbanext/libvbanext.vcxproj @@ -71,10 +71,12 @@ + + diff --git a/vbanext/msvs/libvbanext/libvbanext.vcxproj.filters b/vbanext/msvs/libvbanext/libvbanext.vcxproj.filters index 3deff3727c..17408fd5f3 100644 --- a/vbanext/msvs/libvbanext/libvbanext.vcxproj.filters +++ b/vbanext/msvs/libvbanext/libvbanext.vcxproj.filters @@ -21,6 +21,9 @@ Source Files + + Source Files + @@ -38,6 +41,9 @@ Header Files + + Header Files + diff --git a/vbanext/newstate.cpp b/vbanext/newstate.cpp new file mode 100644 index 0000000000..1b356e3a86 --- /dev/null +++ b/vbanext/newstate.cpp @@ -0,0 +1,64 @@ +#include "newstate.h" +#include + +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/vbanext/newstate.h b/vbanext/newstate.h new file mode 100644 index 0000000000..2f0f75f8ef --- /dev/null +++ b/vbanext/newstate.h @@ -0,0 +1,99 @@ +#ifndef NEWSTATE_H +#define NEWSTATE_H + +#include +#include + +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 SSS_HACKY(x,extra) do { ns->EnterSection(#x); (x).SyncState(ns, extra); ns->ExitSection(#x); } while (0) + +#define TSS(x) do { ns->EnterSection(#x); (x)->SyncState(ns); ns->ExitSection(#x); } while (0) + +#endif