2 * Copyright (C) 2002-2003 Pcsx2 Team
\r
4 * This program is free software; you can redistribute it and/or modify
\r
5 * it under the terms of the GNU General Public License as published by
\r
6 * the Free Software Foundation; either version 2 of the License, or
\r
7 * (at your option) any later version.
\r
9 * This program is distributed in the hope that it will be useful,
\r
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
12 * GNU General Public License for more details.
\r
14 * You should have received a copy of the GNU General Public License
\r
15 * along with this program; if not, write to the Free Software
\r
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA
\r
18 #if defined (_WIN32)
\r
19 #include <windows.h>
\r
25 #include "ix86-64.h"
\r
27 #if defined (_MSC_VER) && _MSC_VER >= 1400
\r
29 void __cpuid(int* CPUInfo, int InfoType);
\r
30 unsigned __int64 __rdtsc();
\r
32 #pragma intrinsic(__cpuid)
\r
33 #pragma intrinsic(__rdtsc)
\r
37 CAPABILITIES cpucaps;
\r
40 #define cpuid(cmd,a,b,c,d) \
\r
41 __asm__ __volatile__("cpuid" \
\r
42 : "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "0" (cmd))
\r
44 static s32 iCpuId( u32 cmd, u32 *regs )
\r
48 #if defined (_MSC_VER) && _MSC_VER >= 1400
\r
50 __cpuid( regs, cmd );
\r
54 #elif defined (_MSC_VER)
\r
93 #endif // __x86_64__
\r
100 // see if we can use cpuid
\r
101 __asm__ __volatile__ (
\r
102 "sub $0x18, %%esp\n"
\r
105 "mov %%eax, %%edx\n"
\r
106 "xor $0x200000, %%eax\n"
\r
111 "xor %%edx, %%eax\n"
\r
113 "add $0x18, %%esp\n"
\r
121 cpuid(cmd, regs[0], regs[1], regs[2], regs[3]);
\r
126 u64 GetCPUTick( void )
\r
128 #if defined (_MSC_VER) && _MSC_VER >= 1400
\r
132 #elif defined(__MSCW32__) && !defined(__x86_64__)
\r
139 __asm__ __volatile__ ("rdtsc" : "=a"(_a), "=d"(_d));
\r
140 return (u64)_a | ((u64)_d << 32);
\r
145 #if defined __LINUX__
\r
147 #include <sys/time.h>
\r
150 unsigned long timeGetTime2()
\r
153 gettimeofday(&tv, 0); // well, maybe there are better ways
\r
154 return (unsigned long)tv.tv_sec * 1000 + tv.tv_usec/1000; // to do that, but at least it works
\r
159 s64 CPUSpeedHz( unsigned int time )
\r
167 if( ! cpucaps.hasTimeStampCounter )
\r
169 return 0; //check if function is supported
\r
172 overhead = GetCPUTick() - GetCPUTick();
\r
174 timeStart = timeGetTime2( );
\r
175 while( timeGetTime2( ) == timeStart )
\r
177 timeStart = timeGetTime2( );
\r
181 timeStop = timeGetTime2( );
\r
182 if ( ( timeStop - timeStart ) > 1 )
\r
184 startTick = GetCPUTick( );
\r
189 timeStart = timeStop;
\r
192 timeStop = timeGetTime2( );
\r
193 if ( ( timeStop - timeStart ) > time )
\r
195 endTick = GetCPUTick( );
\r
200 return (s64)( ( endTick - startTick ) + ( overhead ) );
\r
203 ////////////////////////////////////////////////////
\r
204 void cpudetectInit( void )
\r
209 s8 AMDspeedString[10];
\r
210 int cputype=0; // Cpu type
\r
212 u32 x86_64_8BITBRANDID;
\r
213 u32 x86_64_12BITBRANDID;
\r
214 memset( cpuinfo.x86ID, 0, sizeof( cpuinfo.x86ID ) );
\r
215 cpuinfo.x86Family = 0;
\r
216 cpuinfo.x86Model = 0;
\r
217 cpuinfo.x86PType = 0;
\r
218 cpuinfo.x86StepID = 0;
\r
219 cpuinfo.x86Flags = 0;
\r
220 cpuinfo.x86EFlags = 0;
\r
222 if ( iCpuId( 0, regs ) == -1 ) return;
\r
225 ((u32*)cpuinfo.x86ID)[ 0 ] = regs[ 1 ];
\r
226 ((u32*)cpuinfo.x86ID)[ 1 ] = regs[ 3 ];
\r
227 ((u32*)cpuinfo.x86ID)[ 2 ] = regs[ 2 ];
\r
228 if ( cmds >= 0x00000001 )
\r
230 if ( iCpuId( 0x00000001, regs ) != -1 )
\r
232 cpuinfo.x86StepID = regs[ 0 ] & 0xf;
\r
233 cpuinfo.x86Model = (regs[ 0 ] >> 4) & 0xf;
\r
234 cpuinfo.x86Family = (regs[ 0 ] >> 8) & 0xf;
\r
235 cpuinfo.x86PType = (regs[ 0 ] >> 12) & 0x3;
\r
236 x86_64_8BITBRANDID = regs[1] & 0xff;
\r
237 cpuinfo.x86Flags = regs[ 3 ];
\r
240 if ( iCpuId( 0x80000000, regs ) != -1 )
\r
243 if ( cmds >= 0x80000001 )
\r
245 if ( iCpuId( 0x80000001, regs ) != -1 )
\r
247 x86_64_12BITBRANDID = regs[1] & 0xfff;
\r
248 cpuinfo.x86EFlags = regs[ 3 ];
\r
253 switch(cpuinfo.x86PType)
\r
256 strcpy( cpuinfo.x86Type, "Standard OEM");
\r
259 strcpy( cpuinfo.x86Type, "Overdrive");
\r
262 strcpy( cpuinfo.x86Type, "Dual");
\r
265 strcpy( cpuinfo.x86Type, "Reserved");
\r
268 strcpy( cpuinfo.x86Type, "Unknown");
\r
271 if ( cpuinfo.x86ID[ 0 ] == 'G' ){ cputype=0;}//trick lines but if you know a way better ;p
\r
272 if ( cpuinfo.x86ID[ 0 ] == 'A' ){ cputype=1;}
\r
274 if ( cputype == 0 ) //intel cpu
\r
276 if( ( cpuinfo.x86Family >= 7 ) && ( cpuinfo.x86Family < 15 ) )
\r
278 strcpy( cpuinfo.x86Fam, "Intel P6 family (Not PIV and Higher then PPro" );
\r
282 switch( cpuinfo.x86Family )
\r
284 // Start at 486 because if it's below 486 there is no cpuid instruction
\r
286 strcpy( cpuinfo.x86Fam, "Intel 486" );
\r
289 switch( cpuinfo.x86Model )
\r
293 strcpy( cpuinfo.x86Fam, "Intel Pentium (MMX)");
\r
296 strcpy( cpuinfo.x86Fam, "Intel Pentium" );
\r
300 switch( cpuinfo.x86Model )
\r
302 case 0: // Pentium pro (P6 A-Step)
\r
303 case 1: // Pentium pro
\r
304 strcpy( cpuinfo.x86Fam, "Intel Pentium Pro" );
\r
307 case 2: // 66 MHz FSB
\r
308 case 5: // Xeon/Celeron (0.25 µm)
\r
309 case 6: // Internal L2 cache
\r
310 strcpy( cpuinfo.x86Fam, "Intel Pentium II" );
\r
313 case 7: // Xeon external L2 cache
\r
314 case 8: // Xeon/Celeron with 256 KB on-die L2 cache
\r
315 case 10: // Xeon/Celeron with 1 or 2 MB on-die L2 cache
\r
316 case 11: // Xeon/Celeron with Tualatin core, on-die cache
\r
317 strcpy( cpuinfo.x86Fam, "Intel Pentium III" );
\r
319 case 15: // Core 2 Duo Allendale/Conroe
\r
320 strcpy( cpuinfo.x86Fam, "Intel Core 2 Duo" );
\r
324 strcpy( cpuinfo.x86Fam, "Intel Pentium Pro (Unknown)" );
\r
328 switch( cpuinfo.x86Model )
\r
330 case 0: // Willamette (A-Step)
\r
331 case 1: // Willamette
\r
332 strcpy( cpuinfo.x86Fam, "Willamette Intel Pentium IV" );
\r
334 case 2: // Northwood
\r
335 strcpy( cpuinfo.x86Fam, "Northwood Intel Pentium IV" );
\r
339 strcpy( cpuinfo.x86Fam, "Intel Pentium IV (Unknown)" );
\r
344 strcpy( cpuinfo.x86Fam, "Unknown Intel CPU" );
\r
348 else if ( cputype == 1 ) //AMD cpu
\r
350 if( cpuinfo.x86Family >= 7 )
\r
352 if((x86_64_12BITBRANDID !=0) || (x86_64_8BITBRANDID !=0))
\r
354 if(x86_64_8BITBRANDID == 0 )
\r
356 switch((x86_64_12BITBRANDID >>6)& 0x3f)
\r
359 strcpy(cpuinfo.x86Fam,"AMD Athlon(tm) 64 Processor");
\r
360 AMDspeed = 22 + (x86_64_12BITBRANDID & 0x1f);
\r
361 //AMDspeedString = strtol(AMDspeed, (char**)NULL,10);
\r
362 sprintf(AMDspeedString," %d",AMDspeed);
\r
363 strcat(AMDspeedString,"00+");
\r
364 strcat(cpuinfo.x86Fam,AMDspeedString);
\r
367 strcpy(cpuinfo.x86Fam,"AMD Opteron(tm) Processor");
\r
370 strcpy( cpuinfo.x86Fam, "AMD Athlon X2 Processor" );
\r
371 AMDspeed = 22 + (x86_64_12BITBRANDID & 0x1f);
\r
372 //AMDspeedString = strtol(AMDspeed, (char**)NULL,10);
\r
373 sprintf(AMDspeedString," %d",AMDspeed);
\r
374 strcat(AMDspeedString,"00+");
\r
375 strcat(cpuinfo.x86Fam,AMDspeedString);
\r
378 strcpy( cpuinfo.x86Fam, "AMD Opteron(tm) Dual Core Processor" );
\r
381 strcpy(cpuinfo.x86Fam,"Unknown AMD 64 proccesor");
\r
385 else //8bit brand id is non zero
\r
387 strcpy(cpuinfo.x86Fam,"Unsupported yet AMD64 cpu");
\r
392 strcpy( cpuinfo.x86Fam, "AMD K7+ Processor" );
\r
397 switch ( cpuinfo.x86Family )
\r
400 switch( cpuinfo.x86Model )
\r
403 case 15: // Write-back enhanced
\r
404 strcpy( cpuinfo.x86Fam, "AMD 5x86 Processor" );
\r
408 case 7: // Write-back enhanced DX2
\r
410 case 9: // Write-back enhanced DX4
\r
411 strcpy( cpuinfo.x86Fam, "AMD 486 Processor" );
\r
416 strcpy( cpuinfo.x86Fam, "AMD Unknown Processor" );
\r
422 switch( cpuinfo.x86Model)
\r
424 case 0: // SSA 5 (75, 90 and 100 Mhz)
\r
425 case 1: // 5k86 (PR 120 and 133 MHz)
\r
426 case 2: // 5k86 (PR 166 MHz)
\r
427 case 3: // K5 5k86 (PR 200 MHz)
\r
428 strcpy( cpuinfo.x86Fam, "AMD K5 Processor" );
\r
432 case 7: // (0.25 µm)
\r
435 case 14: // K6-2+ / K6-III+
\r
436 strcpy( cpuinfo.x86Fam, "AMD K6 Series Processor" );
\r
440 strcpy( cpuinfo.x86Fam, "AMD Unknown Processor" );
\r
444 strcpy( cpuinfo.x86Fam, "AMD Athlon XP Processor" );
\r
447 strcpy( cpuinfo.x86Fam, "Unknown AMD CPU" );
\r
452 cpucaps.hasFloatingPointUnit = ( cpuinfo.x86Flags >> 0 ) & 1;
\r
453 cpucaps.hasVirtual8086ModeEnhancements = ( cpuinfo.x86Flags >> 1 ) & 1;
\r
454 cpucaps.hasDebuggingExtensions = ( cpuinfo.x86Flags >> 2 ) & 1;
\r
455 cpucaps.hasPageSizeExtensions = ( cpuinfo.x86Flags >> 3 ) & 1;
\r
456 cpucaps.hasTimeStampCounter = ( cpuinfo.x86Flags >> 4 ) & 1;
\r
457 cpucaps.hasModelSpecificRegisters = ( cpuinfo.x86Flags >> 5 ) & 1;
\r
458 cpucaps.hasPhysicalAddressExtension = ( cpuinfo.x86Flags >> 6 ) & 1;
\r
459 cpucaps.hasMachineCheckArchitecture = ( cpuinfo.x86Flags >> 7 ) & 1;
\r
460 cpucaps.hasCOMPXCHG8BInstruction = ( cpuinfo.x86Flags >> 8 ) & 1;
\r
461 cpucaps.hasAdvancedProgrammableInterruptController = ( cpuinfo.x86Flags >> 9 ) & 1;
\r
462 cpucaps.hasSEPFastSystemCall = ( cpuinfo.x86Flags >> 11 ) & 1;
\r
463 cpucaps.hasMemoryTypeRangeRegisters = ( cpuinfo.x86Flags >> 12 ) & 1;
\r
464 cpucaps.hasPTEGlobalFlag = ( cpuinfo.x86Flags >> 13 ) & 1;
\r
465 cpucaps.hasMachineCheckArchitecture = ( cpuinfo.x86Flags >> 14 ) & 1;
\r
466 cpucaps.hasConditionalMoveAndCompareInstructions = ( cpuinfo.x86Flags >> 15 ) & 1;
\r
467 cpucaps.hasFGPageAttributeTable = ( cpuinfo.x86Flags >> 16 ) & 1;
\r
468 cpucaps.has36bitPageSizeExtension = ( cpuinfo.x86Flags >> 17 ) & 1;
\r
469 cpucaps.hasProcessorSerialNumber = ( cpuinfo.x86Flags >> 18 ) & 1;
\r
470 cpucaps.hasCFLUSHInstruction = ( cpuinfo.x86Flags >> 19 ) & 1;
\r
471 cpucaps.hasDebugStore = ( cpuinfo.x86Flags >> 21 ) & 1;
\r
472 cpucaps.hasACPIThermalMonitorAndClockControl = ( cpuinfo.x86Flags >> 22 ) & 1;
\r
473 cpucaps.hasMultimediaExtensions = ( cpuinfo.x86Flags >> 23 ) & 1; //mmx
\r
474 cpucaps.hasFastStreamingSIMDExtensionsSaveRestore = ( cpuinfo.x86Flags >> 24 ) & 1;
\r
475 cpucaps.hasStreamingSIMDExtensions = ( cpuinfo.x86Flags >> 25 ) & 1; //sse
\r
476 cpucaps.hasStreamingSIMD2Extensions = ( cpuinfo.x86Flags >> 26 ) & 1; //sse2
\r
477 cpucaps.hasSelfSnoop = ( cpuinfo.x86Flags >> 27 ) & 1;
\r
478 cpucaps.hasHyperThreading = ( cpuinfo.x86Flags >> 28 ) & 1;
\r
479 cpucaps.hasThermalMonitor = ( cpuinfo.x86Flags >> 29 ) & 1;
\r
480 cpucaps.hasIntel64BitArchitecture = ( cpuinfo.x86Flags >> 30 ) & 1;
\r
481 //that is only for AMDs
\r
482 cpucaps.hasMultimediaExtensionsExt = ( cpuinfo.x86EFlags >> 22 ) & 1; //mmx2
\r
483 cpucaps.hasAMD64BitArchitecture = ( cpuinfo.x86EFlags >> 29 ) & 1; //64bit cpu
\r
484 cpucaps.has3DNOWInstructionExtensionsExt = ( cpuinfo.x86EFlags >> 30 ) & 1; //3dnow+
\r
485 cpucaps.has3DNOWInstructionExtensions = ( cpuinfo.x86EFlags >> 31 ) & 1; //3dnow
\r
486 cpuinfo.cpuspeed = (u32 )(CPUSpeedHz( 1000 ) / 1000000);
\r