vba next: savestates and other confetti
This commit is contained in:
parent
1d29c7e281
commit
ba93e6ab0e
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
@ -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:
|
||||
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"
|
||||
|
|
|
@ -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
|
|
@ -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" />
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
Loading…
Reference in New Issue