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:
arcum42 2010-11-23 03:11:08 +00:00
parent 21d90150ab
commit 5e73b1ca7e
130 changed files with 7713 additions and 5855 deletions

View File

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

View File

@ -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!
// ===========================================================================================

View File

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

View File

@ -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 );
}
}

View File

@ -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) );
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 ));
}
}

View File

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

View File

@ -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 );
}
}

View File

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

View File

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

View File

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

View File

@ -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() );
}
}

View File

@ -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();
}

View File

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

View File

@ -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();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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,
};

View File

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

View File

@ -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();

View File

@ -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 ) {}

View File

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

View File

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

View File

@ -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() );
}

View File

@ -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();

View File

@ -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)
};

View File

@ -374,6 +374,7 @@ void Pcsx2Config::LoadSave( IniInterface& ini )
IniBitBool( ConsoleToStdio );
IniBitBool( HostFs );
IniBitBool( BackupSavestate );
IniBitBool( McdEnableEjection );
IniBitBool( MultitapPort0_Enabled );
IniBitBool( MultitapPort1_Enabled );

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 );
}

View File

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

View File

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

68
pcsx2/System/RecTypes.h Normal file
View File

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

View File

@ -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();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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();
}

View File

@ -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();

View File

@ -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(); }

View File

@ -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() );
}
// ------------------------------------------------------------------------------------------

View File

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

View File

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

View File

@ -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();
}

View File

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

View File

@ -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();
}

View File

@ -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 );
}

View File

@ -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]);

View File

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

View File

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

View File

@ -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()
{
}

View File

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

View File

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

View File

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

View File

@ -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() );

View File

@ -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);
}
}

View File

@ -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];
}

View File

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

View File

@ -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();
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -59,7 +59,7 @@ bool FirstSearch;
bool FirstShow;
char olds[Ps2MemSize::Base];
char olds[Ps2MemSize::MainRam];
char tn[100];
char to[100];

View File

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