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

Contents of /trunk/pcsx2/System.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 62 - (show annotations) (download)
Tue Sep 7 11:08:22 2010 UTC (9 years, 11 months ago) by william
File size: 15314 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 #include "PrecompiledHeader.h"
17 #include "Common.h"
18 #include "IopCommon.h"
19
20 #include "System/PageFaultSource.h"
21 #include "Utilities/EventSource.inl"
22
23 // Includes needed for cleanup, since we don't have a good system (yet) for
24 // cleaning up these things.
25 #include "sVU_zerorec.h"
26 #include "GameDatabase.h"
27 #include "Elfheader.h"
28
29 extern void closeNewVif(int idx);
30 extern void resetNewVif(int idx);
31
32 template class EventSource< IEventListener_PageFault >;
33
34 SrcType_PageFault Source_PageFault;
35
36 EventListener_PageFault::EventListener_PageFault()
37 {
38 Source_PageFault.Add( *this );
39 }
40
41 EventListener_PageFault::~EventListener_PageFault() throw()
42 {
43 Source_PageFault.Remove( *this );
44 }
45
46 void SrcType_PageFault::Dispatch( const PageFaultInfo& params )
47 {
48 m_handled = false;
49 _parent::Dispatch( params );
50 }
51
52 void SrcType_PageFault::_DispatchRaw( ListenerIterator iter, const ListenerIterator& iend, const PageFaultInfo& evt )
53 {
54 do {
55 (*iter)->DispatchEvent( evt, m_handled );
56 } while( (++iter != iend) && !m_handled );
57 }
58
59
60 #if _MSC_VER
61 # include "svnrev.h"
62 #endif
63
64 const Pcsx2Config EmuConfig;
65
66 // Provides an accessor for quick modification of GS options. All GS options are allowed to be
67 // changed "on the fly" by the *main/gui thread only*.
68 Pcsx2Config::GSOptions& SetGSConfig()
69 {
70 //DbgCon.WriteLn( "Direct modification of EmuConfig.GS detected" );
71 AffinityAssert_AllowFrom_MainUI();
72 return const_cast<Pcsx2Config::GSOptions&>(EmuConfig.GS);
73 }
74
75 // Provides an accessor for quick modification of Recompiler options.
76 // Used by loadGameSettings() to set clamp modes via database at game startup.
77 Pcsx2Config::RecompilerOptions& SetRecompilerConfig()
78 {
79 //DbgCon.WriteLn( "Direct modification of EmuConfig.Gamefixes detected" );
80 AffinityAssert_AllowFrom_MainUI();
81 return const_cast<Pcsx2Config::RecompilerOptions&>(EmuConfig.Cpu.Recompiler);
82 }
83
84 // Provides an accessor for quick modification of Gamefix options.
85 // Used by loadGameSettings() to set gamefixes via database at game startup.
86 Pcsx2Config::GamefixOptions& SetGameFixConfig()
87 {
88 //DbgCon.WriteLn( "Direct modification of EmuConfig.Gamefixes detected" );
89 AffinityAssert_AllowFrom_MainUI();
90 return const_cast<Pcsx2Config::GamefixOptions&>(EmuConfig.Gamefixes);
91 }
92
93 TraceLogFilters& SetTraceConfig()
94 {
95 //DbgCon.WriteLn( "Direct modification of EmuConfig.TraceLog detected" );
96 AffinityAssert_AllowFrom_MainUI();
97 return const_cast<TraceLogFilters&>(EmuConfig.Trace);
98 }
99
100
101 // This function should be called once during program execution.
102 void SysLogMachineCaps()
103 {
104 Console.WriteLn( Color_StrongGreen, "PCSX2 %u.%u.%u.r%d %s - compiled on " __DATE__, PCSX2_VersionHi, PCSX2_VersionMid, PCSX2_VersionLo,
105 SVN_REV, SVN_MODS ? "(modded)" : ""
106 );
107
108 Console.WriteLn( "Savestate version: 0x%x", g_SaveVersion);
109 Console.Newline();
110
111 Console.WriteLn( Color_StrongBlack, "x86-32 Init:" );
112
113 u32 speed = x86caps.CalculateMHz();
114
115 Console.Indent().WriteLn(
116 L"CPU vendor name = %s\n"
117 L"FamilyID = %x\n"
118 L"x86Family = %s\n"
119 L"CPU speed = %d.%03d ghz\n"
120 L"Cores = %d physical [%d logical]\n"
121 L"x86PType = %s\n"
122 L"x86Flags = %8.8x %8.8x\n"
123 L"x86EFlags = %8.8x",
124 fromUTF8( x86caps.VendorName ).c_str(), x86caps.StepID,
125 fromUTF8( x86caps.FamilyName ).Trim().Trim(false).c_str(),
126 speed / 1000, speed % 1000,
127 x86caps.PhysicalCores, x86caps.LogicalCores,
128 x86caps.GetTypeName().c_str(),
129 x86caps.Flags, x86caps.Flags2,
130 x86caps.EFlags
131 );
132
133 Console.Newline();
134
135 wxArrayString features[2]; // 2 lines, for readability!
136
137 if( x86caps.hasMultimediaExtensions ) features[0].Add( L"MMX" );
138 if( x86caps.hasStreamingSIMDExtensions ) features[0].Add( L"SSE" );
139 if( x86caps.hasStreamingSIMD2Extensions ) features[0].Add( L"SSE2" );
140 if( x86caps.hasStreamingSIMD3Extensions ) features[0].Add( L"SSE3" );
141 if( x86caps.hasSupplementalStreamingSIMD3Extensions ) features[0].Add( L"SSSE3" );
142 if( x86caps.hasStreamingSIMD4Extensions ) features[0].Add( L"SSE4.1" );
143 if( x86caps.hasStreamingSIMD4Extensions2 ) features[0].Add( L"SSE4.2" );
144
145 if( x86caps.hasMultimediaExtensionsExt ) features[1].Add( L"MMX2 " );
146 if( x86caps.has3DNOWInstructionExtensions ) features[1].Add( L"3DNOW " );
147 if( x86caps.has3DNOWInstructionExtensionsExt ) features[1].Add( L"3DNOW2" );
148 if( x86caps.hasStreamingSIMD4ExtensionsA ) features[1].Add( L"SSE4a " );
149
150 const wxString result[2] =
151 {
152 JoinString( features[0], L".. " ),
153 JoinString( features[1], L".. " )
154 };
155
156 Console.WriteLn( Color_StrongBlack, L"x86 Features Detected:" );
157 Console.Indent().WriteLn( result[0] + (result[1].IsEmpty() ? L"" : (L"\n" + result[1])) );
158 Console.Newline();
159 }
160
161 template< typename CpuType >
162 class CpuInitializer
163 {
164 public:
165 ScopedPtr<CpuType> MyCpu;
166 ScopedPtr<BaseException> ExThrown;
167
168 CpuInitializer();
169 virtual ~CpuInitializer() throw();
170
171 bool IsAvailable() const
172 {
173 return !!MyCpu;
174 }
175
176 CpuType* GetPtr() { return MyCpu.GetPtr(); }
177 const CpuType* GetPtr() const { return MyCpu.GetPtr(); }
178
179 operator CpuType*() { return GetPtr(); }
180 operator const CpuType*() const { return GetPtr(); }
181 };
182
183 // --------------------------------------------------------------------------------------
184 // CpuInitializer Template
185 // --------------------------------------------------------------------------------------
186 // Helper for initializing various PCSX2 CPU providers, and handing errors and cleanup.
187 //
188 template< typename CpuType >
189 CpuInitializer< CpuType >::CpuInitializer()
190 {
191 try {
192 MyCpu = new CpuType();
193 MyCpu->Allocate();
194 }
195 catch( Exception::RuntimeError& ex )
196 {
197 Console.Error( L"CPU provider error:\n\t" + ex.FormatDiagnosticMessage() );
198 MyCpu = NULL;
199 ExThrown = ex.Clone();
200 }
201 catch( std::runtime_error& ex )
202 {
203 Console.Error( L"CPU provider error (STL Exception)\n\tDetails:" + fromUTF8( ex.what() ) );
204 MyCpu = NULL;
205 ExThrown = new Exception::RuntimeError(ex);
206 }
207 }
208
209 template< typename CpuType >
210 CpuInitializer< CpuType >::~CpuInitializer() throw()
211 {
212 if( MyCpu )
213 MyCpu->Shutdown();
214 }
215
216 class CpuInitializerSet
217 {
218 public:
219 // Note: Allocate sVU first -- it's the most picky.
220
221 CpuInitializer<recSuperVU0> superVU0;
222 CpuInitializer<recSuperVU1> superVU1;
223
224 CpuInitializer<recMicroVU0> microVU0;
225 CpuInitializer<recMicroVU1> microVU1;
226
227 CpuInitializer<InterpVU0> interpVU0;
228 CpuInitializer<InterpVU1> interpVU1;
229
230 public:
231 CpuInitializerSet() {}
232 virtual ~CpuInitializerSet() throw() {}
233 };
234
235
236
237 // returns the translated error message for the Virtual Machine failing to allocate!
238 static wxString GetMemoryErrorVM()
239 {
240 return pxE( ".Error:EmuCore::MemoryForVM",
241 L"PCSX2 is unable to allocate memory needed for the PS2 virtual machine. "
242 L"Close out some memory hogging background tasks and try again."
243 );
244 }
245
246 // --------------------------------------------------------------------------------------
247 // SysAllocVM (implementations)
248 // --------------------------------------------------------------------------------------
249 SysAllocVM::SysAllocVM()
250 {
251 InstallSignalHandler();
252
253 Console.WriteLn( "Allocating memory for the PS2 virtual machine..." );
254
255 try
256 {
257 vtlb_Core_Alloc();
258 memAlloc();
259 psxMemAlloc();
260 vuMicroMemAlloc();
261 }
262 // ----------------------------------------------------------------------------
263 catch( Exception::OutOfMemory& ex )
264 {
265 ex.UserMsg() += L"\n\n" + GetMemoryErrorVM();
266 CleanupMess();
267 throw;
268 }
269 catch( std::bad_alloc& ex )
270 {
271 CleanupMess();
272
273 // re-throw std::bad_alloc as something more friendly. This is needed since
274 // much of the code uses new/delete internally, which throw std::bad_alloc on fail.
275
276 throw Exception::OutOfMemory()
277 .SetDiagMsg(
278 L"std::bad_alloc caught while trying to allocate memory for the PS2 Virtual Machine.\n"
279 L"Error Details: " + fromUTF8( ex.what() )
280 )
281 .SetUserMsg(GetMemoryErrorVM()); // translated
282 }
283 }
284
285 void SysAllocVM::CleanupMess() throw()
286 {
287 try
288 {
289 vuMicroMemShutdown();
290 psxMemShutdown();
291 memShutdown();
292 vtlb_Core_Shutdown();
293 }
294 DESTRUCTOR_CATCHALL
295 }
296
297 SysAllocVM::~SysAllocVM() throw()
298 {
299 CleanupMess();
300 }
301
302 // --------------------------------------------------------------------------------------
303 // SysCpuProviderPack (implementations)
304 // --------------------------------------------------------------------------------------
305 SysCpuProviderPack::SysCpuProviderPack()
306 {
307 Console.WriteLn( "Allocating memory for recompilers..." );
308
309 CpuProviders = new CpuInitializerSet();
310
311 try {
312 recCpu.Allocate();
313 }
314 catch( Exception::RuntimeError& ex )
315 {
316 m_RecExceptionEE = ex.Clone();
317 Console.Error( L"EE Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() );
318 recCpu.Shutdown();
319 }
320
321 try {
322 psxRec.Allocate();
323 }
324 catch( Exception::RuntimeError& ex )
325 {
326 m_RecExceptionIOP = ex.Clone();
327 Console.Error( L"IOP Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() );
328 psxRec.Shutdown();
329 }
330
331 // hmm! : VU0 and VU1 pre-allocations should do sVU and mVU separately? Sounds complicated. :(
332
333 // If both VUrecs failed, then make sure the SuperVU is totally closed out, because it
334 // actually initializes everything once and then shares it between both VU recs.
335 if( !IsRecAvailable_SuperVU0() && !IsRecAvailable_SuperVU1() )
336 SuperVUDestroy( -1 );
337 }
338
339 bool SysCpuProviderPack::IsRecAvailable_MicroVU0() const { return CpuProviders->microVU0.IsAvailable(); }
340 bool SysCpuProviderPack::IsRecAvailable_MicroVU1() const { return CpuProviders->microVU1.IsAvailable(); }
341 BaseException* SysCpuProviderPack::GetException_MicroVU0() const { return CpuProviders->microVU0.ExThrown; }
342 BaseException* SysCpuProviderPack::GetException_MicroVU1() const { return CpuProviders->microVU1.ExThrown; }
343
344 bool SysCpuProviderPack::IsRecAvailable_SuperVU0() const { return CpuProviders->superVU0.IsAvailable(); }
345 bool SysCpuProviderPack::IsRecAvailable_SuperVU1() const { return CpuProviders->superVU1.IsAvailable(); }
346 BaseException* SysCpuProviderPack::GetException_SuperVU0() const { return CpuProviders->superVU0.ExThrown; }
347 BaseException* SysCpuProviderPack::GetException_SuperVU1() const { return CpuProviders->superVU1.ExThrown; }
348
349
350 void SysCpuProviderPack::CleanupMess() throw()
351 {
352 try
353 {
354 closeNewVif(0);
355 closeNewVif(1);
356
357 // Special SuperVU "complete" terminator (stupid hacky recompiler)
358 SuperVUDestroy( -1 );
359
360 psxRec.Shutdown();
361 recCpu.Shutdown();
362 }
363 DESTRUCTOR_CATCHALL
364 }
365
366 SysCpuProviderPack::~SysCpuProviderPack() throw()
367 {
368 CleanupMess();
369 }
370
371 bool SysCpuProviderPack::HadSomeFailures( const Pcsx2Config::RecompilerOptions& recOpts ) const
372 {
373 return (recOpts.EnableEE && !IsRecAvailable_EE()) ||
374 (recOpts.EnableIOP && !IsRecAvailable_IOP()) ||
375 (recOpts.EnableVU0 && recOpts.UseMicroVU0 && !IsRecAvailable_MicroVU0()) ||
376 (recOpts.EnableVU1 && recOpts.UseMicroVU0 && !IsRecAvailable_MicroVU1()) ||
377 (recOpts.EnableVU0 && !recOpts.UseMicroVU0 && !IsRecAvailable_SuperVU0()) ||
378 (recOpts.EnableVU1 && !recOpts.UseMicroVU1 && !IsRecAvailable_SuperVU1());
379
380 }
381
382 BaseVUmicroCPU* CpuVU0 = NULL;
383 BaseVUmicroCPU* CpuVU1 = NULL;
384
385 void SysCpuProviderPack::ApplyConfig() const
386 {
387 Cpu = CHECK_EEREC ? &recCpu : &intCpu;
388 psxCpu = CHECK_IOPREC ? &psxRec : &psxInt;
389
390 CpuVU0 = CpuProviders->interpVU0;
391 CpuVU1 = CpuProviders->interpVU1;
392
393 if( EmuConfig.Cpu.Recompiler.EnableVU0 )
394 CpuVU0 = EmuConfig.Cpu.Recompiler.UseMicroVU0 ? (BaseVUmicroCPU*)CpuProviders->microVU0 : (BaseVUmicroCPU*)CpuProviders->superVU0;
395
396 if( EmuConfig.Cpu.Recompiler.EnableVU1 )
397 CpuVU1 = EmuConfig.Cpu.Recompiler.UseMicroVU1 ? (BaseVUmicroCPU*)CpuProviders->microVU1 : (BaseVUmicroCPU*)CpuProviders->superVU1;
398 }
399
400 // This is a semi-hacky function for convenience
401 BaseVUmicroCPU* SysCpuProviderPack::getVUprovider(int whichProvider, int vuIndex) const {
402 switch (whichProvider) {
403 case 0: return vuIndex ? (BaseVUmicroCPU*)CpuProviders->interpVU1 : (BaseVUmicroCPU*)CpuProviders->interpVU0;
404 case 1: return vuIndex ? (BaseVUmicroCPU*)CpuProviders->superVU1 : (BaseVUmicroCPU*)CpuProviders->superVU0;
405 case 2: return vuIndex ? (BaseVUmicroCPU*)CpuProviders->microVU1 : (BaseVUmicroCPU*)CpuProviders->microVU0;
406 }
407 return NULL;
408 }
409
410 // Resets all PS2 cpu execution caches, which does not affect that actual PS2 state/condition.
411 // This can be called at any time outside the context of a Cpu->Execute() block without
412 // bad things happening (recompilers will slow down for a brief moment since rec code blocks
413 // are dumped).
414 // Use this method to reset the recs when important global pointers like the MTGS are re-assigned.
415 void SysClearExecutionCache()
416 {
417 GetCpuProviders().ApplyConfig();
418
419 // SuperVUreset will do nothing is none of the recs are initialized.
420 // But it's needed if one or the other is initialized.
421 SuperVUReset(-1);
422
423 Cpu->Reset();
424 psxCpu->Reset();
425 // mVU's VU0 needs to be properly initialised for macro mode even if it's not used for micro mode!
426 if (CHECK_EEREC)
427 ((BaseVUmicroCPU*)GetCpuProviders().CpuProviders->microVU0)->Reset();
428 CpuVU0->Reset();
429 CpuVU1->Reset();
430
431 resetNewVif(0);
432 resetNewVif(1);
433 }
434
435 // Maps a block of memory for use as a recompiled code buffer, and ensures that the
436 // allocation is below a certain memory address (specified in "bounds" parameter).
437 // The allocated block has code execution privileges.
438 // Returns NULL on allocation failure.
439 u8* SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller)
440 {
441 u8* Mem = (u8*)HostSys::Mmap( base, size );
442
443 if( (Mem == NULL) || (bounds != 0 && (((uptr)Mem + size) > bounds)) )
444 {
445 if( base != NULL )
446 {
447 DbgCon.Warning( "First try failed allocating %s at address 0x%x", caller, base );
448
449 // memory allocation *must* have the top bit clear, so let's try again
450 // with NULL (let the OS pick something for us).
451
452 SafeSysMunmap( Mem, size );
453
454 Mem = (u8*)HostSys::Mmap( NULL, size );
455 }
456
457 if( bounds != 0 && (((uptr)Mem + size) > bounds) )
458 {
459 DevCon.Warning( "Second try failed allocating %s, block ptr 0x%x does not meet required criteria.", caller, Mem );
460 SafeSysMunmap( Mem, size );
461
462 // returns NULL, caller should throw an exception.
463 }
464 }
465 return Mem;
466 }
467
468 // This function always returns a valid DiscID -- using the Sony serial when possible, and
469 // falling back on the CRC checksum of the ELF binary if the PS2 software being run is
470 // homebrew or some other serial-less item.
471 wxString SysGetDiscID()
472 {
473 if( !DiscSerial.IsEmpty() ) return DiscSerial;
474
475 if( !ElfCRC )
476 {
477 // FIXME: If the system is currently running the BIOS, it should return a serial based on
478 // the BIOS being run (either a checksum of the BIOS roms, and/or a string based on BIOS
479 // region and revision).
480 }
481
482 return wxsFormat( L"%8.8x", ElfCRC );
483 }

  ViewVC Help
Powered by ViewVC 1.1.22