Commit | Line | Data |
---|---|---|
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 | |
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 |