📄 cpu_info.cpp
字号:
QueryPerformanceFrequency (&liCountsPerSecond);
dDifference = (((double) liEnd.QuadPart - (double) liStart.QuadPart) / (double) liCountsPerSecond.QuadPart);
// Calculate the clock speed.
if (ChipID.Family == 3) {
// 80386 processors.... Loop time is 115 cycles!
dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 115) / dDifference) / 1048576);
} else if (ChipID.Family == 4) {
// 80486 processors.... Loop time is 47 cycles!
dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 47) / dDifference) / 1048576);
} else if (ChipID.Family == 5) {
// Pentium processors.... Loop time is 43 cycles!
dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 43) / dDifference) / 1048576);
}
// Save the clock speed.
Features.CPUSpeed = (int) dFrequency;
return true;
}
bool __cdecl CPUInfo::RetrieveCPUExtendedLevelSupport (int CPULevelToCheck)
{
int MaxCPUExtendedLevel = 0;
// The extended CPUID is supported by various vendors starting with the following CPU models:
//
// Manufacturer & Chip Name | Family Model Revision
//
// AMD K6, K6-2 | 5 6 x
// Cyrix GXm, Cyrix III "Joshua" | 5 4 x
// IDT C6-2 | 5 8 x
// VIA Cyrix III | 6 5 x
// Transmeta Crusoe | 5 x x
// Intel Pentium 4 | f x x
//
// We check to see if a supported processor is present...
if (ChipManufacturer == AMD) {
if (ChipID.Family < 5) return false;
if ((ChipID.Family == 5) && (ChipID.Model < 6)) return false;
} else if (ChipManufacturer == Cyrix) {
if (ChipID.Family < 5) return false;
if ((ChipID.Family == 5) && (ChipID.Model < 4)) return false;
if ((ChipID.Family == 6) && (ChipID.Model < 5)) return false;
} else if (ChipManufacturer == IDT) {
if (ChipID.Family < 5) return false;
if ((ChipID.Family == 5) && (ChipID.Model < 8)) return false;
} else if (ChipManufacturer == Transmeta) {
if (ChipID.Family < 5) return false;
} else if (ChipManufacturer == Intel) {
if (ChipID.Family < 0xf) return false;
}
// Use assembly to detect CPUID information...
__try {
_asm {
#ifdef CPUID_AWARE_COMPILER
; we must push/pop the registers <<CPUID>> writes to, as the
; optimiser doesn't know about <<CPUID>>, and so doesn't expect
; these registers to change.
push eax
push ebx
push ecx
push edx
#endif
; <<CPUID>>
; eax = 0x80000000 --> eax: maximum supported extended level
mov eax,0x80000000
CPUID_INSTRUCTION
mov MaxCPUExtendedLevel, eax
#ifdef CPUID_AWARE_COMPILER
pop edx
pop ecx
pop ebx
pop eax
#endif
}
}
// A generic catch-all just to be sure...
__except (1) {
return false;
}
// Now we have to check the level wanted vs level returned...
int nLevelWanted = (CPULevelToCheck & 0x7FFFFFFF);
int nLevelReturn = (MaxCPUExtendedLevel & 0x7FFFFFFF);
// Check to see if the level provided is supported...
if (nLevelWanted > nLevelReturn) return false;
return true;
}
bool __cdecl CPUInfo::RetrieveExtendedCPUFeatures ()
{
int CPUExtendedFeatures = 0;
// Check that we are not using an Intel processor as it does not support this.
if (ChipManufacturer == Intel) return false;
// Check to see if what we are about to do is supported...
if (!RetrieveCPUExtendedLevelSupport (0x80000001)) return false;
// Use assembly to detect CPUID information...
__try {
_asm {
#ifdef CPUID_AWARE_COMPILER
; we must push/pop the registers <<CPUID>> writes to, as the
; optimiser doesn't know about <<CPUID>>, and so doesn't expect
; these registers to change.
push eax
push ebx
push ecx
push edx
#endif
; <<CPUID>>
; eax = 0x80000001 --> eax: CPU ID - bits 31..16 - unused, bits 15..12 - type, bits 11..8 - family, bits 7..4 - model, bits 3..0 - mask revision
; ebx: 31..24 - default APIC ID, 23..16 - logical processsor ID, 15..8 - CFLUSH chunk size , 7..0 - brand ID
; edx: CPU feature flags
mov eax,0x80000001
CPUID_INSTRUCTION
mov CPUExtendedFeatures, edx
#ifdef CPUID_AWARE_COMPILER
pop edx
pop ecx
pop ebx
pop eax
#endif
}
}
// A generic catch-all just to be sure...
__except (1) {
return false;
}
// Retrieve the extended features of CPU present.
Features.ExtendedFeatures.Has3DNow = ((CPUExtendedFeatures & 0x80000000) != 0); // 3DNow Present --> Bit 31.
Features.ExtendedFeatures.Has3DNowPlus = ((CPUExtendedFeatures & 0x40000000) != 0); // 3DNow+ Present -- > Bit 30.
Features.ExtendedFeatures.HasSSEMMX = ((CPUExtendedFeatures & 0x00400000) != 0); // SSE MMX Present --> Bit 22.
Features.ExtendedFeatures.SupportsMP = ((CPUExtendedFeatures & 0x00080000) != 0); // MP Capable -- > Bit 19.
// Retrieve AMD specific extended features.
if (ChipManufacturer == AMD) {
Features.ExtendedFeatures.HasMMXPlus = ((CPUExtendedFeatures & 0x00400000) != 0); // AMD specific: MMX-SSE --> Bit 22
}
// Retrieve Cyrix specific extended features.
if (ChipManufacturer == Cyrix) {
Features.ExtendedFeatures.HasMMXPlus = ((CPUExtendedFeatures & 0x01000000) != 0); // Cyrix specific: Extended MMX --> Bit 24
}
return true;
}
bool __cdecl CPUInfo::RetrieveProcessorSerialNumber ()
{
int SerialNumber[3];
// Check to see if the processor supports the processor serial number.
if (!Features.HasSerial) return false;
// Use assembly to detect CPUID information...
__try {
_asm {
#ifdef CPUID_AWARE_COMPILER
; we must push/pop the registers <<CPUID>> writes to, as the
; optimiser doesn't know about <<CPUID>>, and so doesn't expect
; these registers to change.
push eax
push ebx
push ecx
push edx
#endif
; <<CPUID>>
; eax = 3 --> ebx: top 32 bits are the processor signature bits --> NB: Transmeta only ?!?
; ecx: middle 32 bits are the processor signature bits
; edx: bottom 32 bits are the processor signature bits
mov eax, 3
CPUID_INSTRUCTION
mov SerialNumber[0 * TYPE int], ebx
mov SerialNumber[1 * TYPE int], ecx
mov SerialNumber[2 * TYPE int], edx
#ifdef CPUID_AWARE_COMPILER
pop edx
pop ecx
pop ebx
pop eax
#endif
}
}
// A generic catch-all just to be sure...
__except (1) {
return false;
}
// Process the returned information.
sprintf (ChipID.SerialNumber, "%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x",
((SerialNumber[0] & 0xff000000) >> 24),
((SerialNumber[0] & 0x00ff0000) >> 16),
((SerialNumber[0] & 0x0000ff00) >> 8),
((SerialNumber[0] & 0x000000ff) >> 0),
((SerialNumber[1] & 0xff000000) >> 24),
((SerialNumber[1] & 0x00ff0000) >> 16),
((SerialNumber[1] & 0x0000ff00) >> 8),
((SerialNumber[1] & 0x000000ff) >> 0),
((SerialNumber[2] & 0xff000000) >> 24),
((SerialNumber[2] & 0x00ff0000) >> 16),
((SerialNumber[2] & 0x0000ff00) >> 8),
((SerialNumber[2] & 0x000000ff) >> 0));
return true;
}
bool __cdecl CPUInfo::RetrieveCPUPowerManagement ()
{
int CPUPowerManagement = 0;
// Check to see if what we are about to do is supported...
if (!RetrieveCPUExtendedLevelSupport (0x80000007)) {
Features.ExtendedFeatures.PowerManagement.HasFrequencyID = false;
Features.ExtendedFeatures.PowerManagement.HasVoltageID = false;
Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode = false;
return false;
}
// Use assembly to detect CPUID information...
__try {
_asm {
#ifdef CPUID_AWARE_COMPILER
; we must push/pop the registers <<CPUID>> writes to, as the
; optimiser doesn't know about <<CPUID>>, and so doesn't expect
; these registers to change.
push eax
push ebx
push ecx
push edx
#endif
; <<CPUID>>
; eax = 0x80000007 --> edx: get processor power management
mov eax,0x80000007
CPUID_INSTRUCTION
mov CPUPowerManagement, edx
#ifdef CPUID_AWARE_COMPILER
pop edx
pop ecx
pop ebx
pop eax
#endif
}
}
// A generic catch-all just to be sure...
__except (1) {
return false;
}
// Check for the power management capabilities of the CPU.
Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode = ((CPUPowerManagement & 0x00000001) != 0);
Features.ExtendedFeatures.PowerManagement.HasFrequencyID = ((CPUPowerManagement & 0x00000002) != 0);
Features.ExtendedFeatures.PowerManagement.HasVoltageID = ((CPUPowerManagement & 0x00000004) != 0);
return true;
}
bool __cdecl CPUInfo::RetrieveExtendedCPUIdentity ()
{
int ProcessorNameStartPos = 0;
int CPUExtendedIdentity[12];
// Check to see if what we are about to do is supported...
if (!RetrieveCPUExtendedLevelSupport (0x80000002)) return false;
if (!RetrieveCPUExtendedLevelSupport (0x80000003)) return false;
if (!RetrieveCPUExtendedLevelSupport (0x80000004)) return false;
// Use assembly to detect CPUID information...
__try {
_asm {
#ifdef CPUID_AWARE_COMPILER
; we must push/pop the registers <<CPUID>> writes to, as the
; optimiser doesn't know about <<CPUID>>, and so doesn't expect
; these registers to change.
push eax
push ebx
push ecx
push edx
#endif
; <<CPUID>>
; eax = 0x80000002 --> eax, ebx, ecx, edx: get processor name string (part 1)
mov eax,0x80000002
CPUID_INSTRUCTION
mov CPUExtendedIdentity[0 * TYPE int], eax
mov CPUExtendedIdentity[1 * TYPE int], ebx
mov CPUExtendedIdentity[2 * TYPE int], ecx
mov CPUExtendedIdentity[3 * TYPE int], edx
; <<CPUID>>
; eax = 0x80000003 --> eax, ebx, ecx, edx: get processor name string (part 2)
mov eax,0x80000003
CPUID_INSTRUCTION
mov CPUExtendedIdentity[4 * TYPE int], eax
mov CPUExtendedIdentity[5 * TYPE int], ebx
mov CPUExtendedIdentity[6 * TYPE int], ecx
mov CPUExtendedIdentity[7 * TYPE int], edx
; <<CPUID>>
; eax = 0x80000004 --> eax, ebx, ecx, edx: get processor name string (part 3)
mov eax,0x80000004
CPUID_INSTRUCTION
mov CPUExtendedIdentity[8 * TYPE int], eax
mov CPUExtendedIdentity[9 * TYPE int], ebx
mov CPUExtendedIdentity[10 * TYPE int], ecx
mov CPUExtendedIdentity[11 * TYPE int], edx
#ifdef CPUID_AWARE_COMPILER
pop edx
pop ecx
pop ebx
pop eax
#endif
}
}
// A generic catch-all just to be sure...
__except (1) {
return false;
}
// Process the returned information.
memcpy (ChipID.ProcessorName, &(CPUExtendedIdentity[0]), sizeof (int));
memcpy (&(ChipID.ProcessorName[4]), &(CPUExtendedIdentity[1]), sizeof (int));
memcpy (&(ChipID.ProcessorName[8]), &(CPUExtendedIdentity[2]), sizeof (int));
memcpy (&(ChipID.ProcessorName[12]), &(CPUExtendedIdentity[3]), sizeof (int));
memcpy (&(ChipID.ProcessorName[16]), &(CPUExtendedIdentity[4]), sizeof (int));
memcpy (&(ChipID.ProcessorName[20]), &(CPUExtendedIdentity[5]), sizeof (int));
memcpy (&(ChipID.ProcessorName[24]), &(CPUExtendedIdentity[6]), sizeof (int));
memcpy (&(ChipID.ProcessorName[28]), &(CPUExtendedIdentity[7]), sizeof (int));
memcpy (&(ChipID.ProcessorName[32]), &(CPUExtendedIdentity[8]), sizeof (int));
memcpy (&(ChipID.ProcessorName[36]), &(CPUExtendedIdentity[9]), sizeof (int));
memcpy (&(ChipID.ProcessorName[40]), &(CPUExtendedIdentity[10]), sizeof (int));
memcpy (&(ChipID.ProcessorName[44]), &(CPUExtendedIdentity[11]), sizeof (int));
ChipID.ProcessorName[48] = '\0';
// Because some manufacturers (<cough>Intel</cough>) have leading white space - we have to post-process the name.
if (ChipManufacturer == Intel) {
for (int nCounter = 0; nCounter < CHIPNAME_STRING_LENGTH; nCounter ++) {
// There will either be NULL (\0) or spaces ( ) as the leading characters.
if ((ChipID.ProcessorName[nCounter] != '\0') && (ChipID.ProcessorName[nCounter] != ' ')) {
// We have found the starting position of the name.
ProcessorNameStartPos = nCounter;
// Terminate the loop.
break;
}
}
// Check to see if there is any white space at the start.
if (ProcessorNameStartPos == 0) return true;
// Now move the name forward so that there is no white space.
memmove (ChipID.ProcessorName, &(ChipID.ProcessorName[ProcessorNameStartPos]), (CHIPNAME_STRING_LENGTH - ProcessorNameStartPos));
}
return true;
}
bool _cdecl CPUInfo::RetrieveClassicalCPUIdentity ()
{
// Start by decided which manufacturer we are using....
switch (ChipManufacturer) {
case Intel:
// Check the family / model / revision to determine the CPU ID.
switch (ChipID.Family) {
case 3:
sprintf (ChipID.ProcessorName, "Newer i80386 family");
break;
case 4:
switch (ChipID.Model) {
case 0: STORE_CLASSICAL_NAME ("i80486DX-25/33"); break;
case 1: STORE_CLASSICAL_NAME ("i80486DX-50"); break;
case 2: STORE_CLASSICAL_NAME ("i80486SX"); break;
case 3: STORE_CLASSICAL_NAME ("i80486DX2"); break;
case 4: STORE_CLASSICAL_NAME ("i80486SL"); break;
case 5: STORE_CLASSICAL_NAME ("i80486SX2"); break;
case 7: STORE_CLASSICAL_NAME ("i80486DX2 WriteBack"); break;
case 8: STORE_CLASSICAL_NAME ("i80486DX4"); break;
case 9: STORE_CLASSICAL_NAME ("i80486DX4 WriteBack"); break;
default: STORE_CLASSICAL_NAME ("Unknown 80486 family"); return false;
}
break;
case 5:
switch (ChipID.Model) {
case 0: STORE_CLASSICAL_NAME ("P5 A-Step"); break;
case 1: STORE_CLASSICAL_NAME ("P5"); break;
case 2: STORE_CLASSICAL_NAME ("P54C"); break;
case 3: STORE_CLASSICAL_NAME ("P24T OverDrive"); break;
case 4: STORE_CLASSICAL_NAME ("P55C"); break;
case 7: STORE_CLASSICAL_NAME ("P54C"); break;
case 8: STORE_CLASSICAL_NAME ("P55C (0.25祄)"); break;
default: STORE_CLASSICAL_NAME ("Unknown Pentium
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -