comparison src/cpuinfo/gcpuinfo.c @ 739:22dbf364c017

Added SDL_HasMMX(), SDL_Has3DNow(), SDL_HasSSE() in SDL_cpuinfo.h
author Sam Lantinga <slouken@libsdl.org>
date Tue, 18 Nov 2003 01:27:06 +0000
parents
children
comparison
equal deleted inserted replaced
738:82b85b731fe3 739:22dbf364c017
1 /****************************************************************************
2 *
3 * SciTech OS Portability Manager Library
4 *
5 * ========================================================================
6 *
7 * Copyright (C) 1991-2002 SciTech Software, Inc. All rights reserved.
8 *
9 * This file may be distributed and/or modified under the terms of the
10 * GNU Lesser General Public License version 2.1 as published by the Free
11 * Software Foundation and appearing in the file LICENSE.LGPL included
12 * in the packaging of this file.
13 *
14 * Licensees holding a valid Commercial License for this product from
15 * SciTech Software, Inc. may use this file in accordance with the
16 * Commercial License Agreement provided with the Software.
17 *
18 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
19 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE.
21 *
22 * See http://www.scitechsoft.com/license/ for information about
23 * the licensing options available and how to purchase a Commercial
24 * License Agreement.
25 *
26 * Contact license@scitechsoft.com if any conditions of this licensing
27 * are not clear to you, or you have questions about licensing options.
28 *
29 * ========================================================================
30 *
31 * Language: ANSI C
32 * Environment: Any
33 *
34 * Description: Main module to implement the Zen Timer support functions.
35 *
36 ****************************************************************************/
37
38 #include "cpuinfo.h"
39 //#include "pmapi.h"
40 //#include "oshdr.h"
41
42 /*----------------------------- Implementation ----------------------------*/
43
44 /* External Intel assembler functions */
45 #ifdef __INTEL__
46 /* {secret} */
47 ibool _ASMAPI _CPU_haveCPUID(void);
48 /* {secret} */
49 ibool _ASMAPI _CPU_check80386(void);
50 /* {secret} */
51 ibool _ASMAPI _CPU_check80486(void);
52 /* {secret} */
53 uint _ASMAPI _CPU_checkCPUID(void);
54 /* {secret} */
55 uint _ASMAPI _CPU_getCPUIDModel(void);
56 /* {secret} */
57 uint _ASMAPI _CPU_getCPUIDStepping(void);
58 /* {secret} */
59 uint _ASMAPI _CPU_getCPUIDFeatures(void);
60 /* {secret} */
61 uint _ASMAPI _CPU_getCacheSize(void);
62 /* {secret} */
63 uint _ASMAPI _CPU_have3DNow(void);
64 /* {secret} */
65 ibool _ASMAPI _CPU_checkClone(void);
66 /* {secret} */
67 void _ASMAPI _CPU_readTimeStamp(CPU_largeInteger *time);
68 /* {secret} */
69 void _ASMAPI _CPU_runBSFLoop(ulong iterations);
70 /* {secret} */
71 ulong _ASMAPI _CPU_mulDiv(ulong a,ulong b,ulong c);
72 /* {secret} */
73 #define CPU_HaveMMX 0x00800000
74 #define CPU_HaveRDTSC 0x00000010
75 #define CPU_HaveSSE 0x02000000
76 #endif
77
78 /*------------------------ Public interface routines ----------------------*/
79
80 #ifdef __INTEL__
81 extern Uint8 PM_inpb(int port);
82 extern void PM_outpb(int port,Uint8 val);
83
84 /****************************************************************************
85 REMARKS:
86 Read an I/O port location.
87 ****************************************************************************/
88 static uchar rdinx(
89 int port,
90 int index)
91 {
92 PM_outpb(port,(uchar)index);
93 return PM_inpb(port+1);
94 }
95
96 /****************************************************************************
97 REMARKS:
98 Write an I/O port location.
99 ****************************************************************************/
100 static void wrinx(
101 ushort port,
102 ushort index,
103 ushort value)
104 {
105 PM_outpb(port,(uchar)index);
106 PM_outpb(port+1,(uchar)value);
107 }
108
109 /****************************************************************************
110 REMARKS:
111 Enables the Cyrix CPUID instruction to properly detect MediaGX and 6x86
112 processors.
113 ****************************************************************************/
114 static void _CPU_enableCyrixCPUID(void)
115 {
116 uchar ccr3;
117
118 //PM_init();
119 ccr3 = rdinx(0x22,0xC3);
120 wrinx(0x22,0xC3,(uchar)(ccr3 | 0x10));
121 wrinx(0x22,0xE8,(uchar)(rdinx(0x22,0xE8) | 0x80));
122 wrinx(0x22,0xC3,ccr3);
123 }
124 #endif
125
126 /****************************************************************************
127 DESCRIPTION:
128 Returns the type of processor in the system.
129
130 HEADER:
131 cpuinfo.h
132
133 RETURNS:
134 Numerical identifier for the installed processor
135
136 REMARKS:
137 Returns the type of processor in the system. Note that if the CPU is an
138 unknown Pentium family processor that we don't have an enumeration for,
139 the return value will be greater than or equal to the value of CPU_UnkPentium
140 (depending on the value returned by the CPUID instruction).
141
142 SEE ALSO:
143 CPU_getProcessorSpeed, CPU_haveMMX, CPU_getProcessorName
144 ****************************************************************************/
145 uint ZAPI CPU_getProcessorType(void)
146 {
147 #if defined(__INTEL__)
148 uint cpu,vendor,model,cacheSize;
149 static ibool firstTime = true;
150
151 if (_CPU_haveCPUID()) {
152 cpu = _CPU_checkCPUID();
153 vendor = cpu & ~CPU_mask;
154 if (vendor == CPU_Intel) {
155 /* Check for Intel processors */
156 switch (cpu & CPU_mask) {
157 case 4: cpu = CPU_i486; break;
158 case 5: cpu = CPU_Pentium; break;
159 case 6:
160 if ((model = _CPU_getCPUIDModel()) == 1)
161 cpu = CPU_PentiumPro;
162 else if (model <= 6) {
163 cacheSize = _CPU_getCacheSize();
164 if ((model == 5 && cacheSize == 0) ||
165 (model == 5 && cacheSize == 256) ||
166 (model == 6 && cacheSize == 128))
167 cpu = CPU_Celeron;
168 else
169 cpu = CPU_PentiumII;
170 }
171 else if (model >= 7) {
172 /* Model 7 == Pentium III */
173 /* Model 8 == Celeron/Pentium III Coppermine */
174 cacheSize = _CPU_getCacheSize();
175 if ((model == 8 && cacheSize == 128))
176 cpu = CPU_Celeron;
177 else
178 cpu = CPU_PentiumIII;
179 }
180 break;
181 case 7:
182 cpu = CPU_Pentium4;
183 break;
184 default:
185 cpu = CPU_UnkIntel;
186 break;
187 }
188 }
189 else if (vendor == CPU_Cyrix) {
190 /* Check for Cyrix processors */
191 switch (cpu & CPU_mask) {
192 case 4:
193 if ((model = _CPU_getCPUIDModel()) == 4)
194 cpu = CPU_CyrixMediaGX;
195 else
196 cpu = CPU_UnkCyrix;
197 break;
198 case 5:
199 if ((model = _CPU_getCPUIDModel()) == 2)
200 cpu = CPU_Cyrix6x86;
201 else if (model == 4)
202 cpu = CPU_CyrixMediaGXm;
203 else
204 cpu = CPU_UnkCyrix;
205 break;
206 case 6:
207 if ((model = _CPU_getCPUIDModel()) <= 1)
208 cpu = CPU_Cyrix6x86MX;
209 else
210 cpu = CPU_UnkCyrix;
211 break;
212 default:
213 cpu = CPU_UnkCyrix;
214 break;
215 }
216 }
217 else if (vendor == CPU_AMD) {
218 /* Check for AMD processors */
219 switch (cpu & CPU_mask) {
220 case 4:
221 if ((model = _CPU_getCPUIDModel()) == 0)
222 cpu = CPU_AMDAm5x86;
223 else
224 cpu = CPU_AMDAm486;
225 break;
226 case 5:
227 if ((model = _CPU_getCPUIDModel()) <= 3)
228 cpu = CPU_AMDK5;
229 else if (model <= 7)
230 cpu = CPU_AMDK6;
231 else if (model == 8)
232 cpu = CPU_AMDK6_2;
233 else if (model == 9)
234 cpu = CPU_AMDK6_III;
235 else if (model == 13) {
236 if (_CPU_getCPUIDStepping() <= 3)
237 cpu = CPU_AMDK6_IIIplus;
238 else
239 cpu = CPU_AMDK6_2plus;
240 }
241 else
242 cpu = CPU_UnkAMD;
243 break;
244 case 6:
245 if ((model = _CPU_getCPUIDModel()) == 3)
246 cpu = CPU_AMDDuron;
247 else
248 cpu = CPU_AMDAthlon;
249 break;
250 default:
251 cpu = CPU_UnkAMD;
252 break;
253 }
254 }
255 else if (vendor == CPU_IDT) {
256 /* Check for IDT WinChip processors */
257 switch (cpu & CPU_mask) {
258 case 5:
259 if ((model = _CPU_getCPUIDModel()) <= 4)
260 cpu = CPU_WinChipC6;
261 else if (model == 8)
262 cpu = CPU_WinChip2;
263 else
264 cpu = CPU_UnkIDT;
265 break;
266 case 6:
267 vendor = CPU_VIA;
268 if ((model = _CPU_getCPUIDModel()) <= 6)
269 cpu = CPU_ViaCyrixIII;
270 else
271 cpu = CPU_UnkVIA;
272 break;
273 default:
274 vendor = CPU_VIA;
275 cpu = CPU_UnkVIA;
276 break;
277 }
278 }
279 else {
280 /* Assume a Pentium compatible Intel clone */
281 cpu = CPU_Pentium;
282 }
283 return cpu | vendor | (_CPU_getCPUIDStepping() << CPU_steppingShift);
284 }
285 else {
286 if (_CPU_check80386())
287 cpu = CPU_i386;
288 else if (_CPU_check80486()) {
289 /* If we get here we may have a Cyrix processor so we can try
290 * enabling the CPUID instruction and trying again.
291 */
292 if (firstTime) {
293 firstTime = false;
294 _CPU_enableCyrixCPUID();
295 return CPU_getProcessorType();
296 }
297 cpu = CPU_i486;
298 }
299 else
300 cpu = CPU_Pentium;
301 if (!_CPU_checkClone())
302 return cpu | CPU_Intel;
303 return cpu;
304 }
305 #elif defined(__ALPHA__)
306 return CPU_Alpha;
307 #elif defined(__MIPS__)
308 return CPU_Mips;
309 #elif defined(__PPC__)
310 return CPU_PowerPC;
311 #endif
312 }
313
314 /****************************************************************************
315 DESCRIPTION:
316 Returns true if the processor supports Intel MMX extensions.
317
318 HEADER:
319 cpuinfo.h
320
321 RETURNS:
322 True if MMX is available, false if not.
323
324 REMARKS:
325 This function determines if the processor supports the Intel MMX extended
326 instruction set.
327
328 SEE ALSO:
329 CPU_getProcessorType, CPU_getProcessorSpeed, CPU_have3DNow, CPU_haveSSE,
330 CPU_getProcessorName
331 ****************************************************************************/
332 ibool ZAPI CPU_haveMMX(void)
333 {
334 #ifdef __INTEL__
335 if (_CPU_haveCPUID())
336 return (_CPU_getCPUIDFeatures() & CPU_HaveMMX) != 0;
337 return false;
338 #else
339 return false;
340 #endif
341 }
342
343 /****************************************************************************
344 DESCRIPTION:
345 Returns true if the processor supports AMD 3DNow! extensions.
346
347 HEADER:
348 cpuinfo.h
349
350 RETURNS:
351 True if 3DNow! is available, false if not.
352
353 REMARKS:
354 This function determines if the processor supports the AMD 3DNow! extended
355 instruction set.
356
357 SEE ALSO:
358 CPU_getProcessorType, CPU_getProcessorSpeed, CPU_haveMMX, CPU_haveSSE,
359 CPU_getProcessorName
360 ****************************************************************************/
361 ibool ZAPI CPU_have3DNow(void)
362 {
363 #ifdef __INTEL__
364 if (_CPU_haveCPUID())
365 return _CPU_have3DNow();
366 return false;
367 #else
368 return false;
369 #endif
370 }
371
372 /****************************************************************************
373 DESCRIPTION:
374 Returns true if the processor supports Intel SSE extensions.
375
376 HEADER:
377 cpuinfo.h
378
379 RETURNS:
380 True if Intel SSE is available, false if not.
381
382 REMARKS:
383 This function determines if the processor supports the Intel SSE extended
384 instruction set.
385
386 SEE ALSO:
387 CPU_getProcessorType, CPU_getProcessorSpeed, CPU_haveMMX, CPU_have3DNow,
388 CPU_getProcessorName
389 ****************************************************************************/
390 ibool ZAPI CPU_haveSSE(void)
391 {
392 #ifdef __INTEL__
393 if (_CPU_haveCPUID())
394 return (_CPU_getCPUIDFeatures() & CPU_HaveSSE) != 0;
395 return false;
396 #else
397 return false;
398 #endif
399 }
400
401 /****************************************************************************
402 RETURNS:
403 True if the RTSC instruction is available, false if not.
404
405 REMARKS:
406 This function determines if the processor supports the Intel RDTSC
407 instruction, for high precision timing. If the processor is not an Intel or
408 Intel clone CPU, this function will always return false.
409
410 DESCRIPTION:
411 Returns true if the processor supports RDTSC extensions.
412
413 HEADER:
414 cpuinfo.h
415
416 RETURNS:
417 True if RTSC is available, false if not.
418
419 REMARKS:
420 This function determines if the processor supports the RDTSC instruction
421 for reading the processor time stamp counter.
422
423 SEE ALSO:
424 CPU_getProcessorType, CPU_getProcessorSpeed, CPU_haveMMX, CPU_have3DNow,
425 CPU_getProcessorName
426 ****************************************************************************/
427 ibool ZAPI CPU_haveRDTSC(void)
428 {
429 #ifdef __INTEL__
430 if (_CPU_haveCPUID())
431 return (_CPU_getCPUIDFeatures() & CPU_HaveRDTSC) != 0;
432 return false;
433 #else
434 return false;
435 #endif
436 }