dma: don't generate irqs after aborted DMA
[pcsx_rearmed.git] / libpcsxcore / ix86_64 / ix86_cpudetect.c
1 /*  Cpudetection lib \r
2  *  Copyright (C) 2002-2003  Pcsx2 Team\r
3  *\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
8  *\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
13  *\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
17  */\r
18 #if defined (_WIN32)\r
19 #include <windows.h>\r
20 #endif\r
21 \r
22 #include <string.h>\r
23 #include <stdio.h>\r
24 \r
25 #include "ix86-64.h"\r
26 \r
27 #if defined (_MSC_VER) && _MSC_VER >= 1400\r
28 \r
29    void __cpuid(int* CPUInfo, int InfoType);\r
30    unsigned __int64 __rdtsc();\r
31 \r
32    #pragma intrinsic(__cpuid)\r
33    #pragma intrinsic(__rdtsc)\r
34 \r
35 #endif\r
36 \r
37 CAPABILITIES cpucaps;\r
38 CPUINFO cpuinfo;\r
39 \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
43 \r
44 static s32 iCpuId( u32 cmd, u32 *regs ) \r
45 {\r
46    int flag=1;\r
47 \r
48 #if defined (_MSC_VER) && _MSC_VER >= 1400\r
49 \r
50    __cpuid( regs, cmd );\r
51 \r
52    return 0;\r
53 \r
54 #elif defined (_MSC_VER) \r
55 \r
56 #ifdef __x86_64__\r
57    assert(0);\r
58 #else // __x86_64__\r
59    __asm \r
60    {\r
61       push ebx;\r
62       push edi;\r
63 \r
64       pushfd;\r
65       pop eax;\r
66       mov edx, eax;\r
67       xor eax, 1 << 21;\r
68       push eax;\r
69       popfd;\r
70       pushfd;\r
71       pop eax;\r
72       xor eax, edx;\r
73       mov flag, eax;\r
74    }\r
75    if ( ! flag )\r
76    {\r
77       return -1;\r
78    }\r
79 \r
80    __asm \r
81    {\r
82       mov eax, cmd;\r
83       cpuid;\r
84       mov edi, [regs]\r
85       mov [edi], eax;\r
86       mov [edi+4], ebx;\r
87       mov [edi+8], ecx;\r
88       mov [edi+12], edx;\r
89 \r
90       pop edi;\r
91       pop ebx;\r
92    }\r
93 #endif // __x86_64__\r
94    return 0;\r
95 \r
96 \r
97 #else\r
98 \r
99 #ifndef __x86_64__\r
100    // see if we can use cpuid\r
101    __asm__ __volatile__ (\r
102       "sub $0x18, %%esp\n"\r
103       "pushf\n"\r
104       "pop %%eax\n"\r
105       "mov %%eax, %%edx\n"\r
106       "xor $0x200000, %%eax\n"\r
107       "push %%eax\n"\r
108       "popf\n"\r
109       "pushf\n"\r
110       "pop %%eax\n"\r
111       "xor %%edx, %%eax\n"\r
112       "mov %%eax, %0\n"\r
113           "add $0x18, %%esp\n"\r
114       : "=r"(flag) :\r
115    );\r
116 #endif\r
117 \r
118    if ( !flag )\r
119        return -1;\r
120 \r
121    cpuid(cmd, regs[0], regs[1], regs[2], regs[3]);\r
122    return 0;\r
123 #endif // _MSC_VER\r
124 }\r
125 \r
126 u64 GetCPUTick( void ) \r
127 {\r
128 #if defined (_MSC_VER) && _MSC_VER >= 1400\r
129 \r
130    return __rdtsc();\r
131 \r
132 #elif defined(__MSCW32__) && !defined(__x86_64__)\r
133 \r
134    __asm rdtsc;\r
135 \r
136 #else\r
137 \r
138    u32 _a, _d;\r
139         __asm__ __volatile__ ("rdtsc" : "=a"(_a), "=d"(_d));\r
140         return (u64)_a | ((u64)_d << 32);\r
141 \r
142 #endif\r
143 }\r
144 \r
145 #if defined __LINUX__\r
146 \r
147 #include <sys/time.h>\r
148 #include <errno.h>\r
149 //*\r
150 unsigned long timeGetTime2()\r
151 {\r
152  struct timeval tv;\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
155 }\r
156 //*/\r
157 #endif\r
158 \r
159 s64 CPUSpeedHz( unsigned int time )\r
160 {\r
161    s64 timeStart, \r
162             timeStop;\r
163    s64 startTick, \r
164             endTick;\r
165    s64 overhead;\r
166 \r
167    if( ! cpucaps.hasTimeStampCounter )\r
168    {\r
169       return 0; //check if function is supported\r
170    }\r
171 \r
172         overhead = GetCPUTick() - GetCPUTick();\r
173         \r
174         timeStart = timeGetTime2( );\r
175         while( timeGetTime2( ) == timeStart ) \r
176    {\r
177       timeStart = timeGetTime2( );\r
178    }\r
179         for(;;)\r
180         {\r
181                 timeStop = timeGetTime2( );\r
182                 if ( ( timeStop - timeStart ) > 1 )     \r
183                 {\r
184                         startTick = GetCPUTick( );\r
185                         break;\r
186                 }\r
187         }\r
188 \r
189         timeStart = timeStop;\r
190         for(;;)\r
191         {\r
192                 timeStop = timeGetTime2( );\r
193                 if ( ( timeStop - timeStart ) > time )  \r
194                 {\r
195                         endTick = GetCPUTick( );\r
196                         break;\r
197                 }\r
198         }\r
199 \r
200         return (s64)( ( endTick - startTick ) + ( overhead ) );\r
201 }\r
202 \r
203 ////////////////////////////////////////////////////\r
204 void cpudetectInit( void ) \r
205 {\r
206    u32 regs[ 4 ];\r
207    u32 cmds;\r
208    u32 AMDspeed;\r
209    s8 AMDspeedString[10];\r
210    int cputype=0;            // Cpu type\r
211    //AMD 64 STUFF\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
221    \r
222    if ( iCpuId( 0, regs ) == -1 ) return;\r
223 \r
224    cmds = regs[ 0 ];\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
229    {\r
230       if ( iCpuId( 0x00000001, regs ) != -1 )\r
231       {\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
238       }\r
239    }\r
240    if ( iCpuId( 0x80000000, regs ) != -1 )\r
241    {\r
242       cmds = regs[ 0 ];\r
243       if ( cmds >= 0x80000001 ) \r
244       {\r
245                  if ( iCpuId( 0x80000001, regs ) != -1 )\r
246          {\r
247                         x86_64_12BITBRANDID = regs[1] & 0xfff;\r
248             cpuinfo.x86EFlags = regs[ 3 ];\r
249             \r
250          }\r
251       }\r
252    }\r
253    switch(cpuinfo.x86PType)\r
254    {\r
255       case 0:\r
256          strcpy( cpuinfo.x86Type, "Standard OEM");\r
257          break;\r
258       case 1:\r
259          strcpy( cpuinfo.x86Type, "Overdrive");\r
260          break;\r
261       case 2:\r
262          strcpy( cpuinfo.x86Type, "Dual");\r
263          break;\r
264       case 3:\r
265          strcpy( cpuinfo.x86Type, "Reserved");\r
266          break;\r
267       default:\r
268          strcpy( cpuinfo.x86Type, "Unknown");\r
269          break;\r
270    }\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
273    \r
274    if ( cputype == 0 ) //intel cpu\r
275    {\r
276       if( ( cpuinfo.x86Family >= 7 ) && ( cpuinfo.x86Family < 15 ) )\r
277       {\r
278          strcpy( cpuinfo.x86Fam, "Intel P6 family (Not PIV and Higher then PPro" );\r
279       }\r
280       else\r
281       {\r
282          switch( cpuinfo.x86Family )\r
283          {     \r
284             // Start at 486 because if it's below 486 there is no cpuid instruction\r
285             case 4:\r
286                strcpy( cpuinfo.x86Fam, "Intel 486" );\r
287                break;\r
288             case 5:     \r
289                switch( cpuinfo.x86Model )\r
290                {\r
291                case 4:\r
292                case 8:     // 0.25 µm\r
293                   strcpy( cpuinfo.x86Fam, "Intel Pentium (MMX)");\r
294                   break;\r
295                default:\r
296                   strcpy( cpuinfo.x86Fam, "Intel Pentium" );\r
297                }\r
298                break;\r
299             case 6:     \r
300                switch( cpuinfo.x86Model )\r
301                {\r
302                case 0:     // Pentium pro (P6 A-Step)\r
303                case 1:     // Pentium pro\r
304                   strcpy( cpuinfo.x86Fam, "Intel Pentium Pro" );\r
305                   break;\r
306 \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
311                   break;\r
312 \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
318                   break;\r
319                            case 15:    // Core 2 Duo Allendale/Conroe\r
320                                   strcpy( cpuinfo.x86Fam, "Intel Core 2 Duo" );\r
321                                   break;\r
322 \r
323                default:\r
324                   strcpy( cpuinfo.x86Fam, "Intel Pentium Pro (Unknown)" );\r
325                }\r
326                break;\r
327             case 15:\r
328                switch( cpuinfo.x86Model )\r
329                {\r
330                case 0:     // Willamette (A-Step)\r
331                case 1:     // Willamette \r
332                   strcpy( cpuinfo.x86Fam, "Willamette Intel Pentium IV" );\r
333                   break;\r
334                case 2:     // Northwood \r
335                   strcpy( cpuinfo.x86Fam, "Northwood Intel Pentium IV" );\r
336                   break;\r
337 \r
338                default:\r
339                   strcpy( cpuinfo.x86Fam, "Intel Pentium IV (Unknown)" );\r
340                   break;\r
341                }\r
342                break;\r
343             default:\r
344                strcpy( cpuinfo.x86Fam, "Unknown Intel CPU" );\r
345          }\r
346       }\r
347    }\r
348    else if ( cputype == 1 ) //AMD cpu\r
349    {\r
350       if( cpuinfo.x86Family >= 7 )\r
351       {\r
352                   if((x86_64_12BITBRANDID !=0) || (x86_64_8BITBRANDID !=0))\r
353                   {\r
354                     if(x86_64_8BITBRANDID == 0 )\r
355                     {\r
356                switch((x86_64_12BITBRANDID >>6)& 0x3f)\r
357                            {\r
358                             case 4:\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
365                                  break;\r
366                             case 12: \r
367                                  strcpy(cpuinfo.x86Fam,"AMD Opteron(tm) Processor");\r
368                                  break;\r
369                             case 5:\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
376                   break;\r
377                            case 44:\r
378                                    strcpy( cpuinfo.x86Fam, "AMD Opteron(tm) Dual Core Processor" );\r
379                   break;\r
380                             default:\r
381                                    strcpy(cpuinfo.x86Fam,"Unknown AMD 64 proccesor");\r
382                                    \r
383                             }\r
384                      }\r
385                      else //8bit brand id is non zero\r
386                      {\r
387                 strcpy(cpuinfo.x86Fam,"Unsupported yet AMD64 cpu");\r
388                      }\r
389                   }\r
390                   else\r
391                   {              \r
392                           strcpy( cpuinfo.x86Fam, "AMD K7+ Processor" );\r
393                   }\r
394       }\r
395       else\r
396       {\r
397          switch ( cpuinfo.x86Family )\r
398          {\r
399             case 4:\r
400                switch( cpuinfo.x86Model )\r
401                {\r
402                case 14: \r
403                case 15:       // Write-back enhanced\r
404                   strcpy( cpuinfo.x86Fam, "AMD 5x86 Processor" );\r
405                   break;\r
406 \r
407                case 3:        // DX2\r
408                case 7:        // Write-back enhanced DX2\r
409                case 8:        // DX4\r
410                case 9:        // Write-back enhanced DX4\r
411                   strcpy( cpuinfo.x86Fam, "AMD 486 Processor" );\r
412                   break;\r
413                                                    \r
414 \r
415                default:\r
416                   strcpy( cpuinfo.x86Fam, "AMD Unknown Processor" );\r
417 \r
418                }\r
419                break;\r
420 \r
421             case 5:     \r
422                switch( cpuinfo.x86Model)\r
423                {\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
429                   break;\r
430 \r
431                case 6:     \r
432                case 7:     // (0.25 µm)\r
433                case 8:     // K6-2\r
434                case 9:     // K6-III\r
435                case 14:    // K6-2+ / K6-III+\r
436                   strcpy( cpuinfo.x86Fam, "AMD K6 Series Processor" );\r
437                   break;\r
438 \r
439                default:\r
440                   strcpy( cpuinfo.x86Fam, "AMD Unknown Processor" );\r
441                }\r
442                break;\r
443             case 6:     \r
444                strcpy( cpuinfo.x86Fam, "AMD Athlon XP Processor" );\r
445                break;\r
446             default:\r
447                strcpy( cpuinfo.x86Fam, "Unknown AMD CPU" ); \r
448          }\r
449       }\r
450    }\r
451    //capabilities\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
487 }\r