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