mirror of https://github.com/PCSX2/pcsx2.git
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:
parent
a51b407cdb
commit
1f36e97927
|
@ -786,6 +786,7 @@ struct Freeze_v10Compat
|
|||
|
||||
void SaveState::cdvdFreeze()
|
||||
{
|
||||
FreezeTag( "cdvd" );
|
||||
Freeze( cdvd );
|
||||
|
||||
if( IsLoading() )
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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() )
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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.
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -751,6 +751,8 @@ void psxRcntSetGates()
|
|||
|
||||
void SaveState::psxRcntFreeze()
|
||||
{
|
||||
FreezeTag( "iopCounters" );
|
||||
|
||||
Freeze(psxCounters);
|
||||
Freeze(psxNextCounter);
|
||||
Freeze(psxNextsCounter);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -203,6 +203,7 @@ u8 sio2_fifoOut(){
|
|||
|
||||
void SaveState::sio2Freeze()
|
||||
{
|
||||
FreezeTag( "sio2" );
|
||||
Freeze(sio2);
|
||||
}
|
||||
|
||||
|
|
|
@ -116,6 +116,8 @@ static void _mtgsFreezeGIF( SaveState& state, GIFPath (&paths)[3] )
|
|||
|
||||
void SaveState::mtgsFreeze()
|
||||
{
|
||||
FreezeTag( "mtgs" );
|
||||
|
||||
if( mtgsThread != NULL )
|
||||
{
|
||||
mtgsThread->Freeze( *this );
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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();
|
||||
|
||||
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
|
||||
FreezeMem(PS2MEM_SCRATCH, Ps2MemSize::Scratch); // scratch pad
|
||||
FreezeMem(PS2MEM_HW, Ps2MemSize::Hardware); // hardware memory
|
||||
// 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).
|
||||
|
||||
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(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);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue