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

Contents of /trunk/pcsx2/SaveState.cpp

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.22