1 ;****************************************************************************
3 ;* SciTech OS Portability Manager Library
5 ;* ========================================================================
7 ;* The contents of this file are subject to the SciTech MGL Public
8 ;* License Version 1.0 (the "License"); you may not use this file
9 ;* except in compliance with the License. You may obtain a copy of
10 ;* the License at http://www.scitechsoft.com/mgl-license.txt
12 ;* Software distributed under the License is distributed on an
13 ;* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 ;* implied. See the License for the specific language governing
15 ;* rights and limitations under the License.
17 ;* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
19 ;* The Initial Developer of the Original Code is SciTech Software, Inc.
20 ;* All Rights Reserved.
22 ;* ========================================================================
24 ;* Language: NASM or TASM Assembler
25 ;* Environment: Intel 32 bit Protected Mode.
27 ;* Description: Code to determine the Intel processor type.
29 ;****************************************************************************
37 begdataseg _cpuinfo ; Start of data segment
39 cache_id db "01234567890123456"
40 intel_id db "GenuineIntel" ; Intel vendor ID
41 cyrix_id db "CyrixInstead" ; Cyrix vendor ID
42 amd_id db "AuthenticAMD" ; AMD vendor ID
43 idt_id db "CentaurHauls" ; IDT vendor ID
45 CPU_IDT EQU 01000h ; Flag for IDT processors
46 CPU_Cyrix EQU 02000h ; Flag for Cyrix processors
47 CPU_AMD EQU 04000h ; Flag for AMD processors
48 CPU_Intel EQU 08000h ; Flag for Intel processors
52 begcodeseg _cpuinfo ; Start of code segment
74 ;----------------------------------------------------------------------------
75 ; bool _CPU_check80386(void)
76 ;----------------------------------------------------------------------------
77 ; Determines if we have an i386 processor.
78 ;----------------------------------------------------------------------------
79 cprocstart _CPU_check80386
83 xor edx,edx ; EDX = 0, not an 80386
90 pushfd ; Push original EFLAGS
91 pop eax ; Get original EFLAGS
92 mov ecx, eax ; Save original EFLAGS
93 xor eax, 40000h ; Flip AC bit in EFLAGS
94 push eax ; Save new EFLAGS value on
96 popfd ; Replace current EFLAGS value
97 pushfd ; Get new EFLAGS
98 pop eax ; Store new EFLAGS in EAX
99 xor eax, ecx ; Can't toggle AC bit,
101 jnz @@Done ; Jump if not an 80386 processor
102 inc edx ; We have an 80386
113 ;----------------------------------------------------------------------------
114 ; bool _CPU_check80486(void)
115 ;----------------------------------------------------------------------------
116 ; Determines if we have an i486 processor.
117 ;----------------------------------------------------------------------------
118 cprocstart _CPU_check80486
122 ; Distinguish between the i486 and Pentium by the ability to set the ID flag
123 ; in the EFLAGS register. If the ID flag is set, then we can use the CPUID
124 ; instruction to determine the final version of the chip. Otherwise we
125 ; simply have an 80486.
127 ; Distinguish between the i486 and Pentium by the ability to set the ID flag
128 ; in the EFLAGS register. If the ID flag is set, then we can use the CPUID
129 ; instruction to determine the final version of the chip. Otherwise we
130 ; simply have an 80486.
132 pushfd ; Get original EFLAGS
135 xor eax, 200000h ; Flip ID bit in EFLAGS
136 push eax ; Save new EFLAGS value on stack
137 popfd ; Replace current EFLAGS value
138 pushfd ; Get new EFLAGS
139 pop eax ; Store new EFLAGS in EAX
140 xor eax, ecx ; Can not toggle ID bit,
141 jnz @@1 ; Processor=80486
142 mov eax,1 ; We dont have a Pentium
144 @@1: mov eax,0 ; We have Pentium or later
150 ;----------------------------------------------------------------------------
151 ; bool _CPU_checkClone(void)
152 ;----------------------------------------------------------------------------
153 ; Checks if the i386 or i486 processor is a clone or genuine Intel.
154 ;----------------------------------------------------------------------------
155 cprocstart _CPU_checkClone
159 mov ax,5555h ; Check to make sure this is a 32-bit processor
162 div cx ; Perform Division
170 pop eax ; Get the flags
172 xor eax,1 ; EAX=0 is probably Intel, EAX=1 is a Clone
179 ;----------------------------------------------------------------------------
180 ; bool _CPU_haveCPUID(void)
181 ;----------------------------------------------------------------------------
182 ; Determines if we have support for the CPUID instruction.
183 ;----------------------------------------------------------------------------
184 cprocstart _CPU_haveCPUID
189 pushfd ; Get original EFLAGS
192 xor eax, 200000h ; Flip ID bit in EFLAGS
193 push eax ; Save new EFLAGS value on stack
194 popfd ; Replace current EFLAGS value
195 pushfd ; Get new EFLAGS
196 pop eax ; Store new EFLAGS in EAX
197 xor eax, ecx ; Can not toggle ID bit,
198 jnz @@1 ; Processor=80486
199 mov eax,0 ; We dont have CPUID support
201 @@1: mov eax,1 ; We have CPUID support
203 mov eax,0 ; CPUID requires 32-bit pmode
210 ;----------------------------------------------------------------------------
211 ; uint _CPU_checkCPUID(void)
212 ;----------------------------------------------------------------------------
213 ; Determines the CPU type using the CPUID instruction.
214 ;----------------------------------------------------------------------------
215 cprocstart _CPU_checkCPUID
219 xor eax, eax ; Set up for CPUID instruction
220 mCPU_ID ; Get and save vendor ID
221 cmp eax, 1 ; Make sure 1 is valid input for CPUID
222 jl @@Fail ; We dont have the CPUID instruction
223 xor eax,eax ; Assume vendor is unknown
225 ; Check for GenuineIntel processors
230 cmp [DWORD esi+4], edx
232 cmp [DWORD esi+8], ecx
234 mov eax,CPU_Intel ; Flag that we have GenuineIntel
237 ; Check for CyrixInstead processors
243 cmp [DWORD esi+4], edx
245 cmp [DWORD esi+8], ecx
247 mov eax,CPU_Cyrix ; Flag that we have CyrixInstead
250 ; Check for AuthenticAMD processors
256 cmp [DWORD esi+4], edx
258 cmp [DWORD esi+8], ecx
260 mov eax,CPU_AMD ; Flag that we have AuthenticAMD
263 ; Check for CentaurHauls processors
269 cmp [DWORD esi+4], edx
271 cmp [DWORD esi+8], ecx
273 mov eax,CPU_IDT ; Flag that we have AuthenticIDT
282 mCPU_ID ; Get family/model/stepping/features
284 shr eax, 8 ; Isolate family
287 or eax,ecx ; Combine in the clone flag
296 ;----------------------------------------------------------------------------
297 ; uint _CPU_getCPUIDModel(void)
298 ;----------------------------------------------------------------------------
299 ; Determines the CPU type using the CPUID instruction.
300 ;----------------------------------------------------------------------------
301 cprocstart _CPU_getCPUIDModel
305 xor eax, eax ; Set up for CPUID instruction
306 mCPU_ID ; Get and save vendor ID
307 cmp eax, 1 ; Make sure 1 is valid input for CPUID
308 jl @@Fail ; We dont have the CPUID instruction
311 mCPU_ID ; Get family/model/stepping/features
313 shr eax, 4 ; Isolate model
322 ;----------------------------------------------------------------------------
323 ; uint _CPU_getCPUIDStepping(void)
324 ;----------------------------------------------------------------------------
325 ; Determines the CPU type using the CPUID instruction.
326 ;----------------------------------------------------------------------------
327 cprocstart _CPU_getCPUIDStepping
331 xor eax, eax ; Set up for CPUID instruction
332 mCPU_ID ; Get and save vendor ID
333 cmp eax, 1 ; Make sure 1 is valid input for CPUID
334 jl @@Fail ; We dont have the CPUID instruction
337 mCPU_ID ; Get family/model/stepping/features
338 and eax, 00Fh ; Isolate stepping
347 ;----------------------------------------------------------------------------
348 ; uint _CPU_getCPUIDFeatures(void)
349 ;----------------------------------------------------------------------------
350 ; Determines the CPU type using the CPUID instruction.
351 ;----------------------------------------------------------------------------
352 cprocstart _CPU_getCPUIDFeatures
356 xor eax, eax ; Set up for CPUID instruction
357 mCPU_ID ; Get and save vendor ID
358 cmp eax, 1 ; Make sure 1 is valid input for CPUID
359 jl @@Fail ; We dont have the CPUID instruction
362 mCPU_ID ; Get family/model/stepping/features
372 ;----------------------------------------------------------------------------
373 ; uint _CPU_getCacheSize(void)
374 ;----------------------------------------------------------------------------
375 ; Determines the CPU cache size for Intel processors
376 ;----------------------------------------------------------------------------
377 cprocstart _CPU_getCacheSize
380 xor eax, eax ; Set up for CPUID instruction
381 mCPU_ID ; Get and save vendor ID
382 cmp eax,2 ; Make sure 2 is valid input for CPUID
383 jl @@Fail ; We dont have the CPUID instruction
385 mCPU_ID ; Get cache descriptors
386 LEA_L esi,cache_id ; Get address of cache ID (-fPIC aware)
393 LEA_L esi,cache_id ; Get address of cache ID (-fPIC aware)
423 ;----------------------------------------------------------------------------
424 ; uint _CPU_have3DNow(void)
425 ;----------------------------------------------------------------------------
426 ; Determines the CPU type using the CPUID instruction.
427 ;----------------------------------------------------------------------------
428 cprocstart _CPU_have3DNow
432 mov eax,80000000h ; Query for extended functions
433 mCPU_ID ; Get extended function limit
435 jbe @@Fail ; Nope, we dont have function 800000001h
436 mov eax,80000001h ; Setup extended function 800000001h
437 mCPU_ID ; and get the information
438 test edx,80000000h ; Bit 31 is set if 3DNow! present
439 jz @@Fail ; Nope, we dont have 3DNow support
440 mov eax,1 ; Yep, we have 3DNow! support!
449 ;----------------------------------------------------------------------------
450 ; ulong _CPU_quickRDTSC(void)
451 ;----------------------------------------------------------------------------
452 ; Reads the time stamp counter and returns the low order 32-bits
453 ;----------------------------------------------------------------------------
454 cprocstart _CPU_quickRDTSC
461 ;----------------------------------------------------------------------------
462 ; void _CPU_runBSFLoop(ulong interations)
463 ;----------------------------------------------------------------------------
464 ; Runs a loop of BSF instructions for the specified number of iterations
465 ;----------------------------------------------------------------------------
466 cprocstart _CPU_runBSFLoop
490 ;----------------------------------------------------------------------------
491 ; void _CPU_readTimeStamp(CPU_largeInteger *time);
492 ;----------------------------------------------------------------------------
493 ; Reads the time stamp counter and returns the 64-bit result.
494 ;----------------------------------------------------------------------------
495 cprocstart _CPU_readTimeStamp
498 mov ecx,[esp+4] ; Access directly without stack frame
505 ;----------------------------------------------------------------------------
506 ; ulong _CPU_diffTime64(CPU_largeInteger *t1,CPU_largeInteger *t2,CPU_largeInteger *t)
507 ;----------------------------------------------------------------------------
508 ; Computes the difference between two 64-bit numbers.
509 ;----------------------------------------------------------------------------
510 cprocstart _CPU_diffTime64
512 ARG t1:DPTR, t2:DPTR, t:DPTR
517 mov eax,[ecx] ; EAX := t2.low
520 mov edx,eax ; EDX := low difference
522 mov eax,[ecx+4] ; ECX := t2.high
524 sbb eax,[ecx+4] ; EAX := high difference
526 mov ebx,[t] ; Store the result
527 mov [ebx],edx ; Store low part
528 mov [ebx+4],eax ; Store high part
529 mov eax,edx ; Return low part
531 shld edx,eax,16 ; Return in DX:AX
538 ;----------------------------------------------------------------------------
539 ; ulong _CPU_calcMicroSec(CPU_largeInteger *count,ulong freq);
540 ;----------------------------------------------------------------------------
541 ; Computes the value in microseconds for the elapsed time with maximum
542 ; precision. The formula we use is:
544 ; us = (((diff * 0x100000) / freq) * 1000000) / 0x100000)
546 ; The power of two multiple before the first divide allows us to scale the
547 ; 64-bit difference using simple shifts, and then the divide brings the
548 ; final result into the range to fit into a 32-bit integer.
549 ;----------------------------------------------------------------------------
550 cprocstart _CPU_calcMicroSec
552 ARG count:DPTR, freq:ULONG
557 mov eax,[ecx] ; EAX := low part
558 mov edx,[ecx+4] ; EDX := high part
560 shl eax,20 ; diff * 0x100000
561 div [DWORD freq] ; (diff * 0x100000) / freq
564 mul ecx ; ((diff * 0x100000) / freq) * 1000000)
565 shrd eax,edx,20 ; ((diff * 0x100000) / freq) * 1000000) / 0x100000
567 shld edx,eax,16 ; Return in DX:AX
574 ;----------------------------------------------------------------------------
575 ; ulong _CPU_mulDiv(ulong a,ulong b,ulong c);
576 ;----------------------------------------------------------------------------
577 ; Computes the following with 64-bit integer precision:
579 ; result = (a * b) / c
581 ;----------------------------------------------------------------------------
582 cprocstart _CPU_mulDiv
584 ARG a:ULONG, b:ULONG, c:ULONG
591 shld edx,eax,16 ; Return in DX:AX