/[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 31 - (show 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 /* 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