Major overhaul of the savestate system!

Since backwards compat of savestates got totally broken a few revisions ago anyway, I decided to take this opportunity to revamp the savestate system with some significant cleanups (yes it loses all backward compat once again).  Improvements include:

 * Reduced state size by removing some unneeded data (faster saves now too!)
 * Added string tags to varios "sections" of the states to assist in troubleshooting and retaining savestate compat in future versions.
 * Better error handling and fewer memory leaks.
 * Removed some unused/obsolete data from psxRegs, Counters, and psxCounters structures.
 * Removed all old savestate versioning code, since none of the old versions are supported anymore anyways.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@815 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2009-03-19 04:16:24 +00:00
parent a51b407cdb
commit 1f36e97927
21 changed files with 230 additions and 247 deletions

View File

@ -786,6 +786,7 @@ struct Freeze_v10Compat
void SaveState::cdvdFreeze()
{
FreezeTag( "cdvd" );
Freeze( cdvd );
if( IsLoading() )

View File

@ -944,15 +944,9 @@ void cdrReset() {
cdReadTime = (PSXCLK / 1757) * BIAS;
}
void SaveState::cdrFreeze() {
void SaveState::cdrFreeze()
{
FreezeTag( "cdrom" );
Freeze(cdr);
// Alrighty! This code used to, for some reason, recalculate the pTransfer value
// even though it's being saved as part of the cdr struct. Probably a backwards
// compat fix with an earlier save version.
int tmp; // = (int)(cdr.pTransfer - cdr.Transfer);
Freeze(tmp);
//if (Mode == 0) cdr.pTransfer = cdr.Transfer + tmp;
}

View File

@ -43,7 +43,9 @@ int gates = 0;
// Counter 4 takes care of scanlines - hSync/hBlanks
// Counter 5 takes care of vSync/vBlanks
Counter counters[6];
Counter counters[4];
SyncCounter hsyncCounter;
SyncCounter vsyncCounter;
u32 nextsCounter; // records the cpuRegs.cycle value of the last call to rcntUpdate()
s32 nextCounter; // delta from nextsCounter, in cycles, until the next rcntUpdate()
@ -101,7 +103,7 @@ static __forceinline void cpuRcntSet()
int i;
nextsCounter = cpuRegs.cycle;
nextCounter = (counters[5].sCycle + counters[5].CycleT) - cpuRegs.cycle;
nextCounter = (vsyncCounter.sCycle + vsyncCounter.CycleT) - cpuRegs.cycle;
for (i = 0; i < 4; i++)
_rcntSet( i );
@ -124,10 +126,10 @@ void rcntInit() {
counters[2].interrupt = 11;
counters[3].interrupt = 12;
counters[4].modeval = MODE_HRENDER;
counters[4].sCycle = cpuRegs.cycle;
counters[5].modeval = MODE_VRENDER;
counters[5].sCycle = cpuRegs.cycle;
hsyncCounter.Mode = MODE_HRENDER;
hsyncCounter.sCycle = cpuRegs.cycle;
vsyncCounter.Mode = MODE_VRENDER;
vsyncCounter.sCycle = cpuRegs.cycle;
UpdateVSyncRate();
@ -136,7 +138,7 @@ void rcntInit() {
}
// debug code, used for stats
int g_nCounters[4];
int g_nhsyncCounter;
static uint iFrame = 0;
#ifndef _WIN32
@ -235,8 +237,8 @@ u32 UpdateVSyncRate()
vSyncInfoCalc( &vSyncInfo, FRAMERATE_NTSC, SCANLINES_TOTAL_NTSC );
}
counters[4].CycleT = vSyncInfo.hRender; // Amount of cycles before the counter will be updated
counters[5].CycleT = vSyncInfo.Render; // Amount of cycles before the counter will be updated
hsyncCounter.CycleT = vSyncInfo.hRender; // Amount of cycles before the counter will be updated
vsyncCounter.CycleT = vSyncInfo.Render; // Amount of cycles before the counter will be updated
if (Config.CustomFps > 0)
{
@ -393,28 +395,28 @@ static int vblankinc = 0;
__forceinline void rcntUpdate_hScanline()
{
if( !cpuTestCycle( counters[4].sCycle, counters[4].CycleT ) ) return;
if( !cpuTestCycle( hsyncCounter.sCycle, hsyncCounter.CycleT ) ) return;
//iopBranchAction = 1;
if (counters[4].modeval & MODE_HBLANK) { //HBLANK Start
rcntStartGate(false, counters[4].sCycle);
if (hsyncCounter.Mode & MODE_HBLANK) { //HBLANK Start
rcntStartGate(false, hsyncCounter.sCycle);
psxCheckStartGate16(0);
// Setup the hRender's start and end cycle information:
counters[4].sCycle += vSyncInfo.hBlank; // start (absolute cycle value)
counters[4].CycleT = vSyncInfo.hRender; // endpoint (delta from start value)
counters[4].modeval = MODE_HRENDER;
hsyncCounter.sCycle += vSyncInfo.hBlank; // start (absolute cycle value)
hsyncCounter.CycleT = vSyncInfo.hRender; // endpoint (delta from start value)
hsyncCounter.Mode = MODE_HRENDER;
}
else { //HBLANK END / HRENDER Begin
if (CSRw & 0x4) GSCSRr |= 4; // signal
if (!(GSIMR&0x400)) gsIrq();
if (gates) rcntEndGate(false, counters[4].sCycle);
if (gates) rcntEndGate(false, hsyncCounter.sCycle);
if (psxhblankgate) psxCheckEndGate16(0);
// set up the hblank's start and end cycle information:
counters[4].sCycle += vSyncInfo.hRender; // start (absolute cycle value)
counters[4].CycleT = vSyncInfo.hBlank; // endpoint (delta from start value)
counters[4].modeval = MODE_HBLANK;
hsyncCounter.sCycle += vSyncInfo.hRender; // start (absolute cycle value)
hsyncCounter.CycleT = vSyncInfo.hBlank; // endpoint (delta from start value)
hsyncCounter.Mode = MODE_HBLANK;
# ifdef VSYNC_DEBUG
hsc++;
@ -424,30 +426,30 @@ __forceinline void rcntUpdate_hScanline()
__forceinline bool rcntUpdate_vSync()
{
s32 diff = (cpuRegs.cycle - counters[5].sCycle);
if( diff < counters[5].CycleT ) return false;
s32 diff = (cpuRegs.cycle - vsyncCounter.sCycle);
if( diff < vsyncCounter.CycleT ) return false;
//iopBranchAction = 1;
if (counters[5].modeval == MODE_VSYNC)
if (vsyncCounter.Mode == MODE_VSYNC)
{
VSyncEnd(counters[5].sCycle);
VSyncEnd(vsyncCounter.sCycle);
counters[5].sCycle += vSyncInfo.Blank;
counters[5].CycleT = vSyncInfo.Render;
counters[5].modeval = MODE_VRENDER;
vsyncCounter.sCycle += vSyncInfo.Blank;
vsyncCounter.CycleT = vSyncInfo.Render;
vsyncCounter.Mode = MODE_VRENDER;
return true;
}
else // VSYNC end / VRENDER begin
{
VSyncStart(counters[5].sCycle);
VSyncStart(vsyncCounter.sCycle);
counters[5].sCycle += vSyncInfo.Render;
counters[5].CycleT = vSyncInfo.Blank;
counters[5].modeval = MODE_VSYNC;
vsyncCounter.sCycle += vSyncInfo.Render;
vsyncCounter.CycleT = vSyncInfo.Blank;
vsyncCounter.Mode = MODE_VSYNC;
// Accumulate hsync rounding errors:
counters[4].sCycle += vSyncInfo.hSyncError;
hsyncCounter.sCycle += vSyncInfo.hSyncError;
# ifdef VSYNC_DEBUG
vblankinc++;
@ -766,15 +768,12 @@ u32 __fastcall rcntCycle(int index)
void SaveState::rcntFreeze()
{
Freeze(counters);
Freeze(nextCounter);
Freeze(nextsCounter);
// New in version 1 -- save the PAL/NTSC info!
if( GetVersion() >= 0x1 )
{
Freeze( Config.PsxType );
}
Freeze( counters );
Freeze( hsyncCounter );
Freeze( vsyncCounter );
Freeze( nextCounter );
Freeze( nextsCounter );
Freeze( Config.PsxType );
if( IsLoading() )
{

View File

@ -66,7 +66,8 @@ struct EECNT_MODE
// fixme: Cycle and sCycleT members are unused.
// But they can't be removed without making a new savestate version.
struct Counter {
struct Counter
{
u32 count;
union
{
@ -75,10 +76,14 @@ struct Counter {
};
u32 target, hold;
u32 rate, interrupt;
u32 Cycle;
u32 sCycleT; // delta values should be signed.
};
struct SyncCounter
{
u32 Mode;
u32 sCycle; // start cycle of timer
s32 CycleT;
u32 sCycleT; // delta values should be signed.
};
//------------------------------------------------------------------
@ -124,7 +129,10 @@ struct Counter {
#define MODE_HBLANK 0x1 //Set for the remaining ~1/6 of 1 Scanline
extern Counter counters[6];
extern Counter counters[4];
extern SyncCounter hsyncCounter;
extern SyncCounter vsyncCounter;
extern s32 nextCounter; // delta until the next counter event (must be signed)
extern u32 nextsCounter;

View File

@ -615,13 +615,12 @@ void gifMFIFOInterrupt()
void SaveState::gifFreeze()
{
if( GetVersion() >= 0x04 )
{
Freeze( gifstate );
Freeze( gifqwc );
Freeze( gspath3done );
Freeze( gscycles );
FreezeTag( "GIFdma" );
// Note: mfifocycles is not a persistent var, so no need to save it here.
}
Freeze( gifstate );
Freeze( gifqwc );
Freeze( gspath3done );
Freeze( gscycles );
// Note: mfifocycles is not a persistent var, so no need to save it here.
}

View File

@ -163,14 +163,14 @@ void ipuShutdown()
// fixme - ipuFreeze looks fairly broken. Should probably take a closer look at some point.
void SaveState::ipuFreeze() {
void SaveState::ipuFreeze()
{
IPUProcessInterrupt();
if( GetVersion() < 0x04 )
{
// old versions saved the IPU regs, but they're already saved as part of HW!
FreezeMem(ipuRegs, sizeof(IPUregisters));
}
FreezeTag( "IPU" );
// old versions saved the IPU regs, but they're already saved as part of HW!
//FreezeMem(ipuRegs, sizeof(IPUregisters));
Freeze(g_nDMATransfer);
Freeze(FIreadpos);

View File

@ -751,6 +751,8 @@ void psxRcntSetGates()
void SaveState::psxRcntFreeze()
{
FreezeTag( "iopCounters" );
Freeze(psxCounters);
Freeze(psxNextCounter);
Freeze(psxNextsCounter);

View File

@ -25,8 +25,7 @@
struct psxCounter {
u64 count, target;
u32 mode;
u32 rate, interrupt, otarget;
u32 sCycle, Cycle;
u32 rate, interrupt;
u32 sCycleT;
s32 CycleT;
};

View File

@ -203,6 +203,7 @@ u8 sio2_fifoOut(){
void SaveState::sio2Freeze()
{
FreezeTag( "sio2" );
Freeze(sio2);
}

View File

@ -116,6 +116,8 @@ static void _mtgsFreezeGIF( SaveState& state, GIFPath (&paths)[3] )
void SaveState::mtgsFreeze()
{
FreezeTag( "mtgs" );
if( mtgsThread != NULL )
{
mtgsThread->Freeze( *this );

View File

@ -176,9 +176,9 @@ u32 GetBiosVersion() {
}
//2002-09-22 (Florin)
int IsBIOS(char *filename, char *description)
int IsBIOS(const char *filename, char *description)
{
char ROMVER[14+1], zone[12+1];
char ROMVER[14+1];
FILE *fp;
unsigned int fileOffset=0, found=FALSE;
struct romdir rd;
@ -200,31 +200,38 @@ int IsBIOS(char *filename, char *description)
return FALSE; //Unable to locate ROMDIR structure in file or a ioprpXXX.img
}
while(strlen(rd.fileName) > 0){
if (strcmp(rd.fileName, "ROMVER") == 0){ // found romver
unsigned int filepos=ftell(fp);
while(strlen(rd.fileName) > 0)
{
if (strcmp(rd.fileName, "ROMVER") == 0) // found romver
{
uint filepos = ftell(fp);
fseek(fp, fileOffset, SEEK_SET);
if (fread(&ROMVER, 14, 1, fp) == 0) break;
fseek(fp, filepos, SEEK_SET);//go back
switch(ROMVER[4]){
case 'T':sprintf(zone, "T10K "); break;
case 'X':sprintf(zone, "Test ");break;
case 'J':sprintf(zone, "Japan "); break;
case 'A':sprintf(zone, "USA "); break;
case 'E':sprintf(zone, "Europe"); break;
case 'H':sprintf(zone, "HK "); break;
case 'P':sprintf(zone, "Free "); break;
case 'C':sprintf(zone, "China "); break;
default: sprintf(zone, "%c ",ROMVER[4]); break;//shoudn't show
const char zonefail[2] = { ROMVER[4], '\0' }; // the default "zone" (unknown code)
const char* zone = zonefail;
switch(ROMVER[4])
{
case 'T': zone = "T10K "; break;
case 'X': zone = "Test "; break;
case 'J': zone = "Japan "; break;
case 'A': zone = "USA "; break;
case 'E': zone = "Europe"; break;
case 'H': zone = "HK "; break;
case 'P': zone = "Free "; break;
case 'C': zone = "China "; break;
}
sprintf(description, "%s vXX.XX(XX/XX/XXXX) %s", zone,
ROMVER[5]=='C'?"Console":ROMVER[5]=='D'?"Devel":"");
strncpy(description+ 8, ROMVER+ 0, 2);//ver major
strncpy(description+11, ROMVER+ 2, 2);//ver minor
strncpy(description+14, ROMVER+12, 2);//day
strncpy(description+17, ROMVER+10, 2);//month
strncpy(description+20, ROMVER+ 6, 4);//year
sprintf(description, "%s v%c%c.%c%c(%c%c/%c%c/%c%c%c%c) %s", zone,
ROMVER[0], ROMVER[1], // ver major
ROMVER[2], ROMVER[3], // ver minor
ROMVER[12], ROMVER[13], // day
ROMVER[10], ROMVER[11], // month
ROMVER[6], ROMVER[7], ROMVER[8], ROMVER[9], // year!
(ROMVER[5]=='C') ? "Console" : (ROMVER[5]=='D') ? "Devel" : ""
);
found = TRUE;
}

View File

@ -55,8 +55,9 @@ extern u64 GetCPUTicks();
extern u64 GetTickFrequency();
// Used in Misc,and Windows/Linux files.
void ProcessFKeys(int fkey, int shift); // processes fkey related commands value 1-12
int IsBIOS(char *filename, char *description);
extern void ProcessFKeys(int fkey, int shift); // processes fkey related commands value 1-12
extern int IsBIOS(const char *filename, char *description);
char *ParseLang(char *id);
extern const char *LabelAuthors;
extern const char *LabelGreets;

View File

@ -112,10 +112,10 @@ struct psxRegisters {
u32 code; /* The instruction */
u32 cycle;
u32 interrupt;
u32 sCycle[64]; // start cycle for signaled ints
s32 eCycle[64]; // cycle delta for signaled ints (sCycle + eCycle == branch cycle)
u32 _msflag[32];
u32 _smflag[32];
u32 sCycle[32]; // start cycle for signaled ints
s32 eCycle[32]; // cycle delta for signaled ints (sCycle + eCycle == branch cycle)
//u32 _msflag[32];
//u32 _smflag[32];
};
PCSX2_ALIGNED16_EXTERN(psxRegisters psxRegs);

View File

@ -522,7 +522,7 @@ __forceinline bool _cpuBranchTest_Shared()
cpuSetNextBranchDelta( ((g_psxNextBranchCycle-psxRegs.cycle)*8) - EEsCycle );
// Apply the hsync counter's nextCycle
cpuSetNextBranch( counters[4].sCycle, counters[4].CycleT );
cpuSetNextBranch( hsyncCounter.sCycle, hsyncCounter.CycleT );
// Apply vsync and other counter nextCycles
cpuSetNextBranch( nextsCounter, nextCounter );

View File

@ -454,11 +454,9 @@ void SPRTOinterrupt()
void SaveState::sprFreeze()
{
// Gotta save the weird ref-style DMA timing vars!
if( GetVersion() >= 0x05 )
{
Freeze(spr0finished);
Freeze(spr1finished);
Freeze(mfifotransferred);
}
FreezeTag( "SPRdma" );
Freeze(spr0finished);
Freeze(spr1finished);
Freeze(mfifotransferred);
}

View File

@ -53,7 +53,9 @@ string SaveState::GetFilename( int slot )
return Path::Combine( SSTATES_DIR, fmt_string( "%8.8X.%3.3d", ElfCRC, slot ) );
}
SaveState::SaveState( const char* msg, const string& destination ) : m_version( g_SaveVersion )
SaveState::SaveState( const char* msg, const string& destination ) :
m_version( g_SaveVersion )
, m_tagspace( 128 )
{
Console::WriteLn( "%s %hs", params msg, &destination );
}
@ -77,44 +79,76 @@ s32 CALLBACK gsSafeFreeze( int mode, freezeData *data )
}
}
void SaveState::FreezeTag( const char* src )
{
const int length = strlen( src );
m_tagspace.MakeRoomFor( length+1 );
strcpy( m_tagspace.GetPtr(), src );
FreezeMem( m_tagspace.GetPtr(), length );
if( strcmp( m_tagspace.GetPtr(), src ) != 0 )
{
assert( 0 );
throw Exception::BadSavedState( string( "Tag: " )+src );
}
}
void SaveState::FreezeAll()
{
if( IsLoading() )
PreLoadPrep();
// Check the BIOS, and issue a warning if the bios for this state
// doesn't match the bios currently being used (chances are it'll still
// work fine, but some games are very picky).
FreezeMem(PS2MEM_BASE, Ps2MemSize::Base); // 32 MB main memory
FreezeMem(PS2MEM_ROM, Ps2MemSize::Rom); // 4 mb rom memory
FreezeMem(PS2MEM_ROM1, Ps2MemSize::Rom1); // 256kb rom1 memory
char descout[128], descin[128];
memzero_obj( descout );
IsBIOS( Config.Bios, descout );
memcpy_fast( descin, descout, 128 );
Freeze( descin );
if( memcmp( descin, descout, 128 ) != 0 )
{
Console::Error(
"\n\tWarning: BIOS Version Mismatch, savestate may be unstable!\n"
"\t\tCurrent BIOS: %s\n"
"\t\tSavestate BIOS: %s\n",
params descout, descin
);
}
// First Block - Memory Dumps
// ---------------------------
FreezeMem(PS2MEM_BASE, Ps2MemSize::Base); // 32 MB main memory
FreezeMem(PS2MEM_SCRATCH, Ps2MemSize::Scratch); // scratch pad
FreezeMem(PS2MEM_HW, Ps2MemSize::Hardware); // hardware memory
FreezeMem(PS2MEM_HW, Ps2MemSize::Hardware); // hardware memory
FreezeMem(psxM, Ps2MemSize::IopRam); // 2 MB main memory
FreezeMem(psxH, Ps2MemSize::IopHardware); // hardware memory
FreezeMem(psxS, 0x000100); // iop's sif memory
// Second Block - Various CPU Registers and States
// -----------------------------------------------
FreezeTag( "cpuRegs" );
Freeze(cpuRegs); // cpu regs + COP0
Freeze(psxRegs); // iop regs
if (GetVersion() >= 0x6)
Freeze(fpuRegs);
else
{
// Old versiosn didn't save the ACCflags...
FreezeLegacy(fpuRegs, sizeof(u32)); // fpu regs
fpuRegs.ACCflag = 0;
}
Freeze(fpuRegs);
Freeze(tlb); // tlbs
// Third Block - Cycle Timers and Events
// -------------------------------------
FreezeTag( "Cycles" );
Freeze(EEsCycle);
Freeze(EEoCycle);
Freeze(psxRegs.cycle); // used to be IOPoCycle. This retains compatibility.
Freeze(g_nextBranchCycle);
Freeze(g_psxNextBranchCycle);
Freeze(s_iLastCOP0Cycle);
Freeze(s_iLastPERFCycle);
u32 dummy = 1;
Freeze( dummy ); // was g_psxWriteOk
//hope didn't forgot any cpu....
// Fourth Block - EE-related systems
// ---------------------------------
rcntFreeze();
gsFreeze();
vuMicroFreeze();
@ -125,17 +159,16 @@ void SaveState::FreezeAll()
gifFreeze();
sprFreeze();
// iop now
FreezeMem(psxM, Ps2MemSize::IopRam); // 2 MB main memory
FreezeMem(psxH, Ps2MemSize::IopHardware); // hardware memory
//FreezeMem(psxS, 0x00010000); // sif memory
// Fifth Block - iop-related systems
// ---------------------------------
psxRcntFreeze();
sioFreeze();
sio2Freeze();
cdrFreeze();
cdvdFreeze();
psxRcntFreeze();
sio2Freeze();
// Sixth Block - Plugins Galore!
// -----------------------------
FreezePlugin( "GS", gsSafeFreeze );
FreezePlugin( "SPU2", SPU2freeze );
FreezePlugin( "DEV9", DEV9freeze );
@ -147,18 +180,6 @@ void SaveState::FreezeAll()
PostLoadPrep();
}
// this function is yet incomplete. Version numbers hare still < 0x12 so it won't be run.
// (which is good because it won't work :P)
void SaveState::_testCdvdCrc()
{
/*if( GetVersion() < 0x0012 ) return;
u32 thiscrc = ElfCRC;
Freeze( thiscrc );
if( thiscrc != ElfCRC )
throw Exception::StateCrcMismatch( thiscrc, ElfCRC );*/
}
/////////////////////////////////////////////////////////////////////////////
// gzipped to/from disk state saves implementation
@ -215,8 +236,6 @@ gzLoadingState::gzLoadingState( const string& filename ) :
"\tThe savestate was created with a newer version of Pcsx2. I don't know how to load it!" );
throw Exception::UnsupportedStateVersion( m_version );
}
_testCdvdCrc();
}
gzLoadingState::~gzLoadingState() { }
@ -229,34 +248,30 @@ void gzSavingState::FreezeMem( void* data, int size )
void gzLoadingState::FreezeMem( void* data, int size )
{
gzread( m_file, data, size );
if( gzeof( m_file ) )
if( gzread( m_file, data, size ) != size )
throw Exception::BadSavedState( m_filename );
}
void gzSavingState::FreezePlugin( const char* name, s32 (CALLBACK *freezer)(int mode, freezeData *data) )
{
Console::WriteLn( "\tSaving %s", params name );
freezeData fP = { 0, NULL };
Console::WriteLn( "\tSaving %s", params name );
FreezeTag( name );
if (freezer(FREEZE_SIZE, &fP) == -1)
throw Exception::FreezePluginFailure( name, "saving" );
gzwrite(m_file, &fP.size, sizeof(fP.size));
Freeze( fP.size );
if( fP.size == 0 ) return;
fP.data = (s8*)malloc(fP.size);
if (fP.data == NULL)
throw Exception::OutOfMemory();
SafeArray<s8> buffer( fP.size );
fP.data = buffer.GetPtr();
if(freezer(FREEZE_SAVE, &fP) == -1)
throw Exception::FreezePluginFailure( name, "saving" );
if (fP.size)
{
gzwrite(m_file, fP.data, fP.size);
free(fP.data);
}
FreezeMem( fP.data, fP.size );
}
void gzLoadingState::FreezePlugin( const char* name, s32 (CALLBACK *freezer)(int mode, freezeData *data) )
@ -264,21 +279,17 @@ void gzLoadingState::FreezePlugin( const char* name, s32 (CALLBACK *freezer)(int
freezeData fP = { 0, NULL };
Console::WriteLn( "\tLoading %s", params name );
gzread(m_file, &fP.size, sizeof(fP.size));
FreezeTag( name );
Freeze( fP.size );
if( fP.size == 0 ) return;
fP.data = (s8*)malloc(fP.size);
if (fP.data == NULL)
throw Exception::OutOfMemory();
int read = gzread(m_file, fP.data, fP.size);
SafeArray<s8> buffer( fP.size );
fP.data = buffer.GetPtr();
if( read != fP.size )
throw Exception::BadSavedState( m_filename );
FreezeMem( fP.data, fP.size );
if(freezer(FREEZE_LOAD, &fP) == -1)
throw Exception::FreezePluginFailure( name, "loading" );
if (fP.size) free(fP.data);
}
//////////////////////////////////////////////////////////////////////////////////

View File

@ -24,10 +24,14 @@
#include "PS2Edefs.h"
#endif
#include "System.h"
// Savestate Versioning!
// If you make changes to the savestate version, please increment the value below.
// If the change is minor and compatibility with old states is retained, increment
// the lower 16 bit value. IF the change is breaking of all compatibility with old
// states, increment the upper 16 bit value, and clear the lower 16 bits to 0.
static const u32 g_SaveVersion = 0x8b400006;
static const u32 g_SaveVersion = 0x8b410000;
// this function is meant to be used in the place of GSfreeze, and provides a safe layer
// between the GS saving function and the MTGS's needs. :)
@ -41,6 +45,7 @@ class SaveState
{
protected:
u32 m_version; // version of the savestate being loaded.
SafeArray<char> m_tagspace;
public:
SaveState( const char* msg, const string& destination );
@ -76,6 +81,12 @@ public:
FreezeMem( &data, sizeof( T ) - sizeOfNewStuff );
}
// Freezes an identifier value into the savestate for troubleshooting purposes.
// Identifiers can be used to determine where in a savestate that data has become
// skewed (if the value does not match then the error occurs somewhere prior to that
// position).
void FreezeTag( const char* src );
// Loads or saves a plugin. Plugin name is for console logging purposes.
virtual void FreezePlugin( const char* name, s32 (CALLBACK* freezer)(int mode, freezeData *data) )=0;
@ -95,11 +106,6 @@ public:
protected:
// Used internally by constructors to check the cdvd's crc against the CRC of the savestate.
// This allows for proper exception handling of changed CDs on-the-fly.
void _testCdvdCrc();
// Load/Save functions for the various components of our glorious emulator!
void rcntFreeze();

View File

@ -586,22 +586,13 @@ __forceinline void dmaSIF2() {
}
void SaveState::sifFreeze() {
void SaveState::sifFreeze()
{
FreezeTag( "SIFdma" );
Freeze(sif0);
Freeze(sif1);
if( GetVersion() >= 0x0002 )
{
Freeze(eesifbusy);
Freeze(iopsifbusy);
}
else if( IsLoading() )
{
// Old savestate, inferior data so...
// Take an educated guess on what they should be. Or well, set to 1 because
// it more or less forces them to "kick"
iopsifbusy[0] = eesifbusy[0] = 1;
iopsifbusy[1] = eesifbusy[1] = 1;
}
Freeze(eesifbusy);
Freeze(iopsifbusy);
}

View File

@ -566,22 +566,15 @@ void SaveState::sioFreeze()
// CRCs for memory cards.
u64 m_mcdCRCs[2];
FreezeTag( "sio" );
Freeze( sio );
// versions prior to 3 didn't have CRCs.
if( GetVersion() >= 0x03 )
if( IsSaving() )
{
if( IsSaving() )
{
for( int i=0; i<2; ++i )
m_mcdCRCs[i] = MemoryCard::GetCRC( i );
}
Freeze( m_mcdCRCs );
}
else
{
m_mcdCRCs[0] = m_mcdCRCs[1] = 0;
for( int i=0; i<2; ++i )
m_mcdCRCs[i] = MemoryCard::GetCRC( i );
}
Freeze( m_mcdCRCs );
if( IsLoading() && Config.McdEnableEject )
{

View File

@ -160,6 +160,8 @@ void vuMicroMemReset()
void SaveState::vuMicroFreeze()
{
FreezeTag( "vuMicro" );
jASSUME( VU0.Mem != NULL );
jASSUME( VU1.Mem != NULL );
@ -169,15 +171,7 @@ void SaveState::vuMicroFreeze()
FreezeMem(VU0.Micro, 4*1024);
Freeze(VU0.VF);
if( GetVersion() >= 0x02 )
Freeze(VU0.VI);
else
{
// Old versions stored the VIregs as 32 bit values...
memzero_obj( VU0.VI );
for(int i=0; i<32; i++ )
Freeze( VU0.VI[i].UL );
}
Freeze(VU0.VI);
Freeze(VU1.ACC);
Freeze(VU1.code);
@ -185,14 +179,5 @@ void SaveState::vuMicroFreeze()
FreezeMem(VU1.Micro, 16*1024);
Freeze(VU1.VF);
if( GetVersion() >= 0x02 )
Freeze(VU1.VI);
else
{
// Old versions stored the VIregs as 32 bit values...
memzero_obj( VU1.VI );
for(int i=0; i<32; i++ )
Freeze( VU1.VI[i].UL );
}
Freeze(VU1.VI);
}

View File

@ -1344,23 +1344,17 @@ void vif0Reset() {
void SaveState::vif0Freeze()
{
FreezeTag( "VIFdma" );
// Dunno if this one is needed, but whatever, it's small. :)
if( GetVersion() >= 0x04 )
Freeze( g_vifCycles );
Freeze( g_vifCycles );
Freeze( vif0 );
if( GetVersion() >= 0x04 )
{
Freeze( g_vif0HasMask3 );
Freeze( g_vif0Masks );
Freeze( g_vifRow0 );
Freeze( g_vifCol0 );
}
else if( IsLoading() )
{
// Hack to "help" old savestates recover...
SetNewMask(g_vif0Masks, g_vif0HasMask3, vif0Regs->mask, ~vif0Regs->mask);
}
Freeze( g_vif0HasMask3 );
Freeze( g_vif0Masks );
Freeze( g_vifRow0 );
Freeze( g_vifCol0 );
}
//////////////////////////////////////////////////////////////////////////////
@ -2357,16 +2351,8 @@ void SaveState::vif1Freeze()
{
Freeze(vif1);
if( GetVersion() >= 0x04 )
{
Freeze( g_vif1HasMask3 );
Freeze( g_vif1Masks );
Freeze( g_vifRow1 );
Freeze( g_vifCol1 );
}
else if( IsLoading() )
{
SetNewMask(g_vif1Masks, g_vif1HasMask3, vif1Regs->mask, ~vif1Regs->mask);
//if(vif1ch->chcr & 0x100) vif1.done = 0;
}
Freeze( g_vif1HasMask3 );
Freeze( g_vif1Masks );
Freeze( g_vifRow1 );
Freeze( g_vifCol1 );
}