vba next: savestates and other confetti

This commit is contained in:
goyuken 2014-08-08 20:01:09 +00:00
parent 1d29c7e281
commit ba93e6ab0e
10 changed files with 702 additions and 90 deletions

View File

@ -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
/// <returns>true if lagged</returns>
[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);
}
}

View File

@ -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<TextStateData>();
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<TextStateData>)ser.Deserialize(reader, typeof(TextState<TextStateData>));
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

View File

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

Binary file not shown.

View File

@ -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 &times)
{
time_t t = RTCUseRealTime ? time(nullptr) : RTCTime;
#if defined _MSC_VER
gmtime_s(&times, &t);
#elif defined __MINGW32__
tm *tmp = gmtime(&t);
times = *tmp;
#elif defined __GNUC__
gmtime_r(&t, &times);
#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:
template<bool isReader>void 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()
template<bool isReader>void 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*/
template<bool isReader>void 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;
template<bool isReader>void SyncState(NewState *ns)
{
Gb_Osc::SyncState<isReader>(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:
template<bool isReader>void SyncState(NewState *ns)
{
Gb_Env::SyncState<isReader>(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;
template<bool isReader>void SyncState(NewState *ns)
{
Gb_Square::SyncState<isReader>(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*/
template<bool isReader>void SyncState(NewState *ns)
{
Gb_Env::SyncState<isReader>(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*/
template<bool isReader>void SyncState(NewState *ns)
{
Gb_Osc::SyncState<isReader>(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
template<bool isReader>void 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;
template<bool isReader>void 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;
template<bool isReader>void 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:
template<bool isReader>void 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<false>(&dummy);
return dummy.GetLength();
}
EXPORT int BinStateSave(Gigazoid *g, char *data, int length)
{
NewStateExternalBuffer saver(data, length);
g->SyncState<false>(&saver);
return !saver.Overflow() && saver.GetLength() == length;
}
EXPORT int BinStateLoad(Gigazoid *g, const char *data, int length)
{
NewStateExternalBuffer loader(const_cast<char *>(data), length);
g->SyncState<true>(&loader);
return !loader.Overflow() && loader.GetLength() == length;
}
EXPORT void TxtStateSave(Gigazoid *g, FPtrs *ff)
{
NewStateExternalFunctions saver(ff);
g->SyncState<false>(&saver);
}
EXPORT void TxtStateLoad(Gigazoid *g, FPtrs *ff)
{
NewStateExternalFunctions loader(ff);
g->SyncState<true>(&loader);
}
#include "optable.inc"

27
vbanext/mingw/Makefile Normal file
View File

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

View File

@ -71,10 +71,12 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\instance.cpp" />
<ClCompile Include="..\..\newstate.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\constarrays.h" />
<ClInclude Include="..\..\instance.h" />
<ClInclude Include="..\..\newstate.h" />
<ClInclude Include="..\..\port.h" />
<ClInclude Include="..\..\sound_blargg.h" />
<ClInclude Include="..\..\types.h" />

View File

@ -21,6 +21,9 @@
<ClCompile Include="..\..\instance.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\newstate.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\port.h">
@ -38,6 +41,9 @@
<ClInclude Include="..\..\constarrays.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\newstate.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\..\optable.inc">

64
vbanext/newstate.cpp Normal file
View File

@ -0,0 +1,64 @@
#include "newstate.h"
#include <cstring>
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<char *>(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);
}

99
vbanext/newstate.h Normal file
View File

@ -0,0 +1,99 @@
#ifndef NEWSTATE_H
#define NEWSTATE_H
#include <cstring>
#include <cstddef>
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<false>(NewState *ns);\
template void x::SyncState<true>(NewState *ns);\
template<bool isReader>void 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<isReader>(ns); ns->ExitSection(#x); } while (0)
#define SSS_HACKY(x,extra) do { ns->EnterSection(#x); (x).SyncState<isReader>(ns, extra); ns->ExitSection(#x); } while (0)
#define TSS(x) do { ns->EnterSection(#x); (x)->SyncState<isReader>(ns); ns->ExitSection(#x); } while (0)
#endif