diff --git a/pcsx2/CDVD.cpp b/pcsx2/CDVD.cpp index 79ab349afe..8f038abdda 100644 --- a/pcsx2/CDVD.cpp +++ b/pcsx2/CDVD.cpp @@ -786,6 +786,7 @@ struct Freeze_v10Compat void SaveState::cdvdFreeze() { + FreezeTag( "cdvd" ); Freeze( cdvd ); if( IsLoading() ) diff --git a/pcsx2/CdRom.cpp b/pcsx2/CdRom.cpp index 6947ae044a..e6ba423d3d 100644 --- a/pcsx2/CdRom.cpp +++ b/pcsx2/CdRom.cpp @@ -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; } diff --git a/pcsx2/Counters.cpp b/pcsx2/Counters.cpp index 97c4016a11..cb148f8261 100644 --- a/pcsx2/Counters.cpp +++ b/pcsx2/Counters.cpp @@ -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() ) { diff --git a/pcsx2/Counters.h b/pcsx2/Counters.h index f5b2d07253..f4c70776ee 100644 --- a/pcsx2/Counters.h +++ b/pcsx2/Counters.h @@ -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; diff --git a/pcsx2/Gif.cpp b/pcsx2/Gif.cpp index 5b5bab2ea9..af27c1f2c7 100644 --- a/pcsx2/Gif.cpp +++ b/pcsx2/Gif.cpp @@ -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. } diff --git a/pcsx2/IPU/IPU.cpp b/pcsx2/IPU/IPU.cpp index 96edda1524..b7b3ad5fec 100644 --- a/pcsx2/IPU/IPU.cpp +++ b/pcsx2/IPU/IPU.cpp @@ -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); diff --git a/pcsx2/IopCounters.cpp b/pcsx2/IopCounters.cpp index 10027f1ed5..b4f40c801f 100644 --- a/pcsx2/IopCounters.cpp +++ b/pcsx2/IopCounters.cpp @@ -751,6 +751,8 @@ void psxRcntSetGates() void SaveState::psxRcntFreeze() { + FreezeTag( "iopCounters" ); + Freeze(psxCounters); Freeze(psxNextCounter); Freeze(psxNextsCounter); diff --git a/pcsx2/IopCounters.h b/pcsx2/IopCounters.h index 8012b5ace2..058052548a 100644 --- a/pcsx2/IopCounters.h +++ b/pcsx2/IopCounters.h @@ -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; }; diff --git a/pcsx2/IopSio2.cpp b/pcsx2/IopSio2.cpp index 04e704e47a..c4270b7465 100644 --- a/pcsx2/IopSio2.cpp +++ b/pcsx2/IopSio2.cpp @@ -203,6 +203,7 @@ u8 sio2_fifoOut(){ void SaveState::sio2Freeze() { + FreezeTag( "sio2" ); Freeze(sio2); } diff --git a/pcsx2/MTGS.cpp b/pcsx2/MTGS.cpp index 485ba722d7..bc94623e9b 100644 --- a/pcsx2/MTGS.cpp +++ b/pcsx2/MTGS.cpp @@ -116,6 +116,8 @@ static void _mtgsFreezeGIF( SaveState& state, GIFPath (&paths)[3] ) void SaveState::mtgsFreeze() { + FreezeTag( "mtgs" ); + if( mtgsThread != NULL ) { mtgsThread->Freeze( *this ); diff --git a/pcsx2/Misc.cpp b/pcsx2/Misc.cpp index 676ace76b2..738550ad32 100644 --- a/pcsx2/Misc.cpp +++ b/pcsx2/Misc.cpp @@ -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; } diff --git a/pcsx2/Misc.h b/pcsx2/Misc.h index 0f9648b24d..d90a1cf020 100644 --- a/pcsx2/Misc.h +++ b/pcsx2/Misc.h @@ -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; diff --git a/pcsx2/R3000A.h b/pcsx2/R3000A.h index 2c6f1cadcd..41cb4862a5 100644 --- a/pcsx2/R3000A.h +++ b/pcsx2/R3000A.h @@ -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); diff --git a/pcsx2/R5900.cpp b/pcsx2/R5900.cpp index 78ad012144..b7e179f542 100644 --- a/pcsx2/R5900.cpp +++ b/pcsx2/R5900.cpp @@ -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 ); diff --git a/pcsx2/SPR.cpp b/pcsx2/SPR.cpp index d346f33c0e..c9b59e1a25 100644 --- a/pcsx2/SPR.cpp +++ b/pcsx2/SPR.cpp @@ -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); } \ No newline at end of file diff --git a/pcsx2/SaveState.cpp b/pcsx2/SaveState.cpp index 762a1ca4bf..106fc0adc5 100644 --- a/pcsx2/SaveState.cpp +++ b/pcsx2/SaveState.cpp @@ -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 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 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); } ////////////////////////////////////////////////////////////////////////////////// diff --git a/pcsx2/SaveState.h b/pcsx2/SaveState.h index d7fe5fb242..380f7185e3 100644 --- a/pcsx2/SaveState.h +++ b/pcsx2/SaveState.h @@ -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 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(); diff --git a/pcsx2/Sif.cpp b/pcsx2/Sif.cpp index 06b11b45b3..0456780b60 100644 --- a/pcsx2/Sif.cpp +++ b/pcsx2/Sif.cpp @@ -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); } diff --git a/pcsx2/Sio.cpp b/pcsx2/Sio.cpp index 894ad7e180..8e17a70ccc 100644 --- a/pcsx2/Sio.cpp +++ b/pcsx2/Sio.cpp @@ -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 ) { diff --git a/pcsx2/VUmicroMem.cpp b/pcsx2/VUmicroMem.cpp index 1c31f324aa..bdcef00d31 100644 --- a/pcsx2/VUmicroMem.cpp +++ b/pcsx2/VUmicroMem.cpp @@ -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); } diff --git a/pcsx2/VifDma.cpp b/pcsx2/VifDma.cpp index 0f24085f9a..c2a2d13ca5 100644 --- a/pcsx2/VifDma.cpp +++ b/pcsx2/VifDma.cpp @@ -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 ); }