diff --git a/Source/Core/Common/Src/CPUDetect.cpp b/Source/Core/Common/Src/CPUDetect.cpp index 751ef2bc54..552e4bb1a1 100644 --- a/Source/Core/Common/Src/CPUDetect.cpp +++ b/Source/Core/Common/Src/CPUDetect.cpp @@ -22,26 +22,27 @@ //#include #include +// fake cpuid for linux. todo: make a real one. EAX EBX ECX EDX is the right order. void __cpuid(int info[4], int x) {memset(info, 0, sizeof(info));} #endif - #include "Common.h" #include "CPUDetect.h" +#include "StringUtil.h" -// This code was adapted from an example in MSDN: -CPUInfoStruct cpu_info; +CPUInfo cpu_info; -void CPUInfoStruct::Detect() +void CPUInfo::Detect() { + memset(this, 0, sizeof(*this)); #ifdef _M_IX86 Mode64bit = false; #elif defined (_M_X64) Mode64bit = true; OS64bit = true; #endif - numCores = 1; + num_cores = 1; #ifdef _WIN32 #ifdef _M_IX86 @@ -50,197 +51,102 @@ void CPUInfoStruct::Detect() #endif #endif - // __cpuid with an InfoType argument of 0 returns the number of - // valid Ids in CPUInfo[0] and the CPU identification string in - // the other three array elements. The CPU identification string is - // not in linear order. The code below arranges the information - // in a human readable form. - __cpuid(CPUInfo, 0); - nIds = CPUInfo[0]; - memset(CPUString, 0, sizeof(CPUString)); - *((int*)CPUString) = CPUInfo[1]; - *((int*)(CPUString + 4)) = CPUInfo[3]; - *((int*)(CPUString + 8)) = CPUInfo[2]; - - // Assume that everything non-intel is AMD - if (memcmp(CPUString, "GenuineIntel", 12) == 0) + // Set obvious defaults, for extra safety + if (Mode64bit) { - isAMD = false; + bSSE = true; + bSSE2 = true; + bLongMode = true; } + + // Assume CPU supports the CPUID instruction. Those that don't can barely boot modern OS:es anyway. + int cpu_id[4]; + memset(cpu_string, 0, sizeof(cpu_string)); + + // Detect CPU's CPUID capabilities, and grab cpu string + __cpuid(cpu_id, 0x00000000); + u32 max_std_fn = cpu_id[0]; // EAX + *((int *)cpu_string) = cpu_id[1]; + *((int *)(cpu_string + 4)) = cpu_id[3]; + *((int *)(cpu_string + 8)) = cpu_id[2]; + __cpuid(cpu_id, 0x80000000); + u32 max_ex_fn = cpu_id[0]; + if (!strcmp(cpu_string, "GenuineIntel")) + vendor = VENDOR_INTEL; + else if (!strcmp(cpu_string, "AuthenticAMD")) + vendor = VENDOR_AMD; else - { - isAMD = true; - } + vendor = VENDOR_OTHER; - if (nIds >= 2) - { - // Get the information associated with each valid Id - __cpuid(CPUInfo, 1); - - nSteppingID = CPUInfo[0] & 0xf; - nModel = (CPUInfo[0] >> 4) & 0xf; - nFamily = (CPUInfo[0] >> 8) & 0xf; - nProcessorType = (CPUInfo[0] >> 12) & 0x3; - nExtendedmodel = (CPUInfo[0] >> 16) & 0xf; - nExtendedfamily = (CPUInfo[0] >> 20) & 0xff; - nBrandIndex = CPUInfo[1] & 0xff; - nCLFLUSHcachelinesize = ((CPUInfo[1] >> 8) & 0xff) * 8; - nAPICPhysicalID = (CPUInfo[1] >> 24) & 0xff; - bSSE3 = (CPUInfo[2] & 0x1) || false; - bSSSE3 = (CPUInfo[2] & 0x200) || false; - bMONITOR_MWAIT = (CPUInfo[2] & 0x8) || false; - bCPLQualifiedDebugStore = (CPUInfo[2] & 0x10) || false; - bThermalMonitor2 = (CPUInfo[2] & 0x100) || false; - nFeatureInfo = CPUInfo[3]; + // Set reasonable default brand string even if brand string not available. + strcpy(brand_string, cpu_string); - if (CPUInfo[2] & (1 << 23)) - { - bPOPCNT = true; - } - - if (CPUInfo[2] & (1 << 19)) - { - bSSE4_1 = true; - } - - if (CPUInfo[2] & (1 << 20)) - { - bSSE4_2 = true; + // Detect family and other misc stuff. + bool HTT = false; + int logical_cpu_count = 1; + if (max_std_fn >= 1) { + __cpuid(cpu_id, 0x00000001); + logical_cpu_count = (cpu_id[1] >> 16) & 0xFF; + if ((cpu_id[3] >> 28) & 1) { + // wtf, we get here on my core 2 + HTT = true; } + if ((cpu_id[3] >> 25) & 1) bSSE = true; + if ((cpu_id[3] >> 26) & 1) bSSE2 = true; + if (cpu_id[2] & 1) bSSE3 = true; + if ((cpu_id[2] >> 9) & 1) bSSSE3 = true; + if ((cpu_id[2] >> 19) & 1) bSSE4_1 = true; + if ((cpu_id[2] >> 20) & 1) bSSE4_2 = true; } - - if (bSSE3) - { - // Only SSE3 CPU-s support extended infotypes - // Calling __cpuid with 0x80000000 as the InfoType argument - // gets the number of valid extended IDs. - __cpuid(CPUInfo, 0x80000000); - nExIds = CPUInfo[0]; - memset(CPUBrandString, 0, sizeof(CPUBrandString)); - - // Get the information associated with each extended ID. - for (unsigned int i = 0x80000000; i <= nExIds; ++i) - { - __cpuid(CPUInfo, i); - - // Interpret CPU brand string and cache information. - if (i == 0x80000001) - { - // This block seems bugged. - nFeatureInfo2 = CPUInfo[1]; // ECX - bSSE5 = (nFeatureInfo2 & (1 << 11)) ? true : false; - bLZCNT = (nFeatureInfo2 & (1 << 5)) ? true : false; - bSSE4A = (nFeatureInfo2 & (1 << 6)) ? true : false; - bLAHFSAHF64 = (nFeatureInfo2 & (1 << 0)) ? true : false; - - CPU64bit = (CPUInfo[2] & (1 << 29)) ? true : false; - } - else if (i == 0x80000002) - { - memcpy(CPUBrandString, CPUInfo, sizeof(CPUInfo)); - } - else if (i == 0x80000003) - { - memcpy(CPUBrandString + 16, CPUInfo, sizeof(CPUInfo)); - } - else if (i == 0x80000004) - { - memcpy(CPUBrandString + 32, CPUInfo, sizeof(CPUInfo)); - } - else if (i == 0x80000006) - { - nCacheLineSize = CPUInfo[2] & 0xff; - nL2Associativity = (CPUInfo[2] >> 12) & 0xf; - nCacheSizeK = (CPUInfo[2] >> 16) & 0xffff; - } - else if (i == 0x80000008) - { - int numLSB = (CPUInfo[2] >> 12) & 0xF; - numCores = 1 << numLSB; - //int coresPerDie = CPUInfo[2] & 0xFF; - // numCores = coresPerDie; + if (max_std_fn >= 4) { + // Extract brand string + __cpuid(cpu_id, 0x80000002); + memcpy(brand_string, cpu_id, sizeof(cpu_id)); + __cpuid(cpu_id, 0x80000003); + memcpy(brand_string + 16, cpu_id, sizeof(cpu_id)); + __cpuid(cpu_id, 0x80000004); + memcpy(brand_string + 32, cpu_id, sizeof(cpu_id)); + } + if (max_ex_fn >= 0x80000001) { + // Check for more features. + __cpuid(cpu_id, 0x80000001); + bool cmp_legacy = false; + if (cpu_id[2] & 1) bLAHFSAHF64 = true; + if (cpu_id[2] & 2) cmp_legacy = true; //wtf is this? + if ((cpu_id[3] >> 29) & 1) bLongMode = true; + } + if (max_ex_fn >= 0x80000008) { + // Get number of cores. This is a bit complicated. Following AMD manual here. + __cpuid(cpu_id, 0x80000008); + int apic_id_core_id_size = (cpu_id[2] >> 12) & 0xF; + if (apic_id_core_id_size == 0) { + // Use what AMD calls the "legacy method" to determine # of cores. + if (HTT) { + num_cores = logical_cpu_count; + } else { + num_cores = 1; } + } else { + // Use AMD's new method. + num_cores = (cpu_id[2] & 0xFF) + 1; } - } - - // Display all the information in user-friendly format. - // printf_s("\n\nCPU String: %s\n", CPUString); - - if (nIds < 1) - { - bOldCPU = true; - } - - nIds = 1; - bx87FPUOnChip = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bVirtual_8086ModeEnhancement = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bDebuggingExtensions = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bPageSizeExtensions = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bTimeStampCounter = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bRDMSRandWRMSRSupport = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bPhysicalAddressExtensions = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bMachineCheckException = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bCMPXCHG8BInstruction = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bAPICOnChip = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bUnknown1 = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bSYSENTERandSYSEXIT = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bMemoryTypeRangeRegisters = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bPTEGlobalBit = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bMachineCheckArchitecture = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bConditionalMove_CompareInstruction = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bPageAttributeTable = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bPageSizeExtension = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bProcessorSerialNumber = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bCFLUSHExtension = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bUnknown2 = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bDebugStore = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bThermalMonitorandClockCtrl = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bMMXTechnology = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bFXSAVE_FXRSTOR = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bSSE = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bSSE2 = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bSelfSnoop = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bHyper_threadingTechnology = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bThermalMonitor = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bUnknown4 = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - bPendBrkEN = (nFeatureInfo & nIds) ? true : false; - nIds <<= 1; - - if (nExIds < 0x80000004) - { - strcpy(CPUBrandString, "(unknown)"); + } else { + // Wild guess + if (logical_cpu_count) + num_cores = logical_cpu_count; } } - +std::string CPUInfo::Summarize() +{ + std::string sum = StringFromFormat("%s : %i cores. ", cpu_string, num_cores); + if (bSSE) sum += "SSE"; + if (bSSE2) sum += ", SSE2"; + if (bSSE3) sum += ", SSE3"; + if (bSSSE3) sum += ", SSSE3"; + if (bSSE4_1) sum += ", SSE4.1"; + if (bSSE4_2) sum += ", SSE4.2"; + if (bLongMode) sum += ", 64-bit support"; + sum += " (wrong? report)"; + return sum; +} \ No newline at end of file diff --git a/Source/Core/Common/Src/CPUDetect.h b/Source/Core/Common/Src/CPUDetect.h index 389127261a..9dd7a46919 100644 --- a/Source/Core/Common/Src/CPUDetect.h +++ b/Source/Core/Common/Src/CPUDetect.h @@ -18,70 +18,25 @@ #ifndef _CPUDETECT_H #define _CPUDETECT_H -struct CPUInfoStruct +enum CPUVendor { - bool isAMD; + VENDOR_INTEL = 0, + VENDOR_AMD = 1, + VENDOR_OTHER = 2, +}; +struct CPUInfo +{ + CPUVendor vendor; + + char cpu_string[0x21]; + char brand_string[0x41]; bool OS64bit; bool CPU64bit; bool Mode64bit; - int numCores; - char CPUString[0x20]; - char CPUBrandString[0x40]; - int CPUInfo[4]; - int nSteppingID; - int nModel; - int nFamily; - int nProcessorType; - int nExtendedmodel; - int nExtendedfamily; - int nBrandIndex; - int nCLFLUSHcachelinesize; - int nAPICPhysicalID; - int nFeatureInfo; - int nFeatureInfo2; - int nCacheLineSize; - int nL2Associativity; - int nCacheSizeK; - int nRet; - unsigned int nIds, nExIds; - - bool bMONITOR_MWAIT; - bool bCPLQualifiedDebugStore; - bool bThermalMonitor2; - - bool bOldCPU; - bool bx87FPUOnChip; - bool bVirtual_8086ModeEnhancement; - bool bDebuggingExtensions; - bool bPageSizeExtensions; - bool bTimeStampCounter; - bool bRDMSRandWRMSRSupport; - bool bPhysicalAddressExtensions; - bool bMachineCheckException; - bool bCMPXCHG8BInstruction; - bool bAPICOnChip; - bool bUnknown1; - bool bSYSENTERandSYSEXIT; - bool bMemoryTypeRangeRegisters; - bool bPTEGlobalBit; - bool bMachineCheckArchitecture; - bool bConditionalMove_CompareInstruction; - bool bPageAttributeTable; - bool bPageSizeExtension; - bool bProcessorSerialNumber; - bool bCFLUSHExtension; - bool bUnknown2; - bool bDebugStore; - bool bThermalMonitorandClockCtrl; - bool bMMXTechnology; - bool bFXSAVE_FXRSTOR; - bool bSelfSnoop; - bool bHyper_threadingTechnology; - bool bThermalMonitor; - bool bUnknown4; - bool bPendBrkEN; + bool hyper_threaded; + int num_cores; bool bSSE; bool bSSE2; @@ -90,16 +45,17 @@ struct CPUInfoStruct bool bPOPCNT; bool bSSE4_1; bool bSSE4_2; - bool bSSE5; bool bLZCNT; bool bSSE4A; bool bLAHFSAHF64; + bool bLongMode; void Detect(); + std::string Summarize(); }; -extern CPUInfoStruct cpu_info; +extern CPUInfo cpu_info; inline void DetectCPU() {cpu_info.Detect();} diff --git a/Source/Core/Core/Src/Core.cpp b/Source/Core/Core/Src/Core.cpp index 8646260a82..f0106f5651 100644 --- a/Source/Core/Core/Src/Core.cpp +++ b/Source/Core/Core/Src/Core.cpp @@ -141,7 +141,7 @@ bool Init(const SCoreStartupParameter _CoreParameter) // all right ... here we go Host_SetWaitCursor(false); - DisplayMessage(cpu_info.CPUBrandString, 3000); + DisplayMessage("CPU: " + cpu_info.Summarize(), 8000); DisplayMessage(_CoreParameter.m_strFilename, 3000);