From 5e73b1ca7e151db074753d55c8eabb4aee783204 Mon Sep 17 00:00:00 2001 From: arcum42 Date: Tue, 23 Nov 2010 03:11:08 +0000 Subject: [PATCH] GregsMisc: Sync with trunk (r3983-r4044) git-svn-id: http://pcsx2.googlecode.com/svn/branches/GregMiscellaneous@4045 96395faa-99c1-11dd-bbfe-3dabce05a288 --- common/build/Utilities/Utilities.cbp | 3 + common/build/Utilities/utilities.vcproj | 1060 +-- common/include/Utilities/Dependencies.h | 17 +- common/include/Utilities/Exceptions.h | 59 +- common/include/Utilities/General.h | 101 +- common/include/Utilities/MemsetFast.inl | 85 + common/include/Utilities/PageFaultSource.h | 337 + common/include/Utilities/Path.h | 3 +- common/include/Utilities/SafeArray.inl | 21 +- common/include/Utilities/ScopedAlloc.h | 20 + common/include/Utilities/StringHelpers.h | 2 + common/src/Utilities/CMakeLists.txt | 365 +- common/src/Utilities/Exceptions.cpp | 201 +- common/src/Utilities/FastFormatString.cpp | 8 +- common/src/Utilities/Linux/LnxHostSys.cpp | 220 +- common/src/Utilities/PathUtils.cpp | 2 +- common/src/Utilities/StringHelpers.cpp | 1 + common/src/Utilities/VirtualMemory.cpp | 470 ++ common/src/Utilities/Windows/WinHostSys.cpp | 140 +- common/src/Utilities/wxAppWithHelpers.cpp | 2 +- common/src/x86emitter/cpudetect.cpp | 8 +- pcsx2/CDVD/CDVDisoReader.cpp | 19 +- pcsx2/CDVD/IsoFileFormats.cpp | 3 +- pcsx2/CMakeLists.txt | 4 +- pcsx2/Config.h | 2 +- pcsx2/Dmac.h | 2 + pcsx2/Elfheader.cpp | 10 +- pcsx2/Gif.cpp | 169 +- pcsx2/Gif.h | 2 +- pcsx2/Hw.cpp | 46 +- pcsx2/IPU/IPU.cpp | 2 + pcsx2/IPU/IPUdma.cpp | 33 +- pcsx2/IPU/mpeg2lib/Mpeg.cpp | 2 + pcsx2/IPU/mpeg2lib/Mpeg.h | 42 - pcsx2/Interpreter.cpp | 30 +- pcsx2/IopMem.cpp | 50 +- pcsx2/IopMem.h | 1 + pcsx2/Linux/LnxHostSys.cpp | 56 - pcsx2/Linux/LnxKeyCodes.cpp | 2 + pcsx2/Linux/pcsx2.cbp | 13 +- pcsx2/Memory.cpp | 145 +- pcsx2/Memory.h | 8 +- pcsx2/MemoryTypes.h | 31 +- pcsx2/Pcsx2Config.cpp | 1 + pcsx2/PluginManager.cpp | 34 +- pcsx2/Plugins.h | 7 +- pcsx2/PrecompiledHeader.h | 11 +- pcsx2/R3000A.h | 10 +- pcsx2/R3000AInterpreter.cpp | 20 +- pcsx2/R5900.cpp | 9 +- pcsx2/R5900.h | 33 +- pcsx2/SPR.cpp | 9 +- pcsx2/SamplProf.h | 4 + pcsx2/SaveState.cpp | 6 +- pcsx2/Sif1.cpp | 7 +- pcsx2/System.cpp | 310 +- pcsx2/System.h | 76 + pcsx2/System/PageFaultSource.h | 107 - pcsx2/System/RecTypes.h | 68 + pcsx2/System/SysCoreThread.cpp | 17 +- pcsx2/System/SysThreads.h | 1 + pcsx2/VUmicro.h | 81 +- pcsx2/VUmicroMem.cpp | 54 +- pcsx2/Vif0_Dma.cpp | 31 +- pcsx2/Vif1_Dma.cpp | 17 +- pcsx2/Vif1_MFIFO.cpp | 184 +- pcsx2/Vif_Codes.cpp | 2 +- pcsx2/Vif_Transfer.cpp | 31 +- pcsx2/gui/App.h | 7 +- pcsx2/gui/AppAssert.cpp | 153 +- pcsx2/gui/AppCoreThread.cpp | 12 +- pcsx2/gui/AppCoreThread.h | 1 + pcsx2/gui/AppEventListeners.h | 10 +- pcsx2/gui/AppInit.cpp | 31 +- pcsx2/gui/AppMain.cpp | 13 +- pcsx2/gui/ConsoleLogger.cpp | 26 +- pcsx2/gui/CpuUsageProvider.cpp | 2 +- pcsx2/gui/Dialogs/ConfirmationDialogs.cpp | 4 +- pcsx2/gui/Dialogs/GameDatabaseDialog.cpp | 2 - pcsx2/gui/Dialogs/McdConfigDialog.cpp | 20 +- pcsx2/gui/MainFrame.cpp | 4 +- pcsx2/gui/MainFrame.h | 1 + pcsx2/gui/MainMenuClicks.cpp | 5 + pcsx2/gui/Panels/GameDatabasePanel.cpp | 378 +- pcsx2/gui/Panels/LogOptionsPanels.cpp | 12 +- pcsx2/gui/Panels/MemoryCardPanels.h | 1 + pcsx2/gui/Panels/PluginSelectorPanel.cpp | 10 +- pcsx2/gui/SysState.cpp | 24 +- pcsx2/ps2/GIFpath.cpp | 28 +- pcsx2/ps2/LegacyDmac.cpp | 4 +- pcsx2/ps2/eeHwTraceLog.inl | 1 + pcsx2/vtlb.cpp | 301 +- pcsx2/vtlb.h | 125 +- pcsx2/windows/SamplProf.cpp | 44 +- pcsx2/windows/VCprojects/pcsx2_2008.vcproj | 5799 ++++++++--------- pcsx2/windows/WinCompressNTFS.cpp | 4 +- pcsx2/windows/WinSysExec.cpp | 16 +- pcsx2/windows/cheats/browser.cpp | 2 +- pcsx2/windows/cheats/cheats.cpp | 2 +- pcsx2/x86/BaseblockEx.h | 6 +- pcsx2/x86/iR3000A.cpp | 94 +- pcsx2/x86/ix86-32/iR5900-32.cpp | 349 +- pcsx2/x86/ix86-32/recVTLB.cpp | 4 +- pcsx2/x86/microVU.cpp | 143 +- pcsx2/x86/microVU.h | 25 +- pcsx2/x86/microVU_Execute.inl | 10 +- pcsx2/x86/microVU_Misc.h | 9 - pcsx2/x86/microVU_Misc.inl | 6 +- pcsx2/x86/newVif.h | 33 +- pcsx2/x86/newVif_BlockBuffer.h | 86 - pcsx2/x86/newVif_Dynarec.cpp | 46 +- pcsx2/x86/newVif_Unpack.cpp | 17 + pcsx2/x86/newVif_UnpackSSE.cpp | 4 +- pcsx2/x86/sVU_zerorec.cpp | 204 +- .../CDVDnull/Windows/CDVDnull_vs2008.vcproj | 2 +- plugins/CDVDolio/cdvd_vs2008.vcproj | 1 + plugins/FWnull/Windows/FWnull_vc2008.vcproj | 6 +- plugins/GSnull/Windows/GSnull_vc2008.vcproj | 8 +- plugins/LilyPad/LilyPad_VC2008.vcproj | 507 +- plugins/PadNull/Windows/PadNull_vc2008.vcproj | 2 - plugins/SSSPSXPAD/PadSSSPSX_vc2008.vcproj | 2 - plugins/USBnull/Windows/USBnull_vc2008.vcproj | 4 +- .../dev9null/Windows/DEV9null_vc2008.vcproj | 10 +- plugins/onepad/Linux/OnePad.cbp | 2 +- .../spu2-x/src/Windows/Spu2-X_vs2008.vcproj | 4 - plugins/xpad/xpad_vs2008.vcproj | 1 + plugins/zerogs/dx/Windows/zerogs_2008.vcproj | 3 - plugins/zerospu2/Windows/ZeroSPU2_2008.vcproj | 3 - .../opengl/Linux/zzogl-pg/zzogl-pg.cbp | 4 +- .../opengl/Win32/zerogsogl_2008.vcproj | 4 +- 130 files changed, 7713 insertions(+), 5855 deletions(-) create mode 100644 common/include/Utilities/MemsetFast.inl create mode 100644 common/include/Utilities/PageFaultSource.h create mode 100644 common/src/Utilities/VirtualMemory.cpp delete mode 100644 pcsx2/Linux/LnxHostSys.cpp delete mode 100644 pcsx2/System/PageFaultSource.h create mode 100644 pcsx2/System/RecTypes.h delete mode 100644 pcsx2/x86/newVif_BlockBuffer.h diff --git a/common/build/Utilities/Utilities.cbp b/common/build/Utilities/Utilities.cbp index 585bc4c499..cfb00c78c8 100644 --- a/common/build/Utilities/Utilities.cbp +++ b/common/build/Utilities/Utilities.cbp @@ -155,6 +155,8 @@ + + @@ -200,6 +202,7 @@ + diff --git a/common/build/Utilities/utilities.vcproj b/common/build/Utilities/utilities.vcproj index 6d7bf5ee1f..a2f77eafcb 100644 --- a/common/build/Utilities/utilities.vcproj +++ b/common/build/Utilities/utilities.vcproj @@ -1,524 +1,536 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/common/include/Utilities/Dependencies.h b/common/include/Utilities/Dependencies.h index 98b3e7e8a9..f36cac9d1d 100644 --- a/common/include/Utilities/Dependencies.h +++ b/common/include/Utilities/Dependencies.h @@ -160,7 +160,7 @@ public: ~ScopedBool() throw() { - m_boolme = false; + *m_boolme = false; } }; @@ -177,6 +177,21 @@ public: #include "Pcsx2Defs.h" +static const sptr _64kb = 0x10000; +static const sptr _16kb = _64kb / 4; +static const sptr _128kb = _64kb * 2; +static const sptr _256kb = _128kb * 2; + +static const s64 _1mb = 0x100000; +static const s64 _8mb = _1mb * 8; +static const s64 _16mb = _1mb * 16; +static const s64 _32mb = _1mb * 32; +static const s64 _64mb = _1mb * 64; +static const s64 _256mb = _1mb * 256; +static const s64 _1gb = _256mb * 4; +static const s64 _4gb = _1gb * 4; + + // =========================================================================================== // i18n/Translation Feature Set! // =========================================================================================== diff --git a/common/include/Utilities/Exceptions.h b/common/include/Utilities/Exceptions.h index ca73656774..dd0a1610f9 100644 --- a/common/include/Utilities/Exceptions.h +++ b/common/include/Utilities/Exceptions.h @@ -209,7 +209,7 @@ public: \ // class OutOfMemory : public RuntimeError { - DEFINE_RUNTIME_EXCEPTION( OutOfMemory, RuntimeError, wxLt("Out of memory?!") ) + DEFINE_RUNTIME_EXCEPTION( OutOfMemory, RuntimeError, wxEmptyString ) public: wxString AllocDescription; @@ -236,7 +236,12 @@ public: \ // we'd really like to have access to. class VirtualMemoryMapConflict : public OutOfMemory { - DEFINE_RUNTIME_EXCEPTION( VirtualMemoryMapConflict, OutOfMemory, wxLt("Virtual memory map confict: Unable to claim specific required memory regions.") ) + DEFINE_RUNTIME_EXCEPTION( VirtualMemoryMapConflict, OutOfMemory, wxEmptyString ) + + VirtualMemoryMapConflict( const wxString& allocdesc ); + + virtual wxString FormatDisplayMessage() const; + virtual wxString FormatDiagnosticMessage() const; }; class HardwareDeficiency : public RuntimeError @@ -254,43 +259,40 @@ public: \ virtual classname& SetStreamName( const wxString& name ) { StreamName = name; return *this; } \ virtual classname& SetStreamName( const char* name ) { StreamName = fromUTF8(name); return *this; } - #define DEFINE_STREAM_EXCEPTION( classname, parent, message ) \ - DEFINE_RUNTIME_EXCEPTION( classname, parent, message ) \ + #define DEFINE_STREAM_EXCEPTION( classname, parent ) \ + DEFINE_RUNTIME_EXCEPTION( classname, parent, wxEmptyString ) \ classname( const wxString& filename ) { \ StreamName = filename; \ - SetBothMsgs(message); \ } \ DEFINE_STREAM_EXCEPTION_ACCESSORS( classname ) - // Generic stream error. Contains the name of the stream and a message. - // This exception is usually thrown via derived classes, except in the (rare) case of a - // generic / unknown error. + // A generic base error class for bad streams -- corrupted data, sudden closures, loss of + // connection, or anything else that would indicate a failure to open a stream or read the + // data after the stream was successfully opened. // - class Stream : public RuntimeError + class BadStream : public RuntimeError { - DEFINE_STREAM_EXCEPTION( Stream, RuntimeError, wxLt("General file operation error.") ) + DEFINE_STREAM_EXCEPTION( BadStream, RuntimeError ) public: wxString StreamName; // name of the stream (if applicable) virtual wxString FormatDiagnosticMessage() const; virtual wxString FormatDisplayMessage() const; - }; - // A generic base error class for bad streams -- corrupted data, sudden closures, loss of - // connection, or anything else that would indicate a failure to read the data after the - // stream was successfully opened. - // - class BadStream : public Stream - { - DEFINE_STREAM_EXCEPTION( BadStream, Stream, wxLt("File data is corrupted or incomplete, or the stream connection closed unexpectedly.") ) + protected: + void _formatDiagMsg( FastFormatUnicode& dest ) const; + void _formatUserMsg( FastFormatUnicode& dest ) const; }; // A generic exception for odd-ball stream creation errors. // - class CannotCreateStream : public Stream + class CannotCreateStream : public BadStream { - DEFINE_STREAM_EXCEPTION( CannotCreateStream, Stream, wxLt("File could not be created or opened.") ) + DEFINE_STREAM_EXCEPTION( CannotCreateStream, BadStream ) + + virtual wxString FormatDiagnosticMessage() const; + virtual wxString FormatDisplayMessage() const; }; // Exception thrown when an attempt to open a non-existent file is made. @@ -299,22 +301,31 @@ public: \ class FileNotFound : public CannotCreateStream { public: - DEFINE_STREAM_EXCEPTION( FileNotFound, CannotCreateStream, wxLt("File not found.") ) + DEFINE_STREAM_EXCEPTION( FileNotFound, CannotCreateStream ) + + virtual wxString FormatDiagnosticMessage() const; + virtual wxString FormatDisplayMessage() const; }; class AccessDenied : public CannotCreateStream { public: - DEFINE_STREAM_EXCEPTION( AccessDenied, CannotCreateStream, wxLt("Permission denied to file.") ) + DEFINE_STREAM_EXCEPTION( AccessDenied, CannotCreateStream ) + + virtual wxString FormatDiagnosticMessage() const; + virtual wxString FormatDisplayMessage() const; }; // EndOfStream can be used either as an error, or used just as a shortcut for manual // feof checks. // - class EndOfStream : public Stream + class EndOfStream : public BadStream { public: - DEFINE_STREAM_EXCEPTION( EndOfStream, Stream, wxLt("Unexpected end of file or stream.") ); + DEFINE_STREAM_EXCEPTION( EndOfStream, BadStream ) + + virtual wxString FormatDiagnosticMessage() const; + virtual wxString FormatDisplayMessage() const; }; #ifdef __WXMSW__ diff --git a/common/include/Utilities/General.h b/common/include/Utilities/General.h index 4cba92cd50..d405f9472d 100644 --- a/common/include/Utilities/General.h +++ b/common/include/Utilities/General.h @@ -133,14 +133,84 @@ protected: virtual void DoDeletion(); }; - -enum PageProtectionMode +// -------------------------------------------------------------------------------------- +// PageProtectionMode +// -------------------------------------------------------------------------------------- +class PageProtectionMode { - Protect_NoAccess = 0, - Protect_ReadOnly, - Protect_ReadWrite +protected: + bool m_read; + bool m_write; + bool m_exec; + +public: + PageProtectionMode() + { + All( false ); + } + + PageProtectionMode& Read( bool allow=true ) + { + m_read = allow; + return *this; + } + + PageProtectionMode& Write( bool allow=true ) + { + m_write = allow; + return *this; + } + + PageProtectionMode& Execute( bool allow=true ) + { + m_exec = allow; + return *this; + } + + PageProtectionMode& All( bool allow=true ) + { + m_read = m_write = m_exec = allow; + return *this; + } + + bool CanRead() const { return m_read; } + bool CanWrite() const { return m_write; } + bool CanExecute() const { return m_exec && m_read; } + bool IsNone() const { return !m_read && !m_write; } + + wxString ToString() const; }; +static __fi PageProtectionMode PageAccess_None() +{ + return PageProtectionMode(); +} + +static __fi PageProtectionMode PageAccess_ReadOnly() +{ + return PageProtectionMode().Read(); +} + +static __fi PageProtectionMode PageAccess_WriteOnly() +{ + return PageProtectionMode().Write(); +} + +static __fi PageProtectionMode PageAccess_ReadWrite() +{ + return PageAccess_ReadOnly().Write(); +} + +static __fi PageProtectionMode PageAccess_ExecOnly() +{ + return PageAccess_ReadOnly().Execute(); +} + +static __fi PageProtectionMode PageAccess_Any() +{ + return PageProtectionMode().All(); +} + // -------------------------------------------------------------------------------------- // HostSys // -------------------------------------------------------------------------------------- @@ -148,22 +218,29 @@ enum PageProtectionMode // platform prior to wxWidgets .. it should prolly be removed -- air) namespace HostSys { + void* MmapReserve(uptr base, size_t size); + bool MmapCommit(uptr base, size_t size, const PageProtectionMode& mode); + void MmapReset(uptr base, size_t size); + + void* MmapReservePtr(void* base, size_t size); + bool MmapCommitPtr(void* base, size_t size, const PageProtectionMode& mode); + void MmapResetPtr(void* base, size_t size); + // Maps a block of memory for use as a recompiled code buffer. - // The allocated block has code execution privileges. // Returns NULL on allocation failure. - extern void *Mmap(uptr base, u32 size); + extern void* Mmap(uptr base, size_t size); // Unmaps a block allocated by SysMmap - extern void Munmap(uptr base, u32 size); + extern void Munmap(uptr base, size_t size); - extern void MemProtect( void* baseaddr, size_t size, PageProtectionMode mode, bool allowExecution=false ); + extern void MemProtect( void* baseaddr, size_t size, const PageProtectionMode& mode ); - extern void Munmap( void* base, u32 size ); + extern void Munmap( void* base, size_t size ); template< uint size > - void MemProtectStatic( u8 (&arr)[size], PageProtectionMode mode, bool allowExecution=false ) + void MemProtectStatic( u8 (&arr)[size], const PageProtectionMode& mode ) { - MemProtect( arr, size, mode, allowExecution ); + MemProtect( arr, size, mode ); } } diff --git a/common/include/Utilities/MemsetFast.inl b/common/include/Utilities/MemsetFast.inl new file mode 100644 index 0000000000..c52b58e526 --- /dev/null +++ b/common/include/Utilities/MemsetFast.inl @@ -0,0 +1,85 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2010 PCSX2 Dev Team + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#pragma once + +#include + +#define StoreDestIdx(idx) case idx: _mm_store_ps(&destxmm[idx-1][0], srcreg) + + template< u8 data > +__noinline void memset_sse_a( void* dest, const size_t size ) +{ + const uint MZFqwc = size / 16; + + pxAssert( (size & 0xf) == 0 ); + + __m128 srcreg; + + if (data != 0) + { + static __aligned16 const u8 loadval[8] = { data,data,data,data,data,data,data,data }; + srcreg = _mm_loadh_pi( _mm_load_ps( (float*)loadval ), (__m64*)loadval ); + } + else + srcreg = _mm_setzero_ps(); + + float (*destxmm)[4] = (float(*)[4])dest; + + switch( MZFqwc & 0x07 ) + { + StoreDestIdx(0x07); + StoreDestIdx(0x06); + StoreDestIdx(0x05); + StoreDestIdx(0x04); + StoreDestIdx(0x03); + StoreDestIdx(0x02); + StoreDestIdx(0x01); + } + + destxmm += (MZFqwc & 0x07); + for( uint i=0; i( dest, size ); +} + +#undef StoreDestIdx + +template< u8 data, typename T > +__noinline void memset_sse_a( T& dest ) +{ + C_ASSERT( (sizeof(dest) & 0xf) == 0 ); + memset_sse_a( &dest, sizeof(dest) ); +} + +template< typename T > +void memzero_sse_a( T& dest ) +{ + C_ASSERT( (sizeof(dest) & 0xf) == 0 ); + memset_sse_a<0>( &dest, sizeof(dest) ); +} diff --git a/common/include/Utilities/PageFaultSource.h b/common/include/Utilities/PageFaultSource.h new file mode 100644 index 0000000000..41fd4c0924 --- /dev/null +++ b/common/include/Utilities/PageFaultSource.h @@ -0,0 +1,337 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2010 PCSX2 Dev Team + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +// [TODO] Rename this file to VirtualMemory.h !! + +#pragma once + +// ===================================================================================================== +// Cross-Platform Memory Protection (Used by VTLB, Recompilers and Texture caches) +// ===================================================================================================== +// Win32 platforms use the SEH model: __try {} __except {} +// Linux platforms use the POSIX Signals model: sigaction() +// [TODO] OS-X (Darwin) platforms should use the Mach exception model (not implemented) + +#include "EventSource.h" + +struct PageFaultInfo +{ + uptr addr; + + PageFaultInfo( uptr address ) + { + addr = address; + } +}; + +// -------------------------------------------------------------------------------------- +// IEventListener_PageFault +// -------------------------------------------------------------------------------------- +class IEventListener_PageFault : public IEventDispatcher +{ +public: + typedef PageFaultInfo EvtParams; + +public: + virtual ~IEventListener_PageFault() throw() {} + + virtual void DispatchEvent( const PageFaultInfo& evtinfo, bool& handled ) + { + OnPageFaultEvent( evtinfo, handled ); + } + + virtual void DispatchEvent( const PageFaultInfo& evtinfo ) + { + pxFailRel( "Don't call me, damnit. Use DispatchException instead." ); + } + + virtual void OnPageFaultEvent( const PageFaultInfo& evtinfo, bool& handled ) {} +}; + +// -------------------------------------------------------------------------------------- +// EventListener_PageFault / EventListenerHelper_PageFault +// -------------------------------------------------------------------------------------- +class EventListener_PageFault : public IEventListener_PageFault +{ +public: + EventListener_PageFault(); + virtual ~EventListener_PageFault() throw(); +}; + +template< typename TypeToDispatchTo > +class EventListenerHelper_PageFault : public EventListener_PageFault +{ +public: + TypeToDispatchTo* Owner; + +public: + EventListenerHelper_PageFault( TypeToDispatchTo& dispatchTo ) + { + Owner = &dispatchTo; + } + + EventListenerHelper_PageFault( TypeToDispatchTo* dispatchTo ) + { + Owner = dispatchTo; + } + + virtual ~EventListenerHelper_PageFault() throw() {} + +protected: + virtual void OnPageFaultEvent( const PageFaultInfo& info, bool& handled ) + { + Owner->OnPageFaultEvent( info, handled ); + } + +}; + +// -------------------------------------------------------------------------------------- +// SrcType_PageFault +// -------------------------------------------------------------------------------------- +class SrcType_PageFault : public EventSource +{ +protected: + typedef EventSource _parent; + +protected: + bool m_handled; + +public: + SrcType_PageFault() {} + virtual ~SrcType_PageFault() throw() { } + + bool WasHandled() const { return m_handled; } + virtual void Dispatch( const PageFaultInfo& params ); + +protected: + virtual void _DispatchRaw( ListenerIterator iter, const ListenerIterator& iend, const PageFaultInfo& evt ); +}; + + +// -------------------------------------------------------------------------------------- +// VirtualMemoryReserve +// -------------------------------------------------------------------------------------- +class VirtualMemoryReserve +{ + DeclareNoncopyableObject( VirtualMemoryReserve ); + +protected: + wxString m_name; + + // Default size of the reserve, in bytes. Can be specified when the object is contructed. + // Is used as the reserve size when Reserve() is called, unless an override is specified + // in the Reserve parameters. + size_t m_defsize; + + void* m_baseptr; + + // reserved memory (in pages). + uptr m_pages_reserved; + + // Protection mode to be applied to committed blocks. + PageProtectionMode m_prot_mode; + + // Records the number of pages committed to memory. + // (metric for analysis of buffer usage) + uptr m_pages_commited; + +public: + VirtualMemoryReserve( const wxString& name=wxEmptyString, size_t size = 0 ); + virtual ~VirtualMemoryReserve() throw() + { + Release(); + } + + virtual void* Reserve( size_t size = 0, uptr base = 0, uptr upper_bounds = 0 ); + virtual void* ReserveAt( uptr base = 0, uptr upper_bounds = 0 ) + { + return Reserve(m_defsize, base, upper_bounds); + } + + virtual void Reset(); + virtual void Release(); + virtual bool TryResize( uint newsize ); + virtual bool Commit(); + + bool IsOk() const { return m_baseptr != NULL; } + wxString GetName() const { return m_name; } + + uptr GetReserveSizeInBytes() const { return m_pages_reserved * __pagesize; } + uptr GetReserveSizeInPages() const { return m_pages_reserved; } + uint GetCommittedPageCount() const { return m_pages_commited; } + uint GetCommittedBytes() const { return m_pages_commited * __pagesize; } + + u8* GetPtr() { return (u8*)m_baseptr; } + const u8* GetPtr() const { return (u8*)m_baseptr; } + u8* GetPtrEnd() { return (u8*)m_baseptr + (m_pages_reserved * __pagesize); } + const u8* GetPtrEnd() const { return (u8*)m_baseptr + (m_pages_reserved * __pagesize); } + + VirtualMemoryReserve& SetName( const wxString& newname ); + VirtualMemoryReserve& SetBaseAddr( uptr newaddr ); + VirtualMemoryReserve& SetPageAccessOnCommit( const PageProtectionMode& mode ); + + operator void*() { return m_baseptr; } + operator const void*() const { return m_baseptr; } + + operator u8*() { return (u8*)m_baseptr; } + operator const u8*() const { return (u8*)m_baseptr; } + + u8& operator[](uint idx) + { + pxAssume(idx < (m_pages_reserved * __pagesize)); + return *((u8*)m_baseptr + idx); + } + + const u8& operator[](uint idx) const + { + pxAssume(idx < (m_pages_reserved * __pagesize)); + return *((u8*)m_baseptr + idx); + } + +}; + +// -------------------------------------------------------------------------------------- +// BaseVmReserveListener +// -------------------------------------------------------------------------------------- +class BaseVmReserveListener : public VirtualMemoryReserve +{ + DeclareNoncopyableObject( BaseVmReserveListener ); + + typedef VirtualMemoryReserve _parent; + +protected: + EventListenerHelper_PageFault m_pagefault_listener; + + // Incremental size by which the buffer grows (in pages) + uptr m_blocksize; + +public: + BaseVmReserveListener( const wxString& name, size_t size = 0 ); + virtual ~BaseVmReserveListener() throw() { } + + operator void*() { return m_baseptr; } + operator const void*() const { return m_baseptr; } + + operator u8*() { return (u8*)m_baseptr; } + operator const u8*() const { return (u8*)m_baseptr; } + + using _parent::operator[]; + + void OnPageFaultEvent( const PageFaultInfo& info, bool& handled ); + +protected: + + // This function is called from OnPageFaultEvent after the address has been translated + // and confirmed to apply to this reserved area in question. OnPageFaultEvent contains + // a try/catch exception handler, which ensures "reasonable" error response behavior if + // this function throws exceptions. + // + // Important: This method is called from the context of an exception/signal handler. On + // Windows this isn't a big deal (most operations are ok). On Linux, however, logging + // and other facilities are probably not a good idea. + virtual void DoCommitAndProtect( uptr offset )=0; + + // This function is called for every committed block. + virtual void OnCommittedBlock( void* block )=0; + + virtual void CommitBlocks( uptr page, uint blocks ); +}; + +// -------------------------------------------------------------------------------------- +// SpatialArrayReserve +// -------------------------------------------------------------------------------------- +// A spatial array is one where large areas of the memory reserve will remain unused during +// process execution. Only areas put to use will be committed to virtual memory. +// +// Spatial array efficiency depends heavily on selecting the right parameters for the array's +// primary intended use. Memory in a spatial array is arranged by blocks, with each block +// containing some number of pages (pages are 4096 bytes each on most platforms). When the +// array is accessed, the entire block containing the addressed memory will be committed at +// once. Blocks can be a single page in size (4096 bytes), though this is highly discouraged +// due to overhead and fragmentation penalties. +// +// Balancing block sizes: +// Larger blocks are good for reducing memory fragmentation and block-tracking overhead, but +// can also result in a lot of otherwise unused memory being committed to memory. Smaller +// blocks are good for arrays that will tend toward more sequential behavior, as they reduce +// the amount of unused memory being committed. However, since every block requires a +// tracking entry, assigning small blocks to a very large array can result in quite a bit of +// unwanted overhead. Furthermore, if the array is accessed randomly, system physical memory +// will become very fragmented, which will also hurt performance. +// +// By default, the base block size is based on a heuristic that balances the size of the spatial +// array reserve against a best-guess performance profile for the target platform. +// +class SpatialArrayReserve : public BaseVmReserveListener +{ + typedef BaseVmReserveListener _parent; + +protected: + uint m_numblocks; + + // Array of block bits, each bit indicating if the block has been committed to memory + // or not. The array length is typically determined via ((numblocks+7) / 8), though the + // actual array size may be larger in order to accommodate 32-bit or 128-bit accelerated + // operations. + ScopedAlignedAlloc m_blockbits; + +public: + SpatialArrayReserve( const wxString& name ); + + virtual void* Reserve( size_t size = 0, uptr base = 0, uptr upper_bounds = 0 ); + virtual void Reset(); + virtual bool TryResize( uint newsize ); + + void OnCommittedBlock( void* block ); + + SpatialArrayReserve& SetBlockCount( uint blocks ); + SpatialArrayReserve& SetBlockSizeInPages( uint bytes ); + uint SetBlockSize( uint bytes ); + + operator void*() { return m_baseptr; } + operator const void*() const { return m_baseptr; } + + operator u8*() { return (u8*)m_baseptr; } + operator const u8*() const { return (u8*)m_baseptr; } + + using _parent::operator[]; + +protected: + void DoCommitAndProtect( uptr page ); + uint _calcBlockBitArrayLength() const; +}; + +#ifdef __LINUX__ + +# define PCSX2_PAGEFAULT_PROTECT +# define PCSX2_PAGEFAULT_EXCEPT + +#elif defined( _WIN32 ) + +struct _EXCEPTION_POINTERS; +extern int SysPageFaultExceptionFilter(struct _EXCEPTION_POINTERS* eps); + +# define PCSX2_PAGEFAULT_PROTECT __try +# define PCSX2_PAGEFAULT_EXCEPT __except(SysPageFaultExceptionFilter(GetExceptionInformation())) {} + +#else +# error PCSX2 - Unsupported operating system platform. +#endif + +extern void pxInstallSignalHandler(); +extern void _platform_InstallSignalHandler(); + +extern SrcType_PageFault* Source_PageFault; + diff --git a/common/include/Utilities/Path.h b/common/include/Utilities/Path.h index f5274c9a8a..cd64d05d1f 100644 --- a/common/include/Utilities/Path.h +++ b/common/include/Utilities/Path.h @@ -102,6 +102,7 @@ public: wxFileName operator+( const wxFileName& right ) const { return Combine( right ); } wxDirName operator+( const wxDirName& right ) const { return Combine( right ); } + wxFileName operator+( const wxString& right ) const { return Combine( wxFileName(right) ); } bool operator==(const wxDirName& filename) const { return SameAs(filename); } bool operator!=(const wxDirName& filename) const { return !SameAs(filename); } @@ -122,7 +123,7 @@ public: // -------------------------------------------------------------------------------------- // Cross-platform utilities for manipulation of paths and filenames. Mostly these fall // back on wxWidgets APIs internally, but are still helpful because some of wx's file stuff -// has minor glitches, or requies sloppy wxFileName typecasting. +// has minor glitches, or requires sloppy wxFileName typecasting. // namespace Path { diff --git a/common/include/Utilities/SafeArray.inl b/common/include/Utilities/SafeArray.inl index 259651176f..a381c47422 100644 --- a/common/include/Utilities/SafeArray.inl +++ b/common/include/Utilities/SafeArray.inl @@ -31,7 +31,8 @@ SafeArray::SafeArray( const wxChar* name, T* allocated_mem, int initSize ) m_size = initSize; if( m_ptr == NULL ) - throw Exception::OutOfMemory(name + wxsFormat(L" (SafeArray::constructor) [size=%d]", initSize)); + throw Exception::OutOfMemory(name) + .SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ctor' [size=%d]", initSize)); } template< typename T > @@ -79,7 +80,8 @@ SafeArray::SafeArray( int initialSize, const wxChar* name ) m_size = initialSize; if( (initialSize != 0) && (m_ptr == NULL) ) - throw Exception::OutOfMemory(name + wxsFormat(L" (SafeArray::constructor) [size=%d]", initialSize)); + throw Exception::OutOfMemory(name) + .SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ctor' [size=%d]", initialSize)); } // Clears the contents of the array to zero, and frees all memory allocations. @@ -106,9 +108,8 @@ void SafeArray::ExactAlloc( int newsize ) m_ptr = _virtual_realloc( newsize ); if( m_ptr == NULL ) - throw Exception::OutOfMemory(Name + - wxsFormat(L" (SafeArray::ExactAlloc) [oldsize=%d] [newsize=%d]", m_size, newsize) - ); + throw Exception::OutOfMemory(Name) + .SetDiagMsg(wxsFormat(L"Called from 'SafeArray::ExactAlloc' [oldsize=%d] [newsize=%d]", m_size, newsize)); m_size = newsize; } @@ -199,9 +200,8 @@ SafeList::SafeList( int initialSize, const wxChar* name ) m_ptr = (T*)malloc( initialSize * sizeof(T) ); if( m_ptr == NULL ) - throw Exception::OutOfMemory(Name + - wxsFormat(L" (SafeList::Constructor) [length=%d]", m_length) - ); + throw Exception::OutOfMemory(Name) + .SetDiagMsg(wxsFormat(L"called from 'SafeList::ctor' [length=%d]", m_length)); for( int i=0; i::MakeRoomFor( int blockSize ) const int newalloc = blockSize + ChunkSize; m_ptr = _virtual_realloc( newalloc ); if( m_ptr == NULL ) - throw Exception::OutOfMemory(Name + - wxsFormat(L" (SafeList::MakeRoomFor) [oldlen=%d] [newlen=%d]", m_length, blockSize) - ); + throw Exception::OutOfMemory(Name) + .SetDiagMsg(wxsFormat(L"Called from 'SafeList::MakeRoomFor' [oldlen=%d] [newlen=%d]", m_length, blockSize)); for( ; m_allocsize CMakeFiles & CMakeCache.txt") -endif(NOT TOP_CMAKE_WAS_SOURCED) - - -# library name -set(Output Utilities) - -# set common flags -set(CommonFlags - -pthread - -fvisibility=hidden - -fno-dse - -fno-guess-branch-probability - -fno-strict-aliasing - -fno-tree-dse - -pipe - -Wno-format - -Wno-unused-parameter - -Wno-unused-value - -Wunused-variable) - -# set warning flags -set(DebugFlags - -g - -W) - -# set optimization flags -set(OptimizationFlags - -falign-functions - -falign-jumps - -falign-labels - -falign-loops - -fcaller-saves - -fcprop-registers - -fcrossjumping - -fcse-follow-jumps - -fcse-skip-blocks - -fdefer-pop - -fdelete-null-pointer-checks - -fgcse - -fgcse-lm - -fif-conversion - -fif-conversion2 - -fmerge-constants - -foptimize-sibling-calls - -fpeephole2 - -fregmove - -freorder-blocks - -freorder-functions - -frerun-cse-after-loop - -fsched-interblock - -fsched-spec - -fstrict-overflow - -fthread-jumps - -ftree-ccp - -ftree-ch - -ftree-copyrename - -ftree-dce - -ftree-dominator-opts - -ftree-fre - -ftree-lrs - -ftree-pre - -ftree-sra - -ftree-ter - -ftree-vrp - -funit-at-a-time) - -# Debug - Build -if(CMAKE_BUILD_TYPE STREQUAL Debug) - - # add defines - add_definitions(${CommonFlags} ${DebugFlags} -DPCSX2_DEBUG -DPCSX2_DEVBUILD) -endif(CMAKE_BUILD_TYPE STREQUAL Debug) - -# Devel - Build -if(CMAKE_BUILD_TYPE STREQUAL Devel) - - # add defines - add_definitions(${CommonFlags} ${OptimizationFlags} -DPCSX2_DEVBUILD) -endif(CMAKE_BUILD_TYPE STREQUAL Devel) - -# Release - Build -if(CMAKE_BUILD_TYPE STREQUAL Release) - - # add defines - add_definitions(${CommonFlags} ${OptimizationFlags}) -endif(CMAKE_BUILD_TYPE STREQUAL Release) - -# variable with all sources of this library -set(UtilitiesSources - ../../include/Utilities/FixedPointTypes.inl - ../../include/Utilities/EventSource.inl - ../../include/Utilities/SafeArray.inl - ../../include/Utilities/TlsVariable.inl - AlignedMalloc.cpp - CheckedStaticBox.cpp - Console.cpp - EventSource.cpp - Exceptions.cpp - FastFormatString.cpp - HashTools.cpp - IniInterface.cpp - Linux/LnxHostSys.cpp - Linux/LnxMisc.cpp - Linux/LnxThreads.cpp - Mutex.cpp - PathUtils.cpp - PrecompiledHeader.cpp - pxCheckBox.cpp - pxRadioPanel.cpp - pxStaticText.cpp - pxStreams.cpp - pxTranslate.cpp - pxWindowTextWriter.cpp - Semaphore.cpp - StringHelpers.cpp - ThreadingDialogs.cpp - ThreadTools.cpp - vssprintf.cpp - wxAppWithHelpers.cpp - wxGuiTools.cpp - wxHelpers.cpp - x86/MemcpyVibes.cpp -# x86/MemcpyFast.cpp - ) - -# collect .S files -set(UtilitiesSSources - x86/MemcpyFast.S) - -# variable with all headers of this library -set(UtilitiesHeaders - ../../include/Utilities/Assertions.h - ../../include/Utilities/CheckedStaticBox.h - ../../include/Utilities/Console.h - ../../include/Utilities/Dependencies.h - ../../include/Utilities/EventSource.h - ../../include/Utilities/Exceptions.h - ../../include/Utilities/FixedPointTypes.h - ../../include/Utilities/General.h - ../../include/Utilities/HashMap.h - ../../include/Utilities/lnx_memzero.h - ../../include/Utilities/MemcpyFast.h - ../../include/Utilities/Path.h - ../../include/Utilities/pxCheckBox.h - ../../include/Utilities/pxRadioPanel.h - ../../include/Utilities/pxStaticText.h - ../../include/Utilities/pxStreams.h - ../../include/Utilities/RedtapeWindows.h - ../../include/Utilities/SafeArray.h - ../../include/Utilities/ScopedAlloc.h - ../../include/Utilities/ScopedPtr.h - ../../include/Utilities/ScopedPtrMT.h - ../../include/Utilities/StringHelpers.h - ../../include/Utilities/Threading.h - ../../include/Utilities/ThreadingDialogs.h - ../../include/Utilities/TraceLog.h - ../../include/Utilities/wxAppWithHelpers.h - ../../include/Utilities/wxBaseTools.h - ../../include/Utilities/wxGuiTools.h - PrecompiledHeader.h) - -include_directories(.) - -# change language of .S-files to c++ -set_source_files_properties(${UtilitiesSSources} PROPERTIES LANGUAGE CXX) - -# add library -add_library(${Output} STATIC ${UtilitiesSources} ${UtilitiesHeaders} ${UtilitiesSSources}) - -# link target with wx -target_link_libraries(${Output} ${wxWidgets_LIBRARIES}) - -# User flags options -if(NOT USER_CMAKE_LD_FLAGS STREQUAL "") - target_link_libraries(${Output} "${USER_CMAKE_LD_FLAGS}") -endif(NOT USER_CMAKE_LD_FLAGS STREQUAL "") +# Check that people use the good file +if(NOT TOP_CMAKE_WAS_SOURCED) + message(FATAL_ERROR " + You did not 'cmake' the good CMakeLists.txt file. Use the one in the top dir. + It is advice to delete all wrongly generated cmake stuff => CMakeFiles & CMakeCache.txt") +endif(NOT TOP_CMAKE_WAS_SOURCED) + + +# library name +set(Output Utilities) + +# set common flags +set(CommonFlags + -pthread + -fvisibility=hidden + -fno-dse + -fno-guess-branch-probability + -fno-strict-aliasing + -fno-tree-dse + -pipe + -Wno-format + -Wno-unused-parameter + -Wno-unused-value + -Wunused-variable) + +# set warning flags +set(DebugFlags + -g + -W) + +# set optimization flags +set(OptimizationFlags + -falign-functions + -falign-jumps + -falign-labels + -falign-loops + -fcaller-saves + -fcprop-registers + -fcrossjumping + -fcse-follow-jumps + -fcse-skip-blocks + -fdefer-pop + -fdelete-null-pointer-checks + -fgcse + -fgcse-lm + -fif-conversion + -fif-conversion2 + -fmerge-constants + -foptimize-sibling-calls + -fpeephole2 + -fregmove + -freorder-blocks + -freorder-functions + -frerun-cse-after-loop + -fsched-interblock + -fsched-spec + -fstrict-overflow + -fthread-jumps + -ftree-ccp + -ftree-ch + -ftree-copyrename + -ftree-dce + -ftree-dominator-opts + -ftree-fre + -ftree-lrs + -ftree-pre + -ftree-sra + -ftree-ter + -ftree-vrp + -funit-at-a-time) + +# Debug - Build +if(CMAKE_BUILD_TYPE STREQUAL Debug) + + # add defines + add_definitions(${CommonFlags} ${DebugFlags} -DPCSX2_DEBUG -DPCSX2_DEVBUILD) +endif(CMAKE_BUILD_TYPE STREQUAL Debug) + +# Devel - Build +if(CMAKE_BUILD_TYPE STREQUAL Devel) + + # add defines + add_definitions(${CommonFlags} ${OptimizationFlags} -DPCSX2_DEVBUILD) +endif(CMAKE_BUILD_TYPE STREQUAL Devel) + +# Release - Build +if(CMAKE_BUILD_TYPE STREQUAL Release) + + # add defines + add_definitions(${CommonFlags} ${OptimizationFlags}) +endif(CMAKE_BUILD_TYPE STREQUAL Release) + +# variable with all sources of this library +set(UtilitiesSources + ../../include/Utilities/FixedPointTypes.inl + ../../include/Utilities/EventSource.inl + ../../include/Utilities/SafeArray.inl + ../../include/Utilities/TlsVariable.inl + AlignedMalloc.cpp + CheckedStaticBox.cpp + Console.cpp + EventSource.cpp + Exceptions.cpp + FastFormatString.cpp + HashTools.cpp + IniInterface.cpp + Linux/LnxHostSys.cpp + Linux/LnxMisc.cpp + Linux/LnxThreads.cpp + Mutex.cpp + PathUtils.cpp + PrecompiledHeader.cpp + pxCheckBox.cpp + pxRadioPanel.cpp + pxStaticText.cpp + pxStreams.cpp + pxTranslate.cpp + pxWindowTextWriter.cpp + Semaphore.cpp + StringHelpers.cpp + ThreadingDialogs.cpp + ThreadTools.cpp + vssprintf.cpp + VirtualMemory.cpp + wxAppWithHelpers.cpp + wxGuiTools.cpp + wxHelpers.cpp + x86/MemcpyVibes.cpp +# x86/MemcpyFast.cpp + ) + +# collect .S files +set(UtilitiesSSources + x86/MemcpyFast.S) + +# variable with all headers of this library +set(UtilitiesHeaders + ../../include/Utilities/Assertions.h + ../../include/Utilities/CheckedStaticBox.h + ../../include/Utilities/Console.h + ../../include/Utilities/Dependencies.h + ../../include/Utilities/EventSource.h + ../../include/Utilities/Exceptions.h + ../../include/Utilities/FixedPointTypes.h + ../../include/Utilities/General.h + ../../include/Utilities/HashMap.h + ../../include/Utilities/lnx_memzero.h + ../../include/Utilities/MemcpyFast.h + ../../include/Utilities/MemsetFast.inl + ../../include/Utilities/Path.h + ../../include/Utilities/PageFaultSource.h + ../../include/Utilities/pxCheckBox.h + ../../include/Utilities/pxRadioPanel.h + ../../include/Utilities/pxStaticText.h + ../../include/Utilities/pxStreams.h + ../../include/Utilities/RedtapeWindows.h + ../../include/Utilities/SafeArray.h + ../../include/Utilities/ScopedAlloc.h + ../../include/Utilities/ScopedPtr.h + ../../include/Utilities/ScopedPtrMT.h + ../../include/Utilities/StringHelpers.h + ../../include/Utilities/Threading.h + ../../include/Utilities/ThreadingDialogs.h + ../../include/Utilities/TraceLog.h + ../../include/Utilities/wxAppWithHelpers.h + ../../include/Utilities/wxBaseTools.h + ../../include/Utilities/wxGuiTools.h + PrecompiledHeader.h) + +include_directories(.) + +# change language of .S-files to c++ +set_source_files_properties(${UtilitiesSSources} PROPERTIES LANGUAGE CXX) + +# add library +add_library(${Output} STATIC ${UtilitiesSources} ${UtilitiesHeaders} ${UtilitiesSSources}) + +# link target with wx +target_link_libraries(${Output} ${wxWidgets_LIBRARIES}) + +# User flags options +if(NOT USER_CMAKE_LD_FLAGS STREQUAL "") + target_link_libraries(${Output} "${USER_CMAKE_LD_FLAGS}") +endif(NOT USER_CMAKE_LD_FLAGS STREQUAL "") diff --git a/common/src/Utilities/Exceptions.cpp b/common/src/Utilities/Exceptions.cpp index 893365f039..64037aa4d1 100644 --- a/common/src/Utilities/Exceptions.cpp +++ b/common/src/Utilities/Exceptions.cpp @@ -23,6 +23,9 @@ #include #endif +// for lack of a better place... +Fnptr_OutOfMemory pxDoOutOfMemory = NULL; + static wxString GetTranslation( const wxChar* msg ) { return msg ? wxGetTranslation( msg ) : wxEmptyString; @@ -68,12 +71,6 @@ wxString DiagnosticOrigin::ToString( const wxChar* msg ) const } -bool pxAssertImpl_LogIt( const DiagnosticOrigin& origin, const wxChar *msg ) -{ - wxLogError( L"%s", origin.ToString( msg ).c_str() ); - return false; -} - // Because wxTrap isn't available on Linux builds of wxWidgets (non-Debug, typically) void pxTrap() { @@ -94,6 +91,16 @@ void pxTrap() #endif // Win/Unix } + +bool pxAssertImpl_LogIt( const DiagnosticOrigin& origin, const wxChar *msg ) +{ + //wxLogError( L"%s", origin.ToString( msg ).c_str() ); + wxMessageOutputDebug().Printf( L"%s", origin.ToString( msg ).c_str() ); + pxTrap(); + return false; +} + + DEVASSERT_INLINE void pxOnAssert( const DiagnosticOrigin& origin, const wxChar* msg ) { // Recursion guard: Allow at least one recursive call. This is useful because sometimes @@ -191,19 +198,69 @@ Exception::RuntimeError::RuntimeError( const std::exception& ex, const wxString& Exception::OutOfMemory::OutOfMemory( const wxString& allocdesc ) { AllocDescription = allocdesc; - m_message_diag = L"Out of memory exception, while allocating the %s."; - m_message_user = _("Memory allocation failure! Your system has insufficient memory or resources to meet PCSX2's lofty needs."); } wxString Exception::OutOfMemory::FormatDiagnosticMessage() const { - return wxsFormat(m_message_diag, AllocDescription.c_str()); + FastFormatUnicode retmsg; + retmsg.Write(L"Out of memory"); + if (!AllocDescription.IsEmpty()) + retmsg.Write(L" while allocating '%s'", AllocDescription.c_str()); + + if (!m_message_diag.IsEmpty()) + retmsg.Write(L":\n%s", m_message_diag.c_str()); + + return retmsg; } wxString Exception::OutOfMemory::FormatDisplayMessage() const { - if (m_message_user.IsEmpty()) return FormatDisplayMessage(); - return m_message_user + pxsFmt( L"\n\nInternal allocation descriptor: %s", AllocDescription.c_str()); + FastFormatUnicode retmsg; + retmsg.Write( L"%s", _("Oh noes! Out of memory!") ); + + if (!m_message_diag.IsEmpty()) + retmsg.Write(L"\n\n%s", m_message_diag.c_str()); + + return retmsg; +} + + +// -------------------------------------------------------------------------------------- +// Exception::VirtualMemoryMapConflict (implementations) +// -------------------------------------------------------------------------------------- +Exception::VirtualMemoryMapConflict::VirtualMemoryMapConflict( const wxString& allocdesc ) +{ + AllocDescription = allocdesc; + m_message_user = _("Virtual memory mapping failure! Your system may have conflicting device drivers, services, or may simply have insufficient memory or resources to meet PCSX2's lofty needs."); +} + +wxString Exception::VirtualMemoryMapConflict::FormatDiagnosticMessage() const +{ + FastFormatUnicode retmsg; + retmsg.Write(L"Virtual memory map failed"); + if (!AllocDescription.IsEmpty()) + retmsg.Write(L" while reserving '%s'", AllocDescription.c_str()); + + if (!m_message_diag.IsEmpty()) + retmsg.Write(L":\n%s", m_message_diag.c_str()); + + return retmsg; +} + +wxString Exception::VirtualMemoryMapConflict::FormatDisplayMessage() const +{ + FastFormatUnicode retmsg; + retmsg.Write( L"%s", + pxE( ".Error:VirtualMemoryMap", + L"There is not enough virtual memory available, or necessary virtual memory " + L"mappings have already been reserved by other processes, services, or DLLs." + ) + ); + + if (!m_message_diag.IsEmpty()) + retmsg.Write(L"\n\n%s", m_message_diag.c_str()); + + return retmsg; } @@ -218,20 +275,120 @@ wxString Exception::CancelEvent::FormatDisplayMessage() const return L"Action canceled: " + m_message_diag; } -wxString Exception::Stream::FormatDiagnosticMessage() const +// -------------------------------------------------------------------------------------- +// Exception::BadStream (implementations) +// -------------------------------------------------------------------------------------- +wxString Exception::BadStream::FormatDiagnosticMessage() const { - return pxsFmt( - L"%s\n\tFile/Object: %s", - m_message_diag.c_str(), StreamName.c_str() - ); + FastFormatUnicode retval; + _formatDiagMsg(retval); + return retval; } -wxString Exception::Stream::FormatDisplayMessage() const +wxString Exception::BadStream::FormatDisplayMessage() const { - wxString retval( m_message_user ); - if (!StreamName.IsEmpty()) - retval += L"\n\n" + pxsFmt( _("Path: %s"), StreamName.c_str() ); + FastFormatUnicode retval; + _formatUserMsg(retval); + return retval; +} +void Exception::BadStream::_formatDiagMsg( FastFormatUnicode& dest ) const +{ + dest.Write( L"Path: " ); + if (!StreamName.IsEmpty()) + dest.Write( L"%s", StreamName.c_str() ); + else + dest.Write( L"[Unnamed or unknown]" ); + + if (!m_message_diag.IsEmpty()) + dest.Write(L"\n%s", m_message_diag.c_str()); +} + +void Exception::BadStream::_formatUserMsg( FastFormatUnicode& dest ) const +{ + dest.Write( _("Path: ") ); + if (!StreamName.IsEmpty()) + dest.Write( L"%s", StreamName.c_str() ); + else + dest.Write( _("[Unnamed or unknown]") ); + + if (!m_message_user.IsEmpty()) + dest.Write(L"\n%s", m_message_user.c_str()); +} + +// -------------------------------------------------------------------------------------- +// Exception::CannotCreateStream (implementations) +// -------------------------------------------------------------------------------------- +wxString Exception::CannotCreateStream::FormatDiagnosticMessage() const +{ + FastFormatUnicode retval; + retval.Write("File could not be created."); + _formatDiagMsg(retval); + return retval; +} + +wxString Exception::CannotCreateStream::FormatDisplayMessage() const +{ + FastFormatUnicode retval; + retval.Write(_("A file could not be created.")); + _formatUserMsg(retval); + return retval; +} + +// -------------------------------------------------------------------------------------- +// Exception::FileNotFound (implementations) +// -------------------------------------------------------------------------------------- +wxString Exception::FileNotFound::FormatDiagnosticMessage() const +{ + FastFormatUnicode retval; + retval.Write("File not found."); + _formatDiagMsg(retval); + return retval; +} + +wxString Exception::FileNotFound::FormatDisplayMessage() const +{ + FastFormatUnicode retval; + retval.Write(_("File not found.")); + _formatUserMsg(retval); + return retval; +} + +// -------------------------------------------------------------------------------------- +// Exception::AccessDenied (implementations) +// -------------------------------------------------------------------------------------- +wxString Exception::AccessDenied::FormatDiagnosticMessage() const +{ + FastFormatUnicode retval; + retval.Write("Permission denied to file."); + _formatDiagMsg(retval); + return retval; +} + +wxString Exception::AccessDenied::FormatDisplayMessage() const +{ + FastFormatUnicode retval; + retval.Write(_("Permission denied while trying to open file, likely due to insufficient user account rights.")); + _formatUserMsg(retval); + return retval; +} + +// -------------------------------------------------------------------------------------- +// Exception::EndOfStream (implementations) +// -------------------------------------------------------------------------------------- +wxString Exception::EndOfStream::FormatDiagnosticMessage() const +{ + FastFormatUnicode retval; + retval.Write("Unexpected end of file or stream."); + _formatDiagMsg(retval); + return retval; +} + +wxString Exception::EndOfStream::FormatDisplayMessage() const +{ + FastFormatUnicode retval; + retval.Write(_("Unexpected end of file or stream encountered. File is probably truncated or corrupted.")); + _formatUserMsg(retval); return retval; } @@ -249,7 +406,7 @@ BaseException* Exception::FromErrno( const wxString& streamname, int errcode ) { case EINVAL: pxFailDev( L"Invalid argument" ); - return &(new Exception::Stream( streamname ))->SetDiagMsg(L"Invalid argument? (likely caused by an unforgivable programmer error!)" ); + return &(new Exception::BadStream( streamname ))->SetDiagMsg(L"Invalid argument? (likely caused by an unforgivable programmer error!)" ); case EACCES: // Access denied! return new Exception::AccessDenied( streamname ); @@ -270,6 +427,6 @@ BaseException* Exception::FromErrno( const wxString& streamname, int errcode ) return &(new Exception::BadStream( streamname ))->SetDiagMsg(L"Bad file number"); default: - return &(new Exception::Stream( streamname ))->SetDiagMsg(pxsFmt( L"General file/stream error [errno: %d]", errcode )); + return &(new Exception::BadStream( streamname ))->SetDiagMsg(pxsFmt( L"General file/stream error [errno: %d]", errcode )); } } diff --git a/common/src/Utilities/FastFormatString.cpp b/common/src/Utilities/FastFormatString.cpp index bdf0cf4beb..f5d08a724d 100644 --- a/common/src/Utilities/FastFormatString.cpp +++ b/common/src/Utilities/FastFormatString.cpp @@ -55,7 +55,7 @@ protected: typedef char CharType; typedef CharBufferType BufferType; - static const uint BufferCount = 4; + static const uint BufferCount = 6; BufferType m_buffers[BufferCount]; uint m_curslot; @@ -69,7 +69,7 @@ public: for (uint i=0; i #include #include +#include -namespace HostSys +extern void SignalExit(int sig); + +static const uptr m_pagemask = getpagesize()-1; + +// Linux implementation of SIGSEGV handler. Bind it using sigaction(). +static void SysPageFaultSignalFilter( int signal, siginfo_t *siginfo, void * ) { - static const uptr m_pagemask = getpagesize()-1; + // [TODO] : Add a thread ID filter to the Linux Signal handler here. + // Rationale: On windows, the __try/__except model allows per-thread specific behavior + // for page fault handling. On linux, there is a single signal handler for the whole + // process, but the handler is executed by the thread that caused the exception. - void *Mmap(uptr base, u32 size) + + // Stdio Usage note: SIGSEGV handling is a synchronous in-thread signal. It is done + // from the context of the current thread and stackframe. So long as the thread is not + // the main/ui thread, use of the px assertion system should be safe. Use of stdio should + // be safe even on the main thread. + // (in other words, stdio limitations only really apply to process-level asynchronous + // signals) + + // Note: Use of stdio functions isn't safe here. Avoid console logs, + // assertions, file logs, or just about anything else useful. + + Source_PageFault->Dispatch( PageFaultInfo( (uptr)siginfo->si_addr & ~m_pagemask ) ); + + // resumes execution right where we left off (re-executes instruction that + // caused the SIGSEGV). + if (Source_PageFault->WasHandled()) return; + + if (!wxThread::IsMain()) { - u8 *Mem; - Mem = (u8*)mmap((uptr*)base, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); - if (Mem == MAP_FAILED) Console.Warning("Mmap Failed!"); - - return Mem; + pxFailRel(pxsFmt("Unhandled page fault @ 0x%08x", siginfo->si_addr)); } - void Munmap(uptr base, u32 size) - { - munmap((uptr*)base, size); - } + // Bad mojo! Completely invalid address. + // Instigate a trap if we're in a debugger, and if not then do a SIGKILL. - void MemProtect( void* baseaddr, size_t size, PageProtectionMode mode, bool allowExecution ) + wxTrap(); + if (!IsDebugBuild) raise( SIGKILL ); +} + +void _platform_InstallSignalHandler() +{ + Console.WriteLn("Installing POSIX SIGSEGV handler..."); + struct sigaction sa; + + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = SysPageFaultSignalFilter; + sigaction(SIGSEGV, &sa, NULL); +} + +static __ri void PageSizeAssertionTest( size_t size ) +{ + pxAssertMsg( (__pagesize == getpagesize()), pxsFmt( + "Internal system error: Operating system pagesize does not match compiled pagesize.\n\t" + L"\tOS Page Size: 0x%x (%d), Compiled Page Size: 0x%x (%u)", + getpagesize(), getpagesize(), __pagesize, __pagesize ) + ); + + pxAssertDev( (size & (__pagesize-1)) == 0, pxsFmt( + L"Memory block size must be a multiple of the target platform's page size.\n" + L"\tPage Size: 0x%x (%u), Block Size: 0x%x (%u)", + __pagesize, __pagesize, size, size ) + ); +} + +// returns FALSE if the mprotect call fails with an ENOMEM. +// Raises assertions on other types of POSIX errors (since those typically reflect invalid object +// or memory states). +static bool _memprotect( void* baseaddr, size_t size, const PageProtectionMode& mode ) +{ + PageSizeAssertionTest(size); + + uint lnxmode = 0; + + if (mode.CanWrite()) lnxmode |= PROT_WRITE; + if (mode.CanRead()) lnxmode |= PROT_READ; + if (mode.CanExecute()) lnxmode |= PROT_EXEC | PROT_READ; + + const int result = mprotect( baseaddr, size, lnxmode ); + + if (result == 0) return true; + + switch(errno) { - pxAssertDev( (size & (__pagesize-1)) == 0, wxsFormat( - L"Memory block size must be a multiple of the target platform's page size.\n" - L"\tPage Size: 0x%04x (%d), Block Size: 0x%04x (%d)", - __pagesize, __pagesize, size, size ) + case EINVAL: + pxFailDev(pxsFmt(L"mprotect returned EINVAL @ 0x%08X -> 0x%08X (mode=%s)", + baseaddr, (uptr)baseaddr+size, mode.ToString().c_str()) + ); + break; + + case EACCES: + pxFailDev(pxsFmt(L"mprotect returned EACCES @ 0x%08X -> 0x%08X (mode=%s)", + baseaddr, (uptr)baseaddr+size, mode.ToString().c_str()) + ); + break; + + case ENOMEM: + // caller handles assertion or exception, or whatever. + break; + } + return false; +} + +void* HostSys::MmapReservePtr(void* base, size_t size) +{ + PageSizeAssertionTest(size); + + // On linux a reserve-without-commit is performed by using mmap on a read-only + // or anonymous source, with PROT_NONE (no-access) permission. Since the mapping + // is completely inaccessible, the OS will simply reserve it and will not put it + // against the commit table. + return mmap(base, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +} + +bool HostSys::MmapCommitPtr(void* base, size_t size, const PageProtectionMode& mode) +{ + // In linux, reserved memory is automatically committed when its permissions are + // changed to something other than PROT_NONE. If the user is committing memory + // as PROT_NONE, then just ignore this call (memory will be committed automatically + // later when the user changes permissions to something useful via calls to MemProtect). + + if (mode.IsNone()) return false; + + if (_memprotect( base, size, mode )) return true; + + if (!pxDoOutOfMemory) return false; + pxDoOutOfMemory(size); + return _memprotect( base, size, mode ); +} + +void HostSys::MmapResetPtr(void* base, size_t size) +{ + // On linux the only way to reset the memory is to unmap and remap it as PROT_NONE. + // That forces linux to unload all committed pages and start from scratch. + + // FIXME: Ideally this code would have some threading lock on it to prevent any other + // malloc/free code in the current process from interfering with the operation, but I + // can't think of any good way to do that. (generally it shouldn't be a problem in + // PCSX2 anyway, since MmapReset is only called when the ps2vm is suspended; so that + // pretty well stops all PCSX2 threads anyway). + + Munmap(base, size); + void* result = Mmap((uptr)base, size); + + pxAssertRel ((uptr)result != (uptr)base, pxsFmt( + "Virtual memory decommit failed: memory at 0x%08X -> 0x%08X could not be remapped. " + "This is likely caused by multi-thread memory contention.", base, (uptr)base+size + )); +} + +void* HostSys::MmapReserve(uptr base, size_t size) +{ + return MmapReservePtr((void*)base, size); +} + +bool HostSys::MmapCommit(uptr base, size_t size, const PageProtectionMode& mode) +{ + return MmapCommitPtr( (void*)base, size, mode ); +} + +void HostSys::MmapReset(uptr base, size_t size) +{ + MmapResetPtr((void*)base, size); +} + +void* HostSys::Mmap(uptr base, size_t size) +{ + PageSizeAssertionTest(size); + + // MAP_ANONYMOUS - means we have no associated file handle (or device). + + return mmap((void*)base, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +} + +void HostSys::Munmap(uptr base, size_t size) +{ + if (!base) return; + munmap((void*)base, size); +} + +void HostSys::MemProtect( void* baseaddr, size_t size, const PageProtectionMode& mode ) +{ + if (!_memprotect(baseaddr, size, mode)) + { + throw Exception::OutOfMemory( L"MemProtect" ) + .SetDiagMsg(pxsFmt( L"mprotect failed @ 0x%08X -> 0x%08X (mode=%s)", + baseaddr, (uptr)baseaddr+size, mode.ToString().c_str() + ) ); - - int lnxmode = 0; - - // make sure size is aligned to the system page size: - // Check is redundant against the assertion above, but might as well... - size = (size + m_pagemask) & ~m_pagemask; - - switch( mode ) - { - case Protect_NoAccess: break; - case Protect_ReadOnly: lnxmode = PROT_READ; break; - case Protect_ReadWrite: lnxmode = PROT_READ | PROT_WRITE; break; - } - - if( allowExecution ) lnxmode |= PROT_EXEC; - mprotect( baseaddr, size, lnxmode ); } } diff --git a/common/src/Utilities/PathUtils.cpp b/common/src/Utilities/PathUtils.cpp index 668f26df9c..cf5e4b71b9 100644 --- a/common/src/Utilities/PathUtils.cpp +++ b/common/src/Utilities/PathUtils.cpp @@ -143,7 +143,7 @@ wxString Path::Combine( const wxDirName& srcPath, const wxFileName& srcFile ) wxString Path::Combine( const wxString& srcPath, const wxDirName& srcFile ) { - return ((wxDirName)srcPath + srcFile).ToString(); + return (wxDirName( srcPath ) + srcFile).ToString(); } // Replaces the extension of the file with the one given. diff --git a/common/src/Utilities/StringHelpers.cpp b/common/src/Utilities/StringHelpers.cpp index 1b4785fa8a..6b2e749023 100644 --- a/common/src/Utilities/StringHelpers.cpp +++ b/common/src/Utilities/StringHelpers.cpp @@ -118,6 +118,7 @@ wxString JoinString( const wxChar** src, const wxString& separator ) return dest; } + // Attempts to parse and return a value for the given template type, and throws a ParseError // exception if the parse fails. The template type can be anything that is supported/ // implemented via one of the TryParse() method overloads. diff --git a/common/src/Utilities/VirtualMemory.cpp b/common/src/Utilities/VirtualMemory.cpp new file mode 100644 index 0000000000..50969186db --- /dev/null +++ b/common/src/Utilities/VirtualMemory.cpp @@ -0,0 +1,470 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2010 PCSX2 Dev Team + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#include "PrecompiledHeader.h" +#include "PageFaultSource.h" + +#ifndef __WXMSW__ +#include +#endif + +#include "EventSource.inl" +#include "MemsetFast.inl" + +template class EventSource< IEventListener_PageFault >; + +SrcType_PageFault* Source_PageFault = NULL; + +void pxInstallSignalHandler() +{ + if (!Source_PageFault) + { + Source_PageFault = new SrcType_PageFault(); + } + + _platform_InstallSignalHandler(); + + // NOP on Win32 systems -- we use __try{} __except{} instead. +} + +// -------------------------------------------------------------------------------------- +// EventListener_PageFault (implementations) +// -------------------------------------------------------------------------------------- +EventListener_PageFault::EventListener_PageFault() +{ + pxAssume(Source_PageFault); + Source_PageFault->Add( *this ); +} + +EventListener_PageFault::~EventListener_PageFault() throw() +{ + if (Source_PageFault) + Source_PageFault->Remove( *this ); +} + +void SrcType_PageFault::Dispatch( const PageFaultInfo& params ) +{ + m_handled = false; + _parent::Dispatch( params ); +} + +void SrcType_PageFault::_DispatchRaw( ListenerIterator iter, const ListenerIterator& iend, const PageFaultInfo& evt ) +{ + do { + (*iter)->DispatchEvent( evt, m_handled ); + } while( (++iter != iend) && !m_handled ); +} + +// -------------------------------------------------------------------------------------- +// VirtualMemoryReserve (implementations) +// -------------------------------------------------------------------------------------- +VirtualMemoryReserve::VirtualMemoryReserve( const wxString& name, size_t size ) + : m_name( name ) +{ + m_defsize = size; + + m_pages_commited = 0; + m_pages_reserved = 0; + m_baseptr = NULL; + m_prot_mode = PageAccess_None(); +} + +VirtualMemoryReserve& VirtualMemoryReserve::SetName( const wxString& newname ) +{ + m_name = newname; + return *this; +} + +VirtualMemoryReserve& VirtualMemoryReserve::SetBaseAddr( uptr newaddr ) +{ + if (!pxAssertDev(!m_pages_reserved, "Invalid object state: you must release the virtual memory reserve prior to changing its base address!")) return *this; + + m_baseptr = (void*)newaddr; + return *this; +} + +VirtualMemoryReserve& VirtualMemoryReserve::SetPageAccessOnCommit( const PageProtectionMode& mode ) +{ + m_prot_mode = mode; + return *this; +} + +// Notes: +// * This method should be called if the object is already in an released (unreserved) state. +// Subsequent calls will be ignored, and the existing reserve will be returned. +// +// Parameters: +// size - size of the reserve, in bytes. (optional) +// If not specified (or zero), then the default size specified in the constructor for the +// object instance is used. +// +// upper_bounds - criteria that must be met for the allocation to be valid. +// If the OS refuses to allocate the memory below the specified address, the +// object will fail to initialize and an exception will be thrown. +void* VirtualMemoryReserve::Reserve( size_t size, uptr base, uptr upper_bounds ) +{ + if (!pxAssertDev( m_baseptr == NULL, "(VirtualMemoryReserve) Invalid object state; object has already been reserved." )) + return m_baseptr; + + if (!size) size = m_defsize; + if (!size) return NULL; + + m_pages_reserved = (size + __pagesize-4) / __pagesize; + uptr reserved_bytes = m_pages_reserved * __pagesize; + + m_baseptr = (void*)HostSys::MmapReserve(base, reserved_bytes); + + if (!m_baseptr || (upper_bounds != 0 && (((uptr)m_baseptr + reserved_bytes) > upper_bounds))) + { + DevCon.Warning( L"%s: host memory @ %s -> %s is unavailable; attempting to map elsewhere...", + m_name.c_str(), pxsPtr(base), pxsPtr(base + size) ); + + SafeSysMunmap(m_baseptr, reserved_bytes); + + if (base) + { + // Let's try again at an OS-picked memory area, and then hope it meets needed + // boundschecking criteria below. + m_baseptr = HostSys::MmapReserve( 0, reserved_bytes ); + } + } + + if ((upper_bounds != 0) && (((uptr)m_baseptr + reserved_bytes) > upper_bounds)) + { + SafeSysMunmap(m_baseptr, reserved_bytes); + // returns null, caller should throw an exception or handle appropriately. + } + + if (!m_baseptr) return NULL; + + FastFormatUnicode mbkb; + uint mbytes = reserved_bytes / _1mb; + if (mbytes) + mbkb.Write( "[%umb]", mbytes ); + else + mbkb.Write( "[%ukb]", reserved_bytes / 1024 ); + + DevCon.WriteLn( Color_Gray, L"%-32s @ %s -> %s %s", m_name.c_str(), + pxsPtr(m_baseptr), pxsPtr((uptr)m_baseptr+reserved_bytes), mbkb.c_str()); + + return m_baseptr; +} + +// Clears all committed blocks, restoring the allocation to a reserve only. +void VirtualMemoryReserve::Reset() +{ + if (!m_pages_commited) return; + + HostSys::MemProtect(m_baseptr, m_pages_commited*__pagesize, PageAccess_None()); + HostSys::MmapResetPtr(m_baseptr, m_pages_commited*__pagesize); + m_pages_commited = 0; +} + +void VirtualMemoryReserve::Release() +{ + SafeSysMunmap(m_baseptr, m_pages_reserved*__pagesize); +} + +bool VirtualMemoryReserve::Commit() +{ + if (!m_pages_reserved) return false; + if (!pxAssert(!m_pages_commited)) return true; + + m_pages_commited = m_pages_reserved; + return HostSys::MmapCommitPtr(m_baseptr, m_pages_reserved*__pagesize, m_prot_mode); +} + + +// If growing the array, or if shrinking the array to some point that's still *greater* than the +// committed memory range, then attempt a passive "on-the-fly" resize that maps/unmaps some portion +// of the reserve. +// +// If the above conditions are not met, or if the map/unmap fails, this method returns false. +// The caller will be responsible for manually resetting the reserve. +// +// Parameters: +// newsize - new size of the reserved buffer, in bytes. +bool VirtualMemoryReserve::TryResize( uint newsize ) +{ + uint newPages = (newsize + __pagesize - 1) / __pagesize; + + if (newPages > m_pages_reserved) + { + uint toReservePages = newPages - m_pages_reserved; + uint toReserveBytes = toReservePages * __pagesize; + + DevCon.WriteLn( L"%-32s is being expanded by %u pages.", m_name.c_str(), toReservePages); + + m_baseptr = (void*)HostSys::MmapReserve((uptr)GetPtrEnd(), toReserveBytes); + + if (!m_baseptr) + { + Console.Warning("%-32s could not be passively resized due to virtual memory conflict!"); + Console.Indent().Warning("(attempted to map memory @ %08p -> %08p)", m_baseptr, (uptr)m_baseptr+toReserveBytes); + } + + DevCon.WriteLn( Color_Gray, L"%-32s @ %08p -> %08p [%umb]", m_name.c_str(), + m_baseptr, (uptr)m_baseptr+toReserveBytes, toReserveBytes / _1mb); + } + else if (newPages < m_pages_reserved) + { + if (m_pages_commited > newsize) return false; + + uint toRemovePages = m_pages_reserved - newPages; + uint toRemoveBytes = toRemovePages * __pagesize; + + DevCon.WriteLn( L"%-32s is being shrunk by %u pages.", m_name.c_str(), toRemovePages); + + HostSys::MmapResetPtr(GetPtrEnd(), toRemoveBytes); + + DevCon.WriteLn( Color_Gray, L"%-32s @ %08p -> %08p [%umb]", m_name.c_str(), + m_baseptr, (uptr)m_baseptr+toRemoveBytes, toRemoveBytes / _1mb); + } + + return true; +} + +// -------------------------------------------------------------------------------------- +// BaseVmReserveListener (implementations) +// -------------------------------------------------------------------------------------- + +BaseVmReserveListener::BaseVmReserveListener( const wxString& name, size_t size ) + : VirtualMemoryReserve( name, size ) + , m_pagefault_listener( this ) +{ + m_blocksize = __pagesize; +} + +void BaseVmReserveListener::CommitBlocks( uptr page, uint blocks ) +{ + const uptr blocksbytes = blocks * m_blocksize * __pagesize; + void* blockptr = (u8*)m_baseptr + (page * __pagesize); + + // Depending on the operating system, this call could fail if the system is low on either + // physical ram or virtual memory. + if (!HostSys::MmapCommitPtr(blockptr, blocksbytes, m_prot_mode)) + { + throw Exception::OutOfMemory(m_name) + .SetDiagMsg(pxsFmt("An additional %u blocks @ 0x%08x were requested, but could not be committed!", blocks, blockptr)); + } + + u8* init = (u8*)blockptr; + u8* endpos = init + blocksbytes; + for( ; init= m_pages_reserved)) return; + + // Linux Note! the SIGNAL handler is very limited in what it can do, and not only can't + // we let the C++ exception try to unwind the stack, we may not be able to log it either. + // (but we might as well try -- kernel/posix rules says not to do it, but Linux kernel + // implementations seem to support it). + // Note also that logging the exception and/or issuing an assertion dialog are always + // possible if the thread handling the signal is not the main thread. + + // In windows we can let exceptions bubble out of the page fault handler. SEH will more + // or less handle them in a semi-expected way, and might even avoid a GPF long enough + // for the system to log the error or something. + + #ifndef __WXMSW__ + try { + #endif + DoCommitAndProtect( offset ); + handled = true; + + #ifndef __WXMSW__ + } + catch (Exception::BaseException& ex) + { + handled = false; + if (!wxThread::IsMain()) + { + pxFailRel( ex.FormatDiagnosticMessage() ); + } + else + { + wxTrap(); + } + } + #endif +} + + +// -------------------------------------------------------------------------------------- +// SpatialArrayReserve (implementations) +// -------------------------------------------------------------------------------------- + +SpatialArrayReserve::SpatialArrayReserve( const wxString& name ) : + _parent( name ) +{ + m_prot_mode = PageAccess_ReadWrite(); +} + +uint SpatialArrayReserve::_calcBlockBitArrayLength() const +{ + // divide by 8 (rounded up) to compress 8 bits into each byte. + // mask off lower bits (rounded up) to allow for 128-bit alignment and SSE operations. + return (((m_numblocks + 7) / 8) + 15) & ~15; +} + +void* SpatialArrayReserve::Reserve( size_t size, uptr base, uptr upper_bounds ) +{ + void* addr = _parent::Reserve( size, base, upper_bounds ); + if (!addr) return NULL; + + if (m_blocksize) SetBlockSizeInPages( m_blocksize ); + m_blockbits.Alloc( _calcBlockBitArrayLength() ); + + return addr; +} + +// Resets/clears the spatial array, reducing the memory commit pool overhead to zero (0). +void SpatialArrayReserve::Reset() +{ + if (m_pages_commited) + { + u8* curptr = GetPtr(); + const uint blockBytes = m_blocksize * __pagesize; + for (uint i=0; i -namespace HostSys +int SysPageFaultExceptionFilter( EXCEPTION_POINTERS* eps ) { - void *Mmap(uptr base, u32 size) + if( eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION ) + return EXCEPTION_CONTINUE_SEARCH; + + Source_PageFault->Dispatch( PageFaultInfo( (uptr)eps->ExceptionRecord->ExceptionInformation[1] ) ); + return Source_PageFault->WasHandled() ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH; +} + +void _platform_InstallSignalHandler() +{ + // NOP on Win32 systems -- we use __try{} __except{} instead. +} + + +static DWORD ConvertToWinApi( const PageProtectionMode& mode ) +{ + DWORD winmode = PAGE_NOACCESS; + + // Windows has some really bizarre memory protection enumeration that uses bitwise + // numbering (like flags) but is in fact not a flag value. *Someone* from the early + // microsoft days wasn't a very good coder, me thinks. --air + + if (mode.CanExecute()) { - return VirtualAlloc((void*)base, size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); + winmode = mode.CanWrite() ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ; + } + else if (mode.CanRead()) + { + winmode = mode.CanWrite() ? PAGE_READWRITE : PAGE_READONLY; } - void Munmap(uptr base, u32 size) + return winmode; +} + +void* HostSys::MmapReservePtr(void* base, size_t size) +{ + return VirtualAlloc(base, size, MEM_RESERVE, PAGE_NOACCESS); +} + +bool HostSys::MmapCommitPtr(void* base, size_t size, const PageProtectionMode& mode) +{ + void* result = VirtualAlloc(base, size, MEM_COMMIT, ConvertToWinApi(mode)); + if (result) return true; + + const DWORD errcode = GetLastError(); + if (errcode == ERROR_COMMITMENT_MINIMUM) { - if( base == NULL ) return; - VirtualFree((void*)base, size, MEM_DECOMMIT); - VirtualFree((void*)base, 0, MEM_RELEASE); + Console.Warning("(MmapCommit) Received windows error %u {Virtual Memory Minimum Too Low}.", ERROR_COMMITMENT_MINIMUM); + Sleep(1000); // Cut windows some time to rework its memory... + } + else if (errcode != ERROR_NOT_ENOUGH_MEMORY && errcode != ERROR_OUTOFMEMORY) + { + pxFailDev(L"VirtualAlloc COMMIT failed: " + Exception::WinApiError().GetMsgFromWindows()); + return false; } - void MemProtect( void* baseaddr, size_t size, PageProtectionMode mode, bool allowExecution ) + if (!pxDoOutOfMemory) return false; + pxDoOutOfMemory(size); + return VirtualAlloc(base, size, MEM_COMMIT, ConvertToWinApi(mode)) != NULL; +} + +void HostSys::MmapResetPtr(void* base, size_t size) +{ + VirtualFree(base, size, MEM_DECOMMIT); +} + + +void* HostSys::MmapReserve(uptr base, size_t size) +{ + return MmapReservePtr((void*)base, size); +} + +bool HostSys::MmapCommit(uptr base, size_t size, const PageProtectionMode& mode) +{ + return MmapCommitPtr( (void*)base, size, mode ); +} + +void HostSys::MmapReset(uptr base, size_t size) +{ + MmapResetPtr((void*)base, size); +} + + +void* HostSys::Mmap(uptr base, size_t size) +{ + return VirtualAlloc((void*)base, size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); +} + +void HostSys::Munmap(uptr base, size_t size) +{ + if (!base) return; + //VirtualFree((void*)base, size, MEM_DECOMMIT); + VirtualFree((void*)base, 0, MEM_RELEASE); +} + +void HostSys::MemProtect( void* baseaddr, size_t size, const PageProtectionMode& mode ) +{ + pxAssertDev( ((size & (__pagesize-1)) == 0), pxsFmt( + L"Memory block size must be a multiple of the target platform's page size.\n" + L"\tPage Size: 0x%04x (%d), Block Size: 0x%04x (%d)", + __pagesize, __pagesize, size, size ) + ); + + DWORD OldProtect; // enjoy my uselessness, yo! + if (!VirtualProtect( baseaddr, size, ConvertToWinApi(mode), &OldProtect )) { - pxAssertDev( ((size & (__pagesize-1)) == 0), wxsFormat( - L"Memory block size must be a multiple of the target platform's page size.\n" - L"\tPage Size: 0x%04x (%d), Block Size: 0x%04x (%d)", - __pagesize, __pagesize, size, size ) - ); + Exception::WinApiError apiError; + + apiError.SetDiagMsg( + pxsFmt(L"VirtualProtect failed @ 0x%08X -> 0x%08X (mode=%s)", + baseaddr, (uptr)baseaddr + size, mode.ToString().c_str() + )); - DWORD winmode = 0; - - switch( mode ) - { - case Protect_NoAccess: - winmode = ( allowExecution ) ? PAGE_EXECUTE : PAGE_NOACCESS; - break; - - case Protect_ReadOnly: - winmode = ( allowExecution ) ? PAGE_EXECUTE_READ : PAGE_READONLY; - break; - - case Protect_ReadWrite: - winmode = ( allowExecution ) ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; - break; - } - - DWORD OldProtect; // enjoy my uselessness, yo! - VirtualProtect( baseaddr, size, winmode, &OldProtect ); + pxFailDev( apiError.FormatDiagnosticMessage() ); } } diff --git a/common/src/Utilities/wxAppWithHelpers.cpp b/common/src/Utilities/wxAppWithHelpers.cpp index 8a1b28f9ac..7821454cb5 100644 --- a/common/src/Utilities/wxAppWithHelpers.cpp +++ b/common/src/Utilities/wxAppWithHelpers.cpp @@ -675,7 +675,7 @@ void wxAppWithHelpers::OnDeleteThread( wxCommandEvent& evt ) return; } - pxThreadLog.Write(thr->GetName(), (wxString)L"Thread object deleted successfully" + (thr->HasPendingException() ? wxEmptyString : L"[exception pending!]")); + pxThreadLog.Write(thr->GetName(), (wxString)L"Thread object deleted successfully" + (thr->HasPendingException() ? L" [exception pending!]" : wxEmptyString)); thr->RethrowException(); } diff --git a/common/src/x86emitter/cpudetect.cpp b/common/src/x86emitter/cpudetect.cpp index 7fd0bf46d7..95928cf85b 100644 --- a/common/src/x86emitter/cpudetect.cpp +++ b/common/src/x86emitter/cpudetect.cpp @@ -59,13 +59,13 @@ void x86capabilities::SIMD_EstablishMXCSRmask() // the fxsave buffer must be 16-byte aligned to avoid GPF. I just save it to an // unused portion of recSSE, since it has plenty of room to spare. - HostSys::MemProtectStatic( recSSE, Protect_ReadWrite, true ); + HostSys::MemProtectStatic( recSSE, PageAccess_ReadWrite() ); xSetPtr( recSSE ); xFXSAVE( ptr[&targetFXSAVE] ); xRET(); - HostSys::MemProtectStatic( recSSE, Protect_ReadOnly, true ); + HostSys::MemProtectStatic( recSSE, PageAccess_ExecOnly() ); CallAddress( recSSE ); @@ -310,7 +310,7 @@ u32 x86capabilities::CalculateMHz() const // Results of CPU void x86capabilities::SIMD_ExceptionTest() { - HostSys::MemProtectStatic( recSSE, Protect_ReadWrite, true ); + HostSys::MemProtectStatic( recSSE, PageAccess_ReadWrite() ); ////////////////////////////////////////////////////////////////////////////////////////// // SIMD Instruction Support Detection (Second Pass) @@ -336,7 +336,7 @@ void x86capabilities::SIMD_ExceptionTest() xMOVDQU( xmm1, ptr[ecx] ); xRET(); - HostSys::MemProtectStatic( recSSE, Protect_ReadOnly, true ); + HostSys::MemProtectStatic( recSSE, PageAccess_ExecOnly() ); bool sse3_result = _test_instruction( recSSE ); // sse3 bool ssse3_result = _test_instruction( funcSSSE3 ); diff --git a/pcsx2/CDVD/CDVDisoReader.cpp b/pcsx2/CDVD/CDVDisoReader.cpp index d9a22afcba..ea69286364 100644 --- a/pcsx2/CDVD/CDVDisoReader.cpp +++ b/pcsx2/CDVD/CDVDisoReader.cpp @@ -29,12 +29,13 @@ #include "CDVDisoReader.h" static u8 *pbuffer; -static u8 cdbuffer[2352] = {0}; +static u8 cdbuffer[CD_FRAMESIZE_RAW] = {0}; static isoFile iso; static int psize, cdtype; static s32 layer1start = -1; +static bool layer1searched = false; void CALLBACK ISOclose() { @@ -77,7 +78,8 @@ s32 CALLBACK ISOopen(const char* pTitle) } layer1start = -1; - + layer1searched = false; + return 0; } @@ -145,11 +147,14 @@ static bool testForPartitionInfo( const u8 (&tempbuffer)[CD_FRAMESIZE_RAW] ) ); } -static bool FindLayer1Start() +static void FindLayer1Start() { - if( (layer1start != -1) || (iso.GetBlockCount() < 0x230540) ) return true; + if (iso.GetBlockCount() < 0x230540) return; + if (layer1start != -1) return; + if (layer1searched) return; Console.WriteLn("isoFile: searching for layer1..."); + layer1searched = true; int blockresult = -1; @@ -232,7 +237,6 @@ static bool FindLayer1Start() if( layer1start == -1 ) { Console.Error("isoFile: Couldn't find layer1... iso image is probably corrupt or incomplete."); - return false; } else { @@ -243,15 +247,14 @@ static bool FindLayer1Start() layerCacheIni.Write( cacheKey, layer1start ); } } - return true; } // Should return 0 if no error occurred, or -1 if layer detection FAILED. s32 CALLBACK ISOgetDualInfo(s32* dualType, u32* _layer1start) { - if( !FindLayer1Start() ) return -1; + FindLayer1Start(); - if(layer1start<0) + if (layer1start < 0) { *dualType = 0; *_layer1start = iso.GetBlockCount(); diff --git a/pcsx2/CDVD/IsoFileFormats.cpp b/pcsx2/CDVD/IsoFileFormats.cpp index 140913b9a2..a389123b27 100644 --- a/pcsx2/CDVD/IsoFileFormats.cpp +++ b/pcsx2/CDVD/IsoFileFormats.cpp @@ -78,7 +78,6 @@ bool isoFile::tryIsoType(u32 _size, s32 _offset, s32 _blockofs) bool isoFile::Detect( bool readType ) { char buf[32]; - int len = m_filename.Length(); m_type = ISOTYPE_ILLEGAL; @@ -245,7 +244,7 @@ void isoFile::_WriteBlock(const u8* src, uint lsn) void isoFile::_WriteBlockD(const u8* src, uint lsn) { // Find and ignore blocks that have already been dumped: - for (uint i=0; i GIF_APATH_IDLE && gifRegs.stat.APATH < GIF_APATH3)) { + //DevCon.Warning("GIF Stall 2 P1Q %x P2Q %x APATH %x PTH3 %x vif1cmd %x", gifRegs.stat.P1Q, gifRegs.stat.P2Q, gifRegs.stat.APATH, GSTransferStatus.PTH3, vif1.cmd); gifRegs.stat.IP3 = true; CPU_INT(DMAC_GIF, 16); return false; @@ -430,61 +439,90 @@ void dmaGIF() } } - if (dmacRegs.ctrl.MFD == MFD_GIF) // GIF MFIFO - { - //Console.WriteLn("GIF MFIFO"); - gifMFIFOInterrupt(); - return; - } + - GIFdma(); + gsInterrupt(); +} + +static u16 QWCinGIFMFIFO(u32 DrainADDR) +{ + u32 ret; + + + GIF_LOG("GIF MFIFO Requesting %x QWC from the MFIFO Base %x, SPR MADR %x Drain %x", gifch.qwc, dmacRegs.rbor.ADDR, spr0ch.madr, DrainADDR); + //Calculate what we have in the fifo. + if(DrainADDR <= spr0ch.madr) + { + //Drain is below the tadr, calculate the difference between them + ret = (spr0ch.madr - DrainADDR) >> 4; + } + else + { + u32 limit = dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16; + //Drain is higher than SPR so it has looped round, + //calculate from base to the SPR tag addr and what is left in the top of the ring + ret = ((spr0ch.madr - dmacRegs.rbor.ADDR) + (limit - DrainADDR)) >> 4; + } + GIF_LOG("%x Available of the %x requested", ret, gifch.qwc); + if((s32)ret < 0) DevCon.Warning("GIF Returning %x!", ret); + return ret; } // called from only one location, so forceinline it: static __fi bool mfifoGIFrbTransfer() { - u32 mfifoqwc = min(gifqwc, (u32)gifch.qwc); + u16 mfifoqwc = min(QWCinGIFMFIFO(gifch.madr), gifch.qwc); u32 *src; + if(mfifoqwc == 0) return true; //Lets skip all this, we don't have the data + GetMTGS().PrepDataPacket(GIF_PATH_3, mfifoqwc); // TODO (minor optimization): The new GIFpath parser can do rather efficient wrapping of // its own internally now. We just need to groom a version of it that can wrap around MFIFO // memory similarly to how it wraps VU1 memory on PATH1. - + GIF_LOG("MFIFO QWC to Transfer %x", mfifoqwc); /* Check if the transfer should wrap around the ring buffer */ - if ((gifch.madr + mfifoqwc * 16) > (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16)) + if ( (gifch.madr + (mfifoqwc * 16)) > (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16)) { uint s1 = ((dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16) - gifch.madr) >> 4; uint s2 = (mfifoqwc - s1); - + GIF_LOG("Split transfer doing %x QWC of %x Total QWC", s1, mfifoqwc); /* it does (wrap around), so first copy 's1' bytes from 'addr' to 'data' */ /* and second copy 's2' bytes from 'maddr' to '&data[s1]' */ - + + gifch.madr = dmacRegs.rbor.ADDR + (gifch.madr & dmacRegs.rbsr.RMSK); src = (u32*)PSM(gifch.madr); if (src == NULL) return false; uint copied = GIFPath_CopyTag(GIF_PATH_3, (u128*)src, s1); if (copied == s1) // but only copy second if first didn't abort prematurely for some reason. { + GIF_LOG("Transferring last %x QWC", s2); src = (u32*)PSM(dmacRegs.rbor.ADDR); + gifch.madr = dmacRegs.rbor.ADDR; if (src == NULL) return false; copied += GIFPath_CopyTag(GIF_PATH_3, (u128*)src, s2); } mfifoqwc = copied; + GIF_LOG("Copied %x QWC, %x QWC Left", mfifoqwc, gifch.qwc); } else { + GIF_LOG("Direct MFIFO transfer doing %x Total QWC", mfifoqwc); /* it doesn't, so just transfer 'qwc*16' words from 'gifch.madr' to GS */ + + gifch.madr = dmacRegs.rbor.ADDR + (gifch.madr & dmacRegs.rbsr.RMSK); src = (u32*)PSM(gifch.madr); if (src == NULL) return false; mfifoqwc = GIFPath_CopyTag(GIF_PATH_3, (u128*)src, mfifoqwc); - gifch.madr = dmacRegs.rbor.ADDR + (gifch.madr & dmacRegs.rbsr.RMSK); + GIF_LOG("%X QWC Copied direct %x QWC Left", mfifoqwc, gifch.qwc); } GetMTGS().SendDataPacket(); - gifqwc -= mfifoqwc; + //gifqwc -= mfifoqwc; + mfifocycles += (mfifoqwc) * 2; /* guessing */ return true; } @@ -496,14 +534,19 @@ static __fi bool mfifoGIFchain() if (gifch.qwc == 0) return true; if (gifch.madr >= dmacRegs.rbor.ADDR && - gifch.madr <= (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK)) + gifch.madr <= (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16)) { - if (!mfifoGIFrbTransfer()) return false; + bool ret = true; + // if(gifch.madr == (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16)) DevCon.Warning("Edge GIF"); + if (!mfifoGIFrbTransfer()) ret = false; + if(QWCinGIFMFIFO(gifch.madr) == 0) gifstate |= GIF_STATE_EMPTY; + return ret; + } else { int mfifoqwc; - + GIF_LOG("Non-MFIFO Location transfer doing %x Total QWC", gifch.qwc); tDMA_TAG *pMem = dmaGetAddr(gifch.madr, false); if (pMem == NULL) return false; @@ -528,12 +571,13 @@ void mfifoGIFtransfer(int qwc) if(qwc > 0 ) { - gifqwc += qwc; - - if (!(gifstate & GIF_STATE_EMPTY)) return; - // if (gifempty == false) return; - gifstate &= ~GIF_STATE_EMPTY; - gifempty = false; + if ((gifstate & GIF_STATE_EMPTY) && !(cpuRegs.interrupt & (1< 1 ) DevCon.WriteLn("gif mfifo tadr==madr but qwc = %d", gifqwc); - hwDmacIrq(DMAC_MFIFO_EMPTY); - gifstate |= GIF_STATE_EMPTY; - gifempty = true; - return; - } - gifch.tadr = qwctag(gifch.tadr); ptag = dmaGetAddr(gifch.tadr, false); @@ -565,42 +600,10 @@ void mfifoGIFtransfer(int qwc) GIF_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx mfifo qwc = %x spr0 madr = %x", ptag[1]._u32, ptag[0]._u32, gifch.qwc, ptag->ID, gifch.madr, gifch.tadr, gifqwc, spr0ch.madr); - gifqwc--; + gspath3done = hwDmacSrcChainWithStack(gifch, ptag->ID); - switch (ptag->ID) - { - case TAG_REFE: // Refe - Transfer Packet According to ADDR field - gifch.tadr = qwctag(gifch.tadr + 16); - gifstate = GIF_STATE_DONE; //End Transfer - break; - - case TAG_CNT: // CNT - Transfer QWC following the tag. - gifch.madr = qwctag(gifch.tadr + 16); //Set MADR to QW after Tag - gifch.tadr = qwctag(gifch.madr + (gifch.qwc << 4)); //Set TADR to QW following the data - gifstate = GIF_STATE_READY; - break; - - case TAG_NEXT: // Next - Transfer QWC following tag. TADR = ADDR - { - u32 temp = gifch.madr; //Temporarily Store ADDR - gifch.madr = qwctag(gifch.tadr + 16); //Set MADR to QW following the tag - gifch.tadr = temp; //Copy temporarily stored ADDR to Tag - gifstate = GIF_STATE_READY; - break; - } - - case TAG_REF: // Ref - Transfer QWC from ADDR field - case TAG_REFS: // Refs - Transfer QWC from ADDR field (Stall Control) - gifch.tadr = qwctag(gifch.tadr + 16); //Set TADR to next tag - gifstate = GIF_STATE_READY; - break; - - case TAG_END: // End - Transfer QWC following the tag - gifch.madr = qwctag(gifch.tadr + 16); //Set MADR to data following the tag - gifch.tadr = qwctag(gifch.madr + (gifch.qwc << 4)); //Set TADR to QW following the data - gifstate = GIF_STATE_DONE; //End Transfer - break; - } + if(gspath3done == true) gifstate = GIF_STATE_DONE; + else gifstate = GIF_STATE_READY; if ((gifch.chcr.TIE) && (ptag->IRQ)) { @@ -608,7 +611,8 @@ void mfifoGIFtransfer(int qwc) gifstate = GIF_STATE_DONE; gifmfifoirq = true; } - } + if (QWCinGIFMFIFO(gifch.tadr) == 0) gifstate |= GIF_STATE_EMPTY; + } if (!mfifoGIFchain()) { @@ -616,7 +620,7 @@ void mfifoGIFtransfer(int qwc) gifstate = GIF_STATE_STALL; } - if ((gifch.qwc == 0) && (gifstate & GIF_STATE_DONE)) gifstate = GIF_STATE_STALL; + if ((gifch.qwc == 0) && (gifstate & GIF_STATE_DONE)) gifstate |= GIF_STATE_STALL; CPU_INT(DMAC_MFIFO_GIF,mfifocycles); SPR_LOG("mfifoGIFtransfer end %x madr %x, tadr %x", gifch.chcr._u32, gifch.madr, gifch.tadr); @@ -624,9 +628,15 @@ void mfifoGIFtransfer(int qwc) void gifMFIFOInterrupt() { - //Console.WriteLn("gifMFIFOInterrupt"); + GIF_LOG("gifMFIFOInterrupt"); mfifocycles = 0; + if (dmacRegs.ctrl.MFD != MFD_GIF) + { + DevCon.Warning("Not in GIF MFIFO mode! Stopping GIF MFIFO"); + return; + } + if(SIGNAL_IMR_Pending == true) { //DevCon.Warning("Path 3 Paused"); @@ -634,13 +644,20 @@ void gifMFIFOInterrupt() return; } - if(GSTransferStatus.PTH3 == STOPPED_MODE && gifRegs.stat.APATH == GIF_APATH3 ) + if(GSTransferStatus.PTH3 >= PENDINGSTOP_MODE && gifRegs.stat.APATH == GIF_APATH3 ) { gifRegs.stat.OPH = false; + GSTransferStatus.PTH3 = STOPPED_MODE; gifRegs.stat.APATH = GIF_APATH_IDLE; if(gifRegs.stat.P1Q) gsPath1Interrupt(); } + if((gifstate & GIF_STATE_EMPTY)) + { + FireMFIFOEmpty(); + if(!(gifstate & GIF_STATE_STALL)) return; + } + if(CheckPaths(11) == false) return; if (!(gifch.chcr.STR)) @@ -652,16 +669,13 @@ void gifMFIFOInterrupt() if (!(gifstate & GIF_STATE_STALL)) { - if (gifqwc <= 0) + if (QWCinGIFMFIFO(gifch.tadr) == 0) { - //Console.WriteLn("Empty"); - hwDmacIrq(DMAC_MFIFO_EMPTY); gifstate |= GIF_STATE_EMPTY; - gifempty = true; - - gifRegs.stat.IMT = false; + CPU_INT(DMAC_MFIFO_GIF, 4); return; } + mfifoGIFtransfer(0); return; } @@ -685,6 +699,7 @@ void gifMFIFOInterrupt() gifch.chcr.STR = false; gifstate = GIF_STATE_READY; hwDmacIrq(DMAC_GIF); + GIF_LOG("gifMFIFO End"); clearFIFOstuff(false); } diff --git a/pcsx2/Gif.h b/pcsx2/Gif.h index 6a03820659..d02ddf14c9 100644 --- a/pcsx2/Gif.h +++ b/pcsx2/Gif.h @@ -26,7 +26,7 @@ enum gifstate_t enum GSTransferModes //0 = Image Mode (DirectHL), 1 = transferring, 2 = Stopped at End of Packet { - PENDINGIMAGE_MODE = 0, + WAITING_MODE = 0, IMAGE_MODE = 1, TRANSFER_MODE = 2, PENDINGSTOP_MODE = 3, diff --git a/pcsx2/Hw.cpp b/pcsx2/Hw.cpp index f9fbec01e7..fb60f685e2 100644 --- a/pcsx2/Hw.cpp +++ b/pcsx2/Hw.cpp @@ -130,6 +130,14 @@ void hwDmacIrq(int n) if(psHu16(DMAC_STAT+2) & (1< ((dmacRegs.rbsr.RMSK + 16) >> 4)) DevCon.Warning("MFIFO Write bigger than MFIFO! QWC=%x FifoSize=%x", qwc, ((dmacRegs.rbsr.RMSK + 16) >> 4)); // DMAC Address resolution: FIFO can be placed anywhere in the *physical* memory map // for the PS2. Its probably a serious error for a PS2 app to have the buffer cross // valid/invalid page areas of ram, so realistically we only need to test the base address @@ -162,13 +171,15 @@ __ri bool hwMFIFOWrite(u32 addr, const u128* data, uint qwc) __ri bool hwDmacSrcChainWithStack(DMACh& dma, int id) { switch (id) { case TAG_REFE: // Refe - Transfer Packet According to ADDR field + dma.tadr += 16; //End Transfer return true; case TAG_CNT: // CNT - Transfer QWC following the tag. // Set MADR to QW afer tag, and set TADR to QW following the data. - dma.madr = dma.tadr + 16; - dma.tadr = dma.madr + (dma.qwc << 4); + dma.tadr += 16; + dma.madr = dma.tadr; + //dma.tadr = dma.madr + (dma.qwc << 4); return false; case TAG_NEXT: // Next - Transfer QWC following tag. TADR = ADDR @@ -267,6 +278,33 @@ __ri bool hwDmacSrcChainWithStack(DMACh& dma, int id) { return false; } + +/********TADR NOTES*********** +From what i've gathered from testing tadr increment stuff (with CNT) is that we might not be 100% accurate in what +increments it and what doesnt. Previously we presumed REFE and END didn't increment the tag, but SIF and IPU never +liked this. + +From what i've deduced, REFE does in fact increment, but END doesn't, after much testing, i've concluded this is how +we can standardize DMA chains, so i've modified the code to work like this. The below function controls the increment +of the TADR along with the MADR on VIF, GIF and SPR1 when using the CNT tag, the others don't use it yet, but they +can probably be modified to do so now. + +Reason for this:- Many games (such as clock tower 3 and FFX Videos) watched the TADR to see when a transfer has finished, +so we need to simulate this wherever we can! Even the FFX video gets corruption and tries to fire multiple DMA Kicks +if this doesnt happen, which was the reasoning for the hacked up SPR timing we had, that is no longer required. + +-Refraction +******************************/ + +void hwDmacSrcTadrInc(DMACh& dma) +{ + u16 tagid = (dma.chcr.TAG >> 12) & 0x7; + + if(tagid == TAG_CNT) + { + dma.tadr = dma.madr; + } +} bool hwDmacSrcChain(DMACh& dma, int id) { u32 temp; @@ -274,13 +312,14 @@ bool hwDmacSrcChain(DMACh& dma, int id) switch (id) { case TAG_REFE: // Refe - Transfer Packet According to ADDR field + dma.tadr += 16; // End the transfer. return true; case TAG_CNT: // CNT - Transfer QWC following the tag. // Set MADR to QW after the tag, and TADR to QW following the data. dma.madr = dma.tadr + 16; - dma.tadr = dma.madr + (dma.qwc << 4); + dma.tadr = dma.madr; return false; case TAG_NEXT: // Next - Transfer QWC following tag. TADR = ADDR @@ -305,3 +344,4 @@ bool hwDmacSrcChain(DMACh& dma, int id) return false; } + diff --git a/pcsx2/IPU/IPU.cpp b/pcsx2/IPU/IPU.cpp index 0f3c15bc4f..b175067d2f 100644 --- a/pcsx2/IPU/IPU.cpp +++ b/pcsx2/IPU/IPU.cpp @@ -26,6 +26,8 @@ #include "Vif_Dma.h" #include +#include "Utilities/MemsetFast.inl" + // the BP doesn't advance and returns -1 if there is no data to be read __aligned16 tIPU_cmd ipu_cmd; __aligned16 tIPU_BP g_BP; diff --git a/pcsx2/IPU/IPUdma.cpp b/pcsx2/IPU/IPUdma.cpp index 857d3fc922..f430980df5 100644 --- a/pcsx2/IPU/IPUdma.cpp +++ b/pcsx2/IPU/IPUdma.cpp @@ -42,21 +42,6 @@ void SaveStateBase::ipuDmaFreeze() Freeze(IPU1Status); } -static __fi bool ipuDmacPartialChain(tDMA_TAG tag) -{ - switch (tag.ID) - { - case TAG_REFE: // refe - ipu1dma.tadr += 16; - return true; - - case TAG_END: // end - ipu1dma.tadr = ipu1dma.madr; - return true; - } - return false; -} - static __fi void ipuDmacSrcChain() { switch (IPU1Status.ChainMode) @@ -82,7 +67,7 @@ static __fi void ipuDmacSrcChain() break; case TAG_END: // end - ipu1dma.tadr = ipu1dma.madr; + //ipu1dma.tadr = ipu1dma.madr; IPU1Status.DMAFinished = true; break; } @@ -136,15 +121,12 @@ static __fi int IPU1chain() { ipu1dma.qwc -= qwc; totalqwc += qwc; } + + //Update TADR etc + if(IPU1Status.DMAMode == DMA_MODE_CHAIN) ipuDmacSrcChain(); + if( ipu1dma.qwc == 0) - { - //Update TADR etc - if(IPU1Status.DMAMode == DMA_MODE_CHAIN) ipuDmacSrcChain(); - //If the transfer has finished or we have room in the FIFO, schedule to the interrupt code. - - //No data left IPU1Status.InProgress = false; - } //If we still have data the commands should pull this across when need be. return totalqwc; } @@ -238,7 +220,8 @@ int IPU1dma() break; case TAG_CNT: // cnt - ipu1dma.madr = ipu1dma.tadr + 16; + ipu1dma.tadr += 16; + ipu1dma.madr = ipu1dma.tadr; IPU_LOG("Tag should end on %x", ipu1dma.madr + ipu1dma.qwc * 16); //ipu1dma.tadr = ipu1dma.madr + (ipu1dma.qwc * 16); // Set the taddr to the next tag @@ -262,7 +245,7 @@ int IPU1dma() case TAG_END: // end // do not change tadr ipu1dma.madr = ipu1dma.tadr + 16; - ipu1dma.tadr += 16; + //ipu1dma.tadr += 16; IPU_LOG("Tag should end on %x", ipu1dma.madr + ipu1dma.qwc * 16); break; diff --git a/pcsx2/IPU/mpeg2lib/Mpeg.cpp b/pcsx2/IPU/mpeg2lib/Mpeg.cpp index 4a2c3f00d2..f2fd7e3ac8 100644 --- a/pcsx2/IPU/mpeg2lib/Mpeg.cpp +++ b/pcsx2/IPU/mpeg2lib/Mpeg.cpp @@ -33,6 +33,8 @@ #include "Mpeg.h" #include "Vlc.h" +#include "Utilities/MemsetFast.inl" + const int non_linear_quantizer_scale [] = { 0, 1, 2, 3, 4, 5, 6, 7, diff --git a/pcsx2/IPU/mpeg2lib/Mpeg.h b/pcsx2/IPU/mpeg2lib/Mpeg.h index b4741d9574..982007ed6c 100644 --- a/pcsx2/IPU/mpeg2lib/Mpeg.h +++ b/pcsx2/IPU/mpeg2lib/Mpeg.h @@ -24,48 +24,6 @@ #pragma once -#include - -template< typename T > -__noinline void memzero_sse_a( T& dest ) -{ -#define MZFqwc (sizeof(dest)/16) - - C_ASSERT( (sizeof(dest) & 0xf) == 0 ); - - __m128 zeroreg = _mm_setzero_ps(); - - float (*destxmm)[4] = (float(*)[4])&dest; - -#define StoreDestIdx(idx) case idx: _mm_store_ps(&destxmm[idx-1][0], zeroreg) - - switch( MZFqwc & 0x07 ) - { - StoreDestIdx(0x07); - StoreDestIdx(0x06); - StoreDestIdx(0x05); - StoreDestIdx(0x04); - StoreDestIdx(0x03); - StoreDestIdx(0x02); - StoreDestIdx(0x01); - } - - destxmm += (MZFqwc & 0x07); - for( uint i=0; i( psxMemWLUT ); // clears both allocations, RLUT and WLUT - memzero( *iopMem ); // Trick! We're accessing RLUT here through WLUT, since it's the non-const pointer. // So the ones with a 0x2000 prefixed are RLUT tables. @@ -87,15 +104,22 @@ void psxMemReset() //for (i=0; i<0x0008; i++) psxMemWLUT[i + 0xbfc0] = (uptr)&psR[i << 16]; } -void psxMemShutdown() +void iopMemoryReserve::Decommit() { - vtlb_free( iopMem, sizeof(*iopMem) ); - iopMem = NULL; + _parent::Decommit(); safe_aligned_free(psxMemWLUT); psxMemRLUT = NULL; + iopMem = NULL; } +void iopMemoryReserve::Release() +{ + _parent::Release(); + iopMem = NULL; +} + + u8 __fastcall iopMemRead8(u32 mem) { mem &= 0x1fffffff; diff --git a/pcsx2/IopMem.h b/pcsx2/IopMem.h index 3ee0b4cfa6..ae6c6bd6e3 100644 --- a/pcsx2/IopMem.h +++ b/pcsx2/IopMem.h @@ -71,6 +71,7 @@ static __fi u8* iopPhysMem( u32 addr ) #define psxHu16(mem) (*(u16*)&iopHw[(mem) & 0xffff]) #define psxHu32(mem) (*(u32*)&iopHw[(mem) & 0xffff]) +extern void psxMemReserve(); extern void psxMemAlloc(); extern void psxMemReset(); extern void psxMemShutdown(); diff --git a/pcsx2/Linux/LnxHostSys.cpp b/pcsx2/Linux/LnxHostSys.cpp deleted file mode 100644 index 709539334f..0000000000 --- a/pcsx2/Linux/LnxHostSys.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2010 PCSX2 Dev Team - * - * 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. - * - * 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. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "PrecompiledHeader.h" - -#include -#include -#include "Common.h" -#include "System/PageFaultSource.h" - -extern void SignalExit(int sig); - -static const uptr m_pagemask = getpagesize()-1; - -// Linux implementation of SIGSEGV handler. Bind it using sigaction(). -static void SysPageFaultSignalFilter( int signal, siginfo_t *siginfo, void * ) -{ - // Note: Use of most stdio functions isn't safe here. Avoid console logs, - // assertions, file logs, or just about anything else useful. - - Source_PageFault.Dispatch( PageFaultInfo( (uptr)siginfo->si_addr & ~m_pagemask ) ); - - // resumes execution right where we left off (re-executes instruction that - // caused the SIGSEGV). - if( Source_PageFault.WasHandled() ) return; - - // Bad mojo! Completely invalid address. - // Instigate a trap if we're in a debugger, and if not then do a SIGKILL. - - wxTrap(); - if( !IsDebugBuild ) raise( SIGKILL ); -} - -void InstallSignalHandler() -{ - struct sigaction sa; - - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_SIGINFO; - sa.sa_sigaction = SysPageFaultSignalFilter; - sigaction(SIGSEGV, &sa, NULL); -} - -void NTFS_CompressFile( const wxString& file, bool compressStatus ) {} diff --git a/pcsx2/Linux/LnxKeyCodes.cpp b/pcsx2/Linux/LnxKeyCodes.cpp index a98befcb72..d87f7e9efa 100644 --- a/pcsx2/Linux/LnxKeyCodes.cpp +++ b/pcsx2/Linux/LnxKeyCodes.cpp @@ -20,6 +20,8 @@ #include #include +void NTFS_CompressFile( const wxString& file, bool compressStatus ) {} + // Returns a WXK_* keycode, given some kinda GDK input mess! int TranslateGDKtoWXK( u32 keysym ) { diff --git a/pcsx2/Linux/pcsx2.cbp b/pcsx2/Linux/pcsx2.cbp index 56d067c1d6..76feb52187 100644 --- a/pcsx2/Linux/pcsx2.cbp +++ b/pcsx2/Linux/pcsx2.cbp @@ -268,9 +268,7 @@ - - @@ -316,8 +314,6 @@ - - @@ -363,11 +359,10 @@ - - + @@ -421,7 +416,6 @@ - @@ -449,7 +443,6 @@ - @@ -466,7 +459,6 @@ - @@ -572,10 +564,8 @@ - - @@ -647,7 +637,6 @@ - diff --git a/pcsx2/Memory.cpp b/pcsx2/Memory.cpp index 931d7fc17f..beee3cdc40 100644 --- a/pcsx2/Memory.cpp +++ b/pcsx2/Memory.cpp @@ -40,11 +40,12 @@ BIOS #include "IopCommon.h" #include "VUmicro.h" #include "GS.h" -#include "System/PageFaultSource.h" #include "ps2/HwInternal.h" #include "ps2/BiosTools.h" +#include "Utilities/PageFaultSource.h" + #ifdef ENABLECACHE #include "Cache.h" #endif @@ -91,7 +92,6 @@ static vtlbHandler null_handler, tlb_fallback_0, - tlb_fallback_1, tlb_fallback_2, tlb_fallback_3, tlb_fallback_4, @@ -137,9 +137,9 @@ void memMapVUmicro() void memMapPhy() { // Main memory - vtlb_MapBlock(eeMem->Main, 0x00000000,Ps2MemSize::Base);//mirrored on first 256 mb ? + vtlb_MapBlock(eeMem->Main, 0x00000000,Ps2MemSize::MainRam);//mirrored on first 256 mb ? // High memory, uninstalled on the configuration we emulate - vtlb_MapHandler(null_handler, Ps2MemSize::Base, 0x10000000 - Ps2MemSize::Base); + vtlb_MapHandler(null_handler, Ps2MemSize::MainRam, 0x10000000 - Ps2MemSize::MainRam); // Various ROMs (all read-only) vtlb_MapBlock(eeMem->ROM, 0x1fc00000,Ps2MemSize::Rom); @@ -153,14 +153,14 @@ void memMapPhy() vtlb_MapBlock(iopMem->Main,0x1c000000,0x00800000); // Generic Handlers; These fallback to mem* stuff... - vtlb_MapHandler(tlb_fallback_7,0x14000000,0x10000); - vtlb_MapHandler(tlb_fallback_4,0x18000000,0x10000); - vtlb_MapHandler(tlb_fallback_5,0x1a000000,0x10000); - vtlb_MapHandler(tlb_fallback_6,0x12000000,0x10000); - vtlb_MapHandler(tlb_fallback_8,0x1f000000,0x10000); - vtlb_MapHandler(tlb_fallback_3,0x1f400000,0x10000); - vtlb_MapHandler(tlb_fallback_2,0x1f800000,0x10000); - vtlb_MapHandler(tlb_fallback_8,0x1f900000,0x10000); + vtlb_MapHandler(tlb_fallback_7,0x14000000, _64kb); + vtlb_MapHandler(tlb_fallback_4,0x18000000, _64kb); + vtlb_MapHandler(tlb_fallback_5,0x1a000000, _64kb); + vtlb_MapHandler(tlb_fallback_6,0x12000000, _64kb); + vtlb_MapHandler(tlb_fallback_8,0x1f000000, _64kb); + vtlb_MapHandler(tlb_fallback_3,0x1f400000, _64kb); + vtlb_MapHandler(tlb_fallback_2,0x1f800000, _64kb); + vtlb_MapHandler(tlb_fallback_8,0x1f900000, _64kb); // Hardware Register Handlers : specialized/optimized per-page handling of HW register accesses // (note that hw_by_page handles are assigned in memReset prior to calling this function) @@ -186,9 +186,9 @@ void memMapKernelMem() //lower 512 mb: direct map //vtlb_VMap(0x00000000,0x00000000,0x20000000); //0x8* mirror - vtlb_VMap(0x80000000,0x00000000,0x20000000); + vtlb_VMap(0x80000000, 0x00000000, _1mb*512); //0xa* mirror - vtlb_VMap(0xA0000000,0x00000000,0x20000000); + vtlb_VMap(0xA0000000, 0x00000000, _1mb*512); } //what do do with these ? @@ -578,35 +578,15 @@ void memClearPageAddr(u32 vaddr) class mmap_PageFaultHandler : public EventListener_PageFault { -protected: +public: void OnPageFaultEvent( const PageFaultInfo& info, bool& handled ); }; -static mmap_PageFaultHandler mmap_faultHandler; +static mmap_PageFaultHandler* mmap_faultHandler = NULL; EEVM_MemoryAllocMess* eeMem = NULL; - __pagealigned u8 eeHw[Ps2MemSize::Hardware]; -void memAlloc() -{ - if( eeMem == NULL ) - eeMem = (EEVM_MemoryAllocMess*)vtlb_malloc( sizeof(*eeMem), 4096 ); - - if( eeMem == NULL) - throw Exception::OutOfMemory( L"memAlloc > failed to allocate PS2's base ram/rom/scratchpad." ); - - Source_PageFault.Add( mmap_faultHandler ); -} - -void memShutdown() -{ - Source_PageFault.Remove( mmap_faultHandler ); - - vtlb_free( eeMem, sizeof(*eeMem) ); - eeMem = NULL; - vtlb_Term(); -} void memBindConditionalHandlers() { @@ -636,19 +616,44 @@ void memBindConditionalHandlers() } } -// Resets memory mappings, unmaps TLBs, reloads bios roms, etc. -void memReset() + +// -------------------------------------------------------------------------------------- +// eeMemoryReserve (implementations) +// -------------------------------------------------------------------------------------- +eeMemoryReserve::eeMemoryReserve() + : _parent( L"EE Main Memory", sizeof(*eeMem) ) { - // VTLB Protection Preparations. - //HostSys::MemProtect( m_psAllMem, m_allMemSize, Protect_ReadWrite ); +} + +void eeMemoryReserve::Reserve() +{ + _parent::Reserve(HostMemoryMap::EEmem); + //_parent::Reserve(EmuConfig.HostMap.IOP); +} + +void eeMemoryReserve::Commit() +{ + _parent::Commit(); + eeMem = (EEVM_MemoryAllocMess*)m_reserve.GetPtr(); +} + +// Resets memory mappings, unmaps TLBs, reloads bios roms, etc. +void eeMemoryReserve::Reset() +{ + if (!mmap_faultHandler) + { + pxAssume(Source_PageFault); + mmap_faultHandler = new mmap_PageFaultHandler(); + } + + _parent::Reset(); // Note!! Ideally the vtlb should only be initialized once, and then subsequent // resets of the system hardware would only clear vtlb mappings, but since the // rest of the emu is not really set up to support a "soft" reset of that sort // we opt for the hard/safe version. - pxAssume( eeMem != NULL ); - memzero( *eeMem ); + pxAssume( eeMem ); #ifdef ENABLECACHE memset(pCache,0,sizeof(_cacheS)*64); @@ -761,9 +766,24 @@ void memReset() LoadBIOS(); } -////////////////////////////////////////////////////////////////////////////////////////// -// Memory Protection and Block Checking, vtlb Style! -// +void eeMemoryReserve::Decommit() +{ + _parent::Decommit(); + eeMem = NULL; +} + +void eeMemoryReserve::Release() +{ + safe_delete(mmap_faultHandler); + _parent::Release(); + eeMem = NULL; + vtlb_Term(); +} + + +// =========================================================================================== +// Memory Protection and Block Checking, vtlb Style! +// =========================================================================================== // For the first time code is recompiled (executed), the PS2 ram page for that code is // protected using Virtual Memory (mprotect). If the game modifies its own code then this // protection causes an *exception* to be raised (signal in Linux), which is handled by @@ -796,15 +816,17 @@ enum vtlb_ProtectionMode struct vtlb_PageProtectionInfo { - // Ram De-mapping -- used to convert fully translated/mapped offsets into psM back - // into their originating ps2 physical ram address. Values are assigned when pages - // are marked for protection. + // Ram De-mapping -- used to convert fully translated/mapped offsets (which reside with + // in the eeMem->Main block) back into their originating ps2 physical ram address. + // Values are assigned when pages are marked for protection. since pages are automatically + // cleared and reset when TLB-remapped, stale values in this table (due to on-the-fly TLB + // changes) will be re-assigned the next time the page is accessed. u32 ReverseRamMap; vtlb_ProtectionMode Mode; }; -static __aligned16 vtlb_PageProtectionInfo m_PageProtectInfo[Ps2MemSize::Base >> 12]; +static __aligned16 vtlb_PageProtectionInfo m_PageProtectInfo[Ps2MemSize::MainRam >> 12]; // returns: @@ -815,28 +837,33 @@ static __aligned16 vtlb_PageProtectionInfo m_PageProtectInfo[Ps2MemSize::Base >> // int mmap_GetRamPageInfo( u32 paddr ) { + pxAssume( eeMem ); + paddr &= ~0xfff; uptr ptr = (uptr)PSM( paddr ); uptr rampage = ptr - (uptr)eeMem->Main; - if (rampage >= Ps2MemSize::Base) + if (rampage >= Ps2MemSize::MainRam) return -1; //not in ram, no tracking done ... rampage >>= 12; return ( m_PageProtectInfo[rampage].Mode == ProtMode_Manual ) ? 1 : 0; } -// paddr - physically mapped address +// paddr - physically mapped PS2 address void mmap_MarkCountedRamPage( u32 paddr ) { + pxAssume( eeMem ); + paddr &= ~0xfff; uptr ptr = (uptr)PSM( paddr ); int rampage = (ptr - (uptr)eeMem->Main) >> 12; - // Important: reassign paddr here, since TLB changes could alter the paddr->psM mapping - // (and clear blocks accordingly), but don't necessarily clear the protection status. + // Important: Update the ReverseRamMap here because TLB changes could alter the paddr + // mapping into eeMem->Main. + m_PageProtectInfo[rampage].ReverseRamMap = paddr; if( m_PageProtectInfo[rampage].Mode == ProtMode_Write ) @@ -848,7 +875,7 @@ void mmap_MarkCountedRamPage( u32 paddr ) ); m_PageProtectInfo[rampage].Mode = ProtMode_Write; - HostSys::MemProtect( &eeMem->Main[rampage<<12], __pagesize, Protect_ReadOnly ); + HostSys::MemProtect( &eeMem->Main[rampage<<12], __pagesize, PageAccess_ReadOnly() ); } // offset - offset of address relative to psM. @@ -856,6 +883,8 @@ void mmap_MarkCountedRamPage( u32 paddr ) // from code residing in this page will use manual protection. static __fi void mmap_ClearCpuBlock( uint offset ) { + pxAssume( eeMem ); + int rampage = offset >> 12; // Assertion: This function should never be run on a block that's already under @@ -863,16 +892,18 @@ static __fi void mmap_ClearCpuBlock( uint offset ) pxAssertMsg( m_PageProtectInfo[rampage].Mode != ProtMode_Manual, "Attempted to clear a block that is already under manual protection." ); - HostSys::MemProtect( &eeMem->Main[rampage<<12], __pagesize, Protect_ReadWrite ); + HostSys::MemProtect( &eeMem->Main[rampage<<12], __pagesize, PageAccess_ReadWrite() ); m_PageProtectInfo[rampage].Mode = ProtMode_Manual; Cpu->Clear( m_PageProtectInfo[rampage].ReverseRamMap, 0x400 ); } void mmap_PageFaultHandler::OnPageFaultEvent( const PageFaultInfo& info, bool& handled ) { + pxAssume( eeMem ); + // get bad virtual address uptr offset = info.addr - (uptr)eeMem->Main; - if( offset >= Ps2MemSize::Base ) return; + if( offset >= Ps2MemSize::MainRam ) return; mmap_ClearCpuBlock( offset ); handled = true; @@ -886,5 +917,5 @@ void mmap_ResetBlockTracking() { //DbgCon.WriteLn( "vtlb/mmap: Block Tracking reset..." ); memzero( m_PageProtectInfo ); - HostSys::MemProtect( eeMem->Main, Ps2MemSize::Base, Protect_ReadWrite ); + if (eeMem) HostSys::MemProtect( eeMem->Main, Ps2MemSize::MainRam, PageAccess_ReadWrite() ); } diff --git a/pcsx2/Memory.h b/pcsx2/Memory.h index 7a325e1aec..547a9d1d8b 100644 --- a/pcsx2/Memory.h +++ b/pcsx2/Memory.h @@ -24,6 +24,10 @@ #include +// [TODO] This *could* be replaced with an assignment operator on u128 that implicitly +// uses _mm_store and _mm_load internally. However, there are alignment concerns -- +// u128 is not alignment strict. (we would need a u128 and u128a for types known to +// be strictly 128-bit aligned). static __fi void CopyQWC( void* dest, const void* src ) { _mm_store_ps( (float*)dest, _mm_load_ps((const float*)src) ); @@ -103,9 +107,7 @@ static __fi void ZeroQWC( u128& dest ) #define psSu64(mem) (*(u64 *)&eeMem->Scratch[(mem) & 0x3fff]) #define psSu128(mem) (*(u128*)&eeMem->Scratch[(mem) & 0x3fff]) -extern void memAlloc(); -extern void memReset(); // clears PS2 ram and loads the bios. Throws Exception::FileNotFound on error. -extern void memShutdown(); + extern void memSetKernelMode(); //extern void memSetSupervisorMode(); extern void memSetUserMode(); diff --git a/pcsx2/MemoryTypes.h b/pcsx2/MemoryTypes.h index 3ae0c42638..9f13853062 100644 --- a/pcsx2/MemoryTypes.h +++ b/pcsx2/MemoryTypes.h @@ -17,18 +17,18 @@ namespace Ps2MemSize { - static const uint Base = 0x02000000; // 32 MB main memory! - static const uint Rom = 0x00400000; // 4 MB main rom - static const uint Rom1 = 0x00040000; // DVD player - static const uint Rom2 = 0x00080000; // Chinese rom extension (?) - static const uint ERom = 0x001C0000; // DVD player extensions (?) - static const uint Hardware = 0x00010000; - static const uint Scratch = 0x00004000; + static const uint MainRam = _32mb; // 32 MB main memory! + static const uint Rom = _1mb * 4; // 4 MB main rom + static const uint Rom1 = 0x00040000; // DVD player + static const uint Rom2 = 0x00080000; // Chinese rom extension (?) + static const uint ERom = 0x001C0000; // DVD player extensions (?) + static const uint Hardware = _64kb; + static const uint Scratch = _16kb; - static const uint IopRam = 0x00200000; // 2MB main ram on the IOP. - static const uint IopHardware = 0x00010000; + static const uint IopRam = _1mb * 2; // 2MB main ram on the IOP. + static const uint IopHardware = _64kb; - static const uint GSregs = 0x00002000; // 8k for the GS registers and stuff. + static const uint GSregs = 0x00002000; // 8k for the GS registers and stuff. } typedef u8 mem8_t; @@ -53,6 +53,9 @@ typedef u128 mem128_t; // memory, such as hardware registers or scratchpad, the access will generate a page fault, the // compiled block will be cleared and re-compiled using "full" VTLB translation logic. // +// Note that support for this feature may not be doable under x86/32 platforms, due to the +// 2gb/3gb limit of Windows XP (the 3gb feature will make it slightly more feasible at least). +// #define VTLB_UsePageFaulting 0 #if VTLB_UsePageFaulting @@ -61,9 +64,9 @@ typedef u128 mem128_t; // full breadth of PS2 RAM and ROM mappings are directly supported. struct EEVM_MemoryAllocMess { - u8 (&Main)[Ps2MemSize::Base]; // Main memory (hard-wired to 32MB) + u8 (&Main)[Ps2MemSize::MainRam]; // Main memory (hard-wired to 32MB) - u8 _padding1[0x1e000000-Ps2MemSize::Base] + u8 _padding1[0x1e000000-Ps2MemSize::MainRam] u8 (&ROM1)[Ps2MemSize::Rom1]; // DVD player u8 _padding2[0x1e040000-(0x1e000000+Ps2MemSize::Rom1)] @@ -80,8 +83,8 @@ struct EEVM_MemoryAllocMess struct EEVM_MemoryAllocMess { + u8 Main[Ps2MemSize::MainRam]; // Main memory (hard-wired to 32MB) u8 Scratch[Ps2MemSize::Scratch]; // Scratchpad! - u8 Main[Ps2MemSize::Base]; // Main memory (hard-wired to 32MB) u8 ROM[Ps2MemSize::Rom]; // Boot rom (4MB) u8 ROM1[Ps2MemSize::Rom1]; // DVD player u8 ROM2[Ps2MemSize::Rom2]; // Chinese extensions @@ -101,7 +104,7 @@ struct EEVM_MemoryAllocMess struct IopVM_MemoryAllocMess { u8 Main[Ps2MemSize::IopRam]; // Main memory (hard-wired to 2MB) - u8 P[0x00010000]; // I really have no idea what this is... --air + u8 P[_64kb]; // I really have no idea what this is... --air u8 Sif[0x100]; // a few special SIF/SBUS registers (likely not needed) }; diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp index 80c2e5aaad..91e4054d37 100644 --- a/pcsx2/Pcsx2Config.cpp +++ b/pcsx2/Pcsx2Config.cpp @@ -374,6 +374,7 @@ void Pcsx2Config::LoadSave( IniInterface& ini ) IniBitBool( ConsoleToStdio ); IniBitBool( HostFs ); + IniBitBool( BackupSavestate ); IniBitBool( McdEnableEjection ); IniBitBool( MultitapPort0_Enabled ); IniBitBool( MultitapPort1_Enabled ); diff --git a/pcsx2/PluginManager.cpp b/pcsx2/PluginManager.cpp index c9822f1b24..847cbada0d 100644 --- a/pcsx2/PluginManager.cpp +++ b/pcsx2/PluginManager.cpp @@ -674,18 +674,34 @@ SysCorePlugins *g_plugins = NULL; // Plugin-related Exception Implementations // --------------------------------------------------------------------------------- +wxString Exception::SaveStateLoadError::FormatDiagnosticMessage() const +{ + FastFormatUnicode retval; + retval.Write("Savestate is corrupt or incomplete!"); + _formatDiagMsg(retval); + return retval; +} + +wxString Exception::SaveStateLoadError::FormatDisplayMessage() const +{ + FastFormatUnicode retval; + retval.Write(_("The savestate cannot be loaded, as it appears to be corrupt or incomplete.")); + _formatUserMsg(retval); + return retval; +} + Exception::PluginOpenError::PluginOpenError( PluginsEnum_t pid ) { PluginId = pid; m_message_diag = L"%s plugin failed to open!"; - m_message_user = L"%s plugin failed to open. Your computer may have insufficient resources, or incompatible hardware/drivers."; + m_message_user = _("%s plugin failed to open. Your computer may have insufficient resources, or incompatible hardware/drivers."); } Exception::PluginInitError::PluginInitError( PluginsEnum_t pid ) { PluginId = pid; m_message_diag = L"%s plugin initialization failed!"; - m_message_user = L"%s plugin failed to initialize. Your system may have insufficient memory or resources needed."; + m_message_user = _("%s plugin failed to initialize. Your system may have insufficient memory or resources needed."); } Exception::PluginLoadError::PluginLoadError( PluginsEnum_t pid ) @@ -695,29 +711,29 @@ Exception::PluginLoadError::PluginLoadError( PluginsEnum_t pid ) wxString Exception::PluginLoadError::FormatDiagnosticMessage() const { - return wxsFormat( m_message_diag, tbl_PluginInfo[PluginId].GetShortname().c_str() ) + + return pxsFmt( m_message_diag, tbl_PluginInfo[PluginId].GetShortname().c_str() ) + L"\n\n" + StreamName; } wxString Exception::PluginLoadError::FormatDisplayMessage() const { - return wxsFormat( m_message_user, tbl_PluginInfo[PluginId].GetShortname().c_str() ) + + return pxsFmt( m_message_user, tbl_PluginInfo[PluginId].GetShortname().c_str() ) + L"\n\n" + StreamName; } wxString Exception::PluginError::FormatDiagnosticMessage() const { - return wxsFormat( m_message_diag, tbl_PluginInfo[PluginId].GetShortname().c_str() ); + return pxsFmt( m_message_diag, tbl_PluginInfo[PluginId].GetShortname().c_str() ); } wxString Exception::PluginError::FormatDisplayMessage() const { - return wxsFormat( m_message_user, tbl_PluginInfo[PluginId].GetShortname().c_str() ); + return pxsFmt( m_message_user, tbl_PluginInfo[PluginId].GetShortname().c_str() ); } wxString Exception::FreezePluginFailure::FormatDiagnosticMessage() const { - return wxsFormat( + return pxsFmt( L"%s plugin returned an error while saving the state.\n\n", tbl_PluginInfo[PluginId].shortname ); @@ -731,7 +747,7 @@ wxString Exception::FreezePluginFailure::FormatDisplayMessage() const wxString Exception::ThawPluginFailure::FormatDiagnosticMessage() const { - return wxsFormat( + return pxsFmt( L"%s plugin returned an error while loading the state.\n\n", tbl_PluginInfo[PluginId].shortname ); @@ -1262,7 +1278,7 @@ void SysCorePlugins::Init( PluginsEnum_t pid ) if( !m_info[pid] || m_info[pid]->IsInitialized ) return; Console.Indent().WriteLn( "Init %s", tbl_PluginInfo[pid].shortname ); - if( NULL != m_info[pid]->CommonBindings.Init() ) + if( 0 != m_info[pid]->CommonBindings.Init() ) throw Exception::PluginInitError( pid ); m_info[pid]->IsInitialized = true; diff --git a/pcsx2/Plugins.h b/pcsx2/Plugins.h index fd2443874b..80b445a730 100644 --- a/pcsx2/Plugins.h +++ b/pcsx2/Plugins.h @@ -57,12 +57,15 @@ namespace Exception // Exception thrown when a corrupted or truncated savestate is encountered. class SaveStateLoadError : public BadStream { - DEFINE_STREAM_EXCEPTION( SaveStateLoadError, BadStream, wxLt("The savestate appears to be corrupt or incomplete.") ) + DEFINE_STREAM_EXCEPTION( SaveStateLoadError, BadStream ) + + virtual wxString FormatDiagnosticMessage() const; + virtual wxString FormatDisplayMessage() const; }; class PluginError : public RuntimeError { - DEFINE_RUNTIME_EXCEPTION( PluginError, RuntimeError, L"Generic plugin error") + DEFINE_RUNTIME_EXCEPTION( PluginError, RuntimeError, L"Generic plugin error!" ) public: PluginsEnum_t PluginId; diff --git a/pcsx2/PrecompiledHeader.h b/pcsx2/PrecompiledHeader.h index c8bdcffc83..5788d481cd 100644 --- a/pcsx2/PrecompiledHeader.h +++ b/pcsx2/PrecompiledHeader.h @@ -102,14 +102,9 @@ typedef int BOOL; typedef void FnType_Void(); typedef FnType_Void* Fnptr_Void; -static const s64 _1mb = 0x100000; -static const s64 _8mb = _1mb * 8; -static const s64 _16mb = _1mb * 16; -static const s64 _256mb = _1mb * 256; -static const s64 _1gb = _256mb * 4; - -////////////////////////////////////////////////////////////////////////////////////////// -// Compiler/OS specific macros and defines -- Begin Section +// -------------------------------------------------------------------------------------- +// Compiler/OS specific macros and defines +// -------------------------------------------------------------------------------------- // Linux isn't set up for svn version numbers yet. #ifdef __LINUX__ diff --git a/pcsx2/R3000A.h b/pcsx2/R3000A.h index 62b6e6af71..143abc101a 100644 --- a/pcsx2/R3000A.h +++ b/pcsx2/R3000A.h @@ -178,16 +178,20 @@ extern bool iopEventTestIsActive; // Branching status used when throwing exceptions. extern bool iopIsDelaySlot; -//////////////////////////////////////////////////////////////////// -// R3000A Public Interface / API +// -------------------------------------------------------------------------------------- +// R3000Acpu +// -------------------------------------------------------------------------------------- struct R3000Acpu { - void (*Allocate)(); + void (*Reserve)(); void (*Reset)(); void (*Execute)(); s32 (*ExecuteBlock)( s32 eeCycles ); // executes the given number of EE cycles. void (*Clear)(u32 Addr, u32 Size); void (*Shutdown)(); + + uint (*GetCacheReserve)(); + void (*SetCacheReserve)( uint reserveInMegs ); }; extern R3000Acpu *psxCpu; diff --git a/pcsx2/R3000AInterpreter.cpp b/pcsx2/R3000AInterpreter.cpp index 106ae9ed8c..1722932123 100644 --- a/pcsx2/R3000AInterpreter.cpp +++ b/pcsx2/R3000AInterpreter.cpp @@ -150,10 +150,14 @@ static void doBranch(s32 tar) { iopEventTest(); } +static void intReserve() { +} + static void intAlloc() { } static void intReset() { + intAlloc(); } static void intExecute() { @@ -180,11 +184,23 @@ static void intClear(u32 Addr, u32 Size) { static void intShutdown() { } +static void intSetCacheReserve( uint reserveInMegs ) +{ +} + +static uint intGetCacheReserve() +{ + return 0; +} + R3000Acpu psxInt = { - intAlloc, + intReserve, intReset, intExecute, intExecuteBlock, intClear, - intShutdown + intShutdown, + + intGetCacheReserve, + intSetCacheReserve }; diff --git a/pcsx2/R5900.cpp b/pcsx2/R5900.cpp index 6c5d915256..4ac9680a29 100644 --- a/pcsx2/R5900.cpp +++ b/pcsx2/R5900.cpp @@ -32,7 +32,6 @@ #include "CDVD/CDVD.h" #include "Patch.h" #include "GameDatabase.h" -#include "SamplProf.h" using namespace R5900; // for R5900 disasm tools @@ -51,14 +50,14 @@ static const uint eeWaitCycles = 3072; bool eeEventTestIsActive = false; +extern SysMainMemory& GetVmMemory(); + void cpuReset() { - if( GetMTGS().IsOpen() ) + if (GetMTGS().IsOpen()) GetMTGS().WaitGS(); // GS better be done processing before we reset the EE, just in case. - memReset(); - psxMemReset(); - vuMicroMemReset(); + GetVmMemory().ResetAll(); memzero(cpuRegs); memzero(fpuRegs); diff --git a/pcsx2/R5900.h b/pcsx2/R5900.h index d865a3b2a8..227bc9018f 100644 --- a/pcsx2/R5900.h +++ b/pcsx2/R5900.h @@ -273,25 +273,25 @@ extern void __fastcall eeloadReplaceOSDSYS(); struct R5900cpu { // Memory allocation function, for allocating virtual memory spaces needed by - // the emulator. (ints/recs are free to allocate additional memory while running - // code, however any virtual mapped memory should always be allocated as soon - // as possible, to claim the memory before some plugin does..) - // + // the virtual cpu provider. Allocating additional heap memory from this method is + // NOT recommended. Heap allocations should be performed by Reset only. This + // maximizes the likeliness of reservations claiming addresses they prefer. + // // Thread Affinity: - // Can be called from any thread. Execute status must be suspended or stopped - // to prevent multi-thread race conditions. + // Called from the main/UI thread only. Cpu execution status is guaranteed to + // be inactive. No locking is necessary. // // Exception Throws: + // HardwareDeficiency - The host machine's hardware does not support this CPU provider. // OutOfMemory - Not enough memory, or the memory areas required were already // reserved. - // - void (*Allocate)(); + void (*Reserve)(); - // Deallocates ram allocated by Allocate and/or by runtime code execution. + // Deallocates ram allocated by Allocate, Reserve, and/or by runtime code execution. // // Thread Affinity: - // Can be called from any thread. Execute status must be suspended or stopped - // to prevent multi-thread race conditions. + // Called from the main/UI thread only. Cpu execution status is guaranteed to + // be inactive. No locking is necessary. // // Exception Throws: None. This function is a destructor, and should not throw. // @@ -302,8 +302,10 @@ struct R5900cpu // rely on the CPU/VM states almost entirely. // // Thread Affinity: - // Can be called from any thread. Execute status must be suspended or stopped - // to prevent multi-thread race conditions. + // Can be called from any thread. CPU execution status is indeterminate and may + // already be in progress. Implementations should be sure to queue and execute + // resets at the earliest safe convenience (typically right before recompiling a + // new block of code, or after a vsync event). // // Exception Throws: Emulator-defined. Common exception types to expect are // OutOfMemory, Stream Exceptions @@ -365,7 +367,7 @@ struct R5900cpu // better off replaced with some generic API callbacks from VTLB block protection. // Also: the calls from COP0's TLB remap code should be replaced with full recompiler // resets, since TLB remaps affect more than just the code they contain (code that - // may reference the remaped blocks via memory loads/stores, for example). + // may reference the remapped blocks via memory loads/stores, for example). // // Thread Affinity Rule: // Can be called from any thread (namely for being called from debugging threads) @@ -374,6 +376,9 @@ struct R5900cpu // doesn't matter if we're stripping it out soon. ;) // void (*Clear)(u32 Addr, u32 Size); + + uint (*GetCacheReserve)(); + void (*SetCacheReserve)( uint reserveInMegs ); }; extern R5900cpu *Cpu; diff --git a/pcsx2/SPR.cpp b/pcsx2/SPR.cpp index 5ea0243ae9..3164661e0a 100644 --- a/pcsx2/SPR.cpp +++ b/pcsx2/SPR.cpp @@ -86,7 +86,7 @@ int _SPR0chain() __fi void SPR0chain() { - CPU_INT(DMAC_FROM_SPR, _SPR0chain() / BIAS); + CPU_INT(DMAC_FROM_SPR, _SPR0chain() * BIAS); spr0ch.qwc = 0; } @@ -102,7 +102,7 @@ void _SPR0interleave() SPR_LOG("SPR0 interleave size=%d, tqwc=%d, sqwc=%d, addr=%lx sadr=%lx", spr0ch.qwc, tqwc, sqwc, spr0ch.madr, spr0ch.sadr); - CPU_INT(DMAC_FROM_SPR, qwc / BIAS); + CPU_INT(DMAC_FROM_SPR, qwc * BIAS); while (qwc > 0) { @@ -290,13 +290,14 @@ int _SPR1chain() SPR1transfer(pMem, spr1ch.qwc); spr1ch.madr += spr1ch.qwc * 16; + hwDmacSrcTadrInc(spr1ch); return (spr1ch.qwc); } __fi void SPR1chain() { - CPU_INT(DMAC_TO_SPR, _SPR1chain() / BIAS); + CPU_INT(DMAC_TO_SPR, _SPR1chain() * BIAS); spr1ch.qwc = 0; } @@ -310,7 +311,7 @@ void _SPR1interleave() if (tqwc == 0) tqwc = qwc; SPR_LOG("SPR1 interleave size=%d, tqwc=%d, sqwc=%d, addr=%lx sadr=%lx", spr1ch.qwc, tqwc, sqwc, spr1ch.madr, spr1ch.sadr); - CPU_INT(DMAC_TO_SPR, qwc / BIAS); + CPU_INT(DMAC_TO_SPR, qwc * BIAS); while (qwc > 0) { spr1ch.qwc = std::min(tqwc, qwc); diff --git a/pcsx2/SamplProf.h b/pcsx2/SamplProf.h index 5ad112293d..7fa918d7c6 100644 --- a/pcsx2/SamplProf.h +++ b/pcsx2/SamplProf.h @@ -30,6 +30,10 @@ void ProfilerRegisterSource(const char* Name, const void* buff, u32 sz); void ProfilerRegisterSource(const char* Name, const void* function); void ProfilerTerminateSource( const char* Name ); +void ProfilerRegisterSource(const wxString& Name, const void* buff, u32 sz); +void ProfilerRegisterSource(const wxString& Name, const void* function); +void ProfilerTerminateSource( const wxString& Name ); + #else // Disables the profiler in Debug & Linux builds. diff --git a/pcsx2/SaveState.cpp b/pcsx2/SaveState.cpp index 767830000f..c9a547942e 100644 --- a/pcsx2/SaveState.cpp +++ b/pcsx2/SaveState.cpp @@ -48,7 +48,7 @@ static void PostLoadPrep() wxString SaveStateBase::GetFilename( int slot ) { return (g_Conf->Folders.Savestates + - wxsFormat( L"%8.8X.%3.3d", ElfCRC, slot )).GetFullPath(); + pxsFmt( L"%08X.%03d", ElfCRC, slot )).GetFullPath(); } SaveStateBase::SaveStateBase( SafeArray& memblock ) @@ -142,7 +142,7 @@ void SaveStateBase::FreezeBios() } static const int MainMemorySizeInBytes = - Ps2MemSize::Base + Ps2MemSize::Scratch + Ps2MemSize::Hardware + + Ps2MemSize::MainRam + Ps2MemSize::Scratch + Ps2MemSize::Hardware + Ps2MemSize::IopRam + Ps2MemSize::IopHardware + 0x0100; void SaveStateBase::FreezeMainMemory() @@ -152,7 +152,7 @@ void SaveStateBase::FreezeMainMemory() // First Block - Memory Dumps // --------------------------- - FreezeMem(eeMem->Main, Ps2MemSize::Base); // 32 MB main memory + FreezeMem(eeMem->Main, Ps2MemSize::MainRam); // 32 MB main memory FreezeMem(eeMem->Scratch, Ps2MemSize::Scratch); // scratch pad FreezeMem(eeHw, Ps2MemSize::Hardware); // hardware memory diff --git a/pcsx2/Sif1.cpp b/pcsx2/Sif1.cpp index 67fb0148e5..e8f7fdc3cd 100644 --- a/pcsx2/Sif1.cpp +++ b/pcsx2/Sif1.cpp @@ -52,6 +52,7 @@ static __fi bool WriteEEtoFifo() sif1.fifo.write((u32*)ptag, writeSize << 2); sif1dma.madr += writeSize << 4; + hwDmacSrcTadrInc(sif1dma); sif1.ee.cycles += writeSize; // fixme : BIAS is factored in above sif1dma.qwc -= writeSize; @@ -114,8 +115,8 @@ static __fi bool ProcessEETag() break; case TAG_CNT: - sif1dma.madr = sif1dma.tadr + 16; - sif1dma.tadr = sif1dma.madr + (sif1dma.qwc << 4); + sif1dma.tadr += 16; + sif1dma.madr = sif1dma.tadr; break; case TAG_NEXT: @@ -132,7 +133,7 @@ static __fi bool ProcessEETag() case TAG_END: sif1.ee.end = true; sif1dma.madr = sif1dma.tadr + 16; - sif1dma.tadr = sif1dma.madr + (sif1dma.qwc << 4); + //sif1dma.tadr = sif1dma.madr + (sif1dma.qwc << 4); break; default: diff --git a/pcsx2/System.cpp b/pcsx2/System.cpp index 93779a3d99..eb3dd07a3a 100644 --- a/pcsx2/System.cpp +++ b/pcsx2/System.cpp @@ -16,44 +16,144 @@ #include "PrecompiledHeader.h" #include "Common.h" #include "IopCommon.h" +#include "VUmicro.h" +#include "newVif.h" -#include "System/PageFaultSource.h" -#include "Utilities/EventSource.inl" +#include "SamplProf.h" // Includes needed for cleanup, since we don't have a good system (yet) for // cleaning up these things. -#include "sVU_zerorec.h" #include "GameDatabase.h" #include "Elfheader.h" -extern void closeNewVif(int idx); -extern void resetNewVif(int idx); +#include "System/RecTypes.h" -template class EventSource< IEventListener_PageFault >; +#include "Utilities/MemsetFast.inl" -SrcType_PageFault Source_PageFault; -EventListener_PageFault::EventListener_PageFault() +// -------------------------------------------------------------------------------------- +// RecompiledCodeReserve (implementations) +// -------------------------------------------------------------------------------------- + +// Constructor! +// Parameters: +// name - a nice long name that accurately describes the contents of this reserve. +RecompiledCodeReserve::RecompiledCodeReserve( const wxString& name, uint defCommit ) + : BaseVmReserveListener( name ) { - Source_PageFault.Add( *this ); + m_blocksize = (1024 * 128) / __pagesize; + m_prot_mode = PageAccess_Any(); + m_def_commit = defCommit / __pagesize; + + m_profiler_registered = false; } -EventListener_PageFault::~EventListener_PageFault() throw() +RecompiledCodeReserve::~RecompiledCodeReserve() throw() { - Source_PageFault.Remove( *this ); + _termProfiler(); } -void SrcType_PageFault::Dispatch( const PageFaultInfo& params ) +void RecompiledCodeReserve::_registerProfiler() { - m_handled = false; - _parent::Dispatch( params ); + if (m_profiler_name.IsEmpty() || !IsOk()) return; + ProfilerRegisterSource( m_profiler_name, m_baseptr, GetReserveSizeInBytes() ); + m_profiler_registered = true; } -void SrcType_PageFault::_DispatchRaw( ListenerIterator iter, const ListenerIterator& iend, const PageFaultInfo& evt ) +void RecompiledCodeReserve::_termProfiler() { - do { - (*iter)->DispatchEvent( evt, m_handled ); - } while( (++iter != iend) && !m_handled ); + if (m_profiler_registered) + ProfilerTerminateSource( m_profiler_name ); +} + +uint RecompiledCodeReserve::_calcDefaultCommitInBlocks() const +{ + return (m_def_commit + m_blocksize - 1) / m_blocksize; +} + +void* RecompiledCodeReserve::Reserve( size_t size, uptr base, uptr upper_bounds ) +{ + if (!_parent::Reserve(size, base, upper_bounds)) return NULL; + _registerProfiler(); + return m_baseptr; +} + + +// Sets the abbreviated name used by the profiler. Name should be under 10 characters long. +// After a name has been set, a profiler source will be automatically registered and cleared +// in accordance with changes in the reserve area. +RecompiledCodeReserve& RecompiledCodeReserve::SetProfilerName( const wxString& shortname ) +{ + m_profiler_name = shortname; + _registerProfiler(); + return *this; +} + +void RecompiledCodeReserve::DoCommitAndProtect( uptr page ) +{ + CommitBlocks(page, (m_pages_commited || !m_def_commit) ? 1 : _calcDefaultCommitInBlocks() ); +} + +void RecompiledCodeReserve::OnCommittedBlock( void* block ) +{ + if (IsDevBuild) + { + // Clear the recompiled code block to 0xcc (INT3) -- this helps disasm tools show + // the assembly dump more cleanly. We don't clear the block on Release builds since + // it can add a noticeable amount of overhead to large block recompilations. + + memset_sse_a<0xcc>( block, m_blocksize * __pagesize ); + } +} + +// This error message is shared by R5900, R3000, and microVU recompilers. It is not used by the +// SuperVU recompiler, since it has its own customized message. +void RecompiledCodeReserve::ThrowIfNotOk() const +{ + if (IsOk()) return; + + throw Exception::OutOfMemory(m_name) + .SetDiagMsg(pxsFmt( L"Recompiled code cache could not be mapped." )) + .SetUserMsg( pxE( ".Error:Recompiler:VirtualMemoryAlloc", + L"This recompiler was unable to reserve contiguous memory required for internal caches. " + L"This error can be caused by low virtual memory resources, such as a small or disabled swapfile, " + L"or by another program that is hogging a lot of memory. You can also try reducing the default " + L"cache sizes for all PCSX2 recompilers, found under Host Settings." + )); +} + + +void SysOutOfMemory_EmergencyResponse(uptr blocksize) +{ + // An out of memory error occurred. All we can try to do in response is reset the various + // recompiler caches (which can sometimes total over 120megs, so it can be quite helpful). + // If the user is using interpreters, or if the memory allocation failure was on a very small + // allocation, then this code could fail; but that's fine. We're already trying harder than + // 99.995% of all programs ever written. -- air + + if (Cpu) + { + Cpu->SetCacheReserve( (Cpu->GetCacheReserve() * 3) / 2 ); + Cpu->Reset(); + } + + if (CpuVU0) + { + CpuVU0->SetCacheReserve( (CpuVU0->GetCacheReserve() * 3) / 2 ); + CpuVU0->Reset(); + } + + if (CpuVU1) + { + CpuVU1->SetCacheReserve( (CpuVU1->GetCacheReserve() * 3) / 2 ); + CpuVU1->Reset(); + } + + if (psxCpu) + { + psxCpu->SetCacheReserve( (psxCpu->GetCacheReserve() * 3) / 2 ); + psxCpu->Reset(); + } } @@ -190,7 +290,7 @@ CpuInitializer< CpuType >::CpuInitializer() { try { MyCpu = new CpuType(); - MyCpu->Allocate(); + MyCpu->Reserve(); } catch( Exception::RuntimeError& ex ) { @@ -209,7 +309,7 @@ CpuInitializer< CpuType >::CpuInitializer() template< typename CpuType > CpuInitializer< CpuType >::~CpuInitializer() throw() { - if( MyCpu ) + if (MyCpu) MyCpu->Shutdown(); } @@ -246,96 +346,128 @@ static wxString GetMemoryErrorVM() } // -------------------------------------------------------------------------------------- -// SysAllocVM (implementations) +// SysReserveVM (implementations) // -------------------------------------------------------------------------------------- -SysAllocVM::SysAllocVM() +SysMainMemory::SysMainMemory() { - InstallSignalHandler(); - - Console.WriteLn( "Allocating memory for the PS2 virtual machine..." ); - - try - { - vtlb_Core_Alloc(); - memAlloc(); - psxMemAlloc(); - vuMicroMemAlloc(); - } - // ---------------------------------------------------------------------------- - catch( Exception::OutOfMemory& ex ) - { - ex.UserMsg() += L"\n\n" + GetMemoryErrorVM(); - CleanupMess(); - throw; - } - catch( std::bad_alloc& ex ) - { - CleanupMess(); - - // re-throw std::bad_alloc as something more friendly. This is needed since - // much of the code uses new/delete internally, which throw std::bad_alloc on fail. - - throw Exception::OutOfMemory() - .SetDiagMsg( - L"std::bad_alloc caught while trying to allocate memory for the PS2 Virtual Machine.\n" - L"Error Details: " + fromUTF8( ex.what() ) - ) - .SetUserMsg(GetMemoryErrorVM()); // translated - } } -void SysAllocVM::CleanupMess() throw() +SysMainMemory::~SysMainMemory() throw() { - try - { - vuMicroMemShutdown(); - psxMemShutdown(); - memShutdown(); - vtlb_Core_Shutdown(); - } - DESTRUCTOR_CATCHALL + ReleaseAll(); } -SysAllocVM::~SysAllocVM() throw() +void SysMainMemory::ReserveAll() { - CleanupMess(); + pxInstallSignalHandler(); + + DevCon.WriteLn( Color_StrongBlue, "Mapping host memory for virtual systems..." ); + ConsoleIndentScope indent(1); + + m_ee.Reserve(); + m_iop.Reserve(); + m_vu.Reserve(); + + reserveNewVif(0); + reserveNewVif(1); } +void SysMainMemory::CommitAll() +{ + vtlb_Core_Alloc(); + if (m_ee.IsCommitted() && m_iop.IsCommitted() && m_vu.IsCommitted()) return; + + DevCon.WriteLn( Color_StrongBlue, "Allocating host memory for virtual systems..." ); + ConsoleIndentScope indent(1); + + m_ee.Commit(); + m_iop.Commit(); + m_vu.Commit(); +} + + +void SysMainMemory::ResetAll() +{ + CommitAll(); + + DevCon.WriteLn( Color_StrongBlue, "Resetting host memory for virtual systems..." ); + ConsoleIndentScope indent(1); + + m_ee.Reset(); + m_iop.Reset(); + m_vu.Reset(); + + // Note: newVif is reset as part of other VIF structures. +} + +void SysMainMemory::DecommitAll() +{ + if (!m_ee.IsCommitted() && !m_iop.IsCommitted() && !m_vu.IsCommitted()) return; + + Console.WriteLn( Color_Blue, "Decommitting host memory for virtual systems..." ); + ConsoleIndentScope indent(1); + + m_ee.Decommit(); + m_iop.Decommit(); + m_vu.Decommit(); + + closeNewVif(0); + closeNewVif(1); + + vtlb_Core_Free(); +} + +void SysMainMemory::ReleaseAll() +{ + DecommitAll(); + + Console.WriteLn( Color_Blue, "Releasing host memory maps for virtual systems..." ); + ConsoleIndentScope indent(1); + + vtlb_Core_Free(); // Just to be sure... (calling order could result in it getting missed during Decommit). + + releaseNewVif(0); + releaseNewVif(1); + + m_ee.Decommit(); + m_iop.Decommit(); + m_vu.Decommit(); + + safe_delete(Source_PageFault); +} + + // -------------------------------------------------------------------------------------- // SysCpuProviderPack (implementations) // -------------------------------------------------------------------------------------- SysCpuProviderPack::SysCpuProviderPack() { - Console.WriteLn( "Allocating memory for recompilers..." ); + Console.WriteLn( Color_StrongBlue, "Reserving memory for recompilers..." ); + ConsoleIndentScope indent(1); CpuProviders = new CpuInitializerSet(); try { - recCpu.Allocate(); + recCpu.Reserve(); } catch( Exception::RuntimeError& ex ) { m_RecExceptionEE = ex.Clone(); - Console.Error( L"EE Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() ); + Console.Error( L"EE Recompiler Reservation Failed:\n" + ex.FormatDiagnosticMessage() ); recCpu.Shutdown(); } try { - psxRec.Allocate(); + psxRec.Reserve(); } catch( Exception::RuntimeError& ex ) { m_RecExceptionIOP = ex.Clone(); - Console.Error( L"IOP Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() ); + Console.Error( L"IOP Recompiler Reservation Failed:\n" + ex.FormatDiagnosticMessage() ); psxRec.Shutdown(); } // hmm! : VU0 and VU1 pre-allocations should do sVU and mVU separately? Sounds complicated. :( - - // If both VUrecs failed, then make sure the SuperVU is totally closed out, because it - // actually initializes everything once and then shares it between both VU recs. - if( !IsRecAvailable_SuperVU0() && !IsRecAvailable_SuperVU1() ) - SuperVUDestroy( -1 ); } bool SysCpuProviderPack::IsRecAvailable_MicroVU0() const { return CpuProviders->microVU0.IsAvailable(); } @@ -353,12 +485,6 @@ void SysCpuProviderPack::CleanupMess() throw() { try { - closeNewVif(0); - closeNewVif(1); - - // Special SuperVU "complete" terminator (stupid hacky recompiler) - SuperVUDestroy( -1 ); - psxRec.Shutdown(); recCpu.Shutdown(); } @@ -418,15 +544,13 @@ void SysClearExecutionCache() { GetCpuProviders().ApplyConfig(); - // SuperVUreset will do nothing is none of the recs are initialized. - // But it's needed if one or the other is initialized. - SuperVUReset(-1); - Cpu->Reset(); psxCpu->Reset(); - // mVU's VU0 needs to be properly initialised for macro mode even if it's not used for micro mode! + + // mVU's VU0 needs to be properly initialized for macro mode even if it's not used for micro mode! if (CHECK_EEREC) ((BaseVUmicroCPU*)GetCpuProviders().CpuProviders->microVU0)->Reset(); + CpuVU0->Reset(); CpuVU1->Reset(); @@ -444,19 +568,17 @@ u8* SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller) if( (Mem == NULL) || (bounds != 0 && (((uptr)Mem + size) > bounds)) ) { - if( base != NULL ) + if( base ) { DbgCon.Warning( "First try failed allocating %s at address 0x%x", caller, base ); - // memory allocation *must* have the top bit clear, so let's try again - // with NULL (let the OS pick something for us). - + // Let's try again at an OS-picked memory area, and then hope it meets needed + // boundschecking criteria below. SafeSysMunmap( Mem, size ); - - Mem = (u8*)HostSys::Mmap( NULL, size ); + Mem = (u8*)HostSys::Mmap( 0, size ); } - if( bounds != 0 && (((uptr)Mem + size) > bounds) ) + if( (bounds != 0) && (((uptr)Mem + size) > bounds) ) { DevCon.Warning( "Second try failed allocating %s, block ptr 0x%x does not meet required criteria.", caller, Mem ); SafeSysMunmap( Mem, size ); @@ -481,5 +603,5 @@ wxString SysGetDiscID() // region and revision). } - return wxsFormat( L"%8.8x", ElfCRC ); + return pxsFmt( L"%08x", ElfCRC ); } diff --git a/pcsx2/System.h b/pcsx2/System.h index 1df237c4ba..43159f08d3 100644 --- a/pcsx2/System.h +++ b/pcsx2/System.h @@ -21,8 +21,81 @@ #include "Utilities/Threading.h" // to use threading stuff, include the Threading namespace in your file. #include "CDVD/CDVDaccess.h" +#include "vtlb.h" + typedef SafeArray VmStateBuffer; + class BaseVUmicroCPU; +class RecompiledCodeReserve; + +// This is a table of default virtual map addresses for ps2vm components. These locations +// are provided and used to assist in debugging and possibly hacking; as it makes it possible +// for a programmer to know exactly where to look (consistently!) for the base address of +// the various virtual machine components. These addresses can be keyed directly into the +// debugger's disasm window to get disassembly of recompiled code, and they can be used to help +// identify recompiled code addresses in the callstack. + +// All of these areas should be reserved as soon as possible during program startup, and its +// important that none of the areas overlap. In all but superVU's case, failure due to overlap +// or other conflict will result in the operating system picking a preferred address for the mapping. + +namespace HostMemoryMap +{ + // superVU is OLD SCHOOL, and it requires its allocation to be in the lower 256mb + // of the virtual memory space. (8mb each) + static const uptr sVU0rec = _256mb - (_8mb*3); + static const uptr sVU1rec = _256mb - (_8mb*2); + + // PS2 main memory, SPR, and ROMs + static const uptr EEmem = 0x20000000; + + // IOP main memory and ROMs + static const uptr IOPmem = 0x24000000; + + // VU0 and VU1 memory. + static const uptr VUmem = 0x28000000; + + // EE recompiler code cache area (64mb) + static const uptr EErec = 0x30000000; + + // IOP recompiler code cache area (16 or 32mb) + static const uptr IOPrec = 0x34000000; + + // newVif0 recompiler code cache area (16mb) + static const uptr VIF0rec = 0x36000000; + + // newVif1 recompiler code cache area (32mb) + static const uptr VIF1rec = 0x38000000; + + // microVU1 recompiler code cache area (32 or 64mb) + static const uptr mVU0rec = 0x3C000000; + + // microVU0 recompiler code cache area (64mb) + static const uptr mVU1rec = 0x40000000; + +} + +// -------------------------------------------------------------------------------------- +// SysMainMemory +// -------------------------------------------------------------------------------------- +// This class provides the main memory for the virtual machines. +class SysMainMemory +{ +protected: + eeMemoryReserve m_ee; + iopMemoryReserve m_iop; + vuMemoryReserve m_vu; + +public: + SysMainMemory(); + virtual ~SysMainMemory() throw(); + + virtual void ReserveAll(); + virtual void CommitAll(); + virtual void ResetAll(); + virtual void DecommitAll(); + virtual void ReleaseAll(); +}; // -------------------------------------------------------------------------------------- // SysAllocVM @@ -83,6 +156,7 @@ extern SysCpuProviderPack& GetCpuProviders(); extern void SysLogMachineCaps(); // Detects cpu type and fills cpuInfo structs. extern void SysClearExecutionCache(); // clears recompiled execution caches! +extern void SysOutOfMemory_EmergencyResponse(uptr blocksize); extern u8 *SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller="Unnamed"); extern void vSyncDebugStuff( uint frame ); @@ -90,6 +164,8 @@ extern void NTFS_CompressFile( const wxString& file, bool compressStatus=true ); extern wxString SysGetDiscID(); +extern SysMainMemory& GetVmMemory(); + // -------------------------------------------------------------------------------------- // PCSX2_SEH - Defines existence of "built in" Structured Exception Handling support. // -------------------------------------------------------------------------------------- diff --git a/pcsx2/System/PageFaultSource.h b/pcsx2/System/PageFaultSource.h deleted file mode 100644 index 46fd059772..0000000000 --- a/pcsx2/System/PageFaultSource.h +++ /dev/null @@ -1,107 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2010 PCSX2 Dev Team - * - * 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. - * - * 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. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#pragma once - -// ===================================================================================================== -// Cross-Platform Memory Protection (Used by VTLB, Recompilers and Texture caches) -// ===================================================================================================== -// Win32 platforms use the SEH model: __try {} __except {} -// Linux platforms use the POSIX Signals model: sigaction() - -#include "Utilities/EventSource.h" - -struct PageFaultInfo -{ - uptr addr; - - PageFaultInfo( uptr address ) - { - addr = address; - } -}; - -// -------------------------------------------------------------------------------------- -// IEventListener_PageFault -// -------------------------------------------------------------------------------------- -class IEventListener_PageFault : public IEventDispatcher -{ -public: - typedef PageFaultInfo EvtParams; - -public: - virtual ~IEventListener_PageFault() throw() {} - - virtual void DispatchEvent( const PageFaultInfo& evtinfo, bool& handled ) - { - OnPageFaultEvent( evtinfo, handled ); - } - - virtual void DispatchEvent( const PageFaultInfo& evtinfo ) - { - pxFailRel( "Don't call me, damnit. Use DispatchException instead." ); - } - -protected: - virtual void OnPageFaultEvent( const PageFaultInfo& evtinfo, bool& handled ) {} -}; - -class EventListener_PageFault : public IEventListener_PageFault -{ -public: - EventListener_PageFault(); - virtual ~EventListener_PageFault() throw(); -}; - -class SrcType_PageFault : public EventSource -{ -protected: - typedef EventSource _parent; - -protected: - bool m_handled; - -public: - SrcType_PageFault() {} - virtual ~SrcType_PageFault() throw() { } - - bool WasHandled() const { return m_handled; } - virtual void Dispatch( const PageFaultInfo& params ); - -protected: - virtual void _DispatchRaw( ListenerIterator iter, const ListenerIterator& iend, const PageFaultInfo& evt ); -}; - -#ifdef __LINUX__ - -# define PCSX2_PAGEFAULT_PROTECT -# define PCSX2_PAGEFAULT_EXCEPT - -#elif defined( _WIN32 ) - -struct _EXCEPTION_POINTERS; -extern int SysPageFaultExceptionFilter(struct _EXCEPTION_POINTERS* eps); - -# define PCSX2_PAGEFAULT_PROTECT __try -# define PCSX2_PAGEFAULT_EXCEPT __except(SysPageFaultExceptionFilter(GetExceptionInformation())) {} - -#else -# error PCSX2 - Unsupported operating system platform. -#endif - - -extern void InstallSignalHandler(); - -extern SrcType_PageFault Source_PageFault; diff --git a/pcsx2/System/RecTypes.h b/pcsx2/System/RecTypes.h new file mode 100644 index 0000000000..29ff43ef78 --- /dev/null +++ b/pcsx2/System/RecTypes.h @@ -0,0 +1,68 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2010 PCSX2 Dev Team + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#pragma once + +#include "Utilities/PageFaultSource.h" + +// -------------------------------------------------------------------------------------- +// RecompiledCodeReserve +// -------------------------------------------------------------------------------------- +// A recompiled code reserve is a simple sequential-growth block of memory which is auto- +// cleared to INT 3 (0xcc) as needed. +// +class RecompiledCodeReserve : public BaseVmReserveListener +{ + typedef BaseVmReserveListener _parent; + +protected: + // Specifies the number of blocks that should be committed automatically when the + // reserve is created. Typically this chunk is larger than the block size, and + // should be based on whatever typical overhead is needed for basic block use. + uint m_def_commit; + + wxString m_profiler_name; + bool m_profiler_registered; + +public: + RecompiledCodeReserve( const wxString& name=wxEmptyString, uint defCommit = 0 ); + virtual ~RecompiledCodeReserve() throw(); + + virtual void* Reserve( size_t size, uptr base=0, uptr upper_bounds=0 ); + virtual void OnCommittedBlock( void* block ); + + virtual RecompiledCodeReserve& SetProfilerName( const wxString& shortname ); + virtual RecompiledCodeReserve& SetProfilerName( const char* shortname ) + { + return SetProfilerName( fromUTF8(shortname) ); + } + + void ThrowIfNotOk() const; + + operator void*() { return m_baseptr; } + operator const void*() const { return m_baseptr; } + + operator u8*() { return (u8*)m_baseptr; } + operator const u8*() const { return (u8*)m_baseptr; } + +protected: + void ResetProcessReserves() const; + void DoCommitAndProtect( uptr page ); + + void _registerProfiler(); + void _termProfiler(); + + uint _calcDefaultCommitInBlocks() const; +}; diff --git a/pcsx2/System/SysCoreThread.cpp b/pcsx2/System/SysCoreThread.cpp index 1238275900..d52b89866c 100644 --- a/pcsx2/System/SysCoreThread.cpp +++ b/pcsx2/System/SysCoreThread.cpp @@ -22,9 +22,9 @@ #include "GS.h" #include "Elfheader.h" #include "Patch.h" -#include "PageFaultSource.h" #include "SysThreads.h" +#include "Utilities/PageFaultSource.h" #include "Utilities/TlsVariable.inl" #ifdef __WXMSW__ @@ -111,13 +111,24 @@ void SysCoreThread::SetElfOverride( const wxString& elf ) Hle_SetElfPath(elf.ToUTF8()); } -void SysCoreThread::Reset() +// Performs a quicker reset that does not deallocate memory associated with PS2 virtual machines +// or cpu providers (recompilers). +void SysCoreThread::ResetQuick() { Suspend(); + m_resetVirtualMachine = true; m_hasActiveMachine = false; } +void SysCoreThread::Reset() +{ + ResetQuick(); + GetVmMemory().DecommitAll(); + SysClearExecutionCache(); +} + + // Applies a full suite of new settings, which will automatically facilitate the necessary // resets of the core and components (including plugins, if needed). The scope of resetting // is determined by comparing the current settings against the new settings, so that only @@ -159,6 +170,8 @@ void SysCoreThread::_reset_stuff_as_needed() // because of changes to the TLB. We don't actually support the TLB, however, so rec // resets aren't in fact *needed* ... yet. But might as well, no harm. --air + GetVmMemory().CommitAll(); + if( m_resetVirtualMachine || m_resetRecompilers || m_resetProfilers ) { SysClearExecutionCache(); diff --git a/pcsx2/System/SysThreads.h b/pcsx2/System/SysThreads.h index b686777269..3ca161c2ae 100644 --- a/pcsx2/System/SysThreads.h +++ b/pcsx2/System/SysThreads.h @@ -184,6 +184,7 @@ public: virtual void OnResumeReady(); virtual void Reset(); + virtual void ResetQuick(); virtual void Cancel( bool isBlocking=true ); virtual bool Cancel( const wxTimeSpan& timeout ); diff --git a/pcsx2/VUmicro.h b/pcsx2/VUmicro.h index 652d9f9afc..3a5d09bbd2 100644 --- a/pcsx2/VUmicro.h +++ b/pcsx2/VUmicro.h @@ -19,15 +19,15 @@ #include "VUops.h" #include "R5900.h" -static const uint VU0_MEMSIZE = 0x1000; -static const uint VU0_PROGSIZE = 0x1000; -static const uint VU1_MEMSIZE = 0x4000; -static const uint VU1_PROGSIZE = 0x4000; +static const uint VU0_MEMSIZE = 0x1000; // 4kb +static const uint VU0_PROGSIZE = 0x1000; // 4kb +static const uint VU1_MEMSIZE = 0x4000; // 16kb +static const uint VU1_PROGSIZE = 0x4000; // 16kb -static const uint VU0_MEMMASK = VU0_MEMSIZE-1; -static const uint VU0_PROGMASK = VU0_PROGSIZE-1; -static const uint VU1_MEMMASK = VU1_MEMSIZE-1; -static const uint VU1_PROGMASK = VU1_PROGSIZE-1; +static const uint VU0_MEMMASK = VU0_MEMSIZE-1; +static const uint VU0_PROGMASK = VU0_PROGSIZE-1; +static const uint VU1_MEMMASK = VU1_MEMSIZE-1; +static const uint VU1_PROGMASK = VU1_PROGSIZE-1; #define vuRunCycles (512*12) // Cycles to run ExecuteBlockJIT() for (called from within recs) #define vu0RunCycles (512*12) // Cycles to run vu0 for whenever ExecuteBlock() is called @@ -47,9 +47,9 @@ static const uint VU1_PROGMASK = VU1_PROGSIZE-1; class BaseCpuProvider { protected: - // allocation counter for multiple init/shutdown calls - // (most or all implementations will need this!) - int m_AllocCount; + // allocation counter for multiple calls to Reserve. Most implementations should utilize + // this variable for sake of robustness. + u32 m_Reserved; public: // this boolean indicates to some generic logging facilities if the VU's registers @@ -60,19 +60,27 @@ public: public: BaseCpuProvider() { - m_AllocCount = 0; + m_Reserved = 0; } virtual ~BaseCpuProvider() throw() { - if( m_AllocCount != 0 ) - Console.Warning( "Cleanup miscount detected on CPU provider. Count=%d", m_AllocCount ); + if( m_Reserved != 0 ) + Console.Warning( "Cleanup miscount detected on CPU provider. Count=%d", m_Reserved ); } virtual const char* GetShortName() const=0; virtual wxString GetLongName() const=0; - virtual void Allocate()=0; + // returns the number of bytes committed to the working caches for this CPU + // provider (typically this refers to recompiled code caches, but could also refer + // to other optional growable allocations). + virtual size_t GetCommittedCache() const + { + return 0; + } + + virtual void Reserve()=0; virtual void Shutdown()=0; virtual void Reset()=0; virtual void Execute(u32 cycles)=0; @@ -88,6 +96,15 @@ public: { cpu->Execute(1024); } + + // Gets the current cache reserve allocated to this CPU (value returned in megabytes) + virtual uint GetCacheReserve() const=0; + + // Specifies the maximum cache reserve amount for this CPU (value in megabytes). + // CPU providers are allowed to reset their reserves (recompiler resets, etc) if such is + // needed to conform to the new amount requested. + virtual void SetCacheReserve( uint reserveInMegs ) const=0; + }; // -------------------------------------------------------------------------------------- @@ -149,13 +166,16 @@ public: const char* GetShortName() const { return "intVU0"; } wxString GetLongName() const { return L"VU0 Interpreter"; } - void Allocate() { } + void Reserve() { } void Shutdown() throw() { } void Reset() { } void Step(); void Execute(u32 cycles); void Clear(u32 addr, u32 size) {} + + uint GetCacheReserve() const { return 0; } + void SetCacheReserve( uint reserveInMegs ) const {} }; class InterpVU1 : public BaseVUmicroCPU @@ -167,13 +187,16 @@ public: const char* GetShortName() const { return "intVU1"; } wxString GetLongName() const { return L"VU1 Interpreter"; } - void Allocate() { } + void Reserve() { } void Shutdown() throw() { } void Reset() { } void Step(); void Execute(u32 cycles); void Clear(u32 addr, u32 size) {} + + uint GetCacheReserve() const { return 0; } + void SetCacheReserve( uint reserveInMegs ) const {} }; // -------------------------------------------------------------------------------------- @@ -188,13 +211,16 @@ public: const char* GetShortName() const { return "mVU0"; } wxString GetLongName() const { return L"microVU0 Recompiler"; } - void Allocate(); + void Reserve(); void Shutdown() throw(); void Reset(); void Execute(u32 cycles); void Clear(u32 addr, u32 size); void Vsync() throw(); + + uint GetCacheReserve() const; + void SetCacheReserve( uint reserveInMegs ) const; }; class recMicroVU1 : public BaseVUmicroCPU @@ -206,12 +232,15 @@ public: const char* GetShortName() const { return "mVU1"; } wxString GetLongName() const { return L"microVU1 Recompiler"; } - void Allocate(); + void Reserve(); void Shutdown() throw(); void Reset(); void Execute(u32 cycles); void Clear(u32 addr, u32 size); void Vsync() throw(); + + uint GetCacheReserve() const; + void SetCacheReserve( uint reserveInMegs ) const; }; // -------------------------------------------------------------------------------------- @@ -226,11 +255,14 @@ public: const char* GetShortName() const { return "sVU0"; } wxString GetLongName() const { return L"SuperVU0 Recompiler"; } - void Allocate(); + void Reserve(); void Shutdown() throw(); void Reset(); void Execute(u32 cycles); void Clear(u32 Addr, u32 Size); + + uint GetCacheReserve() const; + void SetCacheReserve( uint reserveInMegs ) const; }; class recSuperVU1 : public BaseVUmicroCPU @@ -241,21 +273,20 @@ public: const char* GetShortName() const { return "sVU1"; } wxString GetLongName() const { return L"SuperVU1 Recompiler"; } - void Allocate(); + void Reserve(); void Shutdown() throw(); void Reset(); void Execute(u32 cycles); void Clear(u32 Addr, u32 Size); + + uint GetCacheReserve() const; + void SetCacheReserve( uint reserveInMegs ) const; }; extern BaseVUmicroCPU* CpuVU0; extern BaseVUmicroCPU* CpuVU1; -extern void vuMicroMemAlloc(); -extern void vuMicroMemShutdown(); -extern void vuMicroMemReset(); - // VU0 extern void vu0ResetRegs(); extern void __fastcall vu0ExecMicro(u32 addr); diff --git a/pcsx2/VUmicroMem.cpp b/pcsx2/VUmicroMem.cpp index d0aad70822..70c2f9643a 100644 --- a/pcsx2/VUmicroMem.cpp +++ b/pcsx2/VUmicroMem.cpp @@ -18,43 +18,41 @@ #include "Common.h" #include "VUmicro.h" + __aligned16 VURegs vuRegs[2]; -static u8* m_vuAllMem = NULL; -static const uint m_vuMemSize = - 0x1000 + // VU0micro memory - 0x4000 + // VU0 memory - 0x4000 + // VU1 memory - 0x4000; -void vuMicroMemAlloc() +vuMemoryReserve::vuMemoryReserve() + : _parent( L"VU0/1 on-chip memory", VU1_PROGSIZE + VU1_MEMSIZE + VU0_PROGSIZE + VU0_MEMSIZE ) { - if( m_vuAllMem == NULL ) - m_vuAllMem = vtlb_malloc( m_vuMemSize, 16 ); - - if( m_vuAllMem == NULL ) - throw Exception::OutOfMemory( L"VU0 and VU1 on-chip memory" ); - - u8* curpos = m_vuAllMem; - VU0.Micro = curpos; curpos += 0x1000; - VU0.Mem = curpos; curpos += 0x4000; - VU1.Micro = curpos; curpos += 0x4000; - VU1.Mem = curpos; - //curpos += 0x4000; } -void vuMicroMemShutdown() +void vuMemoryReserve::Reserve() { - // -- VTLB Memory Allocation -- + _parent::Reserve(HostMemoryMap::VUmem); + //_parent::Reserve(EmuConfig.HostMemMap.VUmem); - vtlb_free( m_vuAllMem, m_vuMemSize ); - m_vuAllMem = NULL; + u8* curpos = m_reserve.GetPtr(); + VU0.Micro = curpos; curpos += VU0_PROGSIZE; + VU0.Mem = curpos; curpos += VU0_MEMSIZE; + VU1.Micro = curpos; curpos += VU1_PROGSIZE; + VU1.Mem = curpos; curpos += VU1_MEMSIZE; } -void vuMicroMemReset() +void vuMemoryReserve::Release() { - pxAssume( VU0.Mem != NULL ); - pxAssume( VU1.Mem != NULL ); + _parent::Release(); + + VU0.Micro = VU0.Mem = NULL; + VU1.Micro = VU1.Mem = NULL; +} + +void vuMemoryReserve::Reset() +{ + _parent::Reset(); + + pxAssume( VU0.Mem ); + pxAssume( VU1.Mem ); memMapVUmicro(); @@ -67,8 +65,6 @@ void vuMicroMemReset() VU0.VF[0].f.z = 0.0f; VU0.VF[0].f.w = 1.0f; VU0.VI[0].UL = 0; - memzero_ptr<4*1024>(VU0.Mem); - memzero_ptr<4*1024>(VU0.Micro); // === VU1 Initialization === memzero(VU1.ACC); @@ -79,8 +75,6 @@ void vuMicroMemReset() VU1.VF[0].f.z = 0.0f; VU1.VF[0].f.w = 1.0f; VU1.VI[0].UL = 0; - memzero_ptr<16*1024>(VU1.Mem); - memzero_ptr<16*1024>(VU1.Micro); } void SaveStateBase::vuMicroFreeze() diff --git a/pcsx2/Vif0_Dma.cpp b/pcsx2/Vif0_Dma.cpp index b0a39138fe..fc5fed0682 100644 --- a/pcsx2/Vif0_Dma.cpp +++ b/pcsx2/Vif0_Dma.cpp @@ -107,17 +107,36 @@ __fi void vif0SetupTransfer() if (vif0ch.chcr.TTE) { + // Transfer dma tag if tte is set + bool ret; - if (vif0.vifstalled) - ret = VIF0transfer((u32*)ptag + (2 + vif0.irqoffset), 2 - vif0.irqoffset); //Transfer Tag on stall - else - ret = VIF0transfer((u32*)ptag + 2, 2); //Transfer Tag + static __aligned16 u128 masked_tag; - if ((ret == false) && vif0.irqoffset < 2) + masked_tag._u64[0] = 0; + masked_tag._u64[1] = *((u64*)ptag + 1); + + VIF_LOG("\tVIF0 SrcChain TTE=1, data = 0x%08x.%08x", masked_tag._u32[3], masked_tag._u32[2]); + + if (vif0.vifstalled) + { + ret = VIF0transfer((u32*)&masked_tag + vif0.irqoffset, 4 - vif0.irqoffset, true); //Transfer Tag on stall + //ret = VIF0transfer((u32*)ptag + (2 + vif0.irqoffset), 2 - vif0.irqoffset); //Transfer Tag on stall + } + else + { + //Some games (like killzone) do Tags mid unpack, the nops will just write blank data + //to the VU's, which breaks stuff, this is where the 128bit packet will fail, so we ignore the first 2 words + vif0.irqoffset = 2; + ret = VIF0transfer((u32*)&masked_tag + 2, 2, true); //Transfer Tag + //ret = VIF0transfer((u32*)ptag + 2, 2); //Transfer Tag + } + + if (!ret && vif0.irqoffset) { vif0.inprogress = 0; //Better clear this so it has to do it again (Jak 1) - return; //There has been an error or an interrupt + return; //IRQ set by VIFTransfer + } } diff --git a/pcsx2/Vif1_Dma.cpp b/pcsx2/Vif1_Dma.cpp index d15c3bd56b..306ec29c0a 100644 --- a/pcsx2/Vif1_Dma.cpp +++ b/pcsx2/Vif1_Dma.cpp @@ -155,9 +155,9 @@ bool _VIF1chain() vif1ch.qwc, vif1ch.madr, vif1ch.tadr); if (vif1.vifstalled) - return VIF1transfer(pMem + vif1.irqoffset, vif1ch.qwc * 4 - vif1.irqoffset); + return VIF1transfer(pMem + vif1.irqoffset, vif1ch.qwc * 4 - vif1.irqoffset, false); else - return VIF1transfer(pMem, vif1ch.qwc * 4); + return VIF1transfer(pMem, vif1ch.qwc * 4, false); } __fi void vif1SetupTransfer() @@ -205,7 +205,7 @@ __fi void vif1SetupTransfer() bool ret; static __aligned16 u128 masked_tag; - + masked_tag._u64[0] = 0; masked_tag._u64[1] = *((u64*)ptag + 1); @@ -218,7 +218,10 @@ __fi void vif1SetupTransfer() } else { - ret = VIF1transfer((u32*)&masked_tag, 4, true); //Transfer Tag + //Some games (like killzone) do Tags mid unpack, the nops will just write blank data + //to the VU's, which breaks stuff, this is where the 128bit packet will fail, so we ignore the first 2 words + vif1.irqoffset = 2; + ret = VIF1transfer((u32*)&masked_tag + 2, 2, true); //Transfer Tag //ret = VIF1transfer((u32*)ptag + 2, 2); //Transfer Tag } @@ -226,8 +229,7 @@ __fi void vif1SetupTransfer() { vif1.inprogress &= ~1; //Better clear this so it has to do it again (Jak 1) return; //IRQ set by VIFTransfer - - } //else vif1.vifstalled = false; + } } vif1.irqoffset = 0; @@ -488,7 +490,7 @@ void dmaVIF1() if(vif1ch.chcr.MOD == CHAIN_MODE && vif1.dmamode != VIF_NORMAL_TO_MEM_MODE) { vif1.dmamode = VIF_CHAIN_MODE; - DevCon.Warning(L"VIF1 QWC on Chain CHCR " + vif1ch.chcr.desc()); + //DevCon.Warning(L"VIF1 QWC on Chain CHCR " + vif1ch.chcr.desc()); if ((vif1ch.chcr.tag().ID == TAG_REFE) || (vif1ch.chcr.tag().ID == TAG_END)) { @@ -500,6 +502,7 @@ void dmaVIF1() { vif1.dmamode = VIF_CHAIN_MODE; vif1.done = false; + vif1.inprogress = 0; } if (vif1ch.chcr.DIR) vif1Regs.stat.FQC = min((u16)0x10, vif1ch.qwc); diff --git a/pcsx2/Vif1_MFIFO.cpp b/pcsx2/Vif1_MFIFO.cpp index d74d87301c..4142197f37 100644 --- a/pcsx2/Vif1_MFIFO.cpp +++ b/pcsx2/Vif1_MFIFO.cpp @@ -32,14 +32,39 @@ static u32 qwctag(u32 mask) return (dmacRegs.rbor.ADDR + (mask & dmacRegs.rbsr.RMSK)); } +static u16 QWCinVIFMFIFO(u32 DrainADDR) +{ + u32 ret; + + + SPR_LOG("VIF MFIFO Requesting %x QWC from the MFIFO Base %x, SPR MADR %x Drain %x", vif1ch.qwc, dmacRegs.rbor.ADDR, spr0ch.madr, DrainADDR); + //Calculate what we have in the fifo. + if(DrainADDR <= spr0ch.madr) + { + //Drain is below the tadr, calculate the difference between them + ret = (spr0ch.madr - DrainADDR) >> 4; + } + else + { + u32 limit = dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16; + //Drain is higher than SPR so it has looped round, + //calculate from base to the SPR tag addr and what is left in the top of the ring + ret = ((spr0ch.madr - dmacRegs.rbor.ADDR) + (limit - DrainADDR)) >> 4; + } + SPR_LOG("%x Available of the %x requested", ret, vif1ch.qwc); + + return ret; +} static __fi bool mfifoVIF1rbTransfer() { u32 maddr = dmacRegs.rbor.ADDR; u32 msize = dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16; - u16 mfifoqwc = std::min(vif1ch.qwc, vifqwc); + u16 mfifoqwc = min(QWCinVIFMFIFO(vif1ch.madr), vif1ch.qwc); u32 *src; bool ret; + if(mfifoqwc == 0) return true; //Cant do anything, lets forget it + /* Check if the transfer should wrap around the ring buffer */ if ((vif1ch.madr + (mfifoqwc << 4)) > (msize)) { @@ -48,6 +73,8 @@ static __fi bool mfifoVIF1rbTransfer() SPR_LOG("Split MFIFO"); /* it does, so first copy 's1' bytes from 'addr' to 'data' */ + vif1ch.madr = qwctag(vif1ch.madr); + src = (u32*)PSM(vif1ch.madr); if (src == NULL) return false; @@ -56,10 +83,9 @@ static __fi bool mfifoVIF1rbTransfer() else ret = VIF1transfer(src, s1); - vif1ch.madr = qwctag(vif1ch.madr); - if (ret) { + if(vif1.irqoffset != 0) DevCon.Warning("VIF1 MFIFO Offest != 0! vifoffset=%x", vif1.irqoffset); /* and second copy 's2' bytes from 'maddr' to '&data[s1]' */ vif1ch.madr = maddr; @@ -67,13 +93,12 @@ static __fi bool mfifoVIF1rbTransfer() if (src == NULL) return false; VIF1transfer(src, ((mfifoqwc << 2) - s1)); } - vif1ch.madr = qwctag(vif1ch.madr); } else { SPR_LOG("Direct MFIFO"); - + /* it doesn't, so just transfer 'qwc*4' words */ src = (u32*)PSM(vif1ch.madr); if (src == NULL) return false; @@ -83,8 +108,6 @@ static __fi bool mfifoVIF1rbTransfer() else ret = VIF1transfer(src, mfifoqwc << 2); - vif1ch.madr = qwctag(vif1ch.madr); - } return ret; } @@ -99,13 +122,17 @@ static __fi void mfifo_VIF1chain() } if (vif1ch.madr >= dmacRegs.rbor.ADDR && - vif1ch.madr <= (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK)) - { - //Need to exit on mfifo locations, if the madr is matching the madr of spr, we dont have any data left :( - - u16 startqwc = vif1ch.qwc; + vif1ch.madr <= (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16)) + { + if(vif1ch.madr == (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16)) DevCon.Warning("Edge VIF1"); + + vif1ch.madr = qwctag(vif1ch.madr); mfifoVIF1rbTransfer(); - vifqwc -= startqwc - vif1ch.qwc; + vif1ch.tadr = qwctag(vif1ch.tadr); + vif1ch.madr = qwctag(vif1ch.madr); + if(QWCinVIFMFIFO(vif1ch.madr) == 0) vif1.inprogress |= 0x10; + + //vifqwc -= startqwc - vif1ch.qwc; } else @@ -124,8 +151,6 @@ static __fi void mfifo_VIF1chain() } } - - void mfifoVIF1transfer(int qwc) { tDMA_TAG *ptag; @@ -134,11 +159,15 @@ void mfifoVIF1transfer(int qwc) if (qwc > 0) { - vifqwc += qwc; - SPR_LOG("Added %x qw to mfifo, total now %x - Vif CHCR %x Stalled %x done %x", qwc, vifqwc, vif1ch.chcr._u32, vif1.vifstalled, vif1.done); + //vifqwc += qwc; + SPR_LOG("Added %x qw to mfifo, total now %x - Vif CHCR %x Stalled %x done %x", qwc, vif1ch.chcr._u32, vif1.vifstalled, vif1.done); if (vif1.inprogress & 0x10) { - if(vif1ch.chcr.STR == true)CPU_INT(DMAC_MFIFO_VIF, 4); + if(vif1ch.chcr.STR == true && !(cpuRegs.interrupt & (1< 0) + if (vif1ch.qwc == 0) { + vif1ch.tadr = qwctag(vif1ch.tadr); ptag = dmaGetAddr(vif1ch.tadr, false); if (vif1ch.chcr.TTE) @@ -169,62 +199,32 @@ void mfifoVIF1transfer(int qwc) } else { - ret = VIF1transfer((u32*)&masked_tag, 4, true); //Transfer Tag + vif1.irqoffset = 2; + ret = VIF1transfer((u32*)&masked_tag + 2, 2, true); //Transfer Tag //ret = VIF1transfer((u32*)ptag + 2, 2); //Transfer Tag } if (!ret && vif1.irqoffset) { + vif1.inprogress &= ~1; return; //IRQ set by VIFTransfer } //else vif1.vifstalled = false; + g_vifCycles += 2; } - + vif1.irqoffset = 0; vif1ch.unsafeTransfer(ptag); vif1ch.madr = ptag[1]._u32; - vifqwc--; + + //vifqwc--; SPR_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx mfifo qwc = %x spr0 madr = %x", ptag[1]._u32, ptag[0]._u32, vif1ch.qwc, ptag->ID, vif1ch.madr, vif1ch.tadr, vifqwc, spr0ch.madr); - switch (ptag->ID) - { - case TAG_REFE: // Refe - Transfer Packet According to ADDR field - vif1ch.tadr = qwctag(vif1ch.tadr + 16); - vif1.done = true; //End Transfer - break; - - case TAG_CNT: // CNT - Transfer QWC following the tag. - vif1ch.madr = qwctag(vif1ch.tadr + 16); //Set MADR to QW after Tag - vif1ch.tadr = qwctag(vif1ch.madr + (vif1ch.qwc << 4)); //Set TADR to QW following the data - vif1.done = false; - break; - - case TAG_NEXT: // Next - Transfer QWC following tag. TADR = ADDR - { - int temp = vif1ch.madr; //Temporarily Store ADDR - vif1ch.madr = qwctag(vif1ch.tadr + 16); //Set MADR to QW following the tag - vif1ch.tadr = temp; //Copy temporarily stored ADDR to Tag - if ((temp & dmacRegs.rbsr.RMSK) != dmacRegs.rbor.ADDR) Console.WriteLn("Next tag = %x outside ring %x size %x", temp, psHu32(DMAC_RBOR), psHu32(DMAC_RBSR)); - vif1.done = false; - break; - } - - case TAG_REF: // Ref - Transfer QWC from ADDR field - case TAG_REFS: // Refs - Transfer QWC from ADDR field (Stall Control) - vif1ch.tadr = qwctag(vif1ch.tadr + 16); //Set TADR to next tag - vif1.done = false; - break; - - case TAG_END: // End - Transfer QWC following the tag - vif1ch.madr = qwctag(vif1ch.tadr + 16); //Set MADR to data following the tag - vif1ch.tadr = qwctag(vif1ch.madr + (vif1ch.qwc << 4)); //Set TADR to QW following the data - vif1.done = true; //End Transfer - break; - } + vif1.done |= hwDmacSrcChainWithStack(vif1ch, ptag->ID); if (vif1ch.chcr.TIE && ptag->IRQ) { @@ -232,8 +232,16 @@ void mfifoVIF1transfer(int qwc) vif1.done = true; } - vif1Regs.stat.FQC = min(vif1ch.qwc, (u16)16); - vif1.inprogress |= 1; + + if(vif1ch.qwc > 0) vif1.inprogress |= 1; + + vif1ch.tadr = qwctag(vif1ch.tadr); + + if(QWCinVIFMFIFO(vif1ch.tadr) == 0) vif1.inprogress |= 0x10; + } + else + { + DevCon.Warning("Vif MFIFO QWC not 0 on tag"); } @@ -245,6 +253,13 @@ void vifMFIFOInterrupt() g_vifCycles = 0; VIF_LOG("vif mfifo interrupt"); + + if (dmacRegs.ctrl.MFD != MFD_VIF1) + { + DevCon.Warning("Not in VIF MFIFO mode! Stopping VIF MFIFO"); + return; + } + if(GSTransferStatus.PTH2 == STOPPED_MODE && gifRegs.stat.APATH == GIF_APATH2) { GSTransferStatus.PTH2 = STOPPED_MODE; @@ -257,7 +272,11 @@ void vifMFIFOInterrupt() if (schedulepath3msk & 0x10) Vif1MskPath3(); - if(vif1ch.chcr.DIR && CheckPath2GIF(DMAC_MFIFO_VIF) == false) return; + if(vif1ch.chcr.DIR && CheckPath2GIF(DMAC_MFIFO_VIF) == false) + { + SPR_LOG("Waiting for PATH to be ready"); + return; + } //We need to check the direction, if it is downloading from the GS, we handle that seperately (KH2 for testing) //Simulated GS transfer time done, clear the flags @@ -271,8 +290,10 @@ void vifMFIFOInterrupt() vif1Regs.stat.VPS = VPS_IDLE; } + if (vif1.irq && vif1.tag.size == 0) { + SPR_LOG("VIF MFIFO Code Interrupt detected"); vif1Regs.stat.INT = true; hwIntcIrq(INTC_VIF1); --vif1.irq; @@ -281,53 +302,40 @@ void vifMFIFOInterrupt() { /*vif1Regs.stat.FQC = 0; // FQC=0 vif1ch.chcr.STR = false;*/ - if(vif1ch.qwc > 0 || !vif1.done) return; + if((vif1ch.qwc > 0 || !vif1.done) && !(vif1.inprogress & 0x10)) return; } } + if(vif1.inprogress & 0x10) + { + FireMFIFOEmpty(); + if(!(vif1.done && vif1ch.qwc == 0))return; + } + if (vif1.done == false || vif1ch.qwc) { + switch(vif1.inprogress & 1) { case 0: //Set up transfer - if (vif1ch.tadr == spr0ch.madr) + if (QWCinVIFMFIFO(vif1ch.tadr) == 0) { - // Console.WriteLn("Empty 1"); - vifqwc = 0; - if((vif1.inprogress & 0x10) == 0) - { - hwDmacIrq(DMAC_MFIFO_EMPTY); - vif1.inprogress |= 0x10; - } - vif1Regs.stat.FQC = 0; + vif1.inprogress |= 0x10; + CPU_INT(DMAC_MFIFO_VIF, 4 ); return; } - + mfifoVIF1transfer(0); - CPU_INT(DMAC_MFIFO_VIF, 4); - return; - + case 1: //Transfer data mfifo_VIF1chain(); //Sanity check! making sure we always have non-zero values - CPU_INT(DMAC_MFIFO_VIF, (g_vifCycles == 0 ? 4 : g_vifCycles) ); + CPU_INT(DMAC_MFIFO_VIF, (g_vifCycles == 0 ? 4 : g_vifCycles) ); return; } return; - } + } - - //FF7 Dirge of Cerberus seems to like the mfifo to tell it when it's empty, even if it's ending. - //Doesn't seem to care about the vif1 dma interrupting (possibly disabled the interrupt?) - if (vif1ch.tadr == spr0ch.madr) - { - vifqwc = 0; - if((vif1.inprogress & 0x10) == 0) - { - hwDmacIrq(DMAC_MFIFO_EMPTY); - vif1.inprogress |= 0x10; - } - } vif1.vifstalled = false; vif1.done = 1; g_vifCycles = 0; diff --git a/pcsx2/Vif_Codes.cpp b/pcsx2/Vif_Codes.cpp index 1e299668a0..cf2ec2353c 100644 --- a/pcsx2/Vif_Codes.cpp +++ b/pcsx2/Vif_Codes.cpp @@ -154,7 +154,7 @@ template __fi int _vifCode_Direct(int pass, const u8* data, bool isDire } if(SIGNAL_IMR_Pending == true) { - DevCon.Warning("Path 2 Paused (At start)"); + //DevCon.Warning("Path 2 Paused (At start)"); vif1.vifstalled = true; return 0; } diff --git a/pcsx2/Vif_Transfer.cpp b/pcsx2/Vif_Transfer.cpp index f10f82768a..0d35c946b8 100644 --- a/pcsx2/Vif_Transfer.cpp +++ b/pcsx2/Vif_Transfer.cpp @@ -25,7 +25,7 @@ // Doesn't stall if the next vifCode is the Mark command _vifT bool runMark(u32* &data) { if (((vifXRegs.code >> 24) & 0x7f) == 0x7) { - DevCon.WriteLn("Vif%d: Running Mark with I-bit", idx); + //DevCon.WriteLn("Vif%d: Running Mark with I-bit", idx); return 1; // No Stall? } return 1; // Stall @@ -112,7 +112,7 @@ _vifT static __fi bool vifTransfer(u32 *data, int size, bool TTE) { vifStruct& vifX = GetVifX; // irqoffset necessary to add up the right qws, or else will spin (spiderman) - int transferred = vifX.vifstalled ? vifX.irqoffset : 0; + int transferred = vifX.irqoffset; vifX.irqoffset = 0; vifX.vifstalled = false; @@ -139,26 +139,29 @@ _vifT static __fi bool vifTransfer(u32 *data, int size, bool TTE) { vifX.irqoffset = transferred % 4; // cannot lose the offset - if (TTE) return !vifX.vifstalled; + if (!TTE) // *WARNING* - Tags CAN have interrupts! so lets just ignore the dma modifying stuffs (GT4) + { + transferred = transferred >> 2; - transferred = transferred >> 2; + vifXch.madr +=(transferred << 4); + vifXch.qwc -= transferred; + if(vifXch.chcr.STR)hwDmacSrcTadrInc(vifXch); + } - vifXch.madr +=(transferred << 4); - vifXch.qwc -= transferred; - - if (!vifXch.qwc && !vifX.irqoffset) vifX.inprogress &= ~0x1; + if (!vifXch.qwc && !vifX.irqoffset) + { + vifX.inprogress &= ~0x1; + vifX.vifstalled = false; + } if (vifX.irq && vifX.cmd == 0) { //DevCon.WriteLn("Vif IRQ!"); if(((vifXRegs.code >> 24) & 0x7f) != 0x7) { - vifX.vifstalled = true; vifXRegs.stat.VIS = true; // Note: commenting this out fixes WALL-E? - } - - if (!vifXch.qwc && !vifX.irqoffset) vifX.inprogress &= ~1; - return false; - } + vifX.vifstalled = true; + } + } return !vifX.vifstalled; } diff --git a/pcsx2/gui/App.h b/pcsx2/gui/App.h index 7af5792be8..89538f7810 100644 --- a/pcsx2/gui/App.h +++ b/pcsx2/gui/App.h @@ -107,6 +107,7 @@ enum MenuIdentifiers MenuId_Config_SysSettings, MenuId_Config_McdSettings, MenuId_Config_AppSettings, + MenuId_Config_GameDatabase, MenuId_Config_BIOS, // Plugin ID order is important. Must match the order in tbl_PluginInfo. @@ -475,7 +476,7 @@ public: // blocked threads stalling the GUI. ExecutorThread SysExecutorThread; ScopedPtr m_CpuProviders; - ScopedPtr m_VmAllocs; + ScopedPtr m_VmReserve; protected: wxWindowID m_id_MainFrame; @@ -497,6 +498,8 @@ public: void SysExecute( CDVD_SourceType cdvdsrc, const wxString& elf_override=wxEmptyString ); void LogicalVsync(); + SysMainMemory& GetVmReserve(); + GSFrame& GetGsFrame() const; MainEmuFrame& GetMainFrame() const; @@ -526,8 +529,6 @@ public: void StartPendingSave(); void ClearPendingSave(); - void AllocateVM(); - // -------------------------------------------------------------------------- // App-wide Resources // -------------------------------------------------------------------------- diff --git a/pcsx2/gui/AppAssert.cpp b/pcsx2/gui/AppAssert.cpp index f1f176b75d..d729c1a5b0 100644 --- a/pcsx2/gui/AppAssert.cpp +++ b/pcsx2/gui/AppAssert.cpp @@ -19,89 +19,80 @@ #include +class StackDump : public wxStackWalker +{ +protected: + FastFormatUnicode m_stackTrace; + wxString m_srcFuncName; + bool m_ignoreDone; + int m_skipped; + +public: + StackDump( const FnChar_t* src_function_name ) + { + if( src_function_name != NULL ) + m_srcFuncName = fromUTF8(src_function_name); + + m_ignoreDone = false; + m_skipped = 0; + } + + const wxChar* GetStackTrace() const { return m_stackTrace.c_str(); } + +protected: + virtual void OnStackFrame(const wxStackFrame& frame) + { + /*if( m_srcFuncName.IsEmpty() || m_srcFuncName == name ) + { + // FIXME: This logic isn't reliable yet. + // It's possible for our debug information to not match the function names returned by + // __pxFUNCTION__ (might happen in linux a lot, and could happen in win32 due to + // inlining on Dev aserts). The better approach is a system the queues up all the + // stacktrace info in individual wxStrings, and does a two-pass check -- first pass + // for the function name and, if not found, a second pass that just skips the first + // few stack entries. + + // It's important we only walk the stack once because Linux (argh, always linux!) has + // a really god aweful slow stack walker. + + // I'm not doing it right now because I've worked on this mess enough for one week. --air + + m_ignoreDone = true; + } + + if( !m_ignoreDone ) + { + m_skipped++; + return; + }*/ + + m_stackTrace.Write(pxsFmt( L"[%02d]", frame.GetLevel()-m_skipped)); + + if (!frame.GetName().IsEmpty()) + m_stackTrace.Write(pxsFmt( L" %-44s", frame.GetName().c_str() )); + else + m_stackTrace.Write(pxsFmt( L" 0x%-42p", frame.GetAddress() )); + + if( frame.HasSourceLocation() ) + { + wxFileName wxfn(frame.GetFileName()); + + wxfn.SetVolume( wxEmptyString ); + for( int i=0; i<2; ++i ) + wxfn.RemoveDir(0); + + m_stackTrace.Write( L" %s:%d", wxfn.GetFullPath().c_str(), frame.GetLine() ); + } + + m_stackTrace.Write(L"\n"); + } +}; + static wxString pxGetStackTrace( const FnChar_t* calledFrom ) { - wxString stackTrace; - - class StackDump : public wxStackWalker - { - protected: - wxString m_stackTrace; - wxString m_srcFuncName; - bool m_ignoreDone; - int m_skipped; - - public: - StackDump( const FnChar_t* src_function_name ) - { - if( src_function_name != NULL ) - m_srcFuncName = fromUTF8(src_function_name); - - m_ignoreDone = false; - m_skipped = 0; - } - - const wxString& GetStackTrace() const { return m_stackTrace; } - - protected: - virtual void OnStackFrame(const wxStackFrame& frame) - { - wxString name( frame.GetName() ); - if( name.IsEmpty() ) - { - name = wxsFormat( L"%p ", frame.GetAddress() ); - } - /*else if( m_srcFuncName.IsEmpty() || m_srcFuncName == name ) - { - // FIXME: This logic isn't reliable yet. - // It's possible for our debug information to not match the function names returned by - // __pxFUNCTION__ (might happen in linux a lot, and could happen in win32 due to - // inlining on Dev aserts). The better approach is a system the queues up all the - // stacktrace info in individual wxStrings, and does a two-pass check -- first pass - // for the function name and, if not found, a second pass that just skips the first - // few stack entries. - - // It's important we only walk the stack once because Linux (argh, always linux!) has - // a really god aweful slow stack walker. - - // I'm not doing it right now because I've worked on this mess enough for one week. --air - - m_ignoreDone = true; - } - - if( !m_ignoreDone ) - { - m_skipped++; - return; - }*/ - - //wxString briefName; - wxString essenName; - - if( frame.HasSourceLocation() ) - { - wxFileName wxfn(frame.GetFileName()); - //briefName.Printf( L"(%s:%d)", wxfn.GetFullName().c_str(), frame.GetLine() ); - - wxfn.SetVolume( wxEmptyString ); - int count = wxfn.GetDirCount(); - for( int i=0; i<2; ++i ) - wxfn.RemoveDir(0); - - essenName.Printf( L"%s:%d", wxfn.GetFullPath().c_str(), frame.GetLine() ); - } - - m_stackTrace += wxString::Format( L"[%02d] %-44s %s\n", - frame.GetLevel()-m_skipped, - name.c_str(), - essenName.c_str() - ); - } - }; - - StackDump dump( calledFrom ); - dump.Walk( 3 ); - return dump.GetStackTrace(); + StackDump dump( calledFrom ); + dump.Walk( 3 ); + return dump.GetStackTrace(); } #ifdef __WXDEBUG__ diff --git a/pcsx2/gui/AppCoreThread.cpp b/pcsx2/gui/AppCoreThread.cpp index 178864ae9e..7e3a42298a 100644 --- a/pcsx2/gui/AppCoreThread.cpp +++ b/pcsx2/gui/AppCoreThread.cpp @@ -109,6 +109,17 @@ void AppCoreThread::Reset() _parent::Reset(); } +void AppCoreThread::ResetQuick() +{ + if( !GetSysExecutorThread().IsSelf() ) + { + GetSysExecutorThread().PostEvent( SysExecEvent_InvokeCoreThreadMethod(&AppCoreThread::ResetQuick) ); + return; + } + + _parent::ResetQuick(); +} + ExecutorThread& GetSysExecutorThread() { return wxGetApp().SysExecutorThread; @@ -183,7 +194,6 @@ void Pcsx2App::SysApplySettings() void AppCoreThread::OnResumeReady() { wxGetApp().SysApplySettings(); - wxGetApp().AllocateVM(); wxGetApp().PostMethod( AppSaveSettings ); _parent::OnResumeReady(); } diff --git a/pcsx2/gui/AppCoreThread.h b/pcsx2/gui/AppCoreThread.h index 7afd428925..3ed3ae90a8 100644 --- a/pcsx2/gui/AppCoreThread.h +++ b/pcsx2/gui/AppCoreThread.h @@ -134,6 +134,7 @@ public: virtual void Suspend( bool isBlocking=false ); virtual void Resume(); virtual void Reset(); + virtual void ResetQuick(); virtual void Cancel( bool isBlocking=true ); virtual bool StateCheckInThread(); virtual void ChangeCdvdSource(); diff --git a/pcsx2/gui/AppEventListeners.h b/pcsx2/gui/AppEventListeners.h index 54d5021f7c..4a54621a43 100644 --- a/pcsx2/gui/AppEventListeners.h +++ b/pcsx2/gui/AppEventListeners.h @@ -163,6 +163,12 @@ public: // this second layer class to act as a bridge between the event system and the class's // handler implementations. // +// Explained in detail: The class that wants to listen to shit will implement its expected +// virtual overrides from the listener classes (OnCoreThread_Started, for example), and then +// it adds an instance of the EventListenerHelper_CoreThread class to itself, instead of +// *inheriting* from it. Thusly, the Helper gets initialized when the class is created, +// and when events are dispatched to the listener, it forwards the event to the main class. +// --air template< typename TypeToDispatchTo > class EventListenerHelper_CoreThread : public EventListener_CoreThread @@ -212,9 +218,9 @@ public: protected: void CorePlugins_OnLoaded() { Owner.OnCorePlugins_Loaded(); } void CorePlugins_OnInit() { Owner.OnCorePlugins_Init(); } - void CorePlugins_OnOpening() { Owner.OnCorePlugins_Opening(); } + void CorePlugins_OnOpening() { Owner.OnCorePlugins_Opening(); } void CorePlugins_OnOpened() { Owner.OnCorePlugins_Opened(); } - void CorePlugins_OnClosing() { Owner.OnCorePlugins_Closing(); } + void CorePlugins_OnClosing() { Owner.OnCorePlugins_Closing(); } void CorePlugins_OnClosed() { Owner.OnCorePlugins_Closed(); } void CorePlugins_OnShutdown() { Owner.OnCorePlugins_Shutdown(); } void CorePlugins_OnUnloaded() { Owner.OnCorePlugins_Unloaded(); } diff --git a/pcsx2/gui/AppInit.cpp b/pcsx2/gui/AppInit.cpp index e064df29cf..d9f539b5eb 100644 --- a/pcsx2/gui/AppInit.cpp +++ b/pcsx2/gui/AppInit.cpp @@ -238,12 +238,6 @@ void Pcsx2App::OpenProgramLog() if( m_current_focus ) m_current_focus->SetFocus(); } -void Pcsx2App::AllocateVM() -{ - if (m_VmAllocs) return; - m_VmAllocs = new SysAllocVM(); -} - void Pcsx2App::AllocateCoreStuffs() { if( AppRpc_TryInvokeAsync( &Pcsx2App::AllocateCoreStuffs ) ) return; @@ -252,6 +246,8 @@ void Pcsx2App::AllocateCoreStuffs() SysLogMachineCaps(); AppApplySettings(); + GetVmReserve().ReserveAll(); + if( !m_CpuProviders ) { // FIXME : Some or all of SysCpuProviderPack should be run from the SysExecutor thread, @@ -284,40 +280,40 @@ void Pcsx2App::AllocateCoreStuffs() if( BaseException* ex = m_CpuProviders->GetException_EE() ) { - scrollableTextArea->AppendText( L"* R5900 (EE)\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" ); + scrollableTextArea->AppendText( L"* R5900 (EE)\n\t" + ex->FormatDisplayMessage() + L"\n\n" ); recOps.EnableEE = false; } if( BaseException* ex = m_CpuProviders->GetException_IOP() ) { - scrollableTextArea->AppendText( L"* R3000A (IOP)\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" ); + scrollableTextArea->AppendText( L"* R3000A (IOP)\n\t" + ex->FormatDisplayMessage() + L"\n\n" ); recOps.EnableIOP = false; } if( BaseException* ex = m_CpuProviders->GetException_MicroVU0() ) { - scrollableTextArea->AppendText( L"* microVU0\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" ); + scrollableTextArea->AppendText( L"* microVU0\n\t" + ex->FormatDisplayMessage() + L"\n\n" ); recOps.UseMicroVU0 = false; recOps.EnableVU0 = recOps.EnableVU0 && m_CpuProviders->IsRecAvailable_SuperVU0(); } if( BaseException* ex = m_CpuProviders->GetException_MicroVU1() ) { - scrollableTextArea->AppendText( L"* microVU1\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" ); + scrollableTextArea->AppendText( L"* microVU1\n\t" + ex->FormatDisplayMessage() + L"\n\n" ); recOps.UseMicroVU1 = false; recOps.EnableVU1 = recOps.EnableVU1 && m_CpuProviders->IsRecAvailable_SuperVU1(); } if( BaseException* ex = m_CpuProviders->GetException_SuperVU0() ) { - scrollableTextArea->AppendText( L"* SuperVU0\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" ); + scrollableTextArea->AppendText( L"* SuperVU0\n\t" + ex->FormatDisplayMessage() + L"\n\n" ); recOps.UseMicroVU0 = m_CpuProviders->IsRecAvailable_MicroVU0(); recOps.EnableVU0 = recOps.EnableVU0 && recOps.UseMicroVU0; } if( BaseException* ex = m_CpuProviders->GetException_SuperVU1() ) { - scrollableTextArea->AppendText( L"* SuperVU1\n\t" + ex->FormatDiagnosticMessage() + L"\n\n" ); + scrollableTextArea->AppendText( L"* SuperVU1\n\t" + ex->FormatDisplayMessage() + L"\n\n" ); recOps.UseMicroVU1 = m_CpuProviders->IsRecAvailable_MicroVU1(); recOps.EnableVU1 = recOps.EnableVU1 && recOps.UseMicroVU1; } @@ -525,12 +521,15 @@ bool Pcsx2App::OnInit() InitCPUTicks(); - pxDoAssert = AppDoAssert; + pxDoAssert = AppDoAssert; + pxDoOutOfMemory = SysOutOfMemory_EmergencyResponse; + g_Conf = new AppConfig(); wxInitAllImageHandlers(); - Console.WriteLn("Begin parsing commandline..."); + Console.WriteLn("Command line parsing..."); if( !_parent::OnInit() ) return false; + Console.WriteLn("Command line parsed!"); wxLocale::AddCatalogLookupPathPrefix( wxGetCwd() ); @@ -815,12 +814,12 @@ void Pcsx2App::CleanUp() __fi wxString AddAppName( const wxChar* fmt ) { - return wxsFormat( fmt, pxGetAppName().c_str() ); + return pxsFmt( fmt, pxGetAppName().c_str() ); } __fi wxString AddAppName( const char* fmt ) { - return wxsFormat( fromUTF8(fmt), pxGetAppName().c_str() ); + return pxsFmt( fromUTF8(fmt), pxGetAppName().c_str() ); } // ------------------------------------------------------------------------------------------ diff --git a/pcsx2/gui/AppMain.cpp b/pcsx2/gui/AppMain.cpp index a19e23f824..fa64938bd9 100644 --- a/pcsx2/gui/AppMain.cpp +++ b/pcsx2/gui/AppMain.cpp @@ -702,6 +702,12 @@ void Pcsx2App::PostIdleAppMethod( FnPtr_Pcsx2App method ) AddIdleEvent( evt ); } +SysMainMemory& Pcsx2App::GetVmReserve() +{ + if (!m_VmReserve) m_VmReserve = new SysMainMemory(); + return *m_VmReserve; +} + void Pcsx2App::OpenGsPanel() { if( AppRpc_TryInvoke( &Pcsx2App::OpenGsPanel ) ) return; @@ -851,7 +857,7 @@ protected: DbgCon.WriteLn( Color_Gray, "(SysExecute) received." ); - CoreThread.Reset(); + CoreThread.ResetQuick(); CDVDsys_SetFile( CDVDsrc_Iso, g_Conf->CurrentIso ); if( m_UseCDVDsrc ) @@ -930,6 +936,11 @@ MainEmuFrame* GetMainFramePtr() return wxTheApp ? wxGetApp().GetMainFramePtr() : NULL; } +SysMainMemory& GetVmMemory() +{ + return wxGetApp().GetVmReserve(); +} + SysCoreThread& GetCoreThread() { return CoreThread; diff --git a/pcsx2/gui/ConsoleLogger.cpp b/pcsx2/gui/ConsoleLogger.cpp index 2f6457b64f..58a6133aeb 100644 --- a/pcsx2/gui/ConsoleLogger.cpp +++ b/pcsx2/gui/ConsoleLogger.cpp @@ -193,7 +193,7 @@ void ConsoleLogFrame::ColorArray::Create( int fontsize ) new (&m_table[Color_StrongCyan]) wxTextAttr( wxNullColour, wxNullColour, fixedB ); new (&m_table[Color_StrongYellow]) wxTextAttr( wxNullColour, wxNullColour, fixedB ); new (&m_table[Color_StrongWhite]) wxTextAttr( wxNullColour, wxNullColour, fixedB ); - + SetColorScheme_Light(); } @@ -281,10 +281,10 @@ enum MenuIDs_t MenuId_FontSize_Normal, MenuId_FontSize_Large, MenuId_FontSize_Huge, - + MenuId_ColorScheme_Light = 0x20, MenuId_ColorScheme_Dark, - + MenuId_LogSource_EnableAll = 0x30, MenuId_LogSource_DisableAll, MenuId_LogSource_Devel, @@ -322,7 +322,7 @@ public: } }; -static ConsoleLogSource* const ConLogSources[] = +static ConsoleLogSource* const ConLogSources[] = { (ConsoleLogSource*)&SysConsole.eeConsole, (ConsoleLogSource*)&SysConsole.iopConsole, @@ -334,7 +334,7 @@ static ConsoleLogSource* const ConLogSources[] = (ConsoleLogSource*)&pxConLog_Thread, }; -static const bool ConLogDefaults[] = +static const bool ConLogDefaults[] = { true, true, @@ -437,7 +437,7 @@ ConsoleLogFrame::ConsoleLogFrame( MainEmuFrame *parent, const wxString& title, A menuSources.Append( MenuId_LogSource_Devel, _("Dev/Verbose"), _("Shows PCSX2 developer logs"), wxITEM_CHECK ); menuSources.AppendSeparator(); - + uint srcnt = ArraySize(ConLogSources); for (uint i=0; i 0x100000 || m_QueueColorSection.GetLength() > 256 ) { ++m_WaitingThreadsForFlush; @@ -629,7 +629,7 @@ bool ConsoleLogFrame::Write( ConsoleColors color, const wxString& text ) if( m_WaitingThreadsForFlush != 0 ) --m_WaitingThreadsForFlush; } } - + return false; } @@ -790,7 +790,7 @@ void ConsoleLogFrame::OnToggleSource( wxCommandEvent& evt ) if (!pxAssertDev( ArraySize(ConLogSources) > srcid, "Invalid source log index (out of bounds)" )) return; if (!pxAssertDev( ConLogSources[srcid] != NULL, "Invalid source log index (NULL pointer [separator])" )) return; - + if( wxMenuItem* item = GetMenuBar()->FindItem(evt.GetId()) ) { pxAssertDev( item->IsCheckable(), "Uncheckable log source menu item? Seems fishy!" ); @@ -926,7 +926,7 @@ void ConsoleLogFrame::DoFlushQueue() // cap at 512k for now... // fixme - 512k runs well on win32 but appears to be very sluggish on linux (but that could // be a result of my using Xming + CoLinux). Might need platform dependent defaults here. --air - + static const int BufferSize = 0x80000; if( (insertPoint + m_CurQueuePos) > BufferSize ) { @@ -1040,6 +1040,8 @@ const IConsoleWriter ConsoleWriter_File = ConsoleToFile_DoWrite, ConsoleToFile_Newline, ConsoleToFile_SetTitle, + + 0 }; Mutex& Pcsx2App::GetProgramLogLock() @@ -1111,6 +1113,8 @@ static const IConsoleWriter ConsoleWriter_Window = ConsoleToWindow_DoWrite, ConsoleToWindow_Newline, ConsoleToWindow_SetTitle, + + 0 }; static const IConsoleWriter ConsoleWriter_WindowAndFile = @@ -1122,6 +1126,8 @@ static const IConsoleWriter ConsoleWriter_WindowAndFile = ConsoleToWindow_DoWrite, ConsoleToWindow_Newline, ConsoleToWindow_SetTitle, + + 0 }; void Pcsx2App::EnableAllLogging() diff --git a/pcsx2/gui/CpuUsageProvider.cpp b/pcsx2/gui/CpuUsageProvider.cpp index a9dc1febf2..8c638283d5 100644 --- a/pcsx2/gui/CpuUsageProvider.cpp +++ b/pcsx2/gui/CpuUsageProvider.cpp @@ -56,7 +56,7 @@ DefaultCpuUsageProvider::DefaultCpuUsageProvider() void DefaultCpuUsageProvider::Reset() { - for( int i=0; iEmuOptions.MultitapPort0_Enabled = m_check_Multitap[0]->GetValue(); - g_Conf->EmuOptions.MultitapPort1_Enabled = m_check_Multitap[1]->GetValue(); + g_Conf->EmuOptions.MultitapPort0_Enabled = m_check_Multitap[0]->GetValue(); + g_Conf->EmuOptions.MultitapPort1_Enabled = m_check_Multitap[1]->GetValue(); - g_Conf->EmuOptions.McdEnableEjection = m_check_Ejection->GetValue(); + g_Conf->EmuOptions.BackupSavestate = m_check_SavestateBackup->GetValue(); + g_Conf->EmuOptions.McdEnableEjection = m_check_Ejection->GetValue(); } void Panels::McdConfigPanel_Toggles::AppStatusEvent_OnSettingsApplied() { - m_check_Multitap[0] ->SetValue( g_Conf->EmuOptions.MultitapPort0_Enabled ); - m_check_Multitap[1] ->SetValue( g_Conf->EmuOptions.MultitapPort1_Enabled ); + m_check_Multitap[0] ->SetValue( g_Conf->EmuOptions.MultitapPort0_Enabled ); + m_check_Multitap[1] ->SetValue( g_Conf->EmuOptions.MultitapPort1_Enabled ); - m_check_Ejection ->SetValue( g_Conf->EmuOptions.McdEnableEjection ); + m_check_SavestateBackup ->SetValue( g_Conf->EmuOptions.BackupSavestate ); + m_check_Ejection ->SetValue( g_Conf->EmuOptions.McdEnableEjection ); } diff --git a/pcsx2/gui/MainFrame.cpp b/pcsx2/gui/MainFrame.cpp index 2cc10d9c37..7d47e48038 100644 --- a/pcsx2/gui/MainFrame.cpp +++ b/pcsx2/gui/MainFrame.cpp @@ -155,6 +155,7 @@ void MainEmuFrame::ConnectMenus() ConnectMenu( MenuId_Config_SysSettings, Menu_SysSettings_Click ); ConnectMenu( MenuId_Config_McdSettings, Menu_McdSettings_Click ); ConnectMenu( MenuId_Config_AppSettings, Menu_WindowSettings_Click ); + ConnectMenu( MenuId_Config_GameDatabase,Menu_GameDatabase_Click ); ConnectMenu( MenuId_Config_BIOS, Menu_SelectPluginsBios_Click ); ConnectMenu( MenuId_Config_ResetAll, Menu_ResetAllSettings_Click ); @@ -421,7 +422,8 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title) m_menuConfig.Append(MenuId_Config_SysSettings, _("Emulation &Settings") ); m_menuConfig.Append(MenuId_Config_McdSettings, _("&Memory cards") ); - m_menuConfig.Append(MenuId_Config_BIOS, _("&Plugin/BIOS Selector...") ); + m_menuConfig.Append(MenuId_Config_BIOS, _("&Plugin/BIOS Selector") ); + //m_menuConfig.Append(MenuId_Config_GameDatabase, _("Game Database Editor") ); m_menuConfig.AppendSeparator(); m_menuConfig.Append(MenuId_Config_GS, _("&Video (GS)"), m_PluginMenuPacks[PluginId_GS]); diff --git a/pcsx2/gui/MainFrame.h b/pcsx2/gui/MainFrame.h index 6a7aeb12aa..fda813e5df 100644 --- a/pcsx2/gui/MainFrame.h +++ b/pcsx2/gui/MainFrame.h @@ -162,6 +162,7 @@ protected: void Menu_SysSettings_Click(wxCommandEvent &event); void Menu_McdSettings_Click(wxCommandEvent &event); + void Menu_GameDatabase_Click(wxCommandEvent &event); void Menu_WindowSettings_Click(wxCommandEvent &event); void Menu_GSSettings_Click(wxCommandEvent &event); void Menu_SelectPluginsBios_Click(wxCommandEvent &event); diff --git a/pcsx2/gui/MainMenuClicks.cpp b/pcsx2/gui/MainMenuClicks.cpp index 53458bb244..b4dfbb3ced 100644 --- a/pcsx2/gui/MainMenuClicks.cpp +++ b/pcsx2/gui/MainMenuClicks.cpp @@ -48,6 +48,11 @@ void MainEmuFrame::Menu_McdSettings_Click(wxCommandEvent &event) AppOpenDialog( this ); } +void MainEmuFrame::Menu_GameDatabase_Click(wxCommandEvent &event) +{ + AppOpenDialog( this ); +} + void MainEmuFrame::Menu_WindowSettings_Click(wxCommandEvent &event) { wxCommandEvent evt( pxEvt_SetSettingsPage ); diff --git a/pcsx2/gui/Panels/GameDatabasePanel.cpp b/pcsx2/gui/Panels/GameDatabasePanel.cpp index 56c72d2d1c..52db0630b5 100644 --- a/pcsx2/gui/Panels/GameDatabasePanel.cpp +++ b/pcsx2/gui/Panels/GameDatabasePanel.cpp @@ -1,189 +1,189 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2010 PCSX2 Dev Team - * - * 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. - * - * 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. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "PrecompiledHeader.h" -#include "App.h" -#include "AppGameDatabase.h" -#include "ConfigurationPanels.h" - -extern wxString DiscSerial; -using namespace pxSizerFlags; - -#define blankLine() { \ - sizer1+=5; sizer1+=5; sizer1+=Text(L""); sizer1+=5; sizer1+=5; \ -} - -#define placeTextBox(wxBox, txt) { \ - sizer1 += Label(_(txt)); \ - sizer1 += 5; \ - sizer1 += wxBox | pxCenter; \ - sizer1 += 5; \ - sizer1 += 5; \ -} - -wxTextCtrl* CreateMultiLineTextCtrl( wxWindow* parent, int digits, long flags = 0 ) -{ - wxTextCtrl* ctrl = new wxTextCtrl(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE); - pxFitToDigits(ctrl, digits); - return ctrl; -} - -Panels::GameDatabasePanel::GameDatabasePanel( wxWindow* parent ) - : BaseApplicableConfigPanel( parent ) -{ - IGameDatabase* GameDB = AppHost_GetGameDatabase(); - pxAssume( GameDB != NULL ); - - searchBtn = new wxButton (this, wxID_ANY, _("Search")); - - serialBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT); - nameBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT); - regionBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT); - compatBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT); - commentBox = CreateMultiLineTextCtrl(this, 40, wxTE_LEFT); - patchesBox = CreateMultiLineTextCtrl(this, 40, wxTE_LEFT); - - for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i) - gameFixes[i] = new pxCheckBox(this, EnumToString(i), wxCHK_3STATE | wxCHK_ALLOW_3RD_STATE_FOR_USER ); - - *this += Heading(_("Game Database Editor")).Bold() | StdExpand(); - *this += Heading(_("This panel lets you add and edit game titles, game fixes, and game patches.")) | StdExpand(); - - wxFlexGridSizer& sizer1(*new wxFlexGridSizer(5, StdPadding)); - sizer1.AddGrowableCol(0); - - blankLine(); - sizer1 += Label(L"Serial: "); - sizer1 += 5; - sizer1 += serialBox | pxCenter; - sizer1 += 5; - sizer1 += searchBtn; - - placeTextBox(nameBox, "Name: "); - placeTextBox(regionBox, "Region: "); - placeTextBox(compatBox, "Compatibility: "); - placeTextBox(commentBox, "Comments: "); - placeTextBox(patchesBox, "Patches: "); - - blankLine(); - - wxStaticBoxSizer& sizer2 = *new wxStaticBoxSizer(wxVERTICAL, this, _("Gamefixes")); - wxFlexGridSizer& sizer3(*new wxFlexGridSizer(3, 0, StdPadding*4)); - sizer3.AddGrowableCol(0); - - for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i) - sizer3 += gameFixes[i]; - - sizer2 += sizer3 | StdCenter(); - - *this += sizer1 | pxCenter; - *this += sizer2 | pxCenter; - - Connect(searchBtn->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(GameDatabasePanel::Search_Click)); - PopulateFields(); -} - -void Panels::GameDatabasePanel::PopulateFields( const wxString& id ) { - IGameDatabase* GameDB = AppHost_GetGameDatabase(); - if (!pxAssert(GameDB)) return; - - Game_Data game; - if (GameDB->findGame(game, id.IsEmpty() ? SysGetDiscID() : id)) - { - serialBox ->SetLabel(game.getString("Serial")); - nameBox ->SetLabel(game.getString("Name")); - regionBox ->SetLabel(game.getString("Region")); - compatBox ->SetLabel(game.getString("Compat")); - commentBox->SetLabel(game.getString("[comments]")); - patchesBox->SetLabel(game.getString("[patches]")); - - for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i) - { - wxString keyName (EnumToString(i)); keyName += L"Hack"; - if( game.keyExists(keyName) ) - gameFixes[i]->SetValue(game.getBool(keyName)); - else - gameFixes[i]->SetIndeterminate(); - } - } - else { - serialBox ->SetLabel(wxEmptyString); - nameBox ->SetLabel(wxEmptyString); - regionBox ->SetLabel(wxEmptyString); - compatBox ->SetLabel(wxEmptyString); - commentBox->SetLabel(wxEmptyString); - patchesBox->SetLabel(wxEmptyString); - for (int i = 0; i < GamefixId_COUNT; i++) { - gameFixes[i]->SetValue(0); - } - } -} - -#define writeTextBoxToDB(_key, _value) { \ - if (_value.IsEmpty()) GameDB->deleteKey(wxT(_key)); \ - else GameDB->writeString(wxT(_key), _value); \ -} - -// returns True if the database is modified, or FALSE if no changes to save. -bool Panels::GameDatabasePanel::WriteFieldsToDB() { - IGameDatabase* GameDB = AppHost_GetGameDatabase(); - if (!GameDB) return false; - - if (serialBox->GetValue().IsEmpty()) return false; - - Game_Data game; - GameDB->findGame(game, serialBox->GetValue()); - - game.id = serialBox->GetValue(); - - game.writeString(L"Serial", serialBox->GetValue()); - game.writeString(L"Name", nameBox->GetValue()); - game.writeString(L"Region", regionBox->GetValue()); - game.writeString(L"Compat", compatBox->GetValue()); - game.writeString(L"[comments]", commentBox->GetValue()); - game.writeString(L"[patches]", patchesBox->GetValue()); - - for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i) { - wxString keyName (EnumToString(i)); keyName += L"Hack"; - - if (gameFixes[i]->IsIndeterminate()) - game.deleteKey(keyName); - else - game.writeBool(keyName, gameFixes[i]->GetValue()); - } - GameDB->updateGame(game); - return true; -} - -void Panels::GameDatabasePanel::Search_Click(wxCommandEvent& evt) { - IGameDatabase* GameDB = AppHost_GetGameDatabase(); - if( !GameDB ) return; - - PopulateFields( serialBox->GetValue() ); - evt.Skip(); -} - -void Panels::GameDatabasePanel::Apply() { - AppGameDatabase* GameDB = wxGetApp().GetGameDatabase(); - if( WriteFieldsToDB() ) - { - Console.WriteLn("Saving changes to Game Database..."); - GameDB->SaveToFile(); - } -} - -void Panels::GameDatabasePanel::AppStatusEvent_OnSettingsApplied() -{ -} +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2010 PCSX2 Dev Team + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#include "PrecompiledHeader.h" +#include "App.h" +#include "AppGameDatabase.h" +#include "ConfigurationPanels.h" + +extern wxString DiscSerial; +using namespace pxSizerFlags; + +#define blankLine() { \ + sizer1+=5; sizer1+=5; sizer1+=Text(L""); sizer1+=5; sizer1+=5; \ +} + +#define placeTextBox(wxBox, txt) { \ + sizer1 += Label(_(txt)); \ + sizer1 += 5; \ + sizer1 += wxBox | pxCenter; \ + sizer1 += 5; \ + sizer1 += 5; \ +} + +wxTextCtrl* CreateMultiLineTextCtrl( wxWindow* parent, int digits, long flags = 0 ) +{ + wxTextCtrl* ctrl = new wxTextCtrl(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE); + pxFitToDigits(ctrl, digits); + return ctrl; +} + +Panels::GameDatabasePanel::GameDatabasePanel( wxWindow* parent ) + : BaseApplicableConfigPanel( parent ) +{ + IGameDatabase* GameDB = AppHost_GetGameDatabase(); + pxAssume( GameDB != NULL ); + + searchBtn = new wxButton (this, wxID_ANY, _("Search")); + + serialBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT); + nameBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT); + regionBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT); + compatBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT); + commentBox = CreateMultiLineTextCtrl(this, 40, wxTE_LEFT); + patchesBox = CreateMultiLineTextCtrl(this, 40, wxTE_LEFT); + + for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i) + gameFixes[i] = new pxCheckBox(this, EnumToString(i), wxCHK_3STATE | wxCHK_ALLOW_3RD_STATE_FOR_USER ); + + *this += Heading(_("Game Database Editor")).Bold() | StdExpand(); + //*this += Heading(_("This panel lets you add and edit game titles, game fixes, and game patches.")) | StdExpand(); + + wxFlexGridSizer& sizer1(*new wxFlexGridSizer(5, StdPadding)); + sizer1.AddGrowableCol(0); + + blankLine(); + sizer1 += Label(L"Serial: "); + sizer1 += 5; + sizer1 += serialBox | pxCenter; + sizer1 += 5; + sizer1 += searchBtn; + + placeTextBox(nameBox, "Name: "); + placeTextBox(regionBox, "Region: "); + placeTextBox(compatBox, "Compatibility: "); + placeTextBox(commentBox, "Comments: "); + placeTextBox(patchesBox, "Patches: "); + + blankLine(); + + wxStaticBoxSizer& sizer2 = *new wxStaticBoxSizer(wxVERTICAL, this, _("Gamefixes")); + wxFlexGridSizer& sizer3(*new wxFlexGridSizer(3, 0, StdPadding*4)); + sizer3.AddGrowableCol(0); + + for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i) + sizer3 += gameFixes[i]; + + sizer2 += sizer3 | StdCenter(); + + *this += sizer1 | pxCenter; + *this += sizer2 | pxCenter; + + Connect(searchBtn->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(GameDatabasePanel::Search_Click)); + PopulateFields(); +} + +void Panels::GameDatabasePanel::PopulateFields( const wxString& id ) { + IGameDatabase* GameDB = AppHost_GetGameDatabase(); + if (!pxAssert(GameDB)) return; + + Game_Data game; + if (GameDB->findGame(game, id.IsEmpty() ? SysGetDiscID() : id)) + { + serialBox ->SetLabel(game.getString("Serial")); + nameBox ->SetLabel(game.getString("Name")); + regionBox ->SetLabel(game.getString("Region")); + compatBox ->SetLabel(game.getString("Compat")); + commentBox->SetLabel(game.getString("[comments]")); + patchesBox->SetLabel(game.getString("[patches]")); + + for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i) + { + wxString keyName (EnumToString(i)); keyName += L"Hack"; + if( game.keyExists(keyName) ) + gameFixes[i]->SetValue(game.getBool(keyName)); + else + gameFixes[i]->SetIndeterminate(); + } + } + else { + serialBox ->SetLabel(wxEmptyString); + nameBox ->SetLabel(wxEmptyString); + regionBox ->SetLabel(wxEmptyString); + compatBox ->SetLabel(wxEmptyString); + commentBox->SetLabel(wxEmptyString); + patchesBox->SetLabel(wxEmptyString); + for (int i = 0; i < GamefixId_COUNT; i++) { + gameFixes[i]->SetValue(0); + } + } +} + +#define writeTextBoxToDB(_key, _value) { \ + if (_value.IsEmpty()) GameDB->deleteKey(wxT(_key)); \ + else GameDB->writeString(wxT(_key), _value); \ +} + +// returns True if the database is modified, or FALSE if no changes to save. +bool Panels::GameDatabasePanel::WriteFieldsToDB() { + IGameDatabase* GameDB = AppHost_GetGameDatabase(); + if (!GameDB) return false; + + if (serialBox->GetValue().IsEmpty()) return false; + + Game_Data game; + GameDB->findGame(game, serialBox->GetValue()); + + game.id = serialBox->GetValue(); + + game.writeString(L"Serial", serialBox->GetValue()); + game.writeString(L"Name", nameBox->GetValue()); + game.writeString(L"Region", regionBox->GetValue()); + game.writeString(L"Compat", compatBox->GetValue()); + game.writeString(L"[comments]", commentBox->GetValue()); + game.writeString(L"[patches]", patchesBox->GetValue()); + + for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i) { + wxString keyName (EnumToString(i)); keyName += L"Hack"; + + if (gameFixes[i]->IsIndeterminate()) + game.deleteKey(keyName); + else + game.writeBool(keyName, gameFixes[i]->GetValue()); + } + GameDB->updateGame(game); + return true; +} + +void Panels::GameDatabasePanel::Search_Click(wxCommandEvent& evt) { + IGameDatabase* GameDB = AppHost_GetGameDatabase(); + if( !GameDB ) return; + + PopulateFields( serialBox->GetValue() ); + evt.Skip(); +} + +void Panels::GameDatabasePanel::Apply() { + AppGameDatabase* GameDB = wxGetApp().GetGameDatabase(); + if( WriteFieldsToDB() ) + { + Console.WriteLn("Saving changes to Game Database..."); + GameDB->SaveToFile(); + } +} + +void Panels::GameDatabasePanel::AppStatusEvent_OnSettingsApplied() +{ +} diff --git a/pcsx2/gui/Panels/LogOptionsPanels.cpp b/pcsx2/gui/Panels/LogOptionsPanels.cpp index 1bda114407..3014736bc6 100644 --- a/pcsx2/gui/Panels/LogOptionsPanels.cpp +++ b/pcsx2/gui/Panels/LogOptionsPanels.cpp @@ -144,10 +144,10 @@ static SysTraceLog * const traceLogList[] = &SysTrace.EE.SPR, &SysTrace.EE.VIF, &SysTrace.EE.GIF, - - + + // IOP Section - + &SysTrace.IOP.Bios, &SysTrace.IOP.Memcards, &SysTrace.IOP.PAD, @@ -164,7 +164,7 @@ static SysTraceLog * const traceLogList[] = &SysTrace.IOP.CDVD, }; -static const int traceLogCount = ArraySize(traceLogList); +static const uint traceLogCount = ArraySize(traceLogList); void SysTraceLog_LoadSaveSettings( IniInterface& ini ) { @@ -270,7 +270,7 @@ Panels::BaseCpuLogOptionsPanel* Panels::LogOptionsPanel::GetCpuPanel( const wxSt { if( token == L"EE" ) return m_eeSection; if( token == L"IOP" ) return m_iopSection; - + return NULL; } @@ -316,7 +316,7 @@ void Panels::LogOptionsPanel::Apply() m_iopSection->Apply(); m_IsDirty = false; - + for( uint i = 0; i 8) GSTransferStatus.PTH3 = PENDINGSTOP_MODE; else GSTransferStatus.PTH3 = STOPPED_MODE; - if (gifch.chcr.STR) { //Make sure we are really doing a DMA and not using FIFO - //GIF_LOG("Path3 end EOP %x NLOOP %x Status %x", tag.EOP, nloop, GSTransferStatus.PTH3); - gifch.madr += size * 16; - gifch.qwc -= size; - } break; } } - else if(pathidx == 2) + else if( nloop == 0) + { + //Need to set GIF as WAITING, sometimes it can get stuck in a bit of a loop if other paths think it's still doing REGLIST for example. + //Do NOT use IDLE mode here, it will freak Path3 masking out if it gets used. + switch(pathidx) + { + case GIF_PATH_1: + GSTransferStatus.PTH1 = WAITING_MODE; + break; + case GIF_PATH_2: + GSTransferStatus.PTH2 = WAITING_MODE; + break; + case GIF_PATH_3: + if(GSTransferStatus.PTH3 < IDLE_MODE) GSTransferStatus.PTH3 = WAITING_MODE; + break; + } + } + + if(pathidx == 2) { //if(nloop <= 16 && GSTransferStatus.PTH3 == IMAGE_MODE)GSTransferStatus.PTH3 = PENDINGIMAGE_MODE; if (gifch.chcr.STR) { //Make sure we are really doing a DMA and not using FIFO //GIF_LOG("Path3 end EOP %x NLOOP %x Status %x", tag.EOP, nloop, GSTransferStatus.PTH3); gifch.madr += size * 16; gifch.qwc -= size; + hwDmacSrcTadrInc(gifch); } } diff --git a/pcsx2/ps2/LegacyDmac.cpp b/pcsx2/ps2/LegacyDmac.cpp index 7e67e49275..51e1a1db70 100644 --- a/pcsx2/ps2/LegacyDmac.cpp +++ b/pcsx2/ps2/LegacyDmac.cpp @@ -104,7 +104,7 @@ __fi tDMA_TAG *SPRdmaGetAddr(u32 addr, bool write) // FIXME: Why??? DMA uses physical addresses addr &= 0x1ffffff0; - if (addr < Ps2MemSize::Base) + if (addr < Ps2MemSize::MainRam) { return (tDMA_TAG*)&eeMem->Main[addr]; } @@ -133,7 +133,7 @@ __ri tDMA_TAG *dmaGetAddr(u32 addr, bool write) // FIXME: Why??? DMA uses physical addresses addr &= 0x1ffffff0; - if (addr < Ps2MemSize::Base) + if (addr < Ps2MemSize::MainRam) { return (tDMA_TAG*)&eeMem->Main[addr]; } diff --git a/pcsx2/ps2/eeHwTraceLog.inl b/pcsx2/ps2/eeHwTraceLog.inl index 7f3fc8718b..4ac1f14c5e 100644 --- a/pcsx2/ps2/eeHwTraceLog.inl +++ b/pcsx2/ps2/eeHwTraceLog.inl @@ -133,6 +133,7 @@ static __ri const char* _eelog_GetHwName( u32 addr, T val ) EasyCase(VIF0_ASR1); EasyCase(VIF1_CHCR); + EasyCase(VIF1_MADR); EasyCase(VIF1_QWC); EasyCase(VIF1_TADR); EasyCase(VIF1_ASR0); diff --git a/pcsx2/vtlb.cpp b/pcsx2/vtlb.cpp index b0beb6783c..a7d9c35b85 100644 --- a/pcsx2/vtlb.cpp +++ b/pcsx2/vtlb.cpp @@ -33,9 +33,10 @@ #include "Common.h" #include "vtlb.h" #include "COP0.h" - #include "R5900Exceptions.h" +#include "Utilities/MemsetFast.inl" + using namespace R5900; using namespace vtlb_private; @@ -46,7 +47,7 @@ namespace vtlb_private __aligned(64) MapData vtlbdata; } -static vtlbHandler vtlbHandlerCount=0; +static vtlbHandler vtlbHandlerCount = 0; static vtlbHandler DefaultPhyHandler; static vtlbHandler UnmappedVirtHandler0; @@ -78,9 +79,9 @@ DataType __fastcall vtlb_memRead(u32 addr) switch( DataSize ) { - case 8: return ((vtlbMemR8FP*)vtlbdata.RWFT[0][0][hand])(paddr); - case 16: return ((vtlbMemR16FP*)vtlbdata.RWFT[1][0][hand])(paddr); - case 32: return ((vtlbMemR32FP*)vtlbdata.RWFT[2][0][hand])(paddr); + case 8: return ((vtlbMemR8FP*)vtlbdata.RWFT[0][0][hand])(paddr); + case 16: return ((vtlbMemR16FP*)vtlbdata.RWFT[1][0][hand])(paddr); + case 32: return ((vtlbMemR32FP*)vtlbdata.RWFT[2][0][hand])(paddr); jNO_DEFAULT; } @@ -147,9 +148,9 @@ void __fastcall vtlb_memWrite(u32 addr, DataType data) switch( DataSize ) { - case 8: return ((vtlbMemW8FP*)vtlbdata.RWFT[0][1][hand])(paddr, (u8)data); - case 16: return ((vtlbMemW16FP*)vtlbdata.RWFT[1][1][hand])(paddr, (u16)data); - case 32: return ((vtlbMemW32FP*)vtlbdata.RWFT[2][1][hand])(paddr, (u32)data); + case 8: return ((vtlbMemW8FP*)vtlbdata.RWFT[0][1][hand])(paddr, (u8)data); + case 16: return ((vtlbMemW16FP*)vtlbdata.RWFT[1][1][hand])(paddr, (u16)data); + case 32: return ((vtlbMemW32FP*)vtlbdata.RWFT[2][1][hand])(paddr, (u32)data); jNO_DEFAULT; } @@ -255,65 +256,55 @@ _tmpl(void) vtlbUnmappedPWriteLg(u32 addr,const OperandType* data) { vtlb_BusErr static mem8_t __fastcall vtlbDefaultPhyRead8(u32 addr) { - Console.Error("vtlbDefaultPhyRead8: 0x%08X", addr); - pxFailDev("(VTLB) Attempted read from an unmapped physical address."); + pxFailDev(pxsFmt("(VTLB) Attempted read8 from unmapped physical address @ 0x%08X.", addr)); return 0; } static mem16_t __fastcall vtlbDefaultPhyRead16(u32 addr) { - Console.Error("vtlbDefaultPhyRead16: 0x%08X", addr); - pxFailDev("(VTLB) Attempted read from an unmapped physical address."); + pxFailDev(pxsFmt("(VTLB) Attempted read16 from unmapped physical address @ 0x%08X.", addr)); return 0; } static mem32_t __fastcall vtlbDefaultPhyRead32(u32 addr) { - Console.Error("vtlbDefaultPhyRead32: 0x%08X", addr); - pxFailDev("(VTLB) Attempted read from an unmapped physical address."); + pxFailDev(pxsFmt("(VTLB) Attempted read32 from unmapped physical address @ 0x%08X.", addr)); return 0; } static void __fastcall vtlbDefaultPhyRead64(u32 addr, mem64_t* dest) { - Console.Error("vtlbDefaultPhyRead64: 0x%08X", addr); - pxFailDev("(VTLB) Attempted read from an unmapped physical address."); + pxFailDev(pxsFmt("(VTLB) Attempted read64 from unmapped physical address @ 0x%08X.", addr)); } static void __fastcall vtlbDefaultPhyRead128(u32 addr, mem128_t* dest) { - Console.Error("vtlbDefaultPhyRead128: 0x%08X", addr); - pxFailDev("(VTLB) Attempted read from an unmapped physical address."); + pxFailDev(pxsFmt("(VTLB) Attempted read128 from unmapped physical address @ 0x%08X.", addr)); } static void __fastcall vtlbDefaultPhyWrite8(u32 addr, mem8_t data) { - Console.Error("vtlbDefaultPhyWrite8: 0x%08X",addr); - pxFailDev("(VTLB) Attempted write to an unmapped physical address."); + pxFailDev(pxsFmt("(VTLB) Attempted write8 to unmapped physical address @ 0x%08X.", addr)); } static void __fastcall vtlbDefaultPhyWrite16(u32 addr, mem16_t data) { - Console.Error("vtlbDefaultPhyWrite16: 0x%08X",addr); - pxFailDev("(VTLB) Attempted write to an unmapped physical address."); + pxFailDev(pxsFmt("(VTLB) Attempted write16 to unmapped physical address @ 0x%08X.", addr)); } static void __fastcall vtlbDefaultPhyWrite32(u32 addr, mem32_t data) { - Console.Error("vtlbDefaultPhyWrite32: 0x%08X",addr); - pxFailDev("(VTLB) Attempted write to an unmapped physical address."); + pxFailDev(pxsFmt("(VTLB) Attempted write32 to unmapped physical address @ 0x%08X.", addr)); } static void __fastcall vtlbDefaultPhyWrite64(u32 addr,const mem64_t* data) { - Console.Error("vtlbDefaultPhyWrite64: 0x%08X",addr); - pxFailDev("(VTLB) Attempted write to an unmapped physical address."); + pxFailDev(pxsFmt("(VTLB) Attempted write64 to unmapped physical address @ 0x%08X.", addr)); } static void __fastcall vtlbDefaultPhyWrite128(u32 addr,const mem128_t* data) { - Console.Error("vtlbDefaultPhyWrite128: 0x%08X",addr); - pxFailDev("(VTLB) Attempted write to an unmapped physical address."); + pxFailDev(pxsFmt("(VTLB) Attempted write128 to unmapped physical address @ 0x%08X.", addr)); } #undef _tmpl @@ -333,6 +324,8 @@ __ri void vtlb_ReassignHandler( vtlbHandler rv, vtlbMemR8FP* r8,vtlbMemR16FP* r16,vtlbMemR32FP* r32,vtlbMemR64FP* r64,vtlbMemR128FP* r128, vtlbMemW8FP* w8,vtlbMemW16FP* w16,vtlbMemW32FP* w32,vtlbMemW64FP* w64,vtlbMemW128FP* w128 ) { + pxAssume(rv < VTLB_HANDLER_ITEMS); + vtlbdata.RWFT[0][0][rv] = (void*)((r8!=0) ? r8 : vtlbDefaultPhyRead8); vtlbdata.RWFT[1][0][rv] = (void*)((r16!=0) ? r16 : vtlbDefaultPhyRead16); vtlbdata.RWFT[2][0][rv] = (void*)((r32!=0) ? r32 : vtlbDefaultPhyRead32); @@ -348,7 +341,7 @@ __ri void vtlb_ReassignHandler( vtlbHandler rv, vtlbHandler vtlb_NewHandler() { - pxAssertDev( vtlbHandlerCount < 127, "VTLB allowed handler count exceeded!" ); + pxAssertDev( vtlbHandlerCount < VTLB_HANDLER_ITEMS, "VTLB handler count overflow!" ); return vtlbHandlerCount++; } @@ -362,7 +355,7 @@ vtlbHandler vtlb_NewHandler() // Returns a handle for the newly created handler See vtlb_MapHandler for use of the return value. // __ri vtlbHandler vtlb_RegisterHandler( vtlbMemR8FP* r8,vtlbMemR16FP* r16,vtlbMemR32FP* r32,vtlbMemR64FP* r64,vtlbMemR128FP* r128, - vtlbMemW8FP* w8,vtlbMemW16FP* w16,vtlbMemW32FP* w32,vtlbMemW64FP* w64,vtlbMemW128FP* w128) + vtlbMemW8FP* w8,vtlbMemW16FP* w16,vtlbMemW32FP* w32,vtlbMemW64FP* w64,vtlbMemW128FP* w128) { vtlbHandler rv = vtlb_NewHandler(); vtlb_ReassignHandler( rv, r8, r16, r32, r64, r128, w8, w16, w32, w64, w128 ); @@ -377,45 +370,47 @@ __ri vtlbHandler vtlb_RegisterHandler( vtlbMemR8FP* r8,vtlbMemR16FP* r16,vtlbMem // function. // // The memory region start and size parameters must be pagesize aligned. -void vtlb_MapHandler(vtlbHandler handler,u32 start,u32 size) +void vtlb_MapHandler(vtlbHandler handler, u32 start, u32 size) { verify(0==(start&VTLB_PAGE_MASK)); verify(0==(size&VTLB_PAGE_MASK) && size>0); - s32 value=handler|0x80000000; - while(size>0) + s32 value = handler | 0x80000000; + u32 end = start + (size - VTLB_PAGE_SIZE); + pxAssume( (end>>VTLB_PAGE_BITS) < ArraySize(vtlbdata.pmap) ); + + while (start <= end) { - vtlbdata.pmap[start>>VTLB_PAGE_BITS]=value; - - start+=VTLB_PAGE_SIZE; - size-=VTLB_PAGE_SIZE; + vtlbdata.pmap[start>>VTLB_PAGE_BITS] = value; + start += VTLB_PAGE_SIZE; } } -void vtlb_MapBlock(void* base,u32 start,u32 size,u32 blocksize) +void vtlb_MapBlock(void* base, u32 start, u32 size, u32 blocksize) { - s32 baseint=(s32)base; - verify(0==(start&VTLB_PAGE_MASK)); verify(0==(size&VTLB_PAGE_MASK) && size>0); - if (blocksize==0) - blocksize=size; + if (!blocksize) + blocksize = size; verify(0==(blocksize&VTLB_PAGE_MASK) && blocksize>0); verify(0==(size%blocksize)); - while(size>0) + s32 baseint = (s32)base; + u32 end = start + (size - VTLB_PAGE_SIZE); + pxAssume( (end>>VTLB_PAGE_BITS) < ArraySize(vtlbdata.pmap) ); + + while (start <= end) { - u32 blocksz=blocksize; - s32 ptr=baseint; + u32 loopsz = blocksize; + s32 ptr = baseint; - while(blocksz>0) + while (loopsz > 0) { - vtlbdata.pmap[start>>VTLB_PAGE_BITS]=ptr; + vtlbdata.pmap[start>>VTLB_PAGE_BITS] = ptr; - start+=VTLB_PAGE_SIZE; - ptr+=VTLB_PAGE_SIZE; - blocksz-=VTLB_PAGE_SIZE; - size-=VTLB_PAGE_SIZE; + start += VTLB_PAGE_SIZE; + ptr += VTLB_PAGE_SIZE; + loopsz -= VTLB_PAGE_SIZE; } } } @@ -426,13 +421,15 @@ void vtlb_Mirror(u32 new_region,u32 start,u32 size) verify(0==(start&VTLB_PAGE_MASK)); verify(0==(size&VTLB_PAGE_MASK) && size>0); - while(size>0) - { - vtlbdata.pmap[start>>VTLB_PAGE_BITS]=vtlbdata.pmap[new_region>>VTLB_PAGE_BITS]; + u32 end = start + (size-VTLB_PAGE_SIZE); + pxAssume( (end>>VTLB_PAGE_BITS) < ArraySize(vtlbdata.pmap) ); - start+=VTLB_PAGE_SIZE; - new_region+=VTLB_PAGE_SIZE; - size-=VTLB_PAGE_SIZE; + while(start <= end) + { + vtlbdata.pmap[start>>VTLB_PAGE_BITS] = vtlbdata.pmap[new_region>>VTLB_PAGE_BITS]; + + start += VTLB_PAGE_SIZE; + new_region += VTLB_PAGE_SIZE; } } @@ -446,66 +443,70 @@ __fi void* vtlb_GetPhyPtr(u32 paddr) //virtual mappings //TODO: Add invalid paddr checks -void vtlb_VMap(u32 vaddr,u32 paddr,u32 sz) +void vtlb_VMap(u32 vaddr,u32 paddr,u32 size) { verify(0==(vaddr&VTLB_PAGE_MASK)); verify(0==(paddr&VTLB_PAGE_MASK)); - verify(0==(sz&VTLB_PAGE_MASK) && sz>0); + verify(0==(size&VTLB_PAGE_MASK) && size>0); - while(sz>0) + while (size > 0) { s32 pme; - if (paddr>=VTLB_PMAP_SZ) + if (paddr >= VTLB_PMAP_SZ) { - pme=UnmappedPhyHandler0; - if (paddr&0x80000000) - pme=UnmappedPhyHandler1; - pme|=0x80000000; - pme|=paddr;// top bit is set anyway ... + pme = UnmappedPhyHandler0; + if (paddr & 0x80000000) + pme = UnmappedPhyHandler1; + pme |= 0x80000000; + pme |= paddr;// top bit is set anyway ... } else { - pme=vtlbdata.pmap[paddr>>VTLB_PAGE_BITS]; + pme = vtlbdata.pmap[paddr>>VTLB_PAGE_BITS]; if (pme<0) - pme|=paddr;// top bit is set anyway ... + pme |= paddr;// top bit is set anyway ... } - vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS]=pme-vaddr; - vaddr+=VTLB_PAGE_SIZE; - paddr+=VTLB_PAGE_SIZE; - sz-=VTLB_PAGE_SIZE; + + vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS] = pme-vaddr; + vaddr += VTLB_PAGE_SIZE; + paddr += VTLB_PAGE_SIZE; + size -= VTLB_PAGE_SIZE; } } -void vtlb_VMapBuffer(u32 vaddr,void* buffer,u32 sz) +void vtlb_VMapBuffer(u32 vaddr,void* buffer,u32 size) { verify(0==(vaddr&VTLB_PAGE_MASK)); - verify(0==(sz&VTLB_PAGE_MASK) && sz>0); - u32 bu8=(u32)buffer; - while(sz>0) + verify(0==(size&VTLB_PAGE_MASK) && size>0); + + u32 bu8 = (u32)buffer; + while (size > 0) { - vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS]=bu8-vaddr; - vaddr+=VTLB_PAGE_SIZE; - bu8+=VTLB_PAGE_SIZE; - sz-=VTLB_PAGE_SIZE; + vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS] = bu8-vaddr; + vaddr += VTLB_PAGE_SIZE; + bu8 += VTLB_PAGE_SIZE; + size -= VTLB_PAGE_SIZE; } } -void vtlb_VMapUnmap(u32 vaddr,u32 sz) +void vtlb_VMapUnmap(u32 vaddr,u32 size) { verify(0==(vaddr&VTLB_PAGE_MASK)); - verify(0==(sz&VTLB_PAGE_MASK) && sz>0); + verify(0==(size&VTLB_PAGE_MASK) && size>0); - while(sz>0) + while (size > 0) { - u32 handl=UnmappedVirtHandler0; - if (vaddr&0x80000000) + u32 handl = UnmappedVirtHandler0; + if (vaddr & 0x80000000) { - handl=UnmappedVirtHandler1; + handl = UnmappedVirtHandler1; } - handl|=vaddr; // top bit is set anyway ... - handl|=0x80000000; - vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS]=handl-vaddr; - vaddr+=VTLB_PAGE_SIZE; - sz-=VTLB_PAGE_SIZE; + + handl |= vaddr; // top bit is set anyway ... + handl |= 0x80000000; + + vtlbdata.vmap[vaddr>>VTLB_PAGE_BITS] = handl-vaddr; + vaddr += VTLB_PAGE_SIZE; + size -= VTLB_PAGE_SIZE; } } @@ -562,60 +563,86 @@ void vtlb_Term() } // Reserves the vtlb core allocation used by various emulation components! -// +// [TODO] basemem - request allocating memory at the specified virtual location, which can allow +// for easier debugging and/or 3rd party cheat programs. If 0, the operating system +// default is used. void vtlb_Core_Alloc() { - if( vtlbdata.alloc_base != NULL ) return; - - vtlbdata.alloc_current = 0; - -#ifdef __LINUX__ - vtlbdata.alloc_base = SysMmapEx( 0x16000000, VTLB_ALLOC_SIZE, 0x80000000, "Vtlb" ); -#else - // Win32 just needs this, since malloc always maps below 2GB. - vtlbdata.alloc_base = (u8*)_aligned_malloc( VTLB_ALLOC_SIZE, 4096 ); - if( vtlbdata.alloc_base == NULL ) - throw Exception::OutOfMemory( pxsFmt(L"PS2 mappable system ram (%u megs)", VTLB_ALLOC_SIZE / _1mb) ); -#endif + if (!vtlbdata.vmap) + { + vtlbdata.vmap = (s32*)_aligned_malloc( VTLB_VMAP_ITEMS * sizeof(*vtlbdata.vmap), 16 ); + if (!vtlbdata.vmap) + throw Exception::OutOfMemory( L"VTLB Virtual Address Translation LUT" ) + .SetDiagMsg(pxsFmt("(%u megs)", VTLB_VMAP_ITEMS * sizeof(*vtlbdata.vmap) / _1mb) + ); + } } -void vtlb_Core_Shutdown() +void vtlb_Core_Free() { - if( vtlbdata.alloc_base == NULL ) return; - -#ifdef __LINUX__ - SafeSysMunmap( vtlbdata.alloc_base, VTLB_ALLOC_SIZE ); -#else - // Make sure and unprotect memory first, since CrtDebug will try to write to it. - HostSys::MemProtect( vtlbdata.alloc_base, VTLB_ALLOC_SIZE, Protect_ReadWrite ); - safe_aligned_free( vtlbdata.alloc_base ); -#endif - + safe_aligned_free( vtlbdata.vmap ); } -// This function allocates memory block with are compatible with the Vtlb's requirements -// for memory locations. The Vtlb requires the topmost bit (Sign bit) of the memory -// pointer to be cleared. Some operating systems and/or implementations of malloc do that, -// but others do not. So use this instead to allocate the memory correctly for your -// platform. -// -u8* vtlb_malloc( uint size, uint align ) +static wxString GetHostVmErrorMsg() { - vtlbdata.alloc_current += align-1; - vtlbdata.alloc_current &= ~(align-1); - - int rv = vtlbdata.alloc_current; - vtlbdata.alloc_current += size; - - pxAssertDev( vtlbdata.alloc_current < VTLB_ALLOC_SIZE, "(vtlb_malloc) memory overflow! Please increase the size of VTLB_ALLOC_SIZE!" ); - return &vtlbdata.alloc_base[rv]; + return pxE(".Error:HostVmReserve", + L"Your system is too low on virtual resources for PCSX2 to run. This can be " + L"caused by having a small or disabled swapfile, or by other programs that are " + L"hogging resources." + ); } - -void vtlb_free( void* pmem, uint size ) +// -------------------------------------------------------------------------------------- +// VtlbMemoryReserve (implementations) +// -------------------------------------------------------------------------------------- +VtlbMemoryReserve::VtlbMemoryReserve( const wxString& name, size_t size ) + : m_reserve( name, size ) { - vtlbdata.alloc_current -= size; - - pxAssertDev( vtlbdata.alloc_current >= 0, "(vtlb_free) mismatched calls to vtlb_malloc and free detected via memory underflow." ); - - return; + m_reserve.SetPageAccessOnCommit( PageAccess_ReadWrite() ); } + +void VtlbMemoryReserve::SetBaseAddr( uptr newaddr ) +{ + m_reserve.SetBaseAddr( newaddr ); +} + +void VtlbMemoryReserve::Reserve( sptr hostptr ) +{ + if (!m_reserve.ReserveAt( hostptr )) + { + throw Exception::OutOfMemory( m_reserve.GetName() ) + .SetDiagMsg(L"Vtlb memory could not be reserved.") + .SetUserMsg(GetHostVmErrorMsg()); + } +} + +void VtlbMemoryReserve::Commit() +{ + if (IsCommitted()) return; + if (!m_reserve.Commit()) + { + throw Exception::OutOfMemory( m_reserve.GetName() ) + .SetDiagMsg(L"Vtlb memory could not be committed.") + .SetUserMsg(GetHostVmErrorMsg()); + } +} + +void VtlbMemoryReserve::Reset() +{ + Commit(); + memzero_sse_a(m_reserve.GetPtr(), m_reserve.GetCommittedBytes()); +} + +void VtlbMemoryReserve::Decommit() +{ + m_reserve.Reset(); +} + +void VtlbMemoryReserve::Release() +{ + m_reserve.Release(); +} + +bool VtlbMemoryReserve::IsCommitted() const +{ + return !!m_reserve.GetCommittedPageCount(); +} \ No newline at end of file diff --git a/pcsx2/vtlb.h b/pcsx2/vtlb.h index 5b048a384e..891b3c5323 100644 --- a/pcsx2/vtlb.h +++ b/pcsx2/vtlb.h @@ -17,6 +17,10 @@ #include "MemoryTypes.h" +#include "Utilities/PageFaultSource.h" + +static const uptr VTLB_AllocUpperBounds = _1gb * 2; + // Specialized function pointers for each read type typedef mem8_t __fastcall vtlbMemR8FP(u32 addr); typedef mem16_t __fastcall vtlbMemR16FP(u32 addr); @@ -34,12 +38,10 @@ typedef void __fastcall vtlbMemW128FP(u32 addr,const mem128_t* data); typedef u32 vtlbHandler; extern void vtlb_Core_Alloc(); -extern void vtlb_Core_Shutdown(); +extern void vtlb_Core_Free(); extern void vtlb_Init(); extern void vtlb_Reset(); extern void vtlb_Term(); -extern u8* vtlb_malloc( uint size, uint align ); -extern void vtlb_free( void* pmem, uint size ); extern vtlbHandler vtlb_NewHandler(); @@ -85,32 +87,121 @@ extern void vtlb_DynGenWrite_Const( u32 bits, u32 addr_const ); extern void vtlb_DynGenRead64_Const( u32 bits, u32 addr_const ); extern void vtlb_DynGenRead32_Const( u32 bits, bool sign, u32 addr_const ); +// -------------------------------------------------------------------------------------- +// VtlbMemoryReserve +// -------------------------------------------------------------------------------------- +class VtlbMemoryReserve +{ +protected: + VirtualMemoryReserve m_reserve; + +public: + VtlbMemoryReserve( const wxString& name, size_t size ); + virtual ~VtlbMemoryReserve() throw() + { + m_reserve.Release(); + } + + virtual void Reserve( sptr hostptr ); + virtual void Release(); + + virtual void Commit(); + virtual void Reset(); + virtual void Decommit(); + virtual void SetBaseAddr( uptr newaddr ); + + bool IsCommitted() const; +}; + +// -------------------------------------------------------------------------------------- +// eeMemoryReserve +// -------------------------------------------------------------------------------------- +class eeMemoryReserve : public VtlbMemoryReserve +{ + typedef VtlbMemoryReserve _parent; + +public: + eeMemoryReserve(); + virtual ~eeMemoryReserve() throw() + { + Release(); + } + + void Reserve(); + void Commit(); + void Decommit(); + void Reset(); + void Release(); +}; + +// -------------------------------------------------------------------------------------- +// iopMemoryReserve +// -------------------------------------------------------------------------------------- +class iopMemoryReserve : public VtlbMemoryReserve +{ + typedef VtlbMemoryReserve _parent; + +public: + iopMemoryReserve(); + virtual ~iopMemoryReserve() throw() + { + Release(); + } + + void Reserve(); + void Commit(); + void Decommit(); + void Release(); + void Reset(); +}; + +// -------------------------------------------------------------------------------------- +// vuMemoryReserve +// -------------------------------------------------------------------------------------- +class vuMemoryReserve : public VtlbMemoryReserve +{ + typedef VtlbMemoryReserve _parent; + +public: + vuMemoryReserve(); + virtual ~vuMemoryReserve() throw() + { + Release(); + } + + virtual void Reserve(); + virtual void Release(); + + void Reset(); +}; + namespace vtlb_private { - // Allocate enough memory for both EE and IOP memory space (IOP is roughly 2.5mb, - // so we alloc 4mb for now -- a little more than is needed). - static const uint VTLB_ALLOC_SIZE = sizeof(*eeMem) + (_1mb*4); - static const uint VTLB_PAGE_BITS = 12; static const uint VTLB_PAGE_MASK = 4095; static const uint VTLB_PAGE_SIZE = 4096; - static const uint VTLB_PMAP_ITEMS = 0x20000000 / VTLB_PAGE_SIZE; - static const uint VTLB_PMAP_SZ = 0x20000000; - static const uint VTLB_VMAP_ITEMS = 0x100000000ULL / VTLB_PAGE_SIZE; + static const uint VTLB_PMAP_SZ = _1mb * 512; + static const uint VTLB_PMAP_ITEMS = VTLB_PMAP_SZ / VTLB_PAGE_SIZE; + static const uint VTLB_VMAP_ITEMS = _4gb / VTLB_PAGE_SIZE; + + static const uint VTLB_HANDLER_ITEMS = 128; struct MapData { - u8* alloc_base; //base of the memory array - int alloc_current; //current base - - s32 pmap[VTLB_PMAP_ITEMS]; //512KB - s32 vmap[VTLB_VMAP_ITEMS]; //4MB - // first indexer -- 8/16/32/64/128 bit tables [values 0-4] // second indexer -- read/write [0 or 1] // third indexer -- 128 possible handlers! - void* RWFT[5][2][128]; + void* RWFT[5][2][VTLB_HANDLER_ITEMS]; + + s32 pmap[VTLB_PMAP_ITEMS]; //512KB + + s32* vmap; //4MB (allocated by vtlb_init) + + MapData() + { + vmap = NULL; + } }; extern __aligned(64) MapData vtlbdata; diff --git a/pcsx2/windows/SamplProf.cpp b/pcsx2/windows/SamplProf.cpp index 74e3dfaf4b..89ea7302b1 100644 --- a/pcsx2/windows/SamplProf.cpp +++ b/pcsx2/windows/SamplProf.cpp @@ -119,40 +119,47 @@ static bool _registeredName( const wxString& name ) return false; } -void ProfilerRegisterSource(const char* Name, const void* buff, u32 sz) +void ProfilerRegisterSource(const wxString& Name, const void* buff, u32 sz) { if( ProfRunning ) EnterCriticalSection( &ProfModulesLock ); - wxString strName( fromUTF8(Name) ); - if( !_registeredName( strName ) ) - ProfModules.push_back( Module( strName, buff, sz ) ); + if( !_registeredName( Name ) ) + ProfModules.push_back( Module( Name, buff, sz ) ); if( ProfRunning ) LeaveCriticalSection( &ProfModulesLock ); } +void ProfilerRegisterSource(const wxString& Name, const void* function) +{ + if( ProfRunning ) + EnterCriticalSection( &ProfModulesLock ); + + if( !_registeredName( Name ) ) + ProfModules.push_back( Module(Name,function) ); + + if( ProfRunning ) + LeaveCriticalSection( &ProfModulesLock ); +} + +void ProfilerRegisterSource(const char* Name, const void* buff, u32 sz) +{ + ProfilerRegisterSource( fromUTF8(Name), buff, sz ); +} + void ProfilerRegisterSource(const char* Name, const void* function) { - if( ProfRunning ) - EnterCriticalSection( &ProfModulesLock ); - - wxString strName( fromUTF8(Name) ); - if( !_registeredName( strName ) ) - ProfModules.push_back( Module(strName,function) ); - - if( ProfRunning ) - LeaveCriticalSection( &ProfModulesLock ); + ProfilerRegisterSource( fromUTF8(Name), function ); } -void ProfilerTerminateSource( const char* Name ) +void ProfilerTerminateSource( const wxString& Name ) { - wxString strName( fromUTF8(Name) ); for( vector::const_iterator iter = ProfModules.begin(), end = ProfModules.end(); itername.compare( strName ) == 0 ) + if( iter->name.compare( Name ) == 0 ) { ProfModules.erase( iter ); break; @@ -160,6 +167,11 @@ void ProfilerTerminateSource( const char* Name ) } } +void ProfilerTerminateSource( const char* Name ) +{ + ProfilerTerminateSource( fromUTF8(Name) ); +} + static bool DispatchKnownModules( uint Eip ) { bool retval = false; diff --git a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj index 1affaf6adf..c2011ce0c3 100644 --- a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj +++ b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj @@ -1,2901 +1,2898 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pcsx2/windows/WinCompressNTFS.cpp b/pcsx2/windows/WinCompressNTFS.cpp index 3f9a42f848..c49cc0b9ea 100644 --- a/pcsx2/windows/WinCompressNTFS.cpp +++ b/pcsx2/windows/WinCompressNTFS.cpp @@ -46,7 +46,7 @@ void StreamException_ThrowLastError( const wxString& streamname, HANDLE result ) default: { - throw Exception::Stream( streamname ).SetDiagMsg(wxsFormat( L"General Win32 File/stream error [GetLastError: %d]", error )); + throw Exception::BadStream( streamname ).SetDiagMsg(pxsFmt( L"General Win32 File/stream error [GetLastError: %d]", error )); } } } @@ -58,7 +58,7 @@ bool StreamException_LogLastError( const wxString& streamname, const wxChar* act { StreamException_ThrowLastError( streamname, result ); } - catch( Exception::Stream& ex ) + catch( Exception::BadStream& ex ) { Console.WriteLn( Color_Yellow, L"%s: %s", action, ex.FormatDiagnosticMessage().c_str() ); return true; diff --git a/pcsx2/windows/WinSysExec.cpp b/pcsx2/windows/WinSysExec.cpp index 6a11a70c62..462515651e 100644 --- a/pcsx2/windows/WinSysExec.cpp +++ b/pcsx2/windows/WinSysExec.cpp @@ -18,18 +18,4 @@ #include #include "Common.h" -#include "System/PageFaultSource.h" - -int SysPageFaultExceptionFilter( EXCEPTION_POINTERS* eps ) -{ - if( eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION ) - return EXCEPTION_CONTINUE_SEARCH; - - Source_PageFault.Dispatch( PageFaultInfo( (uptr)eps->ExceptionRecord->ExceptionInformation[1] ) ); - return Source_PageFault.WasHandled() ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH; -} - -void InstallSignalHandler() -{ - // NOP on Win32 systems -- we use __try{} __except{} instead. -} +#include "Utilities/PageFaultSource.h" diff --git a/pcsx2/windows/cheats/browser.cpp b/pcsx2/windows/cheats/browser.cpp index 47454a17ef..3024ec0b13 100644 --- a/pcsx2/windows/cheats/browser.cpp +++ b/pcsx2/windows/cheats/browser.cpp @@ -1083,7 +1083,7 @@ BOOL CALLBACK BrowserProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) case IDC_SKIPMPEG: { u8 *p = eeMem->Main; - u8 *d = p + Ps2MemSize::Base; + u8 *d = p + Ps2MemSize::MainRam; d -= 16; u32 *u; diff --git a/pcsx2/windows/cheats/cheats.cpp b/pcsx2/windows/cheats/cheats.cpp index 070e3dfe54..3446fe3d06 100644 --- a/pcsx2/windows/cheats/cheats.cpp +++ b/pcsx2/windows/cheats/cheats.cpp @@ -59,7 +59,7 @@ bool FirstSearch; bool FirstShow; -char olds[Ps2MemSize::Base]; +char olds[Ps2MemSize::MainRam]; char tn[100]; char to[100]; diff --git a/pcsx2/x86/BaseblockEx.h b/pcsx2/x86/BaseblockEx.h index 502242766d..7ae34824e6 100644 --- a/pcsx2/x86/BaseblockEx.h +++ b/pcsx2/x86/BaseblockEx.h @@ -81,9 +81,6 @@ public: __fi int Index (u32 startpc) const { int idx = LastIndex(startpc); - // fixme: I changed the parenthesis to be unambiguous, but this needs to be checked to see if ((x or y or z) and w) - // is correct, or ((x or y) or (z and w)), or some other variation. --arcum42 - // Mixing &&'s and ||'s is not actually ambiguous; &&'s take precedence. Reverted to old behavior -- ChickenLiver. if ((idx == -1) || (startpc < blocks[idx].startpc) || ((blocks[idx].size) && (startpc >= blocks[idx].startpc + blocks[idx].size * 4))) return -1; @@ -139,9 +136,10 @@ public: static void recLUT_SetPage(uptr reclut[0x10000], uptr hwlut[0x10000], BASEBLOCK *mapbase, uint pagebase, uint pageidx, uint mappage) { + // this value is in 64k pages! uint page = pagebase + pageidx; - jASSUME( page < 0x10000 ); + pxAssume( page < 0x10000 ); reclut[page] = (uptr)&mapbase[(mappage - page) << 14]; if (hwlut) hwlut[page] = 0u - (pagebase << 16); diff --git a/pcsx2/x86/iR3000A.cpp b/pcsx2/x86/iR3000A.cpp index 41f836ca56..941125e3d8 100644 --- a/pcsx2/x86/iR3000A.cpp +++ b/pcsx2/x86/iR3000A.cpp @@ -22,6 +22,7 @@ #include "iR3000A.h" #include "BaseblockEx.h" +#include "System/RecTypes.h" #include @@ -32,7 +33,6 @@ #include "IopCommon.h" #include "iCore.h" -#include "SamplProf.h" #include "NakedAsm.h" #include "AppConfig.h" @@ -50,13 +50,8 @@ uptr psxhwLUT[0x10000]; #define HWADDR(mem) (psxhwLUT[mem >> 16] + (mem)) -#define MAPBASE 0x48000000 -#define RECMEM_SIZE (8*1024*1024) +static RecompiledCodeReserve* recMem = NULL; -// R3000A statics -int psxreclog = 0; - -static u8 *recMem = NULL; // the recompiled blocks will be here static BASEBLOCK *recRAM = NULL; // and the ptr to the blocks here static BASEBLOCK *recROM = NULL; // and here static BASEBLOCK *recROM1 = NULL; // also here @@ -130,7 +125,7 @@ static void recEventTest() // stackframe setup code in this function) static void __fastcall StackFrameCheckFailed( int espORebp, int regval ) { - pxFailDev( wxsFormat( L"(R3000A Recompiler Stackframe) Sanity check failed on %s\n\tCurrent=%d; Saved=%d", + pxFailDev( pxsFmt( L"(R3000A Recompiler Stackframe) Sanity check failed on %s\n\tCurrent=%d; Saved=%d", (espORebp==0) ? L"ESP" : L"EBP", regval, (espORebp==0) ? s_store_esp : s_store_ebp ) ); @@ -346,7 +341,7 @@ static DynGenFunc* _DynGen_EnterRecompiledCode() static void _DynGen_Dispatchers() { // In case init gets called multiple times: - HostSys::MemProtectStatic( iopRecDispatchers, Protect_ReadWrite, false ); + HostSys::MemProtectStatic( iopRecDispatchers, PageAccess_ReadWrite() ); // clear the buffer to 0xcc (easier debugging). memset_8<0xcc,__pagesize>( iopRecDispatchers ); @@ -363,7 +358,7 @@ static void _DynGen_Dispatchers() iopJITCompileInBlock = _DynGen_JITCompileInBlock(); iopEnterRecompiledCode = _DynGen_EnterRecompiledCode(); - HostSys::MemProtectStatic( iopRecDispatchers, Protect_ReadOnly, true ); + HostSys::MemProtectStatic( iopRecDispatchers, PageAccess_ExecOnly() ); recBlocks.SetJITCompile( iopJITCompile ); } @@ -754,23 +749,38 @@ void psxRecompileCodeConst3(R3000AFNPTR constcode, R3000AFNPTR_INFO constscode, noconstcode(0); } +static uptr m_ConfiguredCacheReserve = 32; static u8* m_recBlockAlloc = NULL; static const uint m_recBlockAllocSize = (((Ps2MemSize::IopRam + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4) * sizeof(BASEBLOCK)); +static void recReserveCache() +{ + if (!recMem) recMem = new RecompiledCodeReserve(L"R3000A Recompiler Cache", _1mb * 2); + recMem->SetProfilerName("IOPrec"); + + while (!recMem->IsOk()) + { + if (recMem->Reserve( m_ConfiguredCacheReserve * _1mb, HostMemoryMap::IOPrec ) != NULL) break; + + // If it failed, then try again (if possible): + if (m_ConfiguredCacheReserve < 4) break; + m_ConfiguredCacheReserve /= 2; + } + + recMem->ThrowIfNotOk(); +} + +static void recReserve() +{ + // IOP has no hardware requirements! + + recReserveCache(); +} + static void recAlloc() { - // Note: the VUrec depends on being able to grab an allocation below the 0x10000000 line, - // so we give the EErec an address above that to try first as it's basemem address, hence - // the 0x28000000 pick (0x20000000 is picked by the EE) - - if( recMem == NULL ) - recMem = (u8*)SysMmapEx( 0x28000000, RECMEM_SIZE, 0, "recAlloc(R3000a)" ); - - if( recMem == NULL ) - throw Exception::OutOfMemory( L"R3000A recompiled code cache" ); - // Goal: Allocate BASEBLOCKs for every possible branch target in IOP memory. // Any 4-byte aligned address makes a valid branch target as per MIPS design (all instructions are // always 4 bytes long). @@ -795,24 +805,22 @@ static void recAlloc() if( s_pInstCache == NULL ) throw Exception::OutOfMemory( L"R3000 InstCache." ); - ProfilerRegisterSource( "IOP Rec", recMem, RECMEM_SIZE ); _DynGen_Dispatchers(); } void recResetIOP() { - // calling recResetIOP without first calling recInit is bad mojo. - pxAssert( recMem != NULL ); - pxAssert( m_recBlockAlloc != NULL ); - DevCon.WriteLn( "iR3000A Recompiler reset." ); - memset_8<0xcc,RECMEM_SIZE>( recMem ); // 0xcc is INT3 + recAlloc(); + recMem->Reset(); + iopClearRecLUT((BASEBLOCK*)m_recBlockAlloc, (((Ps2MemSize::IopRam + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4))); for (int i = 0; i < 0x10000; i++) recLUT_SetPage(psxRecLUT, 0, 0, 0, i, 0); + // IOP knows 64k pages, hence for the 0x10000's // The bottom 2 bits of PC are always zero, so we <<14 to "compress" @@ -820,6 +828,7 @@ void recResetIOP() // We're only mapping 20 pages here in 4 places. // 0x80 comes from : (Ps2MemSize::IopRam / 0x10000) * 4 + for (int i=0; i<0x80; i++) { recLUT_SetPage(psxRecLUT, psxhwLUT, recRAM, 0x0000, i, i & 0x1f); @@ -847,15 +856,14 @@ void recResetIOP() recBlocks.Reset(); g_psxMaxRecMem = 0; - recPtr = recMem; + recPtr = *recMem; psxbranch = 0; } static void recShutdown() { - ProfilerTerminateSource( "IOPRec" ); + safe_delete( recMem ); - SafeSysMunmap(recMem, RECMEM_SIZE); safe_aligned_free( m_recBlockAlloc ); safe_free( s_pInstCache ); @@ -1202,8 +1210,9 @@ static void __fastcall iopRecRecompile( const u32 startpc ) pxAssert( startpc ); // if recPtr reached the mem limit reset whole mem - if (((uptr)recPtr - (uptr)recMem) >= (RECMEM_SIZE - 0x10000)) + if (recPtr >= (recMem->GetPtrEnd() - _64kb)) { recResetIOP(); + } x86SetPtr( recPtr ); x86Align(16); @@ -1390,12 +1399,12 @@ StartRecomp: } } - pxAssert( x86Ptr < recMem+RECMEM_SIZE ); + pxAssert( xGetPtr() < recMem->GetPtrEnd() ); - pxAssert(x86Ptr - recPtr < 0x10000); - s_pCurBlockEx->x86size = x86Ptr - recPtr; + pxAssert(xGetPtr() - recPtr < _64kb); + s_pCurBlockEx->x86size = xGetPtr() - recPtr; - recPtr = x86Ptr; + recPtr = xGetPtr(); pxAssert( (g_psxHasConstReg&g_psxFlushedConstReg) == g_psxHasConstReg ); @@ -1403,12 +1412,25 @@ StartRecomp: s_pCurBlockEx = NULL; } +static void recSetCacheReserve( uint reserveInMegs ) +{ + m_ConfiguredCacheReserve = reserveInMegs; +} + +static uint recGetCacheReserve() +{ + return m_ConfiguredCacheReserve; +} + R3000Acpu psxRec = { - recAlloc, + recReserve, recResetIOP, recExecute, recExecuteBlock, recClearIOP, - recShutdown + recShutdown, + + recGetCacheReserve, + recSetCacheReserve }; diff --git a/pcsx2/x86/ix86-32/iR5900-32.cpp b/pcsx2/x86/ix86-32/iR5900-32.cpp index b3753a74fd..2be0fafd9c 100644 --- a/pcsx2/x86/ix86-32/iR5900-32.cpp +++ b/pcsx2/x86/ix86-32/iR5900-32.cpp @@ -21,15 +21,14 @@ #include "R5900Exceptions.h" #include "R5900OpcodeTables.h" #include "iR5900.h" - #include "BaseblockEx.h" +#include "System/RecTypes.h" + #include "vtlb.h" -#include "SamplProf.h" #include "Dump.h" #include "System/SysThreads.h" #include "GS.h" - #include "CDVD/CDVD.h" #include "Elfheader.h" @@ -37,14 +36,18 @@ # include #endif + +#include "Utilities/MemsetFast.inl" + + using namespace x86Emitter; using namespace R5900; #define PC_GETBLOCK(x) PC_GETBLOCK_(x, recLUT) u32 maxrecmem = 0; -static __aligned16 uptr recLUT[0x10000]; -static __aligned16 uptr hwLUT[0x10000]; +static __aligned16 uptr recLUT[_64kb]; +static __aligned16 uptr hwLUT[_64kb]; #define HWADDR(mem) (hwLUT[mem >> 16] + (mem)) @@ -57,18 +60,41 @@ __aligned16 GPR_reg64 g_cpuConstRegs[32] = {0}; u32 g_cpuHasConstReg = 0, g_cpuFlushedConstReg = 0; bool g_cpuFlushedPC, g_cpuFlushedCode, g_recompilingDelaySlot, g_maySignalException; +// -------------------------------------------------------------------------------------- +// R5900LutReserve_RAM +// -------------------------------------------------------------------------------------- +class R5900LutReserve_RAM : public SpatialArrayReserve +{ + typedef SpatialArrayReserve _parent; + +public: + R5900LutReserve_RAM( const wxString& name ) + : _parent( name ) + { + } + +protected: + void OnCommittedBlock( void* block ); +}; + + //////////////////////////////////////////////////////////////// // Static Private Variables - R5900 Dynarec #define X86 static const int RECCONSTBUF_SIZE = 16384 * 2; // 64 bit consts in 32 bit units -static u8 *recMem = NULL; // the recompiled blocks will be here +static RecompiledCodeReserve* recMem = NULL; +static SpatialArrayReserve* recRAMCopy = NULL; +static R5900LutReserve_RAM* recLutReserve_RAM = NULL; + +static uptr m_ConfiguredCacheReserve = 64; + static u32* recConstBuf = NULL; // 64-bit pseudo-immediates static BASEBLOCK *recRAM = NULL; // and the ptr to the blocks here static BASEBLOCK *recROM = NULL; // and here static BASEBLOCK *recROM1 = NULL; // also here -static u32 *recRAMCopy = NULL; + static BaseBlocks recBlocks; static u8* recPtr = NULL; static u32 *recConstBufPtr = NULL; @@ -506,7 +532,7 @@ static DynGenFunc* _DynGen_EnterRecompiledCode() static void _DynGen_Dispatchers() { // In case init gets called multiple times: - HostSys::MemProtectStatic( eeRecDispatchers, Protect_ReadWrite, false ); + HostSys::MemProtectStatic( eeRecDispatchers, PageAccess_ReadWrite() ); // clear the buffer to 0xcc (easier debugging). memset_8<0xcc,__pagesize>( eeRecDispatchers ); @@ -523,7 +549,7 @@ static void _DynGen_Dispatchers() JITCompileInBlock = _DynGen_JITCompileInBlock(); EnterRecompiledCode = _DynGen_EnterRecompiledCode(); - HostSys::MemProtectStatic( eeRecDispatchers, Protect_ReadOnly, true ); + HostSys::MemProtectStatic( eeRecDispatchers, PageAccess_ExecOnly() ); recBlocks.SetJITCompile( JITCompile ); } @@ -531,24 +557,45 @@ static void _DynGen_Dispatchers() ////////////////////////////////////////////////////////////////////////////////////////// // -static const int REC_CACHEMEM = 0x01000000; static void __fastcall dyna_block_discard(u32 start,u32 sz); -// memory allocation handle for the entire BASEBLOCK and stack allocations. -static u8* m_recBlockAlloc = NULL; +static __ri void ClearRecLUT(BASEBLOCK* base, int memsize) +{ + for (int i = 0; i < memsize/4; i++) + base[i].SetFnptr((uptr)JITCompile); +} -static const uint m_recBlockAllocSize = - (((Ps2MemSize::Base + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4) * sizeof(BASEBLOCK)) -+ RECCONSTBUF_SIZE * sizeof(u32) + Ps2MemSize::Base; +void R5900LutReserve_RAM::OnCommittedBlock( void* block ) +{ + _parent::OnCommittedBlock(block); + ClearRecLUT((BASEBLOCK*)block, __pagesize * m_blocksize); +} static void recThrowHardwareDeficiency( const wxChar* extFail ) { throw Exception::HardwareDeficiency() - .SetDiagMsg(wxsFormat( L"R5900-32 recompiler init failed: %s is not available.", extFail)) - .SetUserMsg(wxsFormat(_("%s Extensions not found. The R5900-32 recompiler requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail )); + .SetDiagMsg(pxsFmt( L"R5900-32 recompiler init failed: %s is not available.", extFail)) + .SetUserMsg(pxsFmt(_("%s Extensions not found. The R5900-32 recompiler requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail )); } -static void recAlloc() +static void recReserveCache() +{ + if (!recMem) recMem = new RecompiledCodeReserve(L"R5900-32 Recompiler Cache", _1mb * 4); + recMem->SetProfilerName("EErec"); + + while (!recMem->IsOk()) + { + if (recMem->Reserve( m_ConfiguredCacheReserve * _1mb, HostMemoryMap::EErec ) != NULL) break; + + // If it failed, then try again (if possible): + if (m_ConfiguredCacheReserve < 16) break; + m_ConfiguredCacheReserve /= 2; + } + + recMem->ThrowIfNotOk(); +} + +static void recReserve() { // Hardware Requirements Check... @@ -561,99 +608,31 @@ static void recAlloc() if ( !x86caps.hasStreamingSIMD2Extensions ) recThrowHardwareDeficiency( L"SSE2" ); - if( recMem == NULL ) - { - // It's handy to have a constant base address for the EE recompiler buffer, since it - // allows me to key in the address directly in the debugger, and also recognize EE - // recompiled code from user-provisioned stack traces. But besides those, the recompiler - // has no actual restrictions on where it's compiled code buffer is located. - - // Note: the SuperVU recompiler depends on being able to grab an allocation below the - // 0x10000000 line, so we give the EErec an address above that to try first as it's - // basemem address, hence the 0x20000000 pick. - - const uint cachememsize = REC_CACHEMEM+0x1000; - recMem = (u8*)SysMmapEx( 0x20000000, cachememsize, 0, "recAlloc(R5900)" ); - } - - if( recMem == NULL ) - throw Exception::OutOfMemory( L"R5900-32 recompiled code cache" ); - - // Goal: Allocate BASEBLOCKs for every possible branch target in PS2 memory. - // Any 4-byte aligned address makes a valid branch target as per MIPS design (all instructions are - // always 4 bytes long). - - if( m_recBlockAlloc == NULL ) - m_recBlockAlloc = (u8*) _aligned_malloc( m_recBlockAllocSize, 4096 ); - - if( m_recBlockAlloc == NULL ) - throw Exception::OutOfMemory( L"R5900-32 BASEBLOCK tables" ); - - u8* curpos = m_recBlockAlloc; - recRAM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Base / 4) * sizeof(BASEBLOCK); - recROM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom / 4) * sizeof(BASEBLOCK); - recROM1 = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom1 / 4) * sizeof(BASEBLOCK); - recConstBuf = (u32*)curpos; curpos += RECCONSTBUF_SIZE * sizeof(u32); - recRAMCopy = (u32*)curpos; - - if( s_pInstCache == NULL ) - { - s_nInstCacheSize = 128; - s_pInstCache = (EEINST*)malloc( sizeof(EEINST) * s_nInstCacheSize ); - } - - if( s_pInstCache == NULL ) - throw Exception::OutOfMemory( L"R5900-32 InstCache" ); - - // No errors.. Proceed with initialization: - - ProfilerRegisterSource( "EE Rec", recMem, REC_CACHEMEM+0x1000 ); - _DynGen_Dispatchers(); - - x86FpuState = FPU_STATE; + recReserveCache(); } -struct ManualPageTracking +static void recAlloc() { - u16 page; - u8 counter; -}; + if (!recRAMCopy) + { + recRAMCopy = new SpatialArrayReserve( L"R5900 RAM copy" ); + recRAMCopy->SetBlockSize(_16kb); + recRAMCopy->Reserve(Ps2MemSize::MainRam); + } + + if (!recRAM) + { + recLutReserve_RAM = new R5900LutReserve_RAM( L"R5900 RAM LUT" ); + recLutReserve_RAM->SetBlockSize(_16kb); + recLutReserve_RAM->Reserve(Ps2MemSize::MainRam + Ps2MemSize::Rom + Ps2MemSize::Rom1); + } -static __aligned16 u16 manual_page[Ps2MemSize::Base >> 12]; -static __aligned16 u8 manual_counter[Ps2MemSize::Base >> 12]; + BASEBLOCK* basepos = (BASEBLOCK*)recLutReserve_RAM->GetPtr(); + recRAM = basepos; basepos += (Ps2MemSize::MainRam / 4); + recROM = basepos; basepos += (Ps2MemSize::Rom / 4); + recROM1 = basepos; basepos += (Ps2MemSize::Rom1 / 4); -static u32 eeRecIsReset = false; - -//////////////////////////////////////////////////// -void recResetEE( void ) -{ - //AtomicExchange( eeRecNeedsReset, false ); - if( AtomicExchange( eeRecIsReset, true ) ) return; - - Console.WriteLn( Color_StrongBlack, "EE/iR5900-32 Recompiler Reset" ); - - maxrecmem = 0; - - if (IsDevBuild) - memset_8<0xcc, REC_CACHEMEM>(recMem); // 0xcc is INT3 - memzero_ptr( m_recBlockAlloc ); // Excluding the 32mb ram copy - memzero_ptr(recConstBuf); - memzero( manual_page ); - memzero( manual_counter ); - ClearRecLUT((BASEBLOCK*)m_recBlockAlloc, - (((Ps2MemSize::Base + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4))); - - if( s_pInstCache ) - memset( s_pInstCache, 0, sizeof(EEINST)*s_nInstCacheSize ); - - recBlocks.Reset(); - mmap_ResetBlockTracking(); - -#ifdef _MSC_VER - __asm emms; -#else - __asm__("emms"); -#endif + pxAssert(recLutReserve_RAM->GetPtrEnd() == (u8*)basepos); for (int i = 0; i < 0x10000; i++) recLUT_SetPage(recLUT, 0, 0, 0, i, 0); @@ -684,30 +663,100 @@ void recResetEE( void ) recLUT_SetPage(recLUT, hwLUT, recROM1, 0xa000, i, i - 0x1e00); } - x86SetPtr(recMem); + if( recConstBuf == NULL ) + recConstBuf = (u32*) _aligned_malloc( RECCONSTBUF_SIZE * sizeof(*recConstBuf), 16 ); - recPtr = recMem; + if( recConstBuf == NULL ) + throw Exception::OutOfMemory( L"R5900-32 SIMD Constants Buffer" ); + + if( s_pInstCache == NULL ) + { + s_nInstCacheSize = 128; + s_pInstCache = (EEINST*)malloc( sizeof(EEINST) * s_nInstCacheSize ); + } + + if( s_pInstCache == NULL ) + throw Exception::OutOfMemory( L"R5900-32 InstCache" ); + + // No errors.. Proceed with initialization: + + _DynGen_Dispatchers(); + + x86FpuState = FPU_STATE; +} + +struct ManualPageTracking +{ + u16 page; + u8 counter; +}; + +static __aligned16 u16 manual_page[Ps2MemSize::MainRam >> 12]; +static __aligned16 u8 manual_counter[Ps2MemSize::MainRam >> 12]; + +static u32 eeRecIsReset = false; +static u32 eeRecNeedsReset = false; +static bool eeCpuExecuting = false; + +//////////////////////////////////////////////////// +static void recResetRaw() +{ + recAlloc(); + + if( AtomicExchange( eeRecIsReset, true ) ) return; + AtomicExchange( eeRecNeedsReset, false ); + + Console.WriteLn( Color_StrongBlack, "EE/iR5900-32 Recompiler Reset" ); + + recMem->Reset(); + recRAMCopy->Reset(); + recLutReserve_RAM->Reset(); + + maxrecmem = 0; + + memzero_ptr(recConstBuf); + + if( s_pInstCache ) + memset( s_pInstCache, 0, sizeof(EEINST)*s_nInstCacheSize ); + + recBlocks.Reset(); + mmap_ResetBlockTracking(); + + x86SetPtr(*recMem); + + recPtr = *recMem; recConstBufPtr = recConstBuf; x86FpuState = FPU_STATE; branch = 0; } -static void recShutdown( void ) +static void recShutdown() { - ProfilerTerminateSource( "EERec" ); + safe_delete( recMem ); + safe_delete( recRAMCopy ); + safe_delete( recLutReserve_RAM ); + recBlocks.Reset(); - SafeSysMunmap( recMem, REC_CACHEMEM ); - safe_aligned_free( m_recBlockAlloc ); recRAM = recROM = recROM1 = NULL; - recConstBuf = NULL; - recRAMCopy = NULL; + safe_aligned_free( recConstBuf ); safe_free( s_pInstCache ); s_nInstCacheSize = 0; } +static void recResetEE() +{ + if (eeCpuExecuting) + { + AtomicExchange( eeRecNeedsReset, true ); + return; + } + + recResetRaw(); +} + void recStep( void ) { } @@ -744,8 +793,6 @@ static void recCheckExecutionState() } } -static bool m_recExecutingCode = false; - static void recExecute() { // Implementation Notes: @@ -753,12 +800,14 @@ static void recExecute() #if PCSX2_SEH eeRecIsReset = false; - ScopedBool executing(m_recExecutingCode); + ScopedBool executing(eeCpuExecuting); try { EnterRecompiledCode(); } - catch( Exception::ExitCpuExecute& ) { } + catch( Exception::ExitCpuExecute& ) + { + } #else @@ -816,18 +865,8 @@ void R5900::Dynarec::OpcodeImpl::recBREAK( void ) //branch = 2; } -// Clears the recLUT table so that all blocks are mapped to the JIT recompiler by default. -static __ri void ClearRecLUT(BASEBLOCK* base, int count) -{ - for (int i = 0; i < count; i++) - base[i].SetFnptr((uptr)JITCompile); -} - void recClear(u32 addr, u32 size) { - BASEBLOCKEX* pexblock; - BASEBLOCK* pblock; - // necessary since recompiler doesn't call femms/emms #ifdef _MSC_VER __asm emms; @@ -846,14 +885,14 @@ void recClear(u32 addr, u32 size) u32 lowerextent = (u32)-1, upperextent = 0, ceiling = (u32)-1; - pexblock = recBlocks[blockidx + 1]; + BASEBLOCKEX* pexblock = recBlocks[blockidx + 1]; if (pexblock) ceiling = pexblock->startpc; while (pexblock = recBlocks[blockidx]) { u32 blockstart = pexblock->startpc; u32 blockend = pexblock->startpc + pexblock->size * 4; - pblock = PC_GETBLOCK(blockstart); + BASEBLOCK* pblock = PC_GETBLOCK(blockstart); if (pblock == s_pCurBlock) { blockidx--; @@ -889,7 +928,7 @@ void recClear(u32 addr, u32 size) } if (upperextent > lowerextent) - ClearRecLUT(PC_GETBLOCK(lowerextent), (upperextent - lowerextent) / 4); + ClearRecLUT(PC_GETBLOCK(lowerextent), upperextent - lowerextent); } @@ -1354,17 +1393,22 @@ static void __fastcall recRecompile( const u32 startpc ) pxAssume( startpc ); // if recPtr reached the mem limit reset whole mem - if ( ( (uptr)recPtr - (uptr)recMem ) >= REC_CACHEMEM-0x40000 || dumplog == 0xffffffff) { - recResetEE(); + if (recPtr >= (recMem->GetPtrEnd() - _64kb)) { + AtomicExchange( eeRecNeedsReset, true ); } - if ( (recConstBufPtr - recConstBuf) >= RECCONSTBUF_SIZE - 64 ) { + else if ((recConstBufPtr - recConstBuf) >= RECCONSTBUF_SIZE - 64) { Console.WriteLn("EE recompiler stack reset"); - recResetEE(); + AtomicExchange( eeRecNeedsReset, true ); } + if (eeRecNeedsReset) recResetRaw(); + xSetPtr( recPtr ); recPtr = xGetAlignedCallTarget(); + if (0x8000d618 == startpc) + DbgCon.WriteLn("Compiling block @ 0x%08x", startpc); + s_pCurBlock = PC_GETBLOCK(startpc); pxAssert(s_pCurBlock->GetFnptr() == (uptr)JITCompile @@ -1764,7 +1808,7 @@ StartRecomp: pxAssert( (pc-startpc)>>2 <= 0xffff ); s_pCurBlockEx->size = (pc-startpc)>>2; - if (HWADDR(pc) <= Ps2MemSize::Base) { + if (HWADDR(pc) <= Ps2MemSize::MainRam) { BASEBLOCKEX *oldBlock; int i; @@ -1774,10 +1818,12 @@ StartRecomp: continue; if (oldBlock->startpc >= HWADDR(pc)) continue; - if (oldBlock->startpc + oldBlock->size * 4 <= HWADDR(startpc)) + if ((oldBlock->startpc + oldBlock->size * 4) <= HWADDR(startpc)) break; - if (memcmp(&recRAMCopy[oldBlock->startpc / 4], PSM(oldBlock->startpc), - oldBlock->size * 4)) { + + if (memcmp(&(*recRAMCopy)[oldBlock->startpc / 4], PSM(oldBlock->startpc), + oldBlock->size * 4)) + { recClear(startpc, (pc - startpc) / 4); s_pCurBlockEx = recBlocks.Get(HWADDR(startpc)); pxAssert(s_pCurBlockEx->startpc == HWADDR(startpc)); @@ -1785,7 +1831,7 @@ StartRecomp: } } - memcpy_fast(&recRAMCopy[HWADDR(startpc) / 4], PSM(startpc), pc - startpc); + memcpy_fast(&(*recRAMCopy)[HWADDR(startpc) / 4], PSM(startpc), pc - startpc); } s_pCurBlock->SetFnptr((uptr)recPtr); @@ -1836,11 +1882,11 @@ StartRecomp: } } - pxAssert( xGetPtr() < recMem+REC_CACHEMEM ); + pxAssert( xGetPtr() < recMem->GetPtrEnd() ); pxAssert( recConstBufPtr < recConstBuf + RECCONSTBUF_SIZE ); pxAssert( x86FpuState == 0 ); - pxAssert(xGetPtr() - recPtr < 0x10000); + pxAssert(xGetPtr() - recPtr < _64kb); s_pCurBlockEx->x86size = xGetPtr() - recPtr; recPtr = xGetPtr(); @@ -1859,7 +1905,7 @@ static void recThrowException( const BaseR5900Exception& ex ) #if PCSX2_SEH ex.Rethrow(); #else - if (!m_recExecutingCode) ex.Rethrow(); + if (!eeCpuExecuting) ex.Rethrow(); m_cpuException = ex.Clone(); recExitExecution(); #endif @@ -1870,15 +1916,25 @@ static void recThrowException( const BaseException& ex ) #if PCSX2_SEH ex.Rethrow(); #else - if (!m_recExecutingCode) ex.Rethrow(); + if (!eeCpuExecuting) ex.Rethrow(); m_Exception = ex.Clone(); recExitExecution(); #endif } +static void recSetCacheReserve( uint reserveInMegs ) +{ + m_ConfiguredCacheReserve = reserveInMegs; +} + +static uint recGetCacheReserve() +{ + return m_ConfiguredCacheReserve; +} + R5900cpu recCpu = { - recAlloc, + recReserve, recShutdown, recResetEE, @@ -1889,4 +1945,7 @@ R5900cpu recCpu = recThrowException, recThrowException, recClear, + + recGetCacheReserve, + recSetCacheReserve, }; diff --git a/pcsx2/x86/ix86-32/recVTLB.cpp b/pcsx2/x86/ix86-32/recVTLB.cpp index f2a0daae50..f89bbd3b03 100644 --- a/pcsx2/x86/ix86-32/recVTLB.cpp +++ b/pcsx2/x86/ix86-32/recVTLB.cpp @@ -287,7 +287,7 @@ void vtlb_dynarec_init() hasBeenCalled = true; // In case init gets called multiple times: - HostSys::MemProtectStatic( m_IndirectDispatchers, Protect_ReadWrite, false ); + HostSys::MemProtectStatic( m_IndirectDispatchers, PageAccess_ReadWrite() ); // clear the buffer to 0xcc (easier debugging). memset_8<0xcc,0x1000>( m_IndirectDispatchers ); @@ -309,7 +309,7 @@ void vtlb_dynarec_init() } } - HostSys::MemProtectStatic( m_IndirectDispatchers, Protect_ReadOnly, true ); + HostSys::MemProtectStatic( m_IndirectDispatchers, PageAccess_ExecOnly() ); } ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/pcsx2/x86/microVU.cpp b/pcsx2/x86/microVU.cpp index 2721e7da9b..a1bbaf3872 100644 --- a/pcsx2/x86/microVU.cpp +++ b/pcsx2/x86/microVU.cpp @@ -18,6 +18,7 @@ #include "PrecompiledHeader.h" #include "Common.h" #include "microVU.h" +#include "System/RecTypes.h" // Include all the *.inl files (Needed because C++ sucks with templates and *.cpp files) #include "microVU_Clamp.inl" @@ -80,8 +81,20 @@ const __aligned(32) mVU_Globals mVUglob = { static __fi void mVUthrowHardwareDeficiency(const wxChar* extFail, int vuIndex) { throw Exception::HardwareDeficiency() - .SetDiagMsg(wxsFormat(L"microVU%d recompiler init failed: %s is not available.", vuIndex, extFail)) - .SetUserMsg(wxsFormat(_("%s Extensions not found. microVU requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail )); + .SetDiagMsg(pxsFmt(L"microVU%d recompiler init failed: %s is not available.", vuIndex, extFail)) + .SetUserMsg(pxsFmt(_("%s Extensions not found. microVU requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail )); +} + +void microVU::reserveCache() +{ + cache_reserve = new RecompiledCodeReserve( pxsFmt("Micro VU%u Recompiler Cache", index) ); + cache_reserve->SetProfilerName( pxsFmt("mVU%urec", index) ); + + cache = index ? + (u8*)cache_reserve->Reserve( cacheSize * _1mb, HostMemoryMap::mVU1rec ) : + (u8*)cache_reserve->Reserve( cacheSize * _1mb, HostMemoryMap::mVU0rec ); + + cache_reserve->ThrowIfNotOk(); } // Only run this once per VU! ;) @@ -99,22 +112,14 @@ void microVU::init(uint vuIndex) { microMemSize = (index ? 0x4000 : 0x1000); progSize = (index ? 0x4000 : 0x1000) / 4; progMemMask = progSize-1; - dispCache = NULL; - cache = NULL; - cacheSize = mVUcacheSize; - regAlloc = new microRegAlloc(index); - for (u32 i = 0; i < (progSize / 2); i++) { - prog.prog[i] = new deque(); - } + reserveCache(); dispCache = SysMmapEx(0, mVUdispCacheSize, 0, (index ? "Micro VU1 Dispatcher" : "Micro VU0 Dispatcher")); if (!dispCache) throw Exception::OutOfMemory( index ? L"Micro VU1 Dispatcher" : L"Micro VU0 Dispatcher" ); memset(dispCache, 0xcc, mVUdispCacheSize); - // Allocates rec-cache and calls mVUreset() - mVUresizeCache(this, cacheSize + mVUcacheSafeZone); - //if (vuIndex) gen_memcpy_vibes(); + regAlloc = new microRegAlloc(index); } // Resets Rec Data @@ -123,16 +128,12 @@ void microVU::reset() { x86SetPtr(dispCache); mVUdispatcherA(this); mVUdispatcherB(this); - mVUemitSearch(); + mVUemitSearch(); // Clear All Program Data //memset(&prog, 0, sizeof(prog)); memset(&prog.lpState, 0, sizeof(prog.lpState)); - if (IsDevBuild) { // Release builds shouldn't need this - memset(cache, 0xcc, cacheSize); - } - // Program Variables prog.cleared = 1; prog.isSame = -1; @@ -144,9 +145,15 @@ void microVU::reset() { u8* z = cache; prog.x86start = z; prog.x86ptr = z; - prog.x86end = (u8*)((uptr)z + (uptr)(cacheSize - mVUcacheSafeZone)); // "Safe Zone" + prog.x86end = z + ((cacheSize - mVUcacheSafeZone) * _1mb); for (u32 i = 0; i < (progSize / 2); i++) { + if (!prog.prog[i]) + { + prog.prog[i] = new deque(); + continue; + } + deque::iterator it(prog.prog[i]->begin()); for ( ; it != prog.prog[i]->end(); ++it) { if (index) mVUdeleteProg<1>(it[0]); @@ -161,11 +168,13 @@ void microVU::reset() { // Free Allocated Resources void microVU::close() { - if (dispCache) { HostSys::Munmap(dispCache, mVUdispCacheSize); dispCache = NULL; } - if (cache) { HostSys::Munmap(cache, cacheSize); cache = NULL; } + safe_delete(cache_reserve); + + SafeSysMunmap(dispCache, mVUdispCacheSize); // Delete Programs and Block Managers for (u32 i = 0; i < (progSize / 2); i++) { + if (!prog.prog[i]) continue; deque::iterator it(prog.prog[i]->begin()); for ( ; it != prog.prog[i]->end(); ++it) { if (index) mVUdeleteProg<1>(it[0]); @@ -175,35 +184,6 @@ void microVU::close() { } } -static void mVUresizeCache(mV, u32 size) { - - if (size >= (u32)mVUcacheMaxSize) { - if (mVU->cacheSize==mVUcacheMaxSize) { - // We can't grow the rec any larger, so just reset it and start over. - //(if we don't reset, the rec will eventually crash) - Console.WriteLn(Color_Magenta, "microVU%d: Cannot grow cache, size limit reached! [%dmb]. Resetting rec.", mVU->index, mVU->cacheSize/_1mb); - mVU->reset(); - return; - } - size = mVUcacheMaxSize; - } - - if (mVU->cache) Console.WriteLn(Color_Green, "microVU%d: Attempting to resize Cache [%dmb]", mVU->index, size/_1mb); - - u8* cache = SysMmapEx(0, size, 0, (mVU->index ? "Micro VU1 RecCache" : "Micro VU0 RecCache")); - if(!cache && !mVU->cache) throw Exception::OutOfMemory( wxsFormat( L"Micro VU%d recompiled code cache", mVU->index) ); - if(!cache) { Console.Error("microVU%d Error - Cache Resize Failed...", mVU->index); mVU->reset(); return; } - if (mVU->cache) { - HostSys::Munmap(mVU->cache, mVU->cacheSize); - ProfilerTerminateSource(isVU1?"mVU1 Rec":"mVU0 Rec"); - } - - mVU->cache = cache; - mVU->cacheSize = size; - ProfilerRegisterSource(isVU1?"mVU1 Rec":"mVU0 Rec", mVU->cache, mVU->cacheSize); - mVU->reset(); -} - // Clears Block Data in specified range static __fi void mVUclear(mV, u32 addr, u32 size) { if (!mVU->prog.cleared) { @@ -323,55 +303,40 @@ _mVUt __fi void* mVUsearchProg(u32 startPC, uptr pState) { // recMicroVU0 / recMicroVU1 //------------------------------------------------------------------ -static u32 mvu0_allocated = 0; -static u32 mvu1_allocated = 0; - recMicroVU0::recMicroVU0() { m_Idx = 0; IsInterpreter = false; } recMicroVU1::recMicroVU1() { m_Idx = 1; IsInterpreter = false; } void recMicroVU0::Vsync() throw() { mVUvsyncUpdate(µVU0); } void recMicroVU1::Vsync() throw() { mVUvsyncUpdate(µVU1); } -void recMicroVU0::Allocate() { - if(!m_AllocCount) { - m_AllocCount++; - if (AtomicExchange(mvu0_allocated, 1) == 0) - microVU0.init(0); - } +void recMicroVU0::Reserve() { + if (AtomicExchange(m_Reserved, 1) == 0) + microVU0.init(0); } -void recMicroVU1::Allocate() { - if(!m_AllocCount) { - m_AllocCount++; - if (AtomicExchange(mvu1_allocated, 1) == 0) - microVU1.init(1); - } +void recMicroVU1::Reserve() { + if (AtomicExchange(m_Reserved, 1) == 0) + microVU1.init(1); } void recMicroVU0::Shutdown() throw() { - if (m_AllocCount > 0) { - m_AllocCount--; - if (AtomicExchange(mvu0_allocated, 0) == 1) - microVU0.close(); - } + if (AtomicExchange(m_Reserved, 0) == 1) + microVU0.close(); } void recMicroVU1::Shutdown() throw() { - if (m_AllocCount > 0) { - m_AllocCount--; - if (AtomicExchange(mvu1_allocated, 0) == 1) - microVU1.close(); - } + if (AtomicExchange(m_Reserved, 0) == 1) + microVU1.close(); } void recMicroVU0::Reset() { - if(!pxAssertDev(m_AllocCount, "MicroVU0 CPU Provider has not been allocated prior to reset!")) return; + if(!pxAssertDev(m_Reserved, "MicroVU0 CPU Provider has not been reserved prior to reset!")) return; microVU0.reset(); } void recMicroVU1::Reset() { - if(!pxAssertDev(m_AllocCount, "MicroVU1 CPU Provider has not been allocated prior to reset!")) return; + if(!pxAssertDev(m_Reserved, "MicroVU1 CPU Provider has not been reserved prior to reset!")) return; microVU1.reset(); } void recMicroVU0::Execute(u32 cycles) { - pxAssert(mvu0_allocated); // please allocate me first! :| + pxAssert(m_Reserved); // please allocate me first! :| if(!(VU0.VI[REG_VPU_STAT].UL & 1)) return; @@ -381,17 +346,35 @@ void recMicroVU0::Execute(u32 cycles) { ((mVUrecCall)microVU0.startFunct)(VU0.VI[REG_TPC].UL, cycles); } void recMicroVU1::Execute(u32 cycles) { - pxAssert(mvu1_allocated); // please allocate me first! :| + pxAssert(m_Reserved); // please allocate me first! :| if(!(VU0.VI[REG_VPU_STAT].UL & 0x100)) return; ((mVUrecCall)microVU1.startFunct)(VU1.VI[REG_TPC].UL, vu1RunCycles); } void recMicroVU0::Clear(u32 addr, u32 size) { - pxAssert(mvu0_allocated); // please allocate me first! :| + pxAssert(m_Reserved); // please allocate me first! :| mVUclear(µVU0, addr, size); } void recMicroVU1::Clear(u32 addr, u32 size) { - pxAssert(mvu1_allocated); // please allocate me first! :| + pxAssert(m_Reserved); // please allocate me first! :| mVUclear(µVU1, addr, size); } + +uint recMicroVU0::GetCacheReserve() const +{ + return microVU0.cacheSize; +} +uint recMicroVU1::GetCacheReserve() const +{ + return microVU1.cacheSize; +} + +void recMicroVU0::SetCacheReserve( uint reserveInMegs ) const +{ + microVU0.cacheSize = reserveInMegs; +} +void recMicroVU1::SetCacheReserve( uint reserveInMegs ) const +{ + microVU1.cacheSize = reserveInMegs; +} diff --git a/pcsx2/x86/microVU.h b/pcsx2/x86/microVU.h index df113ce718..ce33e897d3 100644 --- a/pcsx2/x86/microVU.h +++ b/pcsx2/x86/microVU.h @@ -28,7 +28,6 @@ using namespace x86Emitter; #include "iR5900.h" #include "R5900OpcodeTables.h" #include "x86emitter/x86emitter.h" -#include "SamplProf.h" #include "microVU_Misc.h" #include "microVU_IR.h" @@ -150,11 +149,8 @@ struct microProgManager { microRegInfo lpState; // Pipeline state from where program left off (useful for continuing execution) }; -#define mVUdispCacheSize (0x1000) // Dispatcher Cache Size -#define mVUcacheSize ((index) ? (_1mb * 17) : (_1mb * 7)) // Initial Size (Excluding Safe-Zone) -#define mVUcacheMaxSize ((mVU->index) ? (_1mb * 100) : (_1mb * 50)) // Max Size allowed to grow to -#define mVUcacheGrowBy ((mVU->index) ? (_1mb * 15) : (_1mb * 10)) // Grows by this amount -#define mVUcacheSafeZone ((index) ? (_1mb * 3) : (_1mb * 3)) // Safe-Zone for last program +static const uint mVUdispCacheSize = __pagesize; // Dispatcher Cache Size (in bytes) +static const uint mVUcacheSafeZone = 3; // Safe-Zone for program recompilation (in megabytes) struct microVU { @@ -171,11 +167,13 @@ struct microVU { u32 progMemMask; // VU Micro Memory Size (in u32's) u32 cacheSize; // VU Cache Size - microProgManager prog; // Micro Program Data + microProgManager prog; // Micro Program Data ScopedPtr regAlloc; // Reg Alloc Class ScopedPtr logFile; // Log File Pointer - u8* cache; // Dynarec Cache Start (where we will start writing the recompiled code to) + + RecompiledCodeReserve* cache_reserve; + u8* cache; // Dynarec Cache Start (where we will start writing the recompiled code to) u8* dispCache; // Dispatchers Cache (where startFunct and exitFunct are written to) u8* startFunct; // Ptr Function to the Start code for recompiled programs u8* exitFunct; // Ptr Function to the Exit code for recompiled programs @@ -224,7 +222,17 @@ struct microVU { pxAssumeDev((prog.IRinfo.curPC & 1) == 0, "microVU recompiler: Upper instructions cannot have valid branch addresses."); return (((prog.IRinfo.curPC + 4) + (Imm11() * 2)) & progMemMask) * 4; } + + microVU() + { + cacheSize = 64; + cache = NULL; + dispCache = NULL; + startFunct = NULL; + exitFunct = NULL; + } + void reserveCache(); void init(uint vuIndex); void reset(); void close(); @@ -239,7 +247,6 @@ int mVUdebugNow = 0; // Main Functions static void mVUclear(mV, u32, u32); -static void mVUresizeCache(mV, u32); static void* mVUblockFetch(microVU* mVU, u32 startPC, uptr pState); _mVUt extern void* __fastcall mVUcompileJIT(u32 startPC, uptr pState); diff --git a/pcsx2/x86/microVU_Execute.inl b/pcsx2/x86/microVU_Execute.inl index 198ab530da..cca83ed6ba 100644 --- a/pcsx2/x86/microVU_Execute.inl +++ b/pcsx2/x86/microVU_Execute.inl @@ -92,7 +92,7 @@ void mVUdispatcherB(mV) { xRET(); - mVUcacheCheck(x86Ptr, mVU->dispCache, mVUdispCacheSize); + pxAssertDev(xGetPtr() < (mVU->dispCache + mVUdispCacheSize), "microVU: Dispatcher generation exceeded reserved cache area!"); } //------------------------------------------------------------------ @@ -121,8 +121,14 @@ _mVUt void mVUcleanUp() { //mVUprint("microVU: Program exited successfully!"); //mVUprint("microVU: VF0 = {%x,%x,%x,%x}", mVU->regs().VF[0].UL[0], mVU->regs().VF[0].UL[1], mVU->regs().VF[0].UL[2], mVU->regs().VF[0].UL[3]); //mVUprint("microVU: VI0 = %x", mVU->regs().VI[0].UL); + mVU->prog.x86ptr = x86Ptr; - mVUcacheCheck(x86Ptr, mVU->prog.x86start, (uptr)(mVU->prog.x86end - mVU->prog.x86start)); + + if ((xGetPtr() < mVU->prog.x86start) || (xGetPtr() >= mVU->prog.x86end)) { + Console.WriteLn(vuIndex ? Color_Orange : Color_Magenta, "microVU%d: Program cache limit reached.", mVU->index); + mVU->reset(); + } + mVU->cycles = mVU->totalCycles - mVU->cycles; mVU->regs().cycle += mVU->cycles; cpuRegs.cycle += ((mVU->cycles < 3000) ? mVU->cycles : 3000) * EmuConfig.Speedhacks.VUCycleSteal; diff --git a/pcsx2/x86/microVU_Misc.h b/pcsx2/x86/microVU_Misc.h index ef58dbe8ef..ff6b1b40e0 100644 --- a/pcsx2/x86/microVU_Misc.h +++ b/pcsx2/x86/microVU_Misc.h @@ -298,15 +298,6 @@ static const bool doConstProp = 0; // Set to 1 to turn on vi15 const propagation //------------------------------------------------------------------ -// Cache Limit Check -#define mVUcacheCheck(ptr, start, limit) { \ - uptr diff = ptr - start; \ - if (diff >= limit) { \ - DevCon.WriteLn("microVU%d: Program cache limit reached. Size = 0x%x", mVU->index, diff); \ - mVUresizeCache(mVU, mVU->cacheSize + mVUcacheGrowBy); \ - } \ -} - extern void mVUmergeRegs(const xmm& dest, const xmm& src, int xyzw, bool modXYZW=false); extern void mVUsaveReg(const xmm& reg, xAddressVoid ptr, int xyzw, bool modXYZW); extern void mVUloadReg(const xmm& reg, xAddressVoid ptr, int xyzw); diff --git a/pcsx2/x86/microVU_Misc.inl b/pcsx2/x86/microVU_Misc.inl index b25ec6b76b..1906e47725 100644 --- a/pcsx2/x86/microVU_Misc.inl +++ b/pcsx2/x86/microVU_Misc.inl @@ -251,7 +251,7 @@ __fi void mVUaddrFix(mV, const x32& gprReg) else { if (IsDevBuild && !isCOP2) mVUbackupRegs(mVU, true); xTEST(gprReg, 0x400); - xForwardJNZ8 jmpA; // if addr & 0x4000, reads VU1's VF regs and VI regs + xForwardJNZ8 jmpA; // if addr & 0x4000, reads VU1's VF regs and VI regs xAND(gprReg, 0xff); // if !(addr & 0x4000), wrap around xForwardJump8 jmpB; jmpA.SetTarget(); @@ -481,7 +481,7 @@ static __pagealigned u8 mVUsearchXMM[__pagesize]; // Generates a custom optimized block-search function // Note: Structs must be 16-byte aligned! (GCC doesn't guarantee this) void mVUcustomSearch() { - HostSys::MemProtectStatic(mVUsearchXMM, Protect_ReadWrite, false); + HostSys::MemProtectStatic(mVUsearchXMM, PageAccess_ReadWrite()); memset_8<0xcc,__pagesize>(mVUsearchXMM); xSetPtr(mVUsearchXMM); @@ -526,5 +526,5 @@ void mVUcustomSearch() { exitPoint.SetTarget(); xRET(); - HostSys::MemProtectStatic(mVUsearchXMM, Protect_ReadOnly, true); + HostSys::MemProtectStatic(mVUsearchXMM, PageAccess_ExecOnly()); } diff --git a/pcsx2/x86/newVif.h b/pcsx2/x86/newVif.h index 7f63bb6b91..1f77cc75a8 100644 --- a/pcsx2/x86/newVif.h +++ b/pcsx2/x86/newVif.h @@ -19,6 +19,8 @@ #include "VU.h" #include "x86emitter/x86emitter.h" +#include "System/RecTypes.h" + using namespace x86Emitter; #define aMax(x, y) std::max(x,y) @@ -28,13 +30,14 @@ using namespace x86Emitter; typedef u32 (__fastcall *nVifCall)(void*, const void*); typedef void (__fastcall *nVifrecCall)(uptr dest, uptr src); -#include "newVif_BlockBuffer.h" #include "newVif_HashBucket.h" extern void mVUmergeRegs(const xRegisterSSE& dest, const xRegisterSSE& src, int xyzw, bool modXYZW = 0); extern void _nVifUnpack (int idx, const u8* data, uint mode, bool isFill); +extern void dVifReserve (int idx); extern void dVifReset (int idx); extern void dVifClose (int idx); +extern void dVifRelease (int idx); extern void VifUnpackSSE_Init(); _vifT extern void dVifUnpack (const u8* data, bool isFill); @@ -76,23 +79,25 @@ struct nVifStruct { u32 bSize; // Size of 'buffer' u32 bPtr; - u32 idx; // VIF0 or VIF1 - u8* recPtr; // Cur Pos to recompile to - u8* recEnd; // 'Safe' End of Rec Cache - BlockBuffer* vifCache; // Block Buffer + uint recReserveSizeMB; // reserve size, in megabytes. + RecompiledCodeReserve* recReserve; + u8* recWritePtr; // current write pos into the reserve + HashBucket<_tParams>* vifBlocks; // Vif Blocks int numBlocks; // # of Blocks Recompiled - - nVifStruct() - { - vifCache = NULL; - vifBlocks = NULL; - numBlocks = 0; - recPtr = NULL; - recEnd = NULL; - } + + // VIF0 or VIF1 - provided for debugging helpfulness only, and is generally unused. + // (templates are used for most or all VIF indexing) + u32 idx; + + nVifStruct(); }; +extern void reserveNewVif(int idx); +extern void closeNewVif(int idx); +extern void resetNewVif(int idx); +extern void releaseNewVif(int idx); + extern __aligned16 nVifStruct nVif[2]; extern __aligned16 nVifCall nVifUpk[(2*2*16)*4]; // ([USN][Masking][Unpack Type]) [curCycle] extern __aligned16 u32 nVifMask[3][4][4]; // [MaskNumber][CycleNumber][Vector] diff --git a/pcsx2/x86/newVif_BlockBuffer.h b/pcsx2/x86/newVif_BlockBuffer.h deleted file mode 100644 index 532c613819..0000000000 --- a/pcsx2/x86/newVif_BlockBuffer.h +++ /dev/null @@ -1,86 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2010 PCSX2 Dev Team - * - * 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. - * - * 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. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#pragma once - -// Allocates a Chunk of memory using SysMmapEx... -// This memory can be used to write recompiled code to. -// Its got basic resizing/growing ability too, but probably -// won't be too useful since growing the block buffer will -// invalidate any pointers pointing to the old block buffer. -// (so remember to invalidate those block pointers :D) -// It also deallocates itself on 'delete', so you can -// just use 'new' and 'delete' for initialization and -// deletion/cleanup respectfully... -class BlockBuffer { -protected: - u32 mSize; // Cur Size (in bytes) - u32 mSizeT; // Total Size (in bytes) - u32 mGrowBy; // amount to grow by when buffer fills (in bytes) - u8* mData; // Data Ptr (allocated via SysMmap) - - void alloc(int size) { - mData = SysMmapEx(0, size, 0, "nVif_BlockBuffer"); - if (!mData) throw Exception::OutOfMemory(L"nVif recompiled code buffer (nVif_BlockBuffer)"); - clear(); - } - void dealloc(u8* &dPtr, int size) { - SafeSysMunmap( dPtr, size ); - } - -public: - virtual ~BlockBuffer() throw() { - dealloc(mData, mSizeT); - } - - BlockBuffer(u32 tSize, u32 growby=_1mb*2) { - mSizeT = tSize; - mGrowBy = growby; - mSize = 0; - alloc(mSizeT); - } - - void append(void *addr, u32 size) { - if ((mSize + size) > mSizeT) grow(mSizeT + mGrowBy); - memcpy_fast(&mData[mSize], addr, size); - mSize += size; - } - - // Increases the allocation size. Warning: Unlike 'realloc' this function will - // CLEAR all contents of the buffer. This is because copying contents of recompiled - // caches is mostly useless since it invalidates any pointers into the block. - // (code relocation techniques are possible, but are difficult, potentially slow, - // and easily bug prone. Not recommended at this time). --air - void grow(u32 newSize) { - pxAssume( newSize > mSizeT ); - u8* temp = mData; - alloc(newSize); - dealloc(temp, mSizeT); - clear(); - mSizeT = newSize; - } - - // clears the entire buffer to recompiler fill (0xcc), and sets mSize to 0. - // (indicating none of the buffer is allocated). - void clear() { - if( mSize == 0 ) return; // no clears needed if nothing's been written/modified - mSize = 0; - memset(mData, 0xcc, mSizeT); - } - - u32 getCurSize() { return mSize; } - u32 getAllocSize() { return mSizeT; } - u8* getBlock() { return mData; } -}; diff --git a/pcsx2/x86/newVif_Dynarec.cpp b/pcsx2/x86/newVif_Dynarec.cpp index 8325341da5..ecf814dfb1 100644 --- a/pcsx2/x86/newVif_Dynarec.cpp +++ b/pcsx2/x86/newVif_Dynarec.cpp @@ -22,34 +22,37 @@ static __aligned16 nVifBlock _vBlock = {0}; -void dVifReset(int idx) { - // If the VIF cache is greater than 12mb, then it's due for a complete reset back - // down to a reasonable starting point of 4mb. - if( nVif[idx].vifCache && (nVif[idx].vifCache->getAllocSize() > _1mb*12) ) - safe_delete(nVif[idx].vifCache); +void dVifReserve(int idx) +{ + if (!nVif[idx].recReserve) + nVif[idx].recReserve = new RecompiledCodeReserve(pxsFmt(L"VIF%u Unpack Recompiler Cache", idx)); - if( !nVif[idx].vifCache ) - nVif[idx].vifCache = new BlockBuffer(_1mb*4); - else - nVif[idx].vifCache->clear(); + nVif[idx].recReserve->Reserve( nVif[idx].recReserveSizeMB * _1mb, idx ? HostMemoryMap::VIF1rec : HostMemoryMap::VIF0rec ); +} + +void dVifReset(int idx) { if( !nVif[idx].vifBlocks ) nVif[idx].vifBlocks = new HashBucket<_tParams>(); else nVif[idx].vifBlocks->clear(); - nVif[idx].numBlocks = 0; - - nVif[idx].recPtr = nVif[idx].vifCache->getBlock(); - nVif[idx].recEnd = &nVif[idx].recPtr[nVif[idx].vifCache->getAllocSize()-(_1mb/4)]; // .25mb Safe Zone + nVif[idx].recReserve->Reset(); + nVif[idx].numBlocks = 0; + nVif[idx].recWritePtr = nVif[idx].recReserve->GetPtr(); } void dVifClose(int idx) { nVif[idx].numBlocks = 0; - safe_delete(nVif[idx].vifCache); + nVif[idx].recReserve->Reset(); + safe_delete(nVif[idx].vifBlocks); } +void dVifRelease(int idx) { + safe_delete(nVif[idx].recReserve); +} + VifUnpackSSE_Dynarec::VifUnpackSSE_Dynarec(const nVifStruct& vif_, const nVifBlock& vifBlock_) : v(vif_) , vB(vifBlock_) @@ -201,7 +204,7 @@ _vifT static __fi u8* dVifsetVUptr(uint cl, uint wl, bool isFill) { u8* startmem = VU.Mem + (vif.tag.addr & (vuMemLimit-0x10)); u8* endmem = VU.Mem + vuMemLimit; - uint length = _vBlock.num * 16; + uint length = (_vBlock.num > 0) ? (_vBlock.num * 16) : 4096; // 0 = 256 if (!isFill) { // Accounting for skipping mode: Subtract the last skip cycle, since the skipped part of the run @@ -223,11 +226,10 @@ _vifT static __fi u8* dVifsetVUptr(uint cl, uint wl, bool isFill) { // [TODO] : Finish implementing support for VIF's growable recBlocks buffer. Currently // it clears the buffer only. static __fi void dVifRecLimit(int idx) { - if (nVif[idx].recPtr > nVif[idx].recEnd) { - DevCon.WriteLn("nVif Rec - Out of Rec Cache! [%x > %x]", nVif[idx].recPtr, nVif[idx].recEnd); - nVif[idx].vifBlocks->clear(); - nVif[idx].recPtr = nVif[idx].vifCache->getBlock(); - nVif[idx].recEnd = &nVif[idx].recPtr[nVif[idx].vifCache->getAllocSize()-(_1mb/4)]; // .25mb Safe Zone + if (nVif[idx].recWritePtr > (nVif[idx].recReserve->GetPtrEnd() - _256kb)) { + DevCon.WriteLn("nVif Recompiler Cache Reset! [0x%08x > 0x%08x]", nVif[idx].recWritePtr, nVif[idx].recReserve->GetPtrEnd()); + nVif[idx].recReserve->Reset(); + nVif[idx].recWritePtr = nVif[idx].recReserve->GetPtr(); } } @@ -277,11 +279,11 @@ _vifT __fi void dVifUnpack(const u8* data, bool isFill) { if (dVifExecuteUnpack(data, isFill)) return; - xSetPtr(v.recPtr); + xSetPtr(v.recWritePtr); _vBlock.startPtr = (uptr)xGetAlignedCallTarget(); v.vifBlocks->add(_vBlock); VifUnpackSSE_Dynarec( v, _vBlock ).CompileRoutine(); - nVif[idx].recPtr = xGetPtr(); + nVif[idx].recWritePtr = xGetPtr(); // [TODO] : Ideally we should test recompile buffer limits prior to each instruction, // which would be safer and more memory efficient than using an 0.25 meg recEnd marker. diff --git a/pcsx2/x86/newVif_Unpack.cpp b/pcsx2/x86/newVif_Unpack.cpp index 0c692292c9..02808d152f 100644 --- a/pcsx2/x86/newVif_Unpack.cpp +++ b/pcsx2/x86/newVif_Unpack.cpp @@ -70,6 +70,19 @@ static const __aligned16 Fnptr_VifUnpackLoop UnpackLoopTable[2][2][2] = { }; // ---------------------------------------------------------------------------- +nVifStruct::nVifStruct() +{ + vifBlocks = NULL; + numBlocks = 0; + + recReserveSizeMB = 8; +} + +void reserveNewVif(int idx) +{ + if (newVifDynaRec) dVifReserve(idx); +} + void resetNewVif(int idx) { // Safety Reset : Reassign all VIF structure info, just in case the VU1 pointers have @@ -86,6 +99,10 @@ void closeNewVif(int idx) { if (newVifDynaRec) dVifClose(idx); } +void releaseNewVif(int idx) { + if (newVifDynaRec) dVifRelease(idx); +} + static __fi u8* getVUptr(uint idx, int offset) { return (u8*)(vuRegs[idx].Mem + ( offset & (idx ? 0x3ff0 : 0xff0) )); } diff --git a/pcsx2/x86/newVif_UnpackSSE.cpp b/pcsx2/x86/newVif_UnpackSSE.cpp index 010913aa97..dc7d7b595b 100644 --- a/pcsx2/x86/newVif_UnpackSSE.cpp +++ b/pcsx2/x86/newVif_UnpackSSE.cpp @@ -295,7 +295,7 @@ static void nVifGen(int usn, int mask, int curCycle) { void VifUnpackSSE_Init() { - HostSys::MemProtectStatic(nVifUpkExec, Protect_ReadWrite, false); + HostSys::MemProtectStatic(nVifUpkExec, PageAccess_ReadWrite()); memset8<0xcc>( nVifUpkExec ); xSetPtr( nVifUpkExec ); @@ -306,5 +306,5 @@ void VifUnpackSSE_Init() nVifGen(a, b, c); }}} - HostSys::MemProtectStatic(nVifUpkExec, Protect_ReadOnly, true); + HostSys::MemProtectStatic(nVifUpkExec, PageAccess_ExecOnly()); } diff --git a/pcsx2/x86/sVU_zerorec.cpp b/pcsx2/x86/sVU_zerorec.cpp index 9a2af40e6b..ff0b03f4ff 100644 --- a/pcsx2/x86/sVU_zerorec.cpp +++ b/pcsx2/x86/sVU_zerorec.cpp @@ -35,9 +35,9 @@ #include "R5900.h" #include "iR5900.h" +#include "System/RecTypes.h" #include "sVU_zerorec.h" -#include "SamplProf.h" #include "NakedAsm.h" #include "AppConfig.h" @@ -72,7 +72,7 @@ extern void iDumpVU1Registers(); #define SUPERVU_CHECKCONDITION 0 // has to be 0!! -#define VU_EXESIZE 0x00800000 +static const uint sVU_EXESIZE = _8mb; #define _Imm11_ (s32)( (vucode & 0x400) ? (0xfffffc00 | (vucode & 0x3ff)) : (vucode & 0x3ff) ) #define _UImm11_ (s32)(vucode & 0x7ff) @@ -90,7 +90,9 @@ static const u32 PWaitTimes[] = { 53, 43, 28, 23, 17, 11, 10 }; static u32 s_vuInfo; // info passed into rec insts static const u32 s_MemSize[2] = {VU0_MEMSIZE, VU1_MEMSIZE}; -static u8* s_recVUMem = NULL, *s_recVUPtr = NULL; +//static u8* s_recVUMem = NULL, *s_recVUPtr = NULL; +static RecompiledCodeReserve* s_recVUMem[2] = { NULL, NULL }; +static u8* s_recVUPtr[2] = { NULL, NULL }; // tables which are defined at the bottom of this massive file. extern void (*recVU_UPPER_OPCODE[64])(VURegs* VU, s32 info); @@ -315,9 +317,11 @@ VuBaseBlock::VuBaseBlock() static list s_listVUHeaders[2]; static list* s_plistCachedHeaders[2] = {NULL, NULL}; -static VuFunctionHeader** recVUHeaders[2] = {NULL, NULL}; -static VuBlockHeader* recVUBlocks[2] = {NULL, NULL}; -static u8* recVUStack = NULL, *recVUStackPtr = NULL; +static VuFunctionHeader** recVUHeaders[2] = { NULL, NULL }; +static VuBlockHeader* recVUBlocks[2] = { NULL, NULL }; +static u8* recVUStack[2] = { NULL, NULL }; +static u8* recVUStackPtr[2] = { NULL, NULL }; + static vector<_x86regs> s_vecRegArray(128); static VURegs* VU = NULL; @@ -343,47 +347,23 @@ static void SuperVURecompile(); // allocate VU resources static void SuperVUAlloc(int vuindex) { - // The old -1 crap has been depreciated on this function. Please - // specify either 0 or 1, thanks. - pxAssert(vuindex >= 0); + if (s_recVUMem[vuindex]) return; + + s_recVUMem[vuindex] = new RecompiledCodeReserve( pxsFmt("SuperVU%u Recompiler Cache", vuindex), 0 ); + s_recVUMem[vuindex]->Reserve( sVU_EXESIZE, vuindex ? HostMemoryMap::sVU1rec : HostMemoryMap::sVU0rec, _256mb ); + s_recVUMem[vuindex]->SetProfilerName(pxsFmt("sVU%urec",vuindex)); // upper 4 bits must be zero! - if (s_recVUMem == NULL) + if (!s_recVUMem[vuindex]->IsOk()) { - // upper 4 bits must be zero! - // Changed "first try base" to 0xf1e0000, since 0x0c000000 liked to fail a lot. (cottonvibes) - s_recVUMem = SysMmapEx(0xf1e0000, VU_EXESIZE, 0x10000000, "SuperVUAlloc"); - - // Try again at some other random memory location... whatever. >_< - if( s_recVUMem == NULL ) - s_recVUMem = SysMmapEx(0xc2b0000, VU_EXESIZE, 0x10000000, "SuperVUAlloc"); - - if (s_recVUMem == NULL) - { - throw Exception::VirtualMemoryMapConflict() - .SetDiagMsg(wxsFormat( L"SuperVU failed to allocate virtual memory below 256MB." )) - .SetUserMsg(pxE( ".Error:superVU:VirtualMemoryAlloc", - L"Out of Memory (sorta): The SuperVU recompiler was unable to reserve the specific memory " - L"ranges required, and will not be available for use. This is not a critical error, since " - L"the sVU rec is obsolete, and you should use microVU instead anyway. :)" - )); - } - - ProfilerRegisterSource("sVU Rec", s_recVUMem, VU_EXESIZE); - - if (recVUStack == NULL) recVUStack = new u8[SUPERVU_STACKSIZE * 4]; - } - - if (vuindex >= 0) - { - pxAssert(s_recVUMem != NULL); - - if (recVUHeaders[vuindex] == NULL) - recVUHeaders[vuindex] = new VuFunctionHeader* [s_MemSize[vuindex] / 8]; - if (recVUBlocks[vuindex] == NULL) - recVUBlocks[vuindex] = new VuBlockHeader[s_MemSize[vuindex] / 8]; - if (s_plistCachedHeaders[vuindex] == NULL) - s_plistCachedHeaders[vuindex] = new list[s_MemSize[vuindex] / 8]; + safe_delete(s_recVUMem[vuindex]); + throw Exception::VirtualMemoryMapConflict( s_recVUMem[vuindex]->GetName() ) + .SetDiagMsg(pxsFmt( L"SuperVU failed to allocate virtual memory below 256MB." )) + .SetUserMsg(pxE( ".Error:superVU:VirtualMemoryAlloc", + L"Out of Memory (sorta): The SuperVU recompiler was unable to reserve the specific memory " + L"ranges required, and will not be available for use. This is not a critical error, since " + L"the sVU rec is obsolete, and you should use microVU instead anyway. :)" + )); } } @@ -416,72 +396,64 @@ void DestroyVUHeaders(int vuindex) // destroy VU resources void SuperVUDestroy(int vuindex) { - list::iterator it; + pxAssumeDev(vuindex >= 0 && vuindex <= 2, "Invalid VU index parameter!"); - if (vuindex < 0) - { - SuperVUDestroy(0); - SuperVUDestroy(1); - ProfilerTerminateSource("VURec"); - SafeSysMunmap(s_recVUMem, VU_EXESIZE); - safe_delete_array(recVUStack); - } - else - { - safe_delete_array(recVUHeaders[vuindex]); - safe_delete_array(recVUBlocks[vuindex]); + safe_delete_array(recVUHeaders[vuindex]); + safe_delete_array(recVUBlocks[vuindex]); - if (s_plistCachedHeaders[vuindex] != NULL) + if (s_plistCachedHeaders[vuindex] != NULL) + { + for (u32 j = 0; j < s_MemSize[vuindex] / 8; ++j) { - for (u32 j = 0; j < s_MemSize[vuindex] / 8; ++j) - { - DestroyCachedHeaders(vuindex, j); - } - safe_delete_array(s_plistCachedHeaders[vuindex]); + DestroyCachedHeaders(vuindex, j); } - DestroyVUHeaders(vuindex); + safe_delete_array(s_plistCachedHeaders[vuindex]); } + DestroyVUHeaders(vuindex); + + safe_delete(s_recVUMem[vuindex]); + safe_delete_array(recVUStack[vuindex]); } // reset VU void SuperVUReset(int vuindex) { + pxAssumeDev(vuindex >= 0 && vuindex <= 2, "Invalid VU index parameter!"); + #ifdef PCSX2_DEBUG s_vucount = 0; #endif - if (s_recVUMem == NULL) - return; + DevCon.WriteLn("SuperVU%d: Resetting function and block lists.", vuindex); - //pxAssume( s_recVUMem != NULL ); + if (recVUHeaders[vuindex] == NULL) + recVUHeaders[vuindex] = new VuFunctionHeader* [s_MemSize[vuindex] / 8]; + if (recVUBlocks[vuindex] == NULL) + recVUBlocks[vuindex] = new VuBlockHeader[s_MemSize[vuindex] / 8]; + if (s_plistCachedHeaders[vuindex] == NULL) + s_plistCachedHeaders[vuindex] = new std::list[s_MemSize[vuindex] / 8]; - if (vuindex < 0) + if (recVUHeaders[vuindex]) memset(recVUHeaders[vuindex], 0, sizeof(VuFunctionHeader*) * (s_MemSize[vuindex] / 8)); + if (recVUBlocks[vuindex]) memset(recVUBlocks[vuindex], 0, sizeof(VuBlockHeader) * (s_MemSize[vuindex] / 8)); + + if (s_plistCachedHeaders[vuindex] != NULL) { - DbgCon.WriteLn("SuperVU: Resetting recompiler memory and structures."); - - // Does this cause problems on VU recompiler resets? It could, if the VU works like - // the EE used to, and actually tries to re-enter the recBlock after issuing a clear. (air) - - //memset_8<0xcd, VU_EXESIZE>(s_recVUMem); - memzero_ptr(recVUStack); - - s_recVUPtr = s_recVUMem; - } - else - { - DbgCon.WriteLn("SuperVU [VU%d]: Resetting the recs and junk", vuindex); - if (recVUHeaders[vuindex]) memset(recVUHeaders[vuindex], 0, sizeof(VuFunctionHeader*) * (s_MemSize[vuindex] / 8)); - if (recVUBlocks[vuindex]) memset(recVUBlocks[vuindex], 0, sizeof(VuBlockHeader) * (s_MemSize[vuindex] / 8)); - - if (s_plistCachedHeaders[vuindex] != NULL) + for (u32 j = 0; j < s_MemSize[vuindex] / 8; ++j) { - for (u32 j = 0; j < s_MemSize[vuindex] / 8; ++j) - { - DestroyCachedHeaders(vuindex, j); - } + DestroyCachedHeaders(vuindex, j); } - DestroyVUHeaders(vuindex); } + DestroyVUHeaders(vuindex); + + if (!s_recVUMem[vuindex] || !s_recVUMem[vuindex]->IsOk()) return; + + DevCon.WriteLn("SuperVU%u: Resetting recompiler cache.", vuindex); + + if (!recVUStack[vuindex]) recVUStack[vuindex] = new u8[SUPERVU_STACKSIZE * 4]; + memzero_ptr(recVUStack[vuindex]); + + s_recVUMem[vuindex]->Reset(); + s_recVUPtr[vuindex] = *s_recVUMem[vuindex]; } // clear the block and any joining blocks @@ -847,16 +819,15 @@ void VuBaseBlock::GetInstsAtPc(int instpc, list& listinsts) static VuFunctionHeader* SuperVURecompileProgram(u32 startpc, int vuindex) { pxAssert(vuindex < 2); - pxAssert(s_recVUPtr != NULL); + pxAssert(s_recVUPtr[vuindex] != NULL); //Console.WriteLn("svu%c rec: %x", '0'+vuindex, startpc); // if recPtr reached the mem limit reset whole mem - if (((uptr)s_recVUPtr - (uptr)s_recVUMem) >= VU_EXESIZE - 0x40000) + if ((s_recVUPtr[vuindex] < s_recVUMem[vuindex]->GetPtr()) || (s_recVUPtr[vuindex] >= s_recVUMem[vuindex]->GetPtrEnd() - _256kb)) { - //Console.WriteLn("SuperVU reset mem"); + Console.WriteLn("SuperVU%u: Recompiler cache reset...", vuindex); SuperVUReset(0); SuperVUReset(1); - SuperVUReset(-1); if (s_TotalVUCycles > 0) { // already executing, so return NULL @@ -912,12 +883,12 @@ static VuFunctionHeader* SuperVURecompileProgram(u32 startpc, int vuindex) #endif // code generation - x86SetPtr(s_recVUPtr); + xSetPtr(s_recVUPtr[vuindex]); branch = 0; SuperVURecompile(); - s_recVUPtr = x86Ptr; + s_recVUPtr[vuindex] = xGetPtr(); // set the function's range VuFunctionHeader::RANGE r; @@ -947,7 +918,7 @@ static VuFunctionHeader* SuperVURecompileProgram(u32 startpc, int vuindex) } s_listBlocks.clear(); - pxAssert(s_recVUPtr < s_recVUMem + VU_EXESIZE); + pxAssertDev(s_recVUPtr[vuindex] < s_recVUMem[vuindex]->GetPtrEnd(), "SuperVU recompiler cache exceeded! (possible memory corruption)"); return s_pFnHeader; } @@ -2697,18 +2668,18 @@ void SuperVUFlush(int p, int wait) // executed only once per program static u32* SuperVUStaticAlloc(u32 size) { - pxAssert(recVUStackPtr + size <= recVUStack + SUPERVU_STACKSIZE); + pxAssert(recVUStackPtr[s_vu] + size <= recVUStack[s_vu] + SUPERVU_STACKSIZE); // always zero - if (size == 4) *(u32*)recVUStackPtr = 0; - else memset(recVUStackPtr, 0, size); - recVUStackPtr += size; - return (u32*)(recVUStackPtr - size); + if (size == 4) *(u32*)recVUStackPtr[s_vu] = 0; + else memset(recVUStackPtr[s_vu], 0, size); + recVUStackPtr[s_vu] += size; + return (u32*)(recVUStackPtr[s_vu] - size); } static void SuperVURecompile() { // save cpu state - recVUStackPtr = recVUStack; + recVUStackPtr[s_vu] = recVUStack[s_vu]; _initXMMregs(); @@ -4617,9 +4588,9 @@ recSuperVU0::recSuperVU0() IsInterpreter = false; } -void recSuperVU0::Allocate() +void recSuperVU0::Reserve() { - SuperVUAlloc( 0 ); + SuperVUAlloc(0); } void recSuperVU0::Shutdown() throw() @@ -4645,6 +4616,15 @@ void recSuperVU0::Clear(u32 Addr, u32 Size) SuperVUClear(Addr, Size, 0); } +uint recSuperVU0::GetCacheReserve() const +{ + return sVU_EXESIZE / _1mb; +} + +void recSuperVU0::SetCacheReserve( uint reserveInMegs ) const +{ + //microVU0.cacheSize = reserveInMegs * _1mb; +} // -------------------------------------------------------------------------------------- // recSuperVU1 Interface @@ -4655,9 +4635,9 @@ recSuperVU1::recSuperVU1() IsInterpreter = false; } -void recSuperVU1::Allocate() +void recSuperVU1::Reserve() { - SuperVUAlloc( 1 ); + SuperVUAlloc(1); } void recSuperVU1::Shutdown() throw() @@ -4670,6 +4650,16 @@ void recSuperVU1::Reset() SuperVUReset( 1 ); } +uint recSuperVU1::GetCacheReserve() const +{ + return sVU_EXESIZE / _1mb; +} + +void recSuperVU1::SetCacheReserve( uint reserveInMegs ) const +{ + //microVU0.cacheSize = reserveInMegs * _1mb; +} + #if 0 #include "sVU_Compare.h" #else diff --git a/plugins/CDVDnull/Windows/CDVDnull_vs2008.vcproj b/plugins/CDVDnull/Windows/CDVDnull_vs2008.vcproj index cd11c1be10..b8ee342239 100644 --- a/plugins/CDVDnull/Windows/CDVDnull_vs2008.vcproj +++ b/plugins/CDVDnull/Windows/CDVDnull_vs2008.vcproj @@ -5,6 +5,7 @@ Name="CDVDnull" ProjectGUID="{F38D9DF0-F68D-49D9-B3A0-932E74FB74A0}" RootNamespace="CDVDnull" + TargetFrameworkVersion="0" > diff --git a/plugins/GSnull/Windows/GSnull_vc2008.vcproj b/plugins/GSnull/Windows/GSnull_vc2008.vcproj index bff4bbf56e..cee39ef0b4 100644 --- a/plugins/GSnull/Windows/GSnull_vc2008.vcproj +++ b/plugins/GSnull/Windows/GSnull_vc2008.vcproj @@ -160,10 +160,6 @@ RelativePath="..\GS.cpp" > - - @@ -192,6 +188,10 @@ RelativePath=".\GSwin.cpp" > + + diff --git a/plugins/LilyPad/LilyPad_VC2008.vcproj b/plugins/LilyPad/LilyPad_VC2008.vcproj index 411038cb6c..9e6e1a1665 100644 --- a/plugins/LilyPad/LilyPad_VC2008.vcproj +++ b/plugins/LilyPad/LilyPad_VC2008.vcproj @@ -69,7 +69,6 @@ OutputFile="$(OutDir)\$(ProjectName)-dbg.dll" LinkIncremental="1" ModuleDefinitionFile=".\LilyPad.def" - RandomizedBaseAddress="1" TargetMachine="1" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -577,23 +582,6 @@ PreprocessorDefinitions="" /> - - - - - - @@ -604,6 +592,15 @@ PreprocessorDefinitions="" /> + + + @@ -638,6 +635,14 @@ PreprocessorDefinitions="" /> + + + @@ -647,23 +652,6 @@ PreprocessorDefinitions="" /> - - - - - - @@ -674,6 +662,15 @@ PreprocessorDefinitions="" /> + + + @@ -701,22 +698,6 @@ UsePrecompiledHeader="1" /> - - - - - - @@ -725,6 +706,14 @@ UsePrecompiledHeader="1" /> + + + @@ -733,6 +722,14 @@ UsePrecompiledHeader="1" /> + + + @@ -774,22 +771,6 @@ PreprocessorDefinitions="" /> - - - - - - @@ -798,6 +779,14 @@ PreprocessorDefinitions="" /> + + + @@ -806,6 +795,14 @@ PreprocessorDefinitions="" /> + + + @@ -934,6 +931,14 @@ PreprocessorDefinitions="" /> + + + @@ -943,23 +948,6 @@ PreprocessorDefinitions="" /> - - - - - - @@ -970,6 +958,15 @@ PreprocessorDefinitions="" /> + + + diff --git a/plugins/PadNull/Windows/PadNull_vc2008.vcproj b/plugins/PadNull/Windows/PadNull_vc2008.vcproj index 98798b08db..5802e8d5a8 100644 --- a/plugins/PadNull/Windows/PadNull_vc2008.vcproj +++ b/plugins/PadNull/Windows/PadNull_vc2008.vcproj @@ -56,7 +56,6 @@ - + @@ -121,7 +120,6 @@ @@ -156,11 +154,11 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm" > diff --git a/plugins/onepad/Linux/OnePad.cbp b/plugins/onepad/Linux/OnePad.cbp index 87f068a49b..04ef189049 100644 --- a/plugins/onepad/Linux/OnePad.cbp +++ b/plugins/onepad/Linux/OnePad.cbp @@ -53,7 +53,6 @@ - @@ -68,6 +67,7 @@ + diff --git a/plugins/spu2-x/src/Windows/Spu2-X_vs2008.vcproj b/plugins/spu2-x/src/Windows/Spu2-X_vs2008.vcproj index 8447a9d62e..90b2bae491 100644 --- a/plugins/spu2-x/src/Windows/Spu2-X_vs2008.vcproj +++ b/plugins/spu2-x/src/Windows/Spu2-X_vs2008.vcproj @@ -73,7 +73,6 @@ OutputFile="$(OutDir)\$(ProjectName)-dev.dll" AdditionalLibraryDirectories="$(SolutionDir)\3rdparty\portaudio" ModuleDefinitionFile=".\Spu2-X.def" - RandomizedBaseAddress="1" TargetMachine="1" /> @@ -242,7 +240,6 @@ ModuleDefinitionFile=".\Spu2-X.def" ProgramDatabaseFile="$(TargetDir)$(TargetName).pdb" StripPrivateSymbols="" - RandomizedBaseAddress="1" TargetMachine="1" /> - - - @@ -187,6 +184,7 @@ + diff --git a/plugins/zzogl-pg/opengl/Win32/zerogsogl_2008.vcproj b/plugins/zzogl-pg/opengl/Win32/zerogsogl_2008.vcproj index 0ee05a4322..5c31476c5b 100644 --- a/plugins/zzogl-pg/opengl/Win32/zerogsogl_2008.vcproj +++ b/plugins/zzogl-pg/opengl/Win32/zerogsogl_2008.vcproj @@ -572,11 +572,11 @@