2009-07-03 00:49:40 +00:00
|
|
|
|
/* Cpudetection lib
|
2010-05-03 14:08:02 +00:00
|
|
|
|
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
2009-10-05 11:05:11 +00:00
|
|
|
|
*
|
2009-09-08 12:08:10 +00:00
|
|
|
|
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
|
|
|
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
|
|
|
|
* ation, either version 3 of the License, or (at your option) any later version.
|
2009-07-03 00:49:40 +00:00
|
|
|
|
*
|
2009-09-08 12:08:10 +00:00
|
|
|
|
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
|
|
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
|
|
|
* PURPOSE. See the GNU General Public License for more details.
|
2009-07-03 20:12:33 +00:00
|
|
|
|
*
|
2009-09-08 12:08:10 +00:00
|
|
|
|
* You should have received a copy of the GNU General Public License along with PCSX2.
|
|
|
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
2009-07-03 00:49:40 +00:00
|
|
|
|
*/
|
2009-10-05 11:05:11 +00:00
|
|
|
|
|
2009-07-03 00:49:40 +00:00
|
|
|
|
#include "PrecompiledHeader.h"
|
2009-11-16 13:54:32 +00:00
|
|
|
|
#include "cpudetect_internal.h"
|
2009-10-07 19:20:11 +00:00
|
|
|
|
#include "internal.h"
|
|
|
|
|
|
2009-07-03 00:49:40 +00:00
|
|
|
|
using namespace x86Emitter;
|
|
|
|
|
|
2010-06-01 03:33:51 +00:00
|
|
|
|
__aligned16 x86capabilities x86caps;
|
|
|
|
|
|
|
|
|
|
// Recompiled code buffer for SSE and MXCSR feature testing.
|
|
|
|
|
static __pagealigned u8 recSSE[__pagesize];
|
|
|
|
|
static __pagealigned u8 targetFXSAVE[512];
|
2009-07-03 00:49:40 +00:00
|
|
|
|
|
|
|
|
|
#ifdef __LINUX__
|
|
|
|
|
# include <sys/time.h>
|
|
|
|
|
# include <errno.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2009-11-16 14:08:53 +00:00
|
|
|
|
static const char* bool_to_char( bool testcond )
|
2009-07-03 00:49:40 +00:00
|
|
|
|
{
|
2009-11-16 13:54:32 +00:00
|
|
|
|
return testcond ? "true" : "false";
|
2009-07-03 00:49:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-06-01 03:33:51 +00:00
|
|
|
|
// Warning! We've had problems with the MXCSR detection code causing stack corruption in
|
|
|
|
|
// MSVC PGO builds. The problem was fixed when I moved the MXCSR code to this function, and
|
|
|
|
|
// moved the recSSE[] array to a global static (it was local to cpudetectInit). Commented
|
|
|
|
|
// here in case the nutty crash ever re-surfaces. >_<
|
|
|
|
|
void x86capabilities::SIMD_EstablishMXCSRmask()
|
|
|
|
|
{
|
|
|
|
|
if( !hasStreamingSIMDExtensions ) return;
|
|
|
|
|
|
|
|
|
|
MXCSR_Mask.bitmask = 0xFFBF; // MMX/SSE default
|
|
|
|
|
|
|
|
|
|
if( hasStreamingSIMD2Extensions )
|
|
|
|
|
{
|
|
|
|
|
// This is generally safe assumption, but FXSAVE is the "correct" way to
|
|
|
|
|
// detect MXCSR masking features of the cpu, so we use it's result below
|
|
|
|
|
// and override this.
|
|
|
|
|
|
|
|
|
|
MXCSR_Mask.bitmask = 0xFFFF; // SSE2 features added
|
|
|
|
|
}
|
2014-07-31 01:58:16 +00:00
|
|
|
|
#ifdef _M_X86_64
|
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
|
// Use the intrinsic that is provided with MSVC 2012
|
|
|
|
|
_fxsave(&targetFXSAVE);
|
|
|
|
|
#else
|
|
|
|
|
// GCC path is supported since GCC 4.6.x
|
|
|
|
|
__asm __volatile ("fxsave %0" : "+m" (targetFXSAVE));
|
|
|
|
|
#endif
|
|
|
|
|
#else
|
|
|
|
|
// Grab the MXCSR mask the x86_32 way.
|
|
|
|
|
//
|
2010-06-01 03:33:51 +00:00
|
|
|
|
// 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.
|
|
|
|
|
|
2014-07-31 01:58:16 +00:00
|
|
|
|
if( !CanEmitShit() ) return;
|
|
|
|
|
|
2010-10-22 16:23:52 +00:00
|
|
|
|
HostSys::MemProtectStatic( recSSE, PageAccess_ReadWrite() );
|
2010-06-01 03:33:51 +00:00
|
|
|
|
|
|
|
|
|
xSetPtr( recSSE );
|
2010-06-04 22:27:06 +00:00
|
|
|
|
xFXSAVE( ptr[&targetFXSAVE] );
|
2010-06-01 03:33:51 +00:00
|
|
|
|
xRET();
|
|
|
|
|
|
2010-10-22 16:23:52 +00:00
|
|
|
|
HostSys::MemProtectStatic( recSSE, PageAccess_ExecOnly() );
|
2010-06-01 03:33:51 +00:00
|
|
|
|
|
|
|
|
|
CallAddress( recSSE );
|
2014-07-31 01:58:16 +00:00
|
|
|
|
#endif
|
2010-06-01 03:33:51 +00:00
|
|
|
|
|
|
|
|
|
u32 result = (u32&)targetFXSAVE[28]; // bytes 28->32 are the MXCSR_Mask.
|
|
|
|
|
if( result != 0 )
|
|
|
|
|
MXCSR_Mask.bitmask = result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Counts the number of cpu cycles executed over the requested number of PerformanceCounter
|
|
|
|
|
// ticks. Returns that exact count.
|
|
|
|
|
// For best results you should pick a period of time long enough to get a reading that won't
|
|
|
|
|
// be prone to rounding error; but short enough that it'll be highly unlikely to be interrupted
|
|
|
|
|
// by the operating system task switches.
|
|
|
|
|
s64 x86capabilities::_CPUSpeedHz( u64 time ) const
|
2009-07-03 00:49:40 +00:00
|
|
|
|
{
|
|
|
|
|
u64 timeStart, timeStop;
|
2009-12-20 01:28:23 +00:00
|
|
|
|
s64 startCycle, endCycle;
|
2009-07-03 00:49:40 +00:00
|
|
|
|
|
2010-06-01 03:33:51 +00:00
|
|
|
|
if( ! hasTimeStampCounter )
|
2009-11-16 13:54:32 +00:00
|
|
|
|
return 0;
|
2009-07-03 00:49:40 +00:00
|
|
|
|
|
2009-11-16 13:54:32 +00:00
|
|
|
|
SingleCoreAffinity affinity_lock;
|
2009-07-03 00:49:40 +00:00
|
|
|
|
|
|
|
|
|
// Align the cpu execution to a cpuTick boundary.
|
|
|
|
|
|
2010-06-01 03:33:51 +00:00
|
|
|
|
do {
|
|
|
|
|
timeStart = GetCPUTicks();
|
2014-02-23 16:00:55 +00:00
|
|
|
|
#ifdef __LINUX__
|
2014-02-23 09:57:01 +00:00
|
|
|
|
startCycle = __pcsx2__rdtsc();
|
2014-02-23 16:00:55 +00:00
|
|
|
|
#else
|
|
|
|
|
startCycle = __rdtsc();
|
|
|
|
|
#endif
|
2010-06-01 03:33:51 +00:00
|
|
|
|
} while( GetCPUTicks() == timeStart );
|
2009-07-03 00:49:40 +00:00
|
|
|
|
|
2010-06-01 03:33:51 +00:00
|
|
|
|
do {
|
2009-07-03 00:49:40 +00:00
|
|
|
|
timeStop = GetCPUTicks();
|
2014-02-23 16:00:55 +00:00
|
|
|
|
#ifdef __LINUX__
|
2014-02-23 09:57:01 +00:00
|
|
|
|
endCycle = __pcsx2__rdtsc();
|
2014-02-23 16:00:55 +00:00
|
|
|
|
#else
|
|
|
|
|
endCycle = __rdtsc();
|
|
|
|
|
#endif
|
2010-06-01 03:33:51 +00:00
|
|
|
|
} while( ( timeStop - timeStart ) < time );
|
2009-07-03 00:49:40 +00:00
|
|
|
|
|
2009-12-20 01:28:23 +00:00
|
|
|
|
s64 cycleCount = endCycle - startCycle;
|
|
|
|
|
s64 timeCount = timeStop - timeStart;
|
|
|
|
|
s64 overrun = timeCount - time;
|
|
|
|
|
if( !overrun ) return cycleCount;
|
|
|
|
|
|
|
|
|
|
// interference could cause us to overshoot the target time, compensate:
|
2010-04-25 00:31:27 +00:00
|
|
|
|
|
2009-12-20 01:28:23 +00:00
|
|
|
|
double cyclesPerTick = (double)cycleCount / (double)timeCount;
|
|
|
|
|
double newCycleCount = (double)cycleCount - (cyclesPerTick * overrun);
|
|
|
|
|
|
|
|
|
|
return (s64)newCycleCount;
|
2009-07-03 00:49:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-06-01 03:33:51 +00:00
|
|
|
|
wxString x86capabilities::GetTypeName() const
|
|
|
|
|
{
|
|
|
|
|
switch( TypeID )
|
|
|
|
|
{
|
|
|
|
|
case 0: return L"Standard OEM";
|
|
|
|
|
case 1: return L"Overdrive";
|
|
|
|
|
case 2: return L"Dual";
|
|
|
|
|
case 3: return L"Reserved";
|
|
|
|
|
default: return L"Unknown";
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-12-08 02:38:13 +00:00
|
|
|
|
|
2010-06-01 03:33:51 +00:00
|
|
|
|
void x86capabilities::CountCores()
|
2009-12-08 02:38:13 +00:00
|
|
|
|
{
|
2010-06-01 03:33:51 +00:00
|
|
|
|
Identify();
|
2009-12-08 02:38:13 +00:00
|
|
|
|
|
2010-06-01 03:33:51 +00:00
|
|
|
|
s32 regs[ 4 ];
|
|
|
|
|
u32 cmds;
|
2009-12-08 02:38:13 +00:00
|
|
|
|
|
2010-06-01 03:33:51 +00:00
|
|
|
|
__cpuid( regs, 0x80000000 );
|
|
|
|
|
cmds = regs[ 0 ];
|
2009-12-24 22:22:34 +00:00
|
|
|
|
|
2010-06-01 03:33:51 +00:00
|
|
|
|
// detect multicore for AMD cpu
|
2009-12-08 02:38:13 +00:00
|
|
|
|
|
2010-06-01 03:33:51 +00:00
|
|
|
|
if ((cmds >= 0x80000008) && (VendorID == x86Vendor_AMD) )
|
|
|
|
|
{
|
2010-06-08 12:09:28 +00:00
|
|
|
|
// AMD note: they don't support hyperthreading, but they like to flag this true
|
|
|
|
|
// anyway. Let's force-unflag it until we come up with a better solution.
|
|
|
|
|
// (note: seems to affect some Phenom II's only? -- Athlon X2's and PhenomI's do
|
|
|
|
|
// not seem to do this) --air
|
|
|
|
|
hasMultiThreading = 0;
|
2010-06-01 03:33:51 +00:00
|
|
|
|
}
|
2009-12-08 02:38:13 +00:00
|
|
|
|
|
2010-06-01 03:33:51 +00:00
|
|
|
|
// This will assign values into LogicalCores and PhysicalCores
|
|
|
|
|
CountLogicalCores();
|
2009-12-08 02:38:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-06-01 03:33:51 +00:00
|
|
|
|
static const char* tbl_x86vendors[] =
|
2009-07-03 00:49:40 +00:00
|
|
|
|
{
|
2010-06-01 03:33:51 +00:00
|
|
|
|
"GenuineIntel",
|
|
|
|
|
"AuthenticAMD"
|
|
|
|
|
"Unknown ",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Performs all _cpuid-related activity. This fills *most* of the x86caps structure, except for
|
|
|
|
|
// the cpuSpeed and the mxcsr masks. Those must be completed manually.
|
|
|
|
|
void x86capabilities::Identify()
|
|
|
|
|
{
|
|
|
|
|
if( isIdentified ) return;
|
|
|
|
|
isIdentified = true;
|
|
|
|
|
|
2009-12-08 02:38:13 +00:00
|
|
|
|
s32 regs[ 4 ];
|
2009-12-07 22:43:16 +00:00
|
|
|
|
u32 cmds;
|
2010-06-01 03:33:51 +00:00
|
|
|
|
|
2009-12-07 22:43:16 +00:00
|
|
|
|
//AMD 64 STUFF
|
|
|
|
|
u32 x86_64_8BITBRANDID;
|
|
|
|
|
u32 x86_64_12BITBRANDID;
|
|
|
|
|
|
2010-06-01 03:33:51 +00:00
|
|
|
|
memzero( VendorName );
|
2009-12-08 02:38:13 +00:00
|
|
|
|
__cpuid( regs, 0 );
|
2009-12-07 22:43:16 +00:00
|
|
|
|
|
|
|
|
|
cmds = regs[ 0 ];
|
2010-06-01 03:33:51 +00:00
|
|
|
|
((u32*)VendorName)[ 0 ] = regs[ 1 ];
|
|
|
|
|
((u32*)VendorName)[ 1 ] = regs[ 3 ];
|
|
|
|
|
((u32*)VendorName)[ 2 ] = regs[ 2 ];
|
2009-12-07 22:43:16 +00:00
|
|
|
|
|
2010-06-01 03:33:51 +00:00
|
|
|
|
// Determine Vendor Specifics!
|
|
|
|
|
// It's really not recommended that we base much (if anything) on CPU vendor names,
|
|
|
|
|
// however it's currently necessary in order to gain a (pseudo)reliable count of cores
|
|
|
|
|
// and threads used by the CPU (AMD and Intel can't agree on how to make this info available).
|
|
|
|
|
|
|
|
|
|
int& vid = (int&)VendorID;
|
|
|
|
|
for( vid=0; vid<x86Vendor_Unknown; ++vid )
|
|
|
|
|
{
|
|
|
|
|
if( memcmp( VendorName, tbl_x86vendors[vid], 12 ) == 0 ) break;
|
|
|
|
|
}
|
2009-12-07 22:43:16 +00:00
|
|
|
|
|
|
|
|
|
if ( cmds >= 0x00000001 )
|
|
|
|
|
{
|
2009-12-08 02:38:13 +00:00
|
|
|
|
__cpuid( regs, 0x00000001 );
|
2009-12-07 22:43:16 +00:00
|
|
|
|
|
2010-06-01 03:33:51 +00:00
|
|
|
|
StepID = regs[ 0 ] & 0xf;
|
|
|
|
|
Model = (regs[ 0 ] >> 4) & 0xf;
|
|
|
|
|
FamilyID = (regs[ 0 ] >> 8) & 0xf;
|
|
|
|
|
TypeID = (regs[ 0 ] >> 12) & 0x3;
|
2009-12-07 22:43:16 +00:00
|
|
|
|
x86_64_8BITBRANDID = regs[ 1 ] & 0xff;
|
2010-06-01 03:33:51 +00:00
|
|
|
|
Flags = regs[ 3 ];
|
|
|
|
|
Flags2 = regs[ 2 ];
|
2009-12-07 22:43:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-12-08 02:38:13 +00:00
|
|
|
|
__cpuid( regs, 0x80000000 );
|
2009-12-07 22:43:16 +00:00
|
|
|
|
cmds = regs[ 0 ];
|
|
|
|
|
if ( cmds >= 0x80000001 )
|
|
|
|
|
{
|
2009-12-08 02:38:13 +00:00
|
|
|
|
__cpuid( regs, 0x80000001 );
|
2009-12-07 22:43:16 +00:00
|
|
|
|
|
|
|
|
|
x86_64_12BITBRANDID = regs[1] & 0xfff;
|
2010-06-01 03:33:51 +00:00
|
|
|
|
EFlags2 = regs[ 2 ];
|
|
|
|
|
EFlags = regs[ 3 ];
|
2009-12-07 22:43:16 +00:00
|
|
|
|
}
|
2010-04-25 00:31:27 +00:00
|
|
|
|
|
2010-06-01 03:33:51 +00:00
|
|
|
|
memzero( FamilyName );
|
|
|
|
|
__cpuid( (int*)FamilyName, 0x80000002);
|
|
|
|
|
__cpuid( (int*)(FamilyName+16), 0x80000003);
|
|
|
|
|
__cpuid( (int*)(FamilyName+32), 0x80000004);
|
|
|
|
|
|
|
|
|
|
hasFloatingPointUnit = ( Flags >> 0 ) & 1;
|
|
|
|
|
hasVirtual8086ModeEnhancements = ( Flags >> 1 ) & 1;
|
|
|
|
|
hasDebuggingExtensions = ( Flags >> 2 ) & 1;
|
|
|
|
|
hasPageSizeExtensions = ( Flags >> 3 ) & 1;
|
|
|
|
|
hasTimeStampCounter = ( Flags >> 4 ) & 1;
|
|
|
|
|
hasModelSpecificRegisters = ( Flags >> 5 ) & 1;
|
|
|
|
|
hasPhysicalAddressExtension = ( Flags >> 6 ) & 1;
|
|
|
|
|
hasMachineCheckArchitecture = ( Flags >> 7 ) & 1;
|
|
|
|
|
hasCOMPXCHG8BInstruction = ( Flags >> 8 ) & 1;
|
|
|
|
|
hasAdvancedProgrammableInterruptController = ( Flags >> 9 ) & 1;
|
|
|
|
|
hasSEPFastSystemCall = ( Flags >> 11 ) & 1;
|
|
|
|
|
hasMemoryTypeRangeRegisters = ( Flags >> 12 ) & 1;
|
|
|
|
|
hasPTEGlobalFlag = ( Flags >> 13 ) & 1;
|
|
|
|
|
hasMachineCheckArchitecture = ( Flags >> 14 ) & 1;
|
|
|
|
|
hasConditionalMoveAndCompareInstructions = ( Flags >> 15 ) & 1;
|
|
|
|
|
hasFGPageAttributeTable = ( Flags >> 16 ) & 1;
|
|
|
|
|
has36bitPageSizeExtension = ( Flags >> 17 ) & 1;
|
|
|
|
|
hasProcessorSerialNumber = ( Flags >> 18 ) & 1;
|
|
|
|
|
hasCFLUSHInstruction = ( Flags >> 19 ) & 1;
|
|
|
|
|
hasDebugStore = ( Flags >> 21 ) & 1;
|
|
|
|
|
hasACPIThermalMonitorAndClockControl = ( Flags >> 22 ) & 1;
|
|
|
|
|
hasMultimediaExtensions = ( Flags >> 23 ) & 1; //mmx
|
|
|
|
|
hasFastStreamingSIMDExtensionsSaveRestore = ( Flags >> 24 ) & 1;
|
|
|
|
|
hasStreamingSIMDExtensions = ( Flags >> 25 ) & 1; //sse
|
|
|
|
|
hasStreamingSIMD2Extensions = ( Flags >> 26 ) & 1; //sse2
|
|
|
|
|
hasSelfSnoop = ( Flags >> 27 ) & 1;
|
|
|
|
|
hasMultiThreading = ( Flags >> 28 ) & 1;
|
|
|
|
|
hasThermalMonitor = ( Flags >> 29 ) & 1;
|
|
|
|
|
hasIntel64BitArchitecture = ( Flags >> 30 ) & 1;
|
|
|
|
|
|
|
|
|
|
// -------------------------------------------------
|
|
|
|
|
// --> SSE3 / SSSE3 / SSE4.1 / SSE 4.2 detection <--
|
|
|
|
|
// -------------------------------------------------
|
2009-12-07 22:43:16 +00:00
|
|
|
|
|
2010-06-01 03:33:51 +00:00
|
|
|
|
hasStreamingSIMD3Extensions = ( Flags2 >> 0 ) & 1; //sse3
|
|
|
|
|
hasSupplementalStreamingSIMD3Extensions = ( Flags2 >> 9 ) & 1; //ssse3
|
|
|
|
|
hasStreamingSIMD4Extensions = ( Flags2 >> 19 ) & 1; //sse4.1
|
|
|
|
|
hasStreamingSIMD4Extensions2 = ( Flags2 >> 20 ) & 1; //sse4.2
|
2011-02-12 21:45:16 +00:00
|
|
|
|
|
|
|
|
|
if((Flags2 >> 27) & 1) // OSXSAVE
|
|
|
|
|
{
|
|
|
|
|
if((__xgetbv(0) & 6) == 6) // XFEATURE_ENABLED_MASK[2:1] = <20>11b<31> (XMM state and YMM state are enabled by OS).
|
|
|
|
|
{
|
|
|
|
|
hasAVX = ( Flags2 >> 28 ) & 1; //avx
|
|
|
|
|
hasFMA = ( Flags2 >> 12 ) & 1; //fma
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-07-03 20:12:33 +00:00
|
|
|
|
|
2010-06-01 03:33:51 +00:00
|
|
|
|
// Ones only for AMDs:
|
|
|
|
|
hasMultimediaExtensionsExt = ( EFlags >> 22 ) & 1; //mmx2
|
|
|
|
|
hasAMD64BitArchitecture = ( EFlags >> 29 ) & 1; //64bit cpu
|
|
|
|
|
has3DNOWInstructionExtensionsExt = ( EFlags >> 30 ) & 1; //3dnow+
|
|
|
|
|
has3DNOWInstructionExtensions = ( EFlags >> 31 ) & 1; //3dnow
|
|
|
|
|
hasStreamingSIMD4ExtensionsA = ( EFlags2 >> 6 ) & 1; //INSERTQ / EXTRQ / MOVNT
|
2009-11-02 07:00:59 +00:00
|
|
|
|
|
2010-06-01 03:33:51 +00:00
|
|
|
|
isIdentified = true;
|
|
|
|
|
}
|
2009-07-03 00:49:40 +00:00
|
|
|
|
|
2010-06-01 03:33:51 +00:00
|
|
|
|
u32 x86capabilities::CalculateMHz() const
|
|
|
|
|
{
|
2009-07-03 00:49:40 +00:00
|
|
|
|
InitCPUTicks();
|
|
|
|
|
u64 span = GetTickFrequency();
|
|
|
|
|
|
|
|
|
|
if( (span % 1000) < 400 ) // helps minimize rounding errors
|
2010-06-01 03:33:51 +00:00
|
|
|
|
return (u32)( _CPUSpeedHz( span / 1000 ) / 1000 );
|
2009-07-03 00:49:40 +00:00
|
|
|
|
else
|
2010-06-01 03:33:51 +00:00
|
|
|
|
return (u32)( _CPUSpeedHz( span / 500 ) / 2000 );
|
|
|
|
|
}
|
2009-07-03 00:49:40 +00:00
|
|
|
|
|
2010-06-01 03:33:51 +00:00
|
|
|
|
// Special extended version of SIMD testning, which uses exceptions to double-check the presence
|
|
|
|
|
// of SSE2/3/4 instructions. Useful if you don't trust cpuid (at least one report of an invalid
|
|
|
|
|
// cpuid has been reported on a Core2 Quad -- the user fixed it by clearing his CMOS).
|
|
|
|
|
//
|
|
|
|
|
// Results of CPU
|
|
|
|
|
void x86capabilities::SIMD_ExceptionTest()
|
|
|
|
|
{
|
2010-10-22 16:23:52 +00:00
|
|
|
|
HostSys::MemProtectStatic( recSSE, PageAccess_ReadWrite() );
|
2010-04-25 00:31:27 +00:00
|
|
|
|
|
2009-07-03 00:49:40 +00:00
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
2009-11-16 13:54:32 +00:00
|
|
|
|
// SIMD Instruction Support Detection (Second Pass)
|
2009-07-03 00:49:40 +00:00
|
|
|
|
//
|
|
|
|
|
|
2009-11-16 13:54:32 +00:00
|
|
|
|
if( CanTestInstructionSets() )
|
2009-07-03 00:49:40 +00:00
|
|
|
|
{
|
|
|
|
|
xSetPtr( recSSE );
|
2009-12-07 22:43:16 +00:00
|
|
|
|
xMOVDQU( ptr[ecx], xmm1 );
|
2009-07-03 00:49:40 +00:00
|
|
|
|
xMOVSLDUP( xmm1, xmm0 );
|
2009-12-07 22:43:16 +00:00
|
|
|
|
xMOVDQU( xmm1, ptr[ecx] );
|
2009-07-03 00:49:40 +00:00
|
|
|
|
xRET();
|
|
|
|
|
|
|
|
|
|
u8* funcSSSE3 = xGetPtr();
|
2009-12-07 22:43:16 +00:00
|
|
|
|
xMOVDQU( ptr[ecx], xmm1 );
|
|
|
|
|
xPABS.W( xmm1, xmm0 );
|
|
|
|
|
xMOVDQU( xmm1, ptr[ecx] );
|
2009-07-03 00:49:40 +00:00
|
|
|
|
xRET();
|
|
|
|
|
|
|
|
|
|
u8* funcSSE41 = xGetPtr();
|
2009-12-07 22:43:16 +00:00
|
|
|
|
xMOVDQU( ptr[ecx], xmm1 );
|
2009-07-03 00:49:40 +00:00
|
|
|
|
xBLEND.VPD( xmm1, xmm0 );
|
2009-12-07 22:43:16 +00:00
|
|
|
|
xMOVDQU( xmm1, ptr[ecx] );
|
2009-07-03 00:49:40 +00:00
|
|
|
|
xRET();
|
2009-07-03 20:12:33 +00:00
|
|
|
|
|
2010-10-22 16:23:52 +00:00
|
|
|
|
HostSys::MemProtectStatic( recSSE, PageAccess_ExecOnly() );
|
2010-06-01 03:33:51 +00:00
|
|
|
|
|
2009-07-03 00:49:40 +00:00
|
|
|
|
bool sse3_result = _test_instruction( recSSE ); // sse3
|
|
|
|
|
bool ssse3_result = _test_instruction( funcSSSE3 );
|
|
|
|
|
bool sse41_result = _test_instruction( funcSSE41 );
|
|
|
|
|
|
|
|
|
|
// Test for and log any irregularities here.
|
|
|
|
|
// We take the instruction test result over cpuid since (in theory) it should be a
|
|
|
|
|
// more reliable gauge of the cpu's actual ability. But since a difference in bit
|
|
|
|
|
// and actual ability may represent a cmos/bios problem, we report it to the user.
|
|
|
|
|
|
2010-06-01 03:33:51 +00:00
|
|
|
|
if( sse3_result != !!hasStreamingSIMD3Extensions )
|
2009-07-03 00:49:40 +00:00
|
|
|
|
{
|
2009-10-29 13:32:40 +00:00
|
|
|
|
Console.Warning( "SSE3 Detection Inconsistency: cpuid=%s, test_result=%s",
|
2010-06-01 03:33:51 +00:00
|
|
|
|
bool_to_char( !!hasStreamingSIMD3Extensions ), bool_to_char( sse3_result ) );
|
2009-07-03 20:12:33 +00:00
|
|
|
|
|
2010-06-01 03:33:51 +00:00
|
|
|
|
hasStreamingSIMD3Extensions = sse3_result;
|
2009-07-03 00:49:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-06-01 03:33:51 +00:00
|
|
|
|
if( ssse3_result != !!hasSupplementalStreamingSIMD3Extensions )
|
2009-07-03 00:49:40 +00:00
|
|
|
|
{
|
2009-10-29 13:32:40 +00:00
|
|
|
|
Console.Warning( "SSSE3 Detection Inconsistency: cpuid=%s, test_result=%s",
|
2010-06-01 03:33:51 +00:00
|
|
|
|
bool_to_char( !!hasSupplementalStreamingSIMD3Extensions ), bool_to_char( ssse3_result ) );
|
2009-07-03 00:49:40 +00:00
|
|
|
|
|
2010-06-01 03:33:51 +00:00
|
|
|
|
hasSupplementalStreamingSIMD3Extensions = ssse3_result;
|
2009-07-03 00:49:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-06-01 03:33:51 +00:00
|
|
|
|
if( sse41_result != !!hasStreamingSIMD4Extensions )
|
2009-07-03 00:49:40 +00:00
|
|
|
|
{
|
2009-10-29 13:32:40 +00:00
|
|
|
|
Console.Warning( "SSE4 Detection Inconsistency: cpuid=%s, test_result=%s",
|
2010-06-01 03:33:51 +00:00
|
|
|
|
bool_to_char( !!hasStreamingSIMD4Extensions ), bool_to_char( sse41_result ) );
|
2009-07-03 00:49:40 +00:00
|
|
|
|
|
2010-06-01 03:33:51 +00:00
|
|
|
|
hasStreamingSIMD4Extensions = sse41_result;
|
2009-07-03 00:49:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
2009-11-02 16:26:35 +00:00
|
|
|
|
|
2010-06-01 03:33:51 +00:00
|
|
|
|
SIMD_EstablishMXCSRmask();
|
2009-07-03 00:49:40 +00:00
|
|
|
|
}
|
|
|
|
|
|