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