Mercurial > sdl-ios-xcode
comparison src/cpuinfo/_cpuinfo.asm @ 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: NASM | |
32 ;* Environment: Intel 32 bit Protected Mode. | |
33 ;* | |
34 ;* Description: Code to determine the Intel processor type. | |
35 ;* | |
36 ;**************************************************************************** | |
37 | |
38 include "scitech.mac" | |
39 | |
40 header _cpuinfo | |
41 | |
42 begdataseg _cpuinfo ; Start of data segment | |
43 | |
44 cache_id db "01234567890123456" | |
45 intel_id db "GenuineIntel" ; Intel vendor ID | |
46 cyrix_id db "CyrixInstead" ; Cyrix vendor ID | |
47 amd_id db "AuthenticAMD" ; AMD vendor ID | |
48 idt_id db "CentaurHauls" ; IDT vendor ID | |
49 | |
50 CPU_IDT EQU 01000h ; Flag for IDT processors | |
51 CPU_Cyrix EQU 02000h ; Flag for Cyrix processors | |
52 CPU_AMD EQU 04000h ; Flag for AMD processors | |
53 CPU_Intel EQU 08000h ; Flag for Intel processors | |
54 | |
55 enddataseg _cpuinfo | |
56 | |
57 begcodeseg _cpuinfo ; Start of code segment | |
58 | |
59 %macro mCPU_ID 0 | |
60 db 00Fh,0A2h | |
61 %endmacro | |
62 | |
63 %macro mRDTSC 0 | |
64 db 00Fh,031h | |
65 %endmacro | |
66 | |
67 ;---------------------------------------------------------------------------- | |
68 ; bool _CPU_check80386(void) | |
69 ;---------------------------------------------------------------------------- | |
70 ; Determines if we have an i386 processor. | |
71 ;---------------------------------------------------------------------------- | |
72 cprocstart _CPU_check80386 | |
73 | |
74 enter_c | |
75 | |
76 xor edx,edx ; EDX = 0, not an 80386 | |
77 mov bx, sp | |
78 and sp, ~3 | |
79 pushfd ; Push original EFLAGS | |
80 pop eax ; Get original EFLAGS | |
81 mov ecx, eax ; Save original EFLAGS | |
82 xor eax, 40000h ; Flip AC bit in EFLAGS | |
83 push eax ; Save new EFLAGS value on | |
84 ; stack | |
85 popfd ; Replace current EFLAGS value | |
86 pushfd ; Get new EFLAGS | |
87 pop eax ; Store new EFLAGS in EAX | |
88 xor eax, ecx ; Can't toggle AC bit, | |
89 ; processor=80386 | |
90 jnz @@Done ; Jump if not an 80386 processor | |
91 inc edx ; We have an 80386 | |
92 | |
93 @@Done: push ecx | |
94 popfd | |
95 mov sp, bx | |
96 mov eax, edx | |
97 leave_c | |
98 ret | |
99 | |
100 cprocend | |
101 | |
102 ;---------------------------------------------------------------------------- | |
103 ; bool _CPU_check80486(void) | |
104 ;---------------------------------------------------------------------------- | |
105 ; Determines if we have an i486 processor. | |
106 ;---------------------------------------------------------------------------- | |
107 cprocstart _CPU_check80486 | |
108 | |
109 enter_c | |
110 | |
111 ; Distinguish between the i486 and Pentium by the ability to set the ID flag | |
112 ; in the EFLAGS register. If the ID flag is set, then we can use the CPUID | |
113 ; instruction to determine the final version of the chip. Otherwise we | |
114 ; simply have an 80486. | |
115 | |
116 ; Distinguish between the i486 and Pentium by the ability to set the ID flag | |
117 ; in the EFLAGS register. If the ID flag is set, then we can use the CPUID | |
118 ; instruction to determine the final version of the chip. Otherwise we | |
119 ; simply have an 80486. | |
120 | |
121 pushfd ; Get original EFLAGS | |
122 pop eax | |
123 mov ecx, eax | |
124 xor eax, 200000h ; Flip ID bit in EFLAGS | |
125 push eax ; Save new EFLAGS value on stack | |
126 popfd ; Replace current EFLAGS value | |
127 pushfd ; Get new EFLAGS | |
128 pop eax ; Store new EFLAGS in EAX | |
129 xor eax, ecx ; Can not toggle ID bit, | |
130 jnz @@1 ; Processor=80486 | |
131 mov eax,1 ; We dont have a Pentium | |
132 jmp @@Done | |
133 @@1: mov eax,0 ; We have Pentium or later | |
134 @@Done: leave_c | |
135 ret | |
136 | |
137 cprocend | |
138 | |
139 ;---------------------------------------------------------------------------- | |
140 ; bool _CPU_checkClone(void) | |
141 ;---------------------------------------------------------------------------- | |
142 ; Checks if the i386 or i486 processor is a clone or genuine Intel. | |
143 ;---------------------------------------------------------------------------- | |
144 cprocstart _CPU_checkClone | |
145 | |
146 enter_c | |
147 | |
148 mov ax,5555h ; Check to make sure this is a 32-bit processor | |
149 xor dx,dx | |
150 mov cx,2h | |
151 div cx ; Perform Division | |
152 clc | |
153 jnz @@NoClone | |
154 jmp @@Clone | |
155 @@NoClone: | |
156 stc | |
157 @@Clone: | |
158 pushfd | |
159 pop eax ; Get the flags | |
160 and eax,1 | |
161 xor eax,1 ; EAX=0 is probably Intel, EAX=1 is a Clone | |
162 | |
163 leave_c | |
164 ret | |
165 | |
166 cprocend | |
167 | |
168 ;---------------------------------------------------------------------------- | |
169 ; bool _CPU_haveCPUID(void) | |
170 ;---------------------------------------------------------------------------- | |
171 ; Determines if we have support for the CPUID instruction. | |
172 ;---------------------------------------------------------------------------- | |
173 cprocstart _CPU_haveCPUID | |
174 | |
175 enter_c | |
176 | |
177 ifdef flatmodel | |
178 pushfd ; Get original EFLAGS | |
179 pop eax | |
180 mov ecx, eax | |
181 xor eax, 200000h ; Flip ID bit in EFLAGS | |
182 push eax ; Save new EFLAGS value on stack | |
183 popfd ; Replace current EFLAGS value | |
184 pushfd ; Get new EFLAGS | |
185 pop eax ; Store new EFLAGS in EAX | |
186 xor eax, ecx ; Can not toggle ID bit, | |
187 jnz @@1 ; Processor=80486 | |
188 mov eax,0 ; We dont have CPUID support | |
189 jmp @@Done | |
190 @@1: mov eax,1 ; We have CPUID support | |
191 else | |
192 mov eax,0 ; CPUID requires 32-bit pmode | |
193 endif | |
194 @@Done: leave_c | |
195 ret | |
196 | |
197 cprocend | |
198 | |
199 ;---------------------------------------------------------------------------- | |
200 ; uint _CPU_checkCPUID(void) | |
201 ;---------------------------------------------------------------------------- | |
202 ; Determines the CPU type using the CPUID instruction. | |
203 ;---------------------------------------------------------------------------- | |
204 cprocstart _CPU_checkCPUID | |
205 | |
206 enter_c | |
207 | |
208 xor eax, eax ; Set up for CPUID instruction | |
209 mCPU_ID ; Get and save vendor ID | |
210 cmp eax, 1 ; Make sure 1 is valid input for CPUID | |
211 jl @@Fail ; We dont have the CPUID instruction | |
212 xor eax,eax ; Assume vendor is unknown | |
213 | |
214 ; Check for GenuineIntel processors | |
215 | |
216 LEA_L esi,intel_id | |
217 cmp [DWORD esi], ebx | |
218 jne @@NotIntel | |
219 cmp [DWORD esi+4], edx | |
220 jne @@NotIntel | |
221 cmp [DWORD esi+8], ecx | |
222 jne @@NotIntel | |
223 mov eax,CPU_Intel ; Flag that we have GenuineIntel | |
224 jmp @@FoundVendor | |
225 | |
226 ; Check for CyrixInstead processors | |
227 | |
228 @@NotIntel: | |
229 LEA_L esi,cyrix_id | |
230 cmp [DWORD esi], ebx | |
231 jne @@NotCyrix | |
232 cmp [DWORD esi+4], edx | |
233 jne @@NotCyrix | |
234 cmp [DWORD esi+8], ecx | |
235 jne @@NotCyrix | |
236 mov eax,CPU_Cyrix ; Flag that we have CyrixInstead | |
237 jmp @@FoundVendor | |
238 | |
239 ; Check for AuthenticAMD processors | |
240 | |
241 @@NotCyrix: | |
242 LEA_L esi,amd_id | |
243 cmp [DWORD esi], ebx | |
244 jne @@NotAMD | |
245 cmp [DWORD esi+4], edx | |
246 jne @@NotAMD | |
247 cmp [DWORD esi+8], ecx | |
248 jne @@NotAMD | |
249 mov eax,CPU_AMD ; Flag that we have AuthenticAMD | |
250 jmp @@FoundVendor | |
251 | |
252 ; Check for CentaurHauls processors | |
253 | |
254 @@NotAMD: | |
255 LEA_L esi,idt_id | |
256 cmp [DWORD esi], ebx | |
257 jne @@NotIDT | |
258 cmp [DWORD esi+4], edx | |
259 jne @@NotIDT | |
260 cmp [DWORD esi+8], ecx | |
261 jne @@NotIDT | |
262 mov eax,CPU_IDT ; Flag that we have AuthenticIDT | |
263 jmp @@FoundVendor | |
264 | |
265 @@NotIDT: | |
266 | |
267 @@FoundVendor: | |
268 push eax | |
269 xor eax, eax | |
270 inc eax | |
271 mCPU_ID ; Get family/model/stepping/features | |
272 and eax, 0F00h | |
273 shr eax, 8 ; Isolate CPU family | |
274 and eax, 0Fh | |
275 cmp eax, 0Fh ; Check for Pentium 4 which is an 0Fh! | |
276 jne @@NotP4 | |
277 mov eax, 07h ; Change P4 ID to 7 for consistency | |
278 @@NotP4: | |
279 pop ecx | |
280 or eax,ecx ; Combine in the CPU vendor flag | |
281 @@Done: leave_c | |
282 ret | |
283 | |
284 @@Fail: xor eax,eax | |
285 jmp @@Done | |
286 | |
287 cprocend | |
288 | |
289 ;---------------------------------------------------------------------------- | |
290 ; uint _CPU_getCPUIDModel(void) | |
291 ;---------------------------------------------------------------------------- | |
292 ; Determines the CPU type using the CPUID instruction. | |
293 ;---------------------------------------------------------------------------- | |
294 cprocstart _CPU_getCPUIDModel | |
295 | |
296 enter_c | |
297 | |
298 xor eax, eax ; Set up for CPUID instruction | |
299 mCPU_ID ; Get and save vendor ID | |
300 cmp eax, 1 ; Make sure 1 is valid input for CPUID | |
301 jl @@Fail ; We dont have the CPUID instruction | |
302 xor eax, eax | |
303 inc eax | |
304 mCPU_ID ; Get family/model/stepping/features | |
305 and eax, 0F0h | |
306 shr eax, 4 ; Isolate model | |
307 @@Done: leave_c | |
308 ret | |
309 | |
310 @@Fail: xor eax,eax | |
311 jmp @@Done | |
312 | |
313 cprocend | |
314 | |
315 ;---------------------------------------------------------------------------- | |
316 ; uint _CPU_getCPUIDStepping(void) | |
317 ;---------------------------------------------------------------------------- | |
318 ; Determines the CPU type using the CPUID instruction. | |
319 ;---------------------------------------------------------------------------- | |
320 cprocstart _CPU_getCPUIDStepping | |
321 | |
322 enter_c | |
323 | |
324 xor eax, eax ; Set up for CPUID instruction | |
325 mCPU_ID ; Get and save vendor ID | |
326 cmp eax, 1 ; Make sure 1 is valid input for CPUID | |
327 jl @@Fail ; We dont have the CPUID instruction | |
328 xor eax, eax | |
329 inc eax | |
330 mCPU_ID ; Get family/model/stepping/features | |
331 and eax, 00Fh ; Isolate stepping | |
332 @@Done: leave_c | |
333 ret | |
334 | |
335 @@Fail: xor eax,eax | |
336 jmp @@Done | |
337 | |
338 cprocend | |
339 | |
340 ;---------------------------------------------------------------------------- | |
341 ; uint _CPU_getCPUIDFeatures(void) | |
342 ;---------------------------------------------------------------------------- | |
343 ; Determines the CPU type using the CPUID instruction. | |
344 ;---------------------------------------------------------------------------- | |
345 cprocstart _CPU_getCPUIDFeatures | |
346 | |
347 enter_c | |
348 | |
349 xor eax, eax ; Set up for CPUID instruction | |
350 mCPU_ID ; Get and save vendor ID | |
351 cmp eax, 1 ; Make sure 1 is valid input for CPUID | |
352 jl @@Fail ; We dont have the CPUID instruction | |
353 xor eax, eax | |
354 inc eax | |
355 mCPU_ID ; Get family/model/stepping/features | |
356 mov eax, edx | |
357 @@Done: leave_c | |
358 ret | |
359 | |
360 @@Fail: xor eax,eax | |
361 jmp @@Done | |
362 | |
363 cprocend | |
364 | |
365 ;---------------------------------------------------------------------------- | |
366 ; uint _CPU_getCacheSize(void) | |
367 ;---------------------------------------------------------------------------- | |
368 ; Determines the CPU cache size for Intel processors | |
369 ;---------------------------------------------------------------------------- | |
370 cprocstart _CPU_getCacheSize | |
371 | |
372 enter_c | |
373 xor eax, eax ; Set up for CPUID instruction | |
374 mCPU_ID ; Get and save vendor ID | |
375 cmp eax,2 ; Make sure 2 is valid input for CPUID | |
376 jl @@Fail ; We dont have the CPUID instruction | |
377 mov eax,2 | |
378 mCPU_ID ; Get cache descriptors | |
379 LEA_L esi,cache_id ; Get address of cache ID (-fPIC aware) | |
380 shr eax,8 | |
381 mov [esi+0],eax | |
382 mov [esi+3],ebx | |
383 mov [esi+7],ecx | |
384 mov [esi+11],edx | |
385 xor eax,eax | |
386 LEA_L esi,cache_id ; Get address of cache ID (-fPIC aware) | |
387 mov edi,15 | |
388 @@ScanLoop: | |
389 cmp [BYTE esi],41h | |
390 mov eax,128 | |
391 je @@Done | |
392 cmp [BYTE esi],42h | |
393 mov eax,256 | |
394 je @@Done | |
395 cmp [BYTE esi],43h | |
396 mov eax,512 | |
397 je @@Done | |
398 cmp [BYTE esi],44h | |
399 mov eax,1024 | |
400 je @@Done | |
401 cmp [BYTE esi],45h | |
402 mov eax,2048 | |
403 je @@Done | |
404 inc esi | |
405 dec edi | |
406 jnz @@ScanLoop | |
407 | |
408 @@Done: leave_c | |
409 ret | |
410 | |
411 @@Fail: xor eax,eax | |
412 jmp @@Done | |
413 | |
414 cprocend | |
415 | |
416 ;---------------------------------------------------------------------------- | |
417 ; uint _CPU_have3DNow(void) | |
418 ;---------------------------------------------------------------------------- | |
419 ; Determines the CPU type using the CPUID instruction. | |
420 ;---------------------------------------------------------------------------- | |
421 cprocstart _CPU_have3DNow | |
422 | |
423 enter_c | |
424 | |
425 mov eax,80000000h ; Query for extended functions | |
426 mCPU_ID ; Get extended function limit | |
427 cmp eax,80000001h | |
428 jbe @@Fail ; Nope, we dont have function 800000001h | |
429 mov eax,80000001h ; Setup extended function 800000001h | |
430 mCPU_ID ; and get the information | |
431 test edx,80000000h ; Bit 31 is set if 3DNow! present | |
432 jz @@Fail ; Nope, we dont have 3DNow support | |
433 mov eax,1 ; Yep, we have 3DNow! support! | |
434 @@Done: leave_c | |
435 ret | |
436 | |
437 @@Fail: xor eax,eax | |
438 jmp @@Done | |
439 | |
440 cprocend | |
441 | |
442 ;---------------------------------------------------------------------------- | |
443 ; ulong _CPU_quickRDTSC(void) | |
444 ;---------------------------------------------------------------------------- | |
445 ; Reads the time stamp counter and returns the low order 32-bits | |
446 ;---------------------------------------------------------------------------- | |
447 cprocstart _CPU_quickRDTSC | |
448 | |
449 mRDTSC | |
450 ret | |
451 | |
452 cprocend | |
453 | |
454 ;---------------------------------------------------------------------------- | |
455 ; void _CPU_runBSFLoop(ulong interations) | |
456 ;---------------------------------------------------------------------------- | |
457 ; Runs a loop of BSF instructions for the specified number of iterations | |
458 ;---------------------------------------------------------------------------- | |
459 cprocstart _CPU_runBSFLoop | |
460 | |
461 ARG iterations:ULONG | |
462 | |
463 push _bp | |
464 mov _bp,_sp | |
465 push _bx | |
466 | |
467 mov edx,[iterations] | |
468 mov eax,80000000h | |
469 mov ebx,edx | |
470 | |
471 ALIGN 4 | |
472 | |
473 @@loop: bsf ecx,eax | |
474 dec ebx | |
475 jnz @@loop | |
476 | |
477 pop _bx | |
478 pop _bp | |
479 ret | |
480 | |
481 cprocend | |
482 | |
483 ;---------------------------------------------------------------------------- | |
484 ; void _CPU_readTimeStamp(CPU_largeInteger *time); | |
485 ;---------------------------------------------------------------------------- | |
486 ; Reads the time stamp counter and returns the 64-bit result. | |
487 ;---------------------------------------------------------------------------- | |
488 cprocstart _CPU_readTimeStamp | |
489 | |
490 mRDTSC | |
491 mov ecx,[esp+4] ; Access directly without stack frame | |
492 mov [ecx],eax | |
493 mov [ecx+4],edx | |
494 ret | |
495 | |
496 cprocend | |
497 | |
498 ;---------------------------------------------------------------------------- | |
499 ; ulong _CPU_diffTime64(CPU_largeInteger *t1,CPU_largeInteger *t2,CPU_largeInteger *t) | |
500 ;---------------------------------------------------------------------------- | |
501 ; Computes the difference between two 64-bit numbers. | |
502 ;---------------------------------------------------------------------------- | |
503 cprocstart _CPU_diffTime64 | |
504 | |
505 ARG t1:DPTR, t2:DPTR, t:DPTR | |
506 | |
507 enter_c | |
508 | |
509 mov ecx,[t2] | |
510 mov eax,[ecx] ; EAX := t2.low | |
511 mov ecx,[t1] | |
512 sub eax,[ecx] | |
513 mov edx,eax ; EDX := low difference | |
514 mov ecx,[t2] | |
515 mov eax,[ecx+4] ; ECX := t2.high | |
516 mov ecx,[t1] | |
517 sbb eax,[ecx+4] ; EAX := high difference | |
518 | |
519 mov ebx,[t] ; Store the result | |
520 mov [ebx],edx ; Store low part | |
521 mov [ebx+4],eax ; Store high part | |
522 mov eax,edx ; Return low part | |
523 ifndef flatmodel | |
524 shld edx,eax,16 ; Return in DX:AX | |
525 endif | |
526 leave_c | |
527 ret | |
528 | |
529 cprocend | |
530 | |
531 ;---------------------------------------------------------------------------- | |
532 ; ulong _CPU_calcMicroSec(CPU_largeInteger *count,ulong freq); | |
533 ;---------------------------------------------------------------------------- | |
534 ; Computes the value in microseconds for the elapsed time with maximum | |
535 ; precision. The formula we use is: | |
536 ; | |
537 ; us = (((diff * 0x100000) / freq) * 1000000) / 0x100000) | |
538 ; | |
539 ; The power of two multiple before the first divide allows us to scale the | |
540 ; 64-bit difference using simple shifts, and then the divide brings the | |
541 ; final result into the range to fit into a 32-bit integer. | |
542 ;---------------------------------------------------------------------------- | |
543 cprocstart _CPU_calcMicroSec | |
544 | |
545 ARG count:DPTR, freq:ULONG | |
546 | |
547 enter_c | |
548 | |
549 mov ecx,[count] | |
550 mov eax,[ecx] ; EAX := low part | |
551 mov edx,[ecx+4] ; EDX := high part | |
552 shld edx,eax,20 | |
553 shl eax,20 ; diff * 0x100000 | |
554 div [DWORD freq] ; (diff * 0x100000) / freq | |
555 mov ecx,1000000 | |
556 xor edx,edx | |
557 mul ecx ; ((diff * 0x100000) / freq) * 1000000) | |
558 shrd eax,edx,20 ; ((diff * 0x100000) / freq) * 1000000) / 0x100000 | |
559 ifndef flatmodel | |
560 shld edx,eax,16 ; Return in DX:AX | |
561 endif | |
562 leave_c | |
563 ret | |
564 | |
565 cprocend | |
566 | |
567 ;---------------------------------------------------------------------------- | |
568 ; ulong _CPU_mulDiv(ulong a,ulong b,ulong c); | |
569 ;---------------------------------------------------------------------------- | |
570 ; Computes the following with 64-bit integer precision: | |
571 ; | |
572 ; result = (a * b) / c | |
573 ; | |
574 ;---------------------------------------------------------------------------- | |
575 cprocstart _CPU_mulDiv | |
576 | |
577 ARG a:ULONG, b:ULONG, c:ULONG | |
578 | |
579 enter_c | |
580 mov eax,[a] | |
581 imul [ULONG b] | |
582 idiv [ULONG c] | |
583 ifndef flatmodel | |
584 shld edx,eax,16 ; Return in DX:AX | |
585 endif | |
586 leave_c | |
587 ret | |
588 | |
589 cprocend | |
590 | |
591 ;---------------------------------------------------------------------------- | |
592 ; int PM_getIOPL(void) | |
593 ;---------------------------------------------------------------------------- | |
594 ; Returns current IOPL, callable from any ring, any OS, any day of the week | |
595 ; (as long as it's 386 compatible). Sort of CPU information too. | |
596 ;---------------------------------------------------------------------------- | |
597 cprocstart PM_getIOPL | |
598 | |
599 pushfd | |
600 pop eax | |
601 and eax,0011000000000000b | |
602 shr eax,12 | |
603 ret | |
604 | |
605 cprocend | |
606 | |
607 | |
608 endcodeseg _cpuinfo | |
609 | |
610 END | |
611 |