2009-09-08 12:08:10 +00:00
|
|
|
/* PCSX2 - PS2 Emulator for PCs
|
|
|
|
* Copyright (C) 2002-2009 PCSX2 Dev Team
|
2009-09-17 02:12:32 +00:00
|
|
|
*
|
2009-09-08 12:08:10 +00:00
|
|
|
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
|
|
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
|
|
|
* ation, either version 3 of the License, or (at your option) any later version.
|
2009-02-09 21:15:56 +00:00
|
|
|
*
|
2009-09-08 12:08:10 +00:00
|
|
|
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
|
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
|
|
* PURPOSE. See the GNU General Public License for more details.
|
2009-02-09 21:15:56 +00:00
|
|
|
*
|
2009-09-08 12:08:10 +00:00
|
|
|
* You should have received a copy of the GNU General Public License along with PCSX2.
|
|
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
2009-02-09 21:15:56 +00:00
|
|
|
*/
|
2009-09-17 02:12:32 +00:00
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
#include "PrecompiledHeader.h"
|
|
|
|
|
2009-03-04 11:33:45 +00:00
|
|
|
#include "HostGui.h"
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-08-31 03:47:05 +00:00
|
|
|
#include "Common.h"
|
2009-03-04 11:33:45 +00:00
|
|
|
#include "VUmicro.h"
|
2009-02-09 21:15:56 +00:00
|
|
|
#include "iR5900.h"
|
2009-03-01 20:44:48 +00:00
|
|
|
#include "R3000A.h"
|
2009-02-09 21:15:56 +00:00
|
|
|
#include "IopMem.h"
|
2009-06-11 09:02:10 +00:00
|
|
|
#include "sVU_zerorec.h" // for SuperVUReset
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-03-04 11:33:45 +00:00
|
|
|
#include "R5900Exceptions.h"
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-07-15 01:17:28 +00:00
|
|
|
#include "CDVD/CDVD.h"
|
|
|
|
|
2009-09-13 17:11:35 +00:00
|
|
|
#if _MSC_VER
|
|
|
|
# include "svnrev.h"
|
2009-09-04 01:56:33 +00:00
|
|
|
#endif
|
2009-07-15 01:17:28 +00:00
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
using namespace std;
|
|
|
|
|
2009-09-22 11:50:27 +00:00
|
|
|
const Pcsx2Config EmuConfig;
|
2009-08-04 08:21:10 +00:00
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
// disable all session overrides by default...
|
2009-08-31 03:47:05 +00:00
|
|
|
SessionOverrideFlags g_Session = {false};
|
2009-02-09 21:15:56 +00:00
|
|
|
|
|
|
|
// This function should be called once during program execution.
|
|
|
|
void SysDetect()
|
|
|
|
{
|
2009-07-18 03:11:51 +00:00
|
|
|
using namespace Console;
|
|
|
|
|
2009-09-08 05:37:40 +00:00
|
|
|
Notice("PCSX2 %d.%d.%d.r%d %s - compiled on " __DATE__, PCSX2_VersionHi, PCSX2_VersionMid, PCSX2_VersionLo,
|
2009-09-06 05:21:07 +00:00
|
|
|
SVN_REV, SVN_MODS ? "(modded)" : ""
|
|
|
|
);
|
2009-09-16 17:23:02 +00:00
|
|
|
|
2009-09-08 05:37:40 +00:00
|
|
|
Notice("Savestate version: %x", g_SaveVersion);
|
2009-02-09 21:15:56 +00:00
|
|
|
|
|
|
|
cpudetectInit();
|
|
|
|
|
2009-07-18 03:11:51 +00:00
|
|
|
SetColor( Color_Black );
|
2009-02-09 21:15:56 +00:00
|
|
|
|
|
|
|
WriteLn( "x86Init:" );
|
2009-07-18 03:11:51 +00:00
|
|
|
WriteLn( wxsFormat(
|
|
|
|
L"\tCPU vendor name = %s\n"
|
|
|
|
L"\tFamilyID = %x\n"
|
|
|
|
L"\tx86Family = %s\n"
|
2009-09-06 05:21:07 +00:00
|
|
|
L"\tCPU speed = %d.%03d ghz\n"
|
2009-07-18 03:11:51 +00:00
|
|
|
L"\tCores = %d physical [%d logical]\n"
|
|
|
|
L"\tx86PType = %s\n"
|
|
|
|
L"\tx86Flags = %8.8x %8.8x\n"
|
|
|
|
L"\tx86EFlags = %8.8x\n",
|
2009-07-29 14:00:00 +00:00
|
|
|
wxString::FromAscii( x86caps.VendorName ).c_str(), x86caps.StepID,
|
2009-08-31 19:47:25 +00:00
|
|
|
wxString::FromAscii( x86caps.FamilyName ).Trim().Trim(false).c_str(),
|
2009-07-29 14:00:00 +00:00
|
|
|
x86caps.Speed / 1000, x86caps.Speed%1000,
|
|
|
|
x86caps.PhysicalCores, x86caps.LogicalCores,
|
|
|
|
wxString::FromAscii( x86caps.TypeName ).c_str(),
|
|
|
|
x86caps.Flags, x86caps.Flags2,
|
|
|
|
x86caps.EFlags
|
2009-07-18 03:11:51 +00:00
|
|
|
) );
|
2009-09-17 02:12:32 +00:00
|
|
|
|
2009-09-16 17:23:02 +00:00
|
|
|
wxArrayString features[2]; // 2 lines, for readability!
|
2009-09-17 02:12:32 +00:00
|
|
|
|
2009-09-16 17:23:02 +00:00
|
|
|
if( x86caps.hasMultimediaExtensions ) features[0].Add( L"MMX" );
|
|
|
|
if( x86caps.hasStreamingSIMDExtensions ) features[0].Add( L"SSE" );
|
|
|
|
if( x86caps.hasStreamingSIMD2Extensions ) features[0].Add( L"SSE2" );
|
|
|
|
if( x86caps.hasStreamingSIMD3Extensions ) features[0].Add( L"SSE3" );
|
|
|
|
if( x86caps.hasSupplementalStreamingSIMD3Extensions ) features[0].Add( L"SSSE3" );
|
|
|
|
if( x86caps.hasStreamingSIMD4Extensions ) features[0].Add( L"SSE4.1" );
|
|
|
|
if( x86caps.hasStreamingSIMD4Extensions2 ) features[0].Add( L"SSE4.2" );
|
|
|
|
|
|
|
|
if( x86caps.hasMultimediaExtensionsExt ) features[1].Add( L"MMX2 " );
|
|
|
|
if( x86caps.has3DNOWInstructionExtensions ) features[1].Add( L"3DNOW " );
|
|
|
|
if( x86caps.has3DNOWInstructionExtensionsExt ) features[1].Add( L"3DNOW2" );
|
|
|
|
if( x86caps.hasStreamingSIMD4ExtensionsA ) features[1].Add( L"SSE4a " );
|
|
|
|
|
|
|
|
wxString result[2];
|
|
|
|
JoinString( result[0], features[0], L".. " );
|
|
|
|
JoinString( result[1], features[1], L".. " );
|
|
|
|
|
2009-09-17 02:12:32 +00:00
|
|
|
WriteLn( L"Features Detected:\n\t" + result[0] + (result[1].IsEmpty() ? L"" : (L"\n\t" + result[1])) + L"\n" );
|
2009-09-16 17:23:02 +00:00
|
|
|
|
|
|
|
//if ( x86caps.VendorName[0] == 'A' ) //AMD cpu
|
2009-02-09 21:15:56 +00:00
|
|
|
|
|
|
|
Console::ClearColor();
|
|
|
|
}
|
|
|
|
|
2009-09-16 17:23:02 +00:00
|
|
|
// returns the translated error message for the Virtual Machine failing to allocate!
|
|
|
|
static wxString GetMemoryErrorVM()
|
|
|
|
{
|
|
|
|
return pxE( ".Popup Error:EmuCore::MemoryForVM",
|
|
|
|
L"PCSX2 is unable to allocate memory needed for the PS2 virtual machine. "
|
|
|
|
L"Close out some memory hogging background tasks and try again."
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2009-09-20 20:54:45 +00:00
|
|
|
SysCoreAllocations::SysCoreAllocations()
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2009-09-16 17:23:02 +00:00
|
|
|
Console::Status( "Initializing PS2 virtual machine..." );
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-09-16 17:23:02 +00:00
|
|
|
RecSuccess_EE = false;
|
|
|
|
RecSuccess_IOP = false;
|
|
|
|
RecSuccess_VU0 = false;
|
|
|
|
RecSuccess_VU1 = false;
|
2009-09-17 02:12:32 +00:00
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
try
|
|
|
|
{
|
2009-04-29 04:24:46 +00:00
|
|
|
vtlb_Core_Alloc();
|
2009-02-09 21:15:56 +00:00
|
|
|
memAlloc();
|
|
|
|
psxMemAlloc();
|
|
|
|
vuMicroMemAlloc();
|
|
|
|
}
|
2009-09-16 17:23:02 +00:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
catch( Exception::OutOfMemory& ex )
|
|
|
|
{
|
|
|
|
wxString newmsg( ex.UserMsg() + L"\n\n" + GetMemoryErrorVM() );
|
|
|
|
ex.UserMsg() = newmsg;
|
|
|
|
CleanupMess();
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
catch( std::bad_alloc& ex )
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2009-09-16 17:23:02 +00:00
|
|
|
CleanupMess();
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-09-16 17:23:02 +00:00
|
|
|
// re-throw std::bad_alloc as something more friendly.
|
2009-08-31 19:47:25 +00:00
|
|
|
|
2009-09-16 17:23:02 +00:00
|
|
|
throw Exception::OutOfMemory(
|
|
|
|
wxsFormat( // Diagnostic (english)
|
|
|
|
L"std::bad_alloc caught while trying to allocate memory for the PS2 Virtual Machine.\n"
|
|
|
|
L"Error Details: " + wxString::FromUTF8( ex.what() )
|
|
|
|
),
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-09-16 17:23:02 +00:00
|
|
|
GetMemoryErrorVM() // translated
|
|
|
|
);
|
|
|
|
}
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-09-16 17:23:02 +00:00
|
|
|
Console::Status( "Allocating memory for recompilers..." );
|
2009-02-09 21:15:56 +00:00
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
recCpu.Allocate();
|
2009-09-16 17:23:02 +00:00
|
|
|
RecSuccess_EE = true;
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
2009-09-16 17:23:02 +00:00
|
|
|
catch( Exception::BaseException& ex )
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2009-09-16 17:23:02 +00:00
|
|
|
Console::Error( L"EE Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() );
|
2009-02-09 21:15:56 +00:00
|
|
|
recCpu.Shutdown();
|
2009-09-16 17:23:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
psxRec.Allocate();
|
|
|
|
RecSuccess_IOP = true;
|
|
|
|
}
|
|
|
|
catch( Exception::BaseException& ex )
|
|
|
|
{
|
|
|
|
Console::Error( L"IOP Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() );
|
2009-02-09 21:15:56 +00:00
|
|
|
psxRec.Shutdown();
|
|
|
|
}
|
|
|
|
|
2009-09-16 17:23:02 +00:00
|
|
|
// hmm! : VU0 and VU1 pre-allocations should do sVU and mVU separately? Sounds complicated. :(
|
2009-09-17 02:12:32 +00:00
|
|
|
|
2009-02-09 21:15:56 +00:00
|
|
|
try
|
|
|
|
{
|
|
|
|
VU0micro::recAlloc();
|
2009-09-16 17:23:02 +00:00
|
|
|
RecSuccess_VU0 = true;
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
2009-09-16 17:23:02 +00:00
|
|
|
catch( Exception::BaseException& ex )
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2009-09-16 17:23:02 +00:00
|
|
|
Console::Error( L"VU0 Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() );
|
2009-02-09 21:15:56 +00:00
|
|
|
VU0micro::recShutdown();
|
|
|
|
}
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
VU1micro::recAlloc();
|
2009-09-16 17:23:02 +00:00
|
|
|
RecSuccess_VU1 = true;
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
2009-09-16 17:23:02 +00:00
|
|
|
catch( Exception::BaseException& ex )
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2009-09-16 17:23:02 +00:00
|
|
|
Console::Error( L"VU1 Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() );
|
2009-02-09 21:15:56 +00:00
|
|
|
VU1micro::recShutdown();
|
|
|
|
}
|
|
|
|
|
2009-09-17 02:12:32 +00:00
|
|
|
// If both VUrecs failed, then make sure the SuperVU is totally closed out, because it
|
2009-09-16 17:23:02 +00:00
|
|
|
// actually initializes everything once and then shares it between both VU recs.
|
|
|
|
if( !RecSuccess_VU0 && !RecSuccess_VU1 )
|
2009-02-09 21:15:56 +00:00
|
|
|
SuperVUDestroy( -1 );
|
|
|
|
}
|
|
|
|
|
2009-09-20 20:54:45 +00:00
|
|
|
void SysCoreAllocations::CleanupMess() throw()
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2009-09-16 17:23:02 +00:00
|
|
|
try
|
|
|
|
{
|
|
|
|
// Special SuperVU "complete" terminator.
|
|
|
|
SuperVUDestroy( -1 );
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-09-16 17:23:02 +00:00
|
|
|
VU1micro::recShutdown();
|
|
|
|
VU0micro::recShutdown();
|
2009-02-09 21:15:56 +00:00
|
|
|
|
2009-09-16 17:23:02 +00:00
|
|
|
psxRec.Shutdown();
|
|
|
|
recCpu.Shutdown();
|
2009-09-09 14:08:15 +00:00
|
|
|
|
2009-09-16 17:23:02 +00:00
|
|
|
vuMicroMemShutdown();
|
|
|
|
psxMemShutdown();
|
|
|
|
memShutdown();
|
|
|
|
vtlb_Core_Shutdown();
|
|
|
|
}
|
|
|
|
DESTRUCTOR_CATCHALL
|
2009-02-09 21:15:56 +00:00
|
|
|
}
|
|
|
|
|
2009-09-20 20:54:45 +00:00
|
|
|
SysCoreAllocations::~SysCoreAllocations() throw()
|
2009-09-09 14:08:15 +00:00
|
|
|
{
|
2009-09-16 17:23:02 +00:00
|
|
|
CleanupMess();
|
|
|
|
}
|
2009-09-09 14:08:15 +00:00
|
|
|
|
2009-09-20 20:54:45 +00:00
|
|
|
bool SysCoreAllocations::HadSomeFailures( const Pcsx2Config::RecompilerOptions& recOpts ) const
|
2009-09-16 17:23:02 +00:00
|
|
|
{
|
|
|
|
return (recOpts.EnableEE && !RecSuccess_EE) ||
|
|
|
|
(recOpts.EnableIOP && !RecSuccess_IOP) ||
|
|
|
|
(recOpts.EnableVU0 && !RecSuccess_VU0) ||
|
|
|
|
(recOpts.EnableVU1 && !RecSuccess_VU1);
|
2009-09-09 14:08:15 +00:00
|
|
|
}
|
2009-03-04 11:33:45 +00:00
|
|
|
|
|
|
|
// Resets all PS2 cpu execution caches, which does not affect that actual PS2 state/condition.
|
2009-02-09 21:15:56 +00:00
|
|
|
// This can be called at any time outside the context of a Cpu->Execute() block without
|
|
|
|
// bad things happening (recompilers will slow down for a brief moment since rec code blocks
|
|
|
|
// are dumped).
|
|
|
|
// Use this method to reset the recs when important global pointers like the MTGS are re-assigned.
|
2009-03-04 11:33:45 +00:00
|
|
|
void SysClearExecutionCache()
|
2009-02-09 21:15:56 +00:00
|
|
|
{
|
2009-08-31 03:47:05 +00:00
|
|
|
Cpu = CHECK_EEREC ? &recCpu : &intCpu;
|
|
|
|
psxCpu = CHECK_IOPREC ? &psxRec : &psxInt;
|
2009-02-09 21:15:56 +00:00
|
|
|
|
|
|
|
Cpu->Reset();
|
|
|
|
psxCpu->Reset();
|
|
|
|
|
|
|
|
vuMicroCpuReset();
|
|
|
|
}
|
|
|
|
|
2009-09-16 17:23:02 +00:00
|
|
|
void SysLoadState( const wxString& srcfile )
|
2009-03-04 11:33:45 +00:00
|
|
|
{
|
2009-09-29 19:16:00 +00:00
|
|
|
//SysClearExecutionCache();
|
|
|
|
//cpuReset();
|
|
|
|
//joe.FreezeAll();
|
2009-03-04 11:33:45 +00:00
|
|
|
}
|
|
|
|
|
2009-08-31 03:47:05 +00:00
|
|
|
// Maps a block of memory for use as a recompiled code buffer, and ensures that the
|
|
|
|
// allocation is below a certain memory address (specified in "bounds" parameter).
|
|
|
|
// The allocated block has code execution privileges.
|
|
|
|
// Returns NULL on allocation failure.
|
2009-02-09 21:15:56 +00:00
|
|
|
u8 *SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller)
|
|
|
|
{
|
2009-03-04 11:33:45 +00:00
|
|
|
u8 *Mem = (u8*)HostSys::Mmap( base, size );
|
2009-02-09 21:15:56 +00:00
|
|
|
|
|
|
|
if( (Mem == NULL) || (bounds != 0 && (((uptr)Mem + size) > bounds)) )
|
|
|
|
{
|
2009-09-08 05:37:40 +00:00
|
|
|
DevCon::Notice( "First try failed allocating %s at address 0x%x", caller, base );
|
2009-02-09 21:15:56 +00:00
|
|
|
|
|
|
|
// memory allocation *must* have the top bit clear, so let's try again
|
|
|
|
// with NULL (let the OS pick something for us).
|
|
|
|
|
|
|
|
SafeSysMunmap( Mem, size );
|
|
|
|
|
2009-03-04 11:33:45 +00:00
|
|
|
Mem = (u8*)HostSys::Mmap( NULL, size );
|
2009-02-09 21:15:56 +00:00
|
|
|
if( bounds != 0 && (((uptr)Mem + size) > bounds) )
|
|
|
|
{
|
2009-09-08 05:37:40 +00:00
|
|
|
DevCon::Error( "Fatal Error:\n\tSecond try failed allocating %s, block ptr 0x%x does not meet required criteria.", caller, Mem );
|
2009-02-09 21:15:56 +00:00
|
|
|
SafeSysMunmap( Mem, size );
|
|
|
|
|
|
|
|
// returns NULL, caller should throw an exception.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Mem;
|
|
|
|
}
|