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 @@