mirror of https://github.com/PCSX2/pcsx2.git
GregsMisc: Sync with trunk (r3983-r4044)
git-svn-id: http://pcsx2.googlecode.com/svn/branches/GregMiscellaneous@4045 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
21d90150ab
commit
5e73b1ca7e
|
@ -155,6 +155,8 @@
|
|||
<Unit filename="../../include/Utilities/HashMap.h" />
|
||||
<Unit filename="../../include/Utilities/IniInterface.h" />
|
||||
<Unit filename="../../include/Utilities/MemcpyFast.h" />
|
||||
<Unit filename="../../include/Utilities/MemsetFast.inl" />
|
||||
<Unit filename="../../include/Utilities/PageFaultSource.h" />
|
||||
<Unit filename="../../include/Utilities/Path.h" />
|
||||
<Unit filename="../../include/Utilities/PersistentThread.h" />
|
||||
<Unit filename="../../include/Utilities/RedtapeWindows.h" />
|
||||
|
@ -200,6 +202,7 @@
|
|||
<Unit filename="../../src/Utilities/ThreadTools.cpp" />
|
||||
<Unit filename="../../src/Utilities/ThreadingDialogs.cpp" />
|
||||
<Unit filename="../../src/Utilities/ThreadingInternal.h" />
|
||||
<Unit filename="../../src/Utilities/VirtualMemory.cpp" />
|
||||
<Unit filename="../../src/Utilities/pxCheckBox.cpp" />
|
||||
<Unit filename="../../src/Utilities/pxRadioPanel.cpp" />
|
||||
<Unit filename="../../src/Utilities/pxStaticText.cpp" />
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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!
|
||||
// ===========================================================================================
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <xmmintrin.h>
|
||||
|
||||
#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<MZFqwc / 8; ++i, destxmm+=8 )
|
||||
{
|
||||
_mm_store_ps(&destxmm[0][0], srcreg);
|
||||
_mm_store_ps(&destxmm[1][0], srcreg);
|
||||
_mm_store_ps(&destxmm[2][0], srcreg);
|
||||
_mm_store_ps(&destxmm[3][0], srcreg);
|
||||
_mm_store_ps(&destxmm[4][0], srcreg);
|
||||
_mm_store_ps(&destxmm[5][0], srcreg);
|
||||
_mm_store_ps(&destxmm[6][0], srcreg);
|
||||
_mm_store_ps(&destxmm[7][0], srcreg);
|
||||
}
|
||||
};
|
||||
|
||||
static __fi void memzero_sse_a( void* dest, const size_t size )
|
||||
{
|
||||
memset_sse_a<0>( 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<data>( &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) );
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// [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<PageFaultInfo>
|
||||
{
|
||||
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<IEventListener_PageFault>
|
||||
{
|
||||
protected:
|
||||
typedef EventSource<IEventListener_PageFault> _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<BaseVmReserveListener> 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<u8,16> 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;
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -31,7 +31,8 @@ SafeArray<T>::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<T>::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<T>::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<T>::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<m_allocsize; ++i )
|
||||
{
|
||||
|
@ -227,9 +227,8 @@ void SafeList<T>::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<newalloc; ++m_allocsize )
|
||||
{
|
||||
|
|
|
@ -60,6 +60,26 @@ extern void pcsx2_aligned_free(void* pmem);
|
|||
# define _aligned_realloc pcsx2_aligned_realloc
|
||||
#endif
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// pxDoOutOfMemory
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
typedef void FnType_OutOfMemory( uptr blocksize );
|
||||
typedef FnType_OutOfMemory* Fnptr_OutOfMemory;
|
||||
|
||||
// This method is meant to be assigned by applications that link against pxWex. It is called
|
||||
// (invoked) prior to most pxWex built-in memory/array classes throwing exceptions, and can be
|
||||
// used by an application to remove unneeded memory allocations and/or reduce internal cache
|
||||
// reserves.
|
||||
//
|
||||
// Example: PCSX2 uses several bloated recompiler code caches. Larger caches improve performance,
|
||||
// however a rouge cache growth could cause memory constraints in the operating system. If an out-
|
||||
// of-memory error occurs, PCSX2's implementation of this function attempts to reset all internal
|
||||
// recompiler caches. This can typically free up 100-150 megs of memory, and will allow the app
|
||||
// to continue running without crashing or hanging the operating system, etc.
|
||||
//
|
||||
extern Fnptr_OutOfMemory pxDoOutOfMemory;
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BaseScopedAlloc
|
||||
|
|
|
@ -222,6 +222,8 @@ extern bool pxParseAssignmentString( const wxString& src, wxString& ldest, wxStr
|
|||
#define pxsFmt FastFormatUnicode().Write
|
||||
#define pxsFmtV FastFormatUnicode().WriteV
|
||||
|
||||
#define pxsPtr(ptr) pxsFmt("0x%08X", (ptr)).c_str()
|
||||
|
||||
extern wxString& operator+=(wxString& str1, const FastFormatUnicode& str2);
|
||||
extern wxString operator+(const wxString& str1, const FastFormatUnicode& str2);
|
||||
extern wxString operator+(const wxChar* str1, const FastFormatUnicode& str2);
|
||||
|
|
|
@ -1,181 +1,184 @@
|
|||
# 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
|
||||
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 "")
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
#include <signal.h>
|
||||
#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 ));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<BufferCount; ++i)
|
||||
{
|
||||
m_buffers[i].Alloc(1024);
|
||||
m_buffers[i].Alloc(512);
|
||||
}
|
||||
|
||||
m_curslot = 0;
|
||||
|
@ -174,7 +174,7 @@ static __ri void format_that_ascii_mess( CharBufferType& buffer, uint writepos,
|
|||
|
||||
len += writepos;
|
||||
if (len < size) break;
|
||||
buffer.Alloc( len + 128 );
|
||||
buffer.Resize( len + 128 );
|
||||
};
|
||||
|
||||
// performing an assertion or log of a truncated string is unsafe, so let's not; even
|
||||
|
@ -206,7 +206,7 @@ static __ri uint format_that_unicode_mess( CharBufferType& buffer, uint writepos
|
|||
|
||||
len += writepos;
|
||||
if (len < size) return len;
|
||||
buffer.Alloc( (len + 128) * sizeof(wxChar) );
|
||||
buffer.Resize( (len + 128) * sizeof(wxChar) );
|
||||
};
|
||||
|
||||
// performing an assertion or log of a truncated string is unsafe, so let's not; even
|
||||
|
|
|
@ -15,50 +15,204 @@
|
|||
|
||||
|
||||
#include "../PrecompiledHeader.h"
|
||||
#include "PageFaultSource.h"
|
||||
|
||||
#include <wx/thread.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "PageFaultSource.h"
|
||||
|
||||
#ifndef __WXMSW__
|
||||
#include <wx/thread.h>
|
||||
#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<endpos; init += m_blocksize*__pagesize )
|
||||
OnCommittedBlock(init);
|
||||
|
||||
m_pages_commited += m_blocksize * blocks;
|
||||
}
|
||||
|
||||
void BaseVmReserveListener::OnPageFaultEvent(const PageFaultInfo& info, bool& handled)
|
||||
{
|
||||
sptr offset = (info.addr - (uptr)m_baseptr) / __pagesize;
|
||||
if ((offset < 0) || ((uptr)offset >= 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<m_numblocks; ++i, curptr+=blockBytes)
|
||||
{
|
||||
uint thisbit = 1 << (i & 7);
|
||||
if (!(m_blockbits[i/8] & thisbit)) continue;
|
||||
|
||||
HostSys::MemProtect(curptr, blockBytes, PageAccess_None());
|
||||
HostSys::MmapResetPtr(curptr, blockBytes);
|
||||
}
|
||||
}
|
||||
|
||||
memzero_sse_a(m_blockbits.GetPtr(), _calcBlockBitArrayLength());
|
||||
}
|
||||
|
||||
// Important! The number of blocks of the array will be altered when using this method.
|
||||
//
|
||||
bool SpatialArrayReserve::TryResize( uint newsize )
|
||||
{
|
||||
uint newpages = (newsize + __pagesize - 1) / __pagesize;
|
||||
|
||||
// find the last allocated block -- we cannot be allowed to resize any smaller than that:
|
||||
|
||||
uint i;
|
||||
for (i=m_numblocks-1; i; --i)
|
||||
{
|
||||
uint bit = i & 7;
|
||||
if (m_blockbits[i / 8] & bit) break;
|
||||
}
|
||||
|
||||
uint pages_in_use = i * m_blocksize;
|
||||
if (newpages < pages_in_use) return false;
|
||||
|
||||
if (!_parent::TryResize( newsize )) return false;
|
||||
|
||||
// On success, we must re-calibrate the internal blockbits array.
|
||||
|
||||
m_blockbits.Resize( (m_numblocks + 7) / 8 );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// This method allows the programmer to specify the block size of the array as a function
|
||||
// of its reserved size. This function *must* be called *after* the reserve has been made,
|
||||
// and *before* the array contents have been accessed.
|
||||
//
|
||||
// Calls to this function prior to initializing the reserve or after the reserve has been
|
||||
// accessed (resulting in committed blocks) will be ignored -- and will generate an assertion
|
||||
// in debug builds.
|
||||
SpatialArrayReserve& SpatialArrayReserve::SetBlockCount( uint blocks )
|
||||
{
|
||||
pxAssumeDev( !m_pages_commited, "Invalid object state: SetBlockCount must be called prior to reserved memory accesses." );
|
||||
|
||||
// Calculate such that the last block extends past the end of the array, if necessary.
|
||||
|
||||
m_numblocks = blocks;
|
||||
m_blocksize = (m_pages_reserved + m_numblocks-1) / m_numblocks;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Sets the block size via pages (pages are defined by the __pagesize global, which is
|
||||
// typically 4096).
|
||||
//
|
||||
// This method must be called prior to accessing or modifying the array contents. Calls to
|
||||
// a modified buffer will be ignored (and generate an assertion in dev/debug modes).
|
||||
SpatialArrayReserve& SpatialArrayReserve::SetBlockSizeInPages( uint pages )
|
||||
{
|
||||
if (pxAssertDev(!m_pages_commited, "Invalid object state: Block size can only be changed prior to accessing or modifying the reserved buffer contents."))
|
||||
{
|
||||
m_blocksize = pages;
|
||||
m_numblocks = (m_pages_reserved + m_blocksize - 1) / m_blocksize;
|
||||
m_blockbits.Alloc( _calcBlockBitArrayLength() );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// SetBlockSize assigns the block size of the spatial array, in bytes. The actual size of
|
||||
// each block will be rounded up to the nearest page size. The resulting size is returned.
|
||||
//
|
||||
// This method must be called prior to accessing or modifying the array contents. Calls to
|
||||
// a modified buffer will be ignored (and generate an assertion in dev/debug modes).
|
||||
uint SpatialArrayReserve::SetBlockSize( uint bytes )
|
||||
{
|
||||
SetBlockSizeInPages((bytes + __pagesize - 1) / __pagesize);
|
||||
return m_blocksize * __pagesize;
|
||||
}
|
||||
|
||||
void SpatialArrayReserve::DoCommitAndProtect( uptr page )
|
||||
{
|
||||
// Spatial Arrays work on block granularity only:
|
||||
// Round the page into a block, and commit the whole block that the page belongs to.
|
||||
|
||||
uint block = page / m_blocksize;
|
||||
CommitBlocks(block*m_blocksize, 1);
|
||||
}
|
||||
|
||||
void SpatialArrayReserve::OnCommittedBlock( void* block )
|
||||
{
|
||||
// Determine the block position in the blockbits array, flag it, and be done!
|
||||
|
||||
uptr relative = (uptr)block - (uptr)m_baseptr;
|
||||
relative /= m_blocksize * __pagesize;
|
||||
|
||||
//DbgCon.WriteLn("Check me out @ 0x%08x", block);
|
||||
|
||||
pxAssert( (m_blockbits[relative/8] & (1 << (relative & 7))) == 0 );
|
||||
m_blockbits[relative/8] |= 1 << (relative & 7);
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// PageProtectionMode (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
wxString PageProtectionMode::ToString() const
|
||||
{
|
||||
wxString modeStr;
|
||||
|
||||
if (m_read) modeStr += L"Read";
|
||||
if (m_write) modeStr += L"Write";
|
||||
if (m_exec) modeStr += L"Exec";
|
||||
|
||||
if (modeStr.IsEmpty()) return L"NoAccess";
|
||||
if (modeStr.Length() <= 5) modeStr += L"Only";
|
||||
|
||||
return modeStr;
|
||||
}
|
|
@ -15,48 +15,124 @@
|
|||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "Utilities/RedtapeWindows.h"
|
||||
#include "PageFaultSource.h"
|
||||
|
||||
#include <winnt.h>
|
||||
|
||||
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() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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<m_dtablesize; ++i)
|
||||
for (int i=0; i<m_dtablesize; ++i)
|
||||
{
|
||||
if (m_dtable[i] == lsn) return;
|
||||
}
|
||||
|
|
|
@ -383,7 +383,6 @@ set(pcsx2IPUHeaders
|
|||
|
||||
# Linux sources
|
||||
set(pcsx2LinuxSources
|
||||
Linux/LnxHostSys.cpp
|
||||
Linux/LnxKeyCodes.cpp)
|
||||
|
||||
# Linux headers
|
||||
|
@ -432,7 +431,7 @@ set(pcsx2SystemSources
|
|||
|
||||
# System headers
|
||||
set(pcsx2SystemHeaders
|
||||
System/PageFaultSource.h
|
||||
System/RecTypes.h
|
||||
System/SysThreads.h)
|
||||
|
||||
# Utilities sources
|
||||
|
@ -542,7 +541,6 @@ set(pcsx2x86Headers
|
|||
x86/microVU_Tables.inl
|
||||
x86/microVU_Upper.inl
|
||||
x86/newVif.h
|
||||
x86/newVif_BlockBuffer.h
|
||||
x86/newVif_HashBucket.h
|
||||
x86/newVif_UnpackSSE.h
|
||||
x86/sVU_Compare.h
|
||||
|
|
|
@ -400,7 +400,7 @@ struct Pcsx2Config
|
|||
|
||||
// when enabled uses BOOT2 injection, skipping sony bios splashes
|
||||
UseBOOT2Injection :1,
|
||||
|
||||
BackupSavestate :1,
|
||||
// enables simulated ejection of memory cards when loading savestates
|
||||
McdEnableEjection :1,
|
||||
|
||||
|
|
|
@ -556,7 +556,9 @@ extern tDMA_TAG *dmaGetAddr(u32 addr, bool write);
|
|||
extern void hwIntcIrq(int n);
|
||||
extern void hwDmacIrq(int n);
|
||||
|
||||
extern void FireMFIFOEmpty();
|
||||
extern bool hwMFIFOWrite(u32 addr, const u128* data, uint size_qwc);
|
||||
extern void hwDmacSrcTadrInc(DMACh& dma);
|
||||
extern bool hwDmacSrcChainWithStack(DMACh& dma, int id);
|
||||
extern bool hwDmacSrcChain(DMACh& dma, int id);
|
||||
|
||||
|
|
|
@ -472,16 +472,16 @@ int GetPS2ElfName( wxString& name )
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
catch (Exception::BadStream& ex)
|
||||
{
|
||||
Console.Error(ex.FormatDiagnosticMessage());
|
||||
return 0; // ISO error
|
||||
}
|
||||
catch( Exception::FileNotFound& )
|
||||
{
|
||||
//Console.Warning(ex.FormatDiagnosticMessage());
|
||||
return 0; // no SYSTEM.CNF, not a PS1/PS2 disc.
|
||||
}
|
||||
catch (Exception::BadStream& ex)
|
||||
{
|
||||
Console.Error(ex.FormatDiagnosticMessage());
|
||||
return 0; // ISO error
|
||||
}
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
FILE *fp;
|
||||
|
|
169
pcsx2/Gif.cpp
169
pcsx2/Gif.cpp
|
@ -97,6 +97,13 @@ __fi void gsInterrupt()
|
|||
{
|
||||
GIF_LOG("gsInterrupt: %8.8x", cpuRegs.cycle);
|
||||
|
||||
if (dmacRegs.ctrl.MFD == MFD_GIF) // GIF MFIFO
|
||||
{
|
||||
//Console.WriteLn("GIF MFIFO");
|
||||
gifMFIFOInterrupt();
|
||||
return;
|
||||
}
|
||||
|
||||
if(SIGNAL_IMR_Pending == true)
|
||||
{
|
||||
//DevCon.Warning("Path 3 Paused");
|
||||
|
@ -234,6 +241,7 @@ bool CheckPaths(int Channel)
|
|||
{
|
||||
if((vif1.cmd & 0x7f) != 0x51 || gifRegs.stat.P1Q == true)
|
||||
{
|
||||
//DevCon.Warning("GIF Stall 1 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;
|
||||
if(gifRegs.stat.P1Q) gsPath1Interrupt();
|
||||
CPU_INT(DMAC_GIF, 16);
|
||||
|
@ -246,6 +254,7 @@ bool CheckPaths(int Channel)
|
|||
//This should cover both scenarios, as DIRECTHL doesn't gain priority when image mode is running (PENDINGIMAGE_MODE == fininshed).
|
||||
if((gifRegs.stat.P1Q == true || gifRegs.stat.P2Q == true) || (gifRegs.stat.APATH > 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<<DMAC_MFIFO_GIF)))
|
||||
{
|
||||
if(gifch.chcr.STR == true)CPU_INT(DMAC_MFIFO_GIF, 4);
|
||||
gifstate &= ~GIF_STATE_EMPTY;
|
||||
}
|
||||
gifRegs.stat.FQC = 16;
|
||||
return;
|
||||
}
|
||||
|
||||
if (gifRegs.ctrl.PSE) // temporarily stop
|
||||
|
@ -545,15 +589,6 @@ void mfifoGIFtransfer(int qwc)
|
|||
|
||||
if (gifch.qwc == 0)
|
||||
{
|
||||
if (gifch.tadr == spr0ch.madr)
|
||||
{
|
||||
//if( gifqwc > 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
46
pcsx2/Hw.cpp
46
pcsx2/Hw.cpp
|
@ -130,6 +130,14 @@ void hwDmacIrq(int n)
|
|||
if(psHu16(DMAC_STAT+2) & (1<<n))cpuTestDMACInts();
|
||||
}
|
||||
|
||||
void FireMFIFOEmpty()
|
||||
{
|
||||
SPR_LOG("VIF MFIFO Data Empty");
|
||||
hwDmacIrq(DMAC_MFIFO_EMPTY);
|
||||
|
||||
if (dmacRegs.ctrl.MFD == MFD_VIF1) vif1Regs.stat.FQC = 0;
|
||||
else if (dmacRegs.ctrl.MFD == MFD_GIF) gifRegs.stat.FQC = 0;
|
||||
}
|
||||
// Write 'size' bytes to memory address 'addr' from 'data'.
|
||||
__ri bool hwMFIFOWrite(u32 addr, const u128* data, uint qwc)
|
||||
{
|
||||
|
@ -137,6 +145,7 @@ __ri bool hwMFIFOWrite(u32 addr, const u128* data, uint qwc)
|
|||
pxAssume((dmacRegs.rbor.ADDR & 15) == 0);
|
||||
pxAssume((addr & 15) == 0);
|
||||
|
||||
if(qwc > ((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;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include "Vif_Dma.h"
|
||||
#include <limits.h>
|
||||
|
||||
#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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -24,48 +24,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <xmmintrin.h>
|
||||
|
||||
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<MZFqwc / 8; ++i, destxmm+=8 )
|
||||
{
|
||||
_mm_store_ps(&destxmm[0][0], zeroreg);
|
||||
_mm_store_ps(&destxmm[1][0], zeroreg);
|
||||
_mm_store_ps(&destxmm[2][0], zeroreg);
|
||||
_mm_store_ps(&destxmm[3][0], zeroreg);
|
||||
_mm_store_ps(&destxmm[4][0], zeroreg);
|
||||
_mm_store_ps(&destxmm[5][0], zeroreg);
|
||||
_mm_store_ps(&destxmm[6][0], zeroreg);
|
||||
_mm_store_ps(&destxmm[7][0], zeroreg);
|
||||
}
|
||||
|
||||
#undef MZFqwc
|
||||
};
|
||||
|
||||
// the IPU is fixed to 16 byte strides (128-bit / QWC resolution):
|
||||
static const uint decoder_stride = 16;
|
||||
|
||||
|
|
|
@ -359,11 +359,19 @@ void JALR()
|
|||
|
||||
} } } // end namespace R5900::Interpreter::OpcodeImpl
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// R5900cpu/intCpu interface (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
static void intReserve()
|
||||
{
|
||||
// fixme : detect cpu for use the optimize asm code
|
||||
}
|
||||
|
||||
static void intAlloc()
|
||||
{
|
||||
// fixme : detect cpu for use the optimize asm code
|
||||
// Nothing to do!
|
||||
}
|
||||
|
||||
static void intReset()
|
||||
|
@ -419,19 +427,28 @@ static void intShutdown() {
|
|||
|
||||
static void intThrowException( const BaseR5900Exception& ex )
|
||||
{
|
||||
// No tricks needed; C++ stack unwnding shoud suffice for MSW and GCC alike.
|
||||
// No tricks needed; C++ stack unwnding should suffice for MSW and GCC alike.
|
||||
ex.Rethrow();
|
||||
}
|
||||
|
||||
static void intThrowException( const BaseException& ex )
|
||||
{
|
||||
// No tricks needed; C++ stack unwnding shoud suffice for MSW and GCC alike.
|
||||
// No tricks needed; C++ stack unwnding should suffice for MSW and GCC alike.
|
||||
ex.Rethrow();
|
||||
}
|
||||
|
||||
static void intSetCacheReserve( uint reserveInMegs )
|
||||
{
|
||||
}
|
||||
|
||||
static uint intGetCacheReserve()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
R5900cpu intCpu =
|
||||
{
|
||||
intAlloc,
|
||||
intReserve,
|
||||
intShutdown,
|
||||
|
||||
intReset,
|
||||
|
@ -442,4 +459,7 @@ R5900cpu intCpu =
|
|||
intThrowException,
|
||||
intThrowException,
|
||||
intClear,
|
||||
|
||||
intGetCacheReserve,
|
||||
intSetCacheReserve,
|
||||
};
|
||||
|
|
|
@ -24,26 +24,43 @@ IopVM_MemoryAllocMess* iopMem = NULL;
|
|||
|
||||
__pagealigned u8 iopHw[Ps2MemSize::IopHardware];
|
||||
|
||||
void psxMemAlloc()
|
||||
// --------------------------------------------------------------------------------------
|
||||
// iopMemoryReserve
|
||||
// --------------------------------------------------------------------------------------
|
||||
iopMemoryReserve::iopMemoryReserve()
|
||||
: _parent( L"IOP Main Memory (2mb)", sizeof(*iopMem) )
|
||||
{
|
||||
if( iopMem == NULL )
|
||||
iopMem = (IopVM_MemoryAllocMess*)vtlb_malloc( sizeof(*iopMem), 4096 );
|
||||
}
|
||||
|
||||
psxMemWLUT = (uptr*)_aligned_malloc(0x2000 * sizeof(uptr) * 2, 16);
|
||||
psxMemRLUT = psxMemWLUT + 0x2000; //(uptr*)_aligned_malloc(0x10000 * sizeof(uptr),16);
|
||||
void iopMemoryReserve::Reserve()
|
||||
{
|
||||
_parent::Reserve(HostMemoryMap::IOPmem);
|
||||
//_parent::Reserve(EmuConfig.HostMap.IOP);
|
||||
}
|
||||
|
||||
void iopMemoryReserve::Commit()
|
||||
{
|
||||
_parent::Commit();
|
||||
iopMem = (IopVM_MemoryAllocMess*)m_reserve.GetPtr();
|
||||
}
|
||||
|
||||
// Note! Resetting the IOP's memory state is dependent on having *all* psx memory allocated,
|
||||
// which is performed by MemInit and PsxMemInit()
|
||||
void psxMemReset()
|
||||
void iopMemoryReserve::Reset()
|
||||
{
|
||||
pxAssume( psxMemWLUT != NULL );
|
||||
pxAssume( iopMem != NULL );
|
||||
_parent::Reset();
|
||||
|
||||
DbgCon.WriteLn( "IOP Resetting physical ram..." );
|
||||
pxAssume( iopMem );
|
||||
|
||||
if (!psxMemWLUT)
|
||||
{
|
||||
psxMemWLUT = (uptr*)_aligned_malloc(0x2000 * sizeof(uptr) * 2, 16);
|
||||
psxMemRLUT = psxMemWLUT + 0x2000; //(uptr*)_aligned_malloc(0x10000 * sizeof(uptr),16);
|
||||
}
|
||||
|
||||
DbgCon.WriteLn("IOP resetting main memory...");
|
||||
|
||||
memzero_ptr<0x2000 * sizeof(uptr) * 2>( 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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <signal.h>
|
||||
#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 ) {}
|
|
@ -20,6 +20,8 @@
|
|||
#include <gdk/gdkkeysyms.h>
|
||||
#include <gdk/gdkx.h>
|
||||
|
||||
void NTFS_CompressFile( const wxString& file, bool compressStatus ) {}
|
||||
|
||||
// Returns a WXK_* keycode, given some kinda GDK input mess!
|
||||
int TranslateGDKtoWXK( u32 keysym )
|
||||
{
|
||||
|
|
|
@ -268,9 +268,7 @@
|
|||
<Unit filename="../DebugTools/DisVUmicro.h" />
|
||||
<Unit filename="../DebugTools/DisVUops.h" />
|
||||
<Unit filename="../Dmac.h" />
|
||||
<Unit filename="../Docs/ChangeLog.txt" />
|
||||
<Unit filename="../Docs/License.txt" />
|
||||
<Unit filename="../Docs/devblog.txt" />
|
||||
<Unit filename="../Dump.cpp" />
|
||||
<Unit filename="../Dump.h" />
|
||||
<Unit filename="../Elfheader.cpp" />
|
||||
|
@ -316,8 +314,6 @@
|
|||
<Unit filename="../IopMem.h" />
|
||||
<Unit filename="../IopSio2.cpp" />
|
||||
<Unit filename="../IopSio2.h" />
|
||||
<Unit filename="../Ipu_fifo.h" />
|
||||
<Unit filename="LnxHostSys.cpp" />
|
||||
<Unit filename="LnxKeyCodes.cpp">
|
||||
<Option compiler="gcc" use="1" buildCommand="$compiler $options $includes `pkg-config gtk+-2.0 --cflags` -c $file -o $object" />
|
||||
</Unit>
|
||||
|
@ -363,11 +359,10 @@
|
|||
<Unit filename="../SourceLog.cpp" />
|
||||
<Unit filename="../Stats.cpp" />
|
||||
<Unit filename="../Stats.h" />
|
||||
<Unit filename="../StringUtils.h" />
|
||||
<Unit filename="../SysForwardDefs.h" />
|
||||
<Unit filename="../System.cpp" />
|
||||
<Unit filename="../System.h" />
|
||||
<Unit filename="../System/PageFaultSource.h" />
|
||||
<Unit filename="../System/RecTypes.h" />
|
||||
<Unit filename="../System/SysCoreThread.cpp" />
|
||||
<Unit filename="../System/SysThreadBase.cpp" />
|
||||
<Unit filename="../System/SysThreads.h" />
|
||||
|
@ -421,7 +416,6 @@
|
|||
<Unit filename="../gui/AppRes.cpp" />
|
||||
<Unit filename="../gui/AppSaveStates.h" />
|
||||
<Unit filename="../gui/ApplyState.h" />
|
||||
<Unit filename="../gui/CheckedStaticBox.h" />
|
||||
<Unit filename="../gui/ConsoleLogger.cpp" />
|
||||
<Unit filename="../gui/ConsoleLogger.h" />
|
||||
<Unit filename="../gui/CpuUsageProvider.cpp" />
|
||||
|
@ -449,7 +443,6 @@
|
|||
<Unit filename="../gui/Dialogs/StuckThreadDialog.cpp" />
|
||||
<Unit filename="../gui/Dialogs/SysConfigDialog.cpp" />
|
||||
<Unit filename="../gui/ExecutorThread.cpp" />
|
||||
<Unit filename="../gui/ExecutorThread.h" />
|
||||
<Unit filename="../gui/FrameForGS.cpp" />
|
||||
<Unit filename="../gui/GlobalCommands.cpp" />
|
||||
<Unit filename="../gui/IsoDropTarget.cpp" />
|
||||
|
@ -466,7 +459,6 @@
|
|||
<Unit filename="../gui/MessageBoxes.cpp" />
|
||||
<Unit filename="../gui/Panels/AudioPanel.cpp" />
|
||||
<Unit filename="../gui/Panels/BaseApplicableConfigPanel.cpp" />
|
||||
<Unit filename="../gui/Panels/BaseConfigPanel.h" />
|
||||
<Unit filename="../gui/Panels/BiosSelectorPanel.cpp" />
|
||||
<Unit filename="../gui/Panels/ConfigurationPanels.h" />
|
||||
<Unit filename="../gui/Panels/CpuPanel.cpp" />
|
||||
|
@ -572,10 +564,8 @@
|
|||
<Unit filename="../gui/Saveslots.cpp" />
|
||||
<Unit filename="../gui/SysState.cpp" />
|
||||
<Unit filename="../gui/UpdateUI.cpp" />
|
||||
<Unit filename="../gui/gsFrame.h" />
|
||||
<Unit filename="../gui/i18n.cpp" />
|
||||
<Unit filename="../gui/i18n.h" />
|
||||
<Unit filename="../gui/pxEvtThread.h" />
|
||||
<Unit filename="../gui/pxLogTextCtrl.cpp" />
|
||||
<Unit filename="../ps2/BiosTools.cpp" />
|
||||
<Unit filename="../ps2/BiosTools.h" />
|
||||
|
@ -647,7 +637,6 @@
|
|||
<Unit filename="../x86/microVU_Tables.inl" />
|
||||
<Unit filename="../x86/microVU_Upper.inl" />
|
||||
<Unit filename="../x86/newVif.h" />
|
||||
<Unit filename="../x86/newVif_BlockBuffer.h" />
|
||||
<Unit filename="../x86/newVif_Dynarec.cpp" />
|
||||
<Unit filename="../x86/newVif_HashBucket.h" />
|
||||
<Unit filename="../x86/newVif_Unpack.cpp" />
|
||||
|
|
145
pcsx2/Memory.cpp
145
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() );
|
||||
}
|
||||
|
|
|
@ -24,6 +24,10 @@
|
|||
|
||||
#include <xmmintrin.h>
|
||||
|
||||
// [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();
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
|
||||
|
|
|
@ -374,6 +374,7 @@ void Pcsx2Config::LoadSave( IniInterface& ini )
|
|||
IniBitBool( ConsoleToStdio );
|
||||
IniBitBool( HostFs );
|
||||
|
||||
IniBitBool( BackupSavestate );
|
||||
IniBitBool( McdEnableEjection );
|
||||
IniBitBool( MultitapPort0_Enabled );
|
||||
IniBitBool( MultitapPort1_Enabled );
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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<u8>& 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
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
310
pcsx2/System.cpp
310
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 );
|
||||
}
|
||||
|
|
|
@ -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<u8> 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.
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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<PageFaultInfo>
|
||||
{
|
||||
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<IEventListener_PageFault>
|
||||
{
|
||||
protected:
|
||||
typedef EventSource<IEventListener_PageFault> _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;
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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;
|
||||
};
|
|
@ -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();
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<<DMAC_MFIFO_VIF)))
|
||||
{
|
||||
SPR_LOG("Data Added, Resuming");
|
||||
CPU_INT(DMAC_MFIFO_VIF, 4);
|
||||
}
|
||||
|
||||
vif1Regs.stat.FQC = 0x10; // FQC=16
|
||||
}
|
||||
|
@ -147,8 +176,9 @@ void mfifoVIF1transfer(int qwc)
|
|||
return;
|
||||
}
|
||||
|
||||
if (vif1ch.qwc == 0 && vifqwc > 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;
|
||||
|
|
|
@ -154,7 +154,7 @@ template<int idx> __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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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<SysCpuProviderPack> m_CpuProviders;
|
||||
ScopedPtr<SysAllocVM> m_VmAllocs;
|
||||
ScopedPtr<SysMainMemory> 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
|
||||
// --------------------------------------------------------------------------
|
||||
|
|
|
@ -19,89 +19,80 @@
|
|||
|
||||
#include <wx/stackwalk.h>
|
||||
|
||||
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__
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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() );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<srcnt; ++i)
|
||||
{
|
||||
|
@ -609,7 +609,7 @@ bool ConsoleLogFrame::Write( ConsoleColors color, const wxString& text )
|
|||
{
|
||||
// Too many color changes causes huge slowdowns when decorating the rich textview, so
|
||||
// include a secondary check to avoid having a colorful log spam killing gui responsiveness.
|
||||
|
||||
|
||||
if( m_CurQueuePos > 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<ConsoleWriter_Stdout>,
|
||||
ConsoleToWindow_Newline<ConsoleWriter_Stdout>,
|
||||
ConsoleToWindow_SetTitle<ConsoleWriter_Stdout>,
|
||||
|
||||
0
|
||||
};
|
||||
|
||||
static const IConsoleWriter ConsoleWriter_WindowAndFile =
|
||||
|
@ -1122,6 +1126,8 @@ static const IConsoleWriter ConsoleWriter_WindowAndFile =
|
|||
ConsoleToWindow_DoWrite<ConsoleWriter_File>,
|
||||
ConsoleToWindow_Newline<ConsoleWriter_File>,
|
||||
ConsoleToWindow_SetTitle<ConsoleWriter_File>,
|
||||
|
||||
0
|
||||
};
|
||||
|
||||
void Pcsx2App::EnableAllLogging()
|
||||
|
|
|
@ -56,7 +56,7 @@ DefaultCpuUsageProvider::DefaultCpuUsageProvider()
|
|||
|
||||
void DefaultCpuUsageProvider::Reset()
|
||||
{
|
||||
for( int i=0; i<QueueDepth; ++i )
|
||||
for( uint i=0; i<QueueDepth; ++i )
|
||||
m_queue[i].LoadWithCurrentTimes();
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ bool MsgButtons::Allows( wxWindowID id ) const
|
|||
|
||||
// [TODO] : maybe add in an Ignore All?
|
||||
case wxID_IGNORE: return HasIgnore();
|
||||
|
||||
|
||||
case wxID_RESET: return HasReset();
|
||||
case wxID_CLOSE: return HasClose();
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ static wxWindowID ParseThatResult( const wxString& src, const MsgButtons& validT
|
|||
wxID_ANY,
|
||||
};
|
||||
|
||||
for( int i=0; i<ArraySize( retvals ); ++i )
|
||||
for( uint i=0; i<ArraySize( retvals ); ++i )
|
||||
{
|
||||
if( (validTypes.Allows( retvals[i] )) && (src == ResultToString(retvals[i], validTypes)) )
|
||||
return retvals[i];
|
||||
|
|
|
@ -21,8 +21,6 @@ Dialogs::GameDatabaseDialog::GameDatabaseDialog(wxWindow* parent)
|
|||
: BaseConfigurationDialog( parent, AddAppName(_("Game Database - %s")), 580 )
|
||||
{
|
||||
ScopedBusyCursor busy( Cursor_ReallyBusy );
|
||||
|
||||
*this += new Panels::GameDatabasePanel(this);
|
||||
|
||||
AddOkCancel();
|
||||
}
|
||||
|
|
|
@ -44,6 +44,8 @@ Panels::McdConfigPanel_Toggles::McdConfigPanel_Toggles(wxWindow *parent)
|
|||
)
|
||||
);
|
||||
|
||||
m_check_SavestateBackup = new pxCheckBox( this, pxsFmt(_("Backup existing Savestate when creating a new one")) );
|
||||
|
||||
for( uint i=0; i<2; ++i )
|
||||
{
|
||||
m_check_Multitap[i] = new pxCheckBox( this, pxsFmt(_("Enable Multitap on Port %u"), i+1) );
|
||||
|
@ -60,23 +62,29 @@ Panels::McdConfigPanel_Toggles::McdConfigPanel_Toggles(wxWindow *parent)
|
|||
|
||||
*this += 4;
|
||||
|
||||
*this += m_check_SavestateBackup;
|
||||
|
||||
*this += 4;
|
||||
|
||||
*this += m_check_Ejection;
|
||||
}
|
||||
|
||||
void Panels::McdConfigPanel_Toggles::Apply()
|
||||
{
|
||||
g_Conf->EmuOptions.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 );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -48,6 +48,11 @@ void MainEmuFrame::Menu_McdSettings_Click(wxCommandEvent &event)
|
|||
AppOpenDialog<McdConfigDialog>( this );
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_GameDatabase_Click(wxCommandEvent &event)
|
||||
{
|
||||
AppOpenDialog<McdConfigDialog>( this );
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_WindowSettings_Click(wxCommandEvent &event)
|
||||
{
|
||||
wxCommandEvent evt( pxEvt_SetSettingsPage );
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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<traceLogCount; ++i )
|
||||
{
|
||||
if (!traceLogList[i] || !m_checks[i]) continue;
|
||||
|
|
|
@ -231,6 +231,7 @@ namespace Panels
|
|||
protected:
|
||||
pxCheckBox* m_check_Multitap[2];
|
||||
pxCheckBox* m_check_Ejection;
|
||||
pxCheckBox* m_check_SavestateBackup;
|
||||
|
||||
public:
|
||||
McdConfigPanel_Toggles( wxWindow* parent );
|
||||
|
|
|
@ -59,7 +59,15 @@ namespace Exception
|
|||
class NotEnumerablePlugin : public BadStream
|
||||
{
|
||||
public:
|
||||
DEFINE_STREAM_EXCEPTION( NotEnumerablePlugin, BadStream, wxLt("File is not a PCSX2 plugin") );
|
||||
DEFINE_STREAM_EXCEPTION( NotEnumerablePlugin, BadStream );
|
||||
|
||||
wxString FormatDiagnosticMessage() const
|
||||
{
|
||||
FastFormatUnicode retval;
|
||||
retval.Write("File is not a PCSX2 plugin");
|
||||
_formatDiagMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -62,21 +62,6 @@ static void SaveStateFile_ReadHeader( IStreamReader& thr )
|
|||
.SetUserMsg(_("Cannot load this savestate. The state is an unsupported version, likely created by a newer edition of PCSX2."));
|
||||
};
|
||||
|
||||
class gzError : public Exception::BadStream
|
||||
{
|
||||
DEFINE_STREAM_EXCEPTION( gzError, BadStream, wxLt("Invalid or corrupted gzip archive") )
|
||||
};
|
||||
|
||||
class gzReadError : public gzError
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
class gzWriteError : public gzError
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// gzipReader
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -351,6 +336,15 @@ void StateCopy_SaveToSlot( uint num )
|
|||
{
|
||||
const wxString file( SaveStateBase::GetFilename( num ) );
|
||||
|
||||
// Backup old Savestate if one exists.
|
||||
if( wxFileExists( file ) && EmuConfig.BackupSavestate )
|
||||
{
|
||||
const wxString copy( SaveStateBase::GetFilename( num ) + pxsFmt( L".backup") );
|
||||
|
||||
Console.Indent().WriteLn( Color_StrongGreen, L"Backing up existing state in slot %d.", num);
|
||||
wxCopyFile( file, copy );
|
||||
}
|
||||
|
||||
Console.WriteLn( Color_StrongGreen, "Saving savestate to slot %d...", num );
|
||||
Console.Indent().WriteLn( Color_StrongGreen, L"filename: %s", file.c_str() );
|
||||
|
||||
|
|
|
@ -897,25 +897,39 @@ __fi int GIFPath::CopyTag(const u128* pMem128, u32 size)
|
|||
case GIF_PATH_2:
|
||||
GSTransferStatus.PTH2 = STOPPED_MODE;
|
||||
break;
|
||||
case GIF_PATH_3:
|
||||
case GIF_PATH_3:
|
||||
//For huge chunks we may have delay problems, so we need to stall it till the interrupt, else we get desync (Lemmings)
|
||||
if(size > 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
301
pcsx2/vtlb.cpp
301
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();
|
||||
}
|
125
pcsx2/vtlb.h
125
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;
|
||||
|
|
|
@ -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<Module>::const_iterator
|
||||
iter = ProfModules.begin(),
|
||||
end = ProfModules.end(); iter<end; ++iter )
|
||||
{
|
||||
if( iter->name.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;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
|
|
|
@ -18,18 +18,4 @@
|
|||
#include <winnt.h>
|
||||
|
||||
#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"
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ bool FirstSearch;
|
|||
|
||||
bool FirstShow;
|
||||
|
||||
char olds[Ps2MemSize::Base];
|
||||
char olds[Ps2MemSize::MainRam];
|
||||
|
||||
char tn[100];
|
||||
char to[100];
|
||||
|
|
|
@ -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);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue