improve ARM feature detection
[pcsx_rearmed.git] / libpcsxcore / ix86_64 / ix86_cpudetect.c
CommitLineData
ef79bbde
P
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
37CAPABILITIES cpucaps;\r
38CPUINFO 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
44static 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
126u64 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
150unsigned 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
159s64 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
204void 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