/[pcsx2_0.9.7]/trunk/pcsx2/SaveState.cpp
ViewVC logotype

Annotation of /trunk/pcsx2/SaveState.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (hide annotations) (download)
Tue Sep 7 03:24:11 2010 UTC (9 years, 5 months ago) by william
File size: 12069 byte(s)
committing r3113 initial commit again...
1 william 31 /* PCSX2 - PS2 Emulator for PCs
2     * Copyright (C) 2002-2010 PCSX2 Dev Team
3     *
4     * PCSX2 is free software: you can redistribute it and/or modify it under the terms
5     * of the GNU Lesser General Public License as published by the Free Software Found-
6     * ation, either version 3 of the License, or (at your option) any later version.
7     *
8     * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9     * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10     * PURPOSE. See the GNU General Public License for more details.
11     *
12     * You should have received a copy of the GNU General Public License along with PCSX2.
13     * If not, see <http://www.gnu.org/licenses/>.
14     */
15    
16    
17     #include "PrecompiledHeader.h"
18     #include "IopCommon.h"
19     #include "SaveState.h"
20    
21     #include "ps2/BiosTools.h"
22     #include "COP0.h"
23     #include "Cache.h"
24     #include "AppConfig.h"
25    
26     #include "Elfheader.h"
27    
28     using namespace R5900;
29    
30    
31     static void PreLoadPrep()
32     {
33     SysClearExecutionCache();
34     }
35    
36     static void PostLoadPrep()
37     {
38     memzero(pCache);
39     // WriteCP0Status(cpuRegs.CP0.n.Status.val);
40     for(int i=0; i<48; i++) MapTLB(i);
41     }
42    
43     wxString SaveStateBase::GetFilename( int slot )
44     {
45     return (g_Conf->Folders.Savestates +
46     wxsFormat( L"%8.8X.%3.3d", ElfCRC, slot )).GetFullPath();
47     }
48    
49     SaveStateBase::SaveStateBase( SafeArray<u8>& memblock )
50     {
51     Init( &memblock );
52     }
53    
54     SaveStateBase::SaveStateBase( SafeArray<u8>* memblock )
55     {
56     Init( memblock );
57     }
58    
59     void SaveStateBase::Init( SafeArray<u8>* memblock )
60     {
61     m_memory = memblock;
62     m_version = g_SaveVersion;
63     m_idx = 0;
64     m_sectid = FreezeId_Unknown;
65     m_pid = PluginId_GS;
66     m_DidBios = false;
67     }
68    
69     void SaveStateBase::PrepBlock( int size )
70     {
71     pxAssumeDev( m_memory, "Savestate memory/buffer pointer is null!" );
72    
73     const int end = m_idx+size;
74     if( IsSaving() )
75     m_memory->MakeRoomFor( end );
76     else
77     {
78     if( m_memory->GetSizeInBytes() < end )
79     throw Exception::SaveStateLoadError();
80     }
81     }
82    
83     void SaveStateBase::FreezeTag( const char* src )
84     {
85     const uint allowedlen = sizeof( m_tagspace )-1;
86     pxAssertDev( strlen(src) < allowedlen, wxsFormat( L"Tag name exceeds the allowed length of %d chars.", allowedlen) );
87    
88     memzero( m_tagspace );
89     strcpy( m_tagspace, src );
90     Freeze( m_tagspace );
91    
92     if( strcmp( m_tagspace, src ) != 0 )
93     {
94     pxFail( "Savestate data corruption detected while reading tag" );
95     throw Exception::SaveStateLoadError(
96     // Untranslated diagnostic msg (use default msg for translation)
97     L"Savestate data corruption detected while reading tag: " + fromUTF8(src)
98     );
99     }
100     }
101    
102     void SaveStateBase::FreezeBios()
103     {
104     // Check the BIOS, and issue a warning if the bios for this state
105     // doesn't match the bios currently being used (chances are it'll still
106     // work fine, but some games are very picky).
107    
108     char descin[128], desccmp[128];
109     wxString descout;
110     IsBIOS( g_Conf->FullpathToBios(), descout );
111     memzero( descin );
112     memzero( desccmp );
113    
114     memcpy_fast( descin, descout.ToUTF8().data(), descout.Length() );
115     memcpy_fast( desccmp, descout.ToUTF8().data(), descout.Length() );
116    
117     // ... and only freeze bios info once per state, since the user msg could
118     // become really annoying on a corrupted state or something. (have to always
119     // load though, so that we advance past the duplicated info, if present)
120    
121     if( IsLoading() || !m_DidBios )
122     Freeze( descin );
123    
124     if( !m_DidBios )
125     {
126     if( memcmp( descin, desccmp, 128 ) != 0 )
127     {
128     Console.Newline();
129     Console.Indent(1).Error( "Warning: BIOS Version Mismatch, savestate may be unstable!" );
130     Console.Indent(2).Error(
131     "Current Version: %s\n"
132     "Savestate Version: %s\n",
133     descout.ToUTF8().data(), descin
134     );
135     }
136     }
137     m_DidBios = true;
138     }
139    
140     static const int MainMemorySizeInBytes =
141     Ps2MemSize::Base + Ps2MemSize::Scratch + Ps2MemSize::Hardware +
142     Ps2MemSize::IopRam + Ps2MemSize::IopHardware + 0x0100;
143    
144     void SaveStateBase::FreezeMainMemory()
145     {
146     if( IsLoading() )
147     PreLoadPrep();
148    
149     // First Block - Memory Dumps
150     // ---------------------------
151     FreezeMem(PS2MEM_BASE, Ps2MemSize::Base); // 32 MB main memory
152     FreezeMem(PS2MEM_SCRATCH, Ps2MemSize::Scratch); // scratch pad
153     FreezeMem(PS2MEM_HW, Ps2MemSize::Hardware); // hardware memory
154    
155     FreezeMem(psxM, Ps2MemSize::IopRam); // 2 MB main memory
156     FreezeMem(psxH, Ps2MemSize::IopHardware); // hardware memory
157     FreezeMem(psxS, 0x000100); // iop's sif memory
158     }
159    
160     void SaveStateBase::FreezeRegisters()
161     {
162     if( IsLoading() )
163     PreLoadPrep();
164    
165     // Second Block - Various CPU Registers and States
166     // -----------------------------------------------
167     FreezeTag( "cpuRegs" );
168     Freeze(cpuRegs); // cpu regs + COP0
169     Freeze(psxRegs); // iop regs
170     Freeze(fpuRegs);
171     Freeze(tlb); // tlbs
172    
173     // Third Block - Cycle Timers and Events
174     // -------------------------------------
175     FreezeTag( "Cycles" );
176     Freeze(EEsCycle);
177     Freeze(EEoCycle);
178     Freeze(g_nextBranchCycle);
179     Freeze(g_psxNextBranchCycle);
180     Freeze(s_iLastCOP0Cycle);
181     Freeze(s_iLastPERFCycle);
182    
183     // Fourth Block - EE-related systems
184     // ---------------------------------
185     FreezeTag( "EE-Subsystems" );
186     rcntFreeze();
187     gsFreeze();
188     vuMicroFreeze();
189     vif0Freeze();
190     vif1Freeze();
191     sifFreeze();
192     ipuFreeze();
193     gifFreeze();
194     sprFreeze();
195    
196     // Fifth Block - iop-related systems
197     // ---------------------------------
198     FreezeTag( "IOP-Subsystems" );
199     #ifdef ENABLE_NEW_IOPDMA
200     iopDmacFreeze();
201     #endif
202     psxRcntFreeze();
203     sioFreeze();
204     sio2Freeze();
205     cdrFreeze();
206     cdvdFreeze();
207    
208     // technically this is HLE BIOS territory, but we don't have enough such stuff
209     // to merit an HLE Bios sub-section... yet.
210     deci2Freeze();
211    
212     if( IsLoading() )
213     PostLoadPrep();
214     }
215    
216     void SaveStateBase::WritebackSectionLength( int seekpos, int sectlen, const wxChar* sectname )
217     {
218     int realsectsize = m_idx - seekpos;
219     if( IsSaving() )
220     {
221     // write back the section length...
222     *((u32*)m_memory->GetPtr(seekpos-4)) = realsectsize;
223     }
224     else // IsLoading!!
225     {
226     if( sectlen != realsectsize ) // if they don't match then we have a problem, jim.
227     {
228     throw Exception::SaveStateLoadError( wxEmptyString,
229     wxsFormat( L"Invalid size encountered on section '%s'.", sectname ),
230     _("The savestate data is invalid or corrupted.")
231     );
232     }
233     }
234     }
235    
236     bool SaveStateBase::FreezeSection( int seek_section )
237     {
238     const bool isSeeking = (seek_section != FreezeId_NotSeeking );
239     if( IsSaving() ) pxAssertDev( !isSeeking, "Cannot seek on a saving-mode savestate stream." );
240    
241     Freeze( m_sectid );
242     if( seek_section == m_sectid ) return false;
243    
244     switch( m_sectid )
245     {
246     case FreezeId_End:
247     return false;
248    
249     case FreezeId_Bios:
250     {
251     int sectlen = 128;
252     FreezeTag( "BiosVersion" );
253     Freeze( sectlen );
254    
255     if( sectlen != 128 )
256     {
257     throw Exception::SaveStateLoadError( wxEmptyString,
258     L"Invalid size encountered on BiosVersion section.",
259     _("The savestate data is invalid or corrupted.")
260     );
261     }
262    
263     if( isSeeking )
264     m_idx += sectlen;
265     else
266     FreezeBios();
267     m_sectid++;
268     }
269     break;
270    
271     case FreezeId_Memory:
272     {
273     FreezeTag( "MainMemory" );
274    
275     int seekpos = m_idx+4;
276     int sectlen = MainMemorySizeInBytes;
277     Freeze( sectlen );
278     if( sectlen != MainMemorySizeInBytes )
279     {
280     throw Exception::SaveStateLoadError( wxEmptyString,
281     L"Invalid size encountered on MainMemory section.",
282     _("The savestate data is invalid or corrupted.")
283     );
284     }
285    
286     if( isSeeking )
287     m_idx += sectlen;
288     else
289     FreezeMainMemory();
290    
291     int realsectsize = m_idx - seekpos;
292     pxAssert( sectlen == realsectsize );
293     m_sectid++;
294     }
295     break;
296    
297     case FreezeId_Registers:
298     {
299     FreezeTag( "HardwareRegisters" );
300     int seekpos = m_idx+4;
301     int sectlen = 0xdead; // gets written back over with "real" data in IsSaving() mode
302    
303     Freeze( sectlen );
304     FreezeRegisters();
305    
306     WritebackSectionLength( seekpos, sectlen, L"HardwareRegisters" );
307     m_sectid++;
308     }
309     break;
310    
311     case FreezeId_Plugin:
312     {
313     FreezeTag( "Plugin" );
314     int seekpos = m_idx+4;
315     int sectlen = 0xdead; // gets written back over with "real" data in IsSaving() mode
316    
317     Freeze( sectlen );
318     Freeze( m_pid );
319    
320     if( isSeeking )
321     m_idx += sectlen;
322     else
323     GetCorePlugins().Freeze( (PluginsEnum_t)m_pid, *this );
324    
325     WritebackSectionLength( seekpos, sectlen, L"Plugins" );
326    
327     // following increments only affect Saving mode, which needs to be sure to save all
328     // plugins (order doesn't matter but sequential is easy enough. (ignored by Loading mode)
329     m_pid++;
330     if( m_pid >= PluginId_Count )
331     m_sectid = FreezeId_End;
332     }
333     break;
334    
335     case FreezeId_Unknown:
336     default:
337     pxAssert( IsSaving() );
338    
339     // Skip unknown sections with a warning log.
340     // Maybe it'll work! (haha?)
341    
342     int size;
343     Freeze( m_tagspace );
344     Freeze( size );
345     m_tagspace[sizeof(m_tagspace)-1] = 0;
346    
347     Console.Warning(
348     "Warning: Unknown tag encountered while loading savestate; going to ignore it!\n"
349     "\tTagname: %s, Size: %d", m_tagspace, size
350     );
351     m_idx += size;
352     break;
353     }
354    
355     if( wxThread::IsMain() )
356     wxSafeYield( NULL, true );
357    
358     return true;
359     }
360    
361     void SaveStateBase::FreezeAll()
362     {
363     if( IsSaving() )
364     {
365     // Loading mode streams will assign these, but saving mode reads them so better
366     // do some setup first.
367    
368     m_sectid = (int)FreezeId_End+1;
369     m_pid = PluginId_GS;
370     }
371    
372     while( FreezeSection() );
373     }
374    
375     //////////////////////////////////////////////////////////////////////////////////
376     // uncompressed to/from memory state saves implementation
377    
378     memSavingState::memSavingState( SafeArray<u8>& save_to )
379     : SaveStateBase( save_to )
380     {
381     }
382    
383     memSavingState::memSavingState( SafeArray<u8>* save_to )
384     : SaveStateBase( save_to )
385     {
386     }
387    
388     // Saving of state data
389     void memSavingState::FreezeMem( void* data, int size )
390     {
391     m_memory->MakeRoomFor( m_idx+size );
392     memcpy_fast( m_memory->GetPtr(m_idx), data, size );
393     m_idx += size;
394     }
395    
396     void memSavingState::FreezeAll()
397     {
398     pxAssumeDev( m_memory, "Savestate memory/buffer pointer is null!" );
399    
400     // 90% of all savestates fit in under 45 megs (and require more than 43 megs, so might as well...)
401     m_memory->ChunkSize = ReallocThreshold;
402     m_memory->MakeRoomFor( MemoryBaseAllocSize );
403    
404     _parent::FreezeAll();
405     }
406    
407     memLoadingState::memLoadingState( const SafeArray<u8>& load_from )
408     : SaveStateBase( const_cast<SafeArray<u8>&>(load_from) )
409     {
410     }
411    
412     memLoadingState::memLoadingState( const SafeArray<u8>* load_from )
413     : SaveStateBase( const_cast<SafeArray<u8>*>(load_from) )
414     {
415     }
416    
417     memLoadingState::~memLoadingState() throw() { }
418    
419     // Loading of state data
420     void memLoadingState::FreezeMem( void* data, int size )
421     {
422     const u8* const src = m_memory->GetPtr(m_idx);
423     m_idx += size;
424     memcpy_fast( data, src, size );
425     }
426    
427     bool memLoadingState::SeekToSection( PluginsEnum_t pid )
428     {
429     m_idx = 0; // start from the beginning
430    
431     do
432     {
433     while( FreezeSection( FreezeId_Plugin ) );
434     if( m_sectid == FreezeId_End ) return false;
435    
436     FreezeTag( "Plugin" );
437     int sectlen = 0xdead;
438    
439     Freeze( sectlen );
440     Freeze( m_pid );
441    
442     } while( m_pid != pid );
443     return true;
444     }
445    
446     // --------------------------------------------------------------------------------------
447     // SaveState Exception Messages
448     // --------------------------------------------------------------------------------------
449    
450     wxString Exception::UnsupportedStateVersion::FormatDiagnosticMessage() const
451     {
452     // Note: no stacktrace needed for this one...
453     return wxsFormat( L"Unknown or unsupported savestate version: 0x%x", Version );
454     }
455    
456     wxString Exception::UnsupportedStateVersion::FormatDisplayMessage() const
457     {
458     // m_message_user contains a recoverable savestate error which is helpful to the user.
459     return wxsFormat(
460     m_message_user + L"\n\n" +
461     wxsFormat( _("Cannot load savestate. It is of an unknown or unsupported version."), Version )
462     );
463     }
464    
465     wxString Exception::StateCrcMismatch::FormatDiagnosticMessage() const
466     {
467     // Note: no stacktrace needed for this one...
468     return wxsFormat(
469     L"Game/CDVD does not match the savestate CRC.\n"
470     L"\tCdvd CRC: 0x%X\n\tGame CRC: 0x%X\n",
471     Crc_Savestate, Crc_Cdvd
472     );
473     }
474    
475     wxString Exception::StateCrcMismatch::FormatDisplayMessage() const
476     {
477     return wxsFormat(
478     m_message_user + L"\n\n" +
479     wxsFormat(
480     L"Savestate game/crc mismatch. Cdvd CRC: 0x%X Game CRC: 0x%X\n",
481     Crc_Savestate, Crc_Cdvd
482     )
483     );
484     }

  ViewVC Help
Powered by ViewVC 1.1.22