📄 cpu_type.ash
字号:
; ----------------------------------------------------------------------------
; CPU_TYPE.ASH Too-Much-In-One-So-Don't-Get-Lost(tm)
; CPU/FPU feature detection library Version 1.17
;
; Copyright(c) 1992-95 by B-coolWare. Written by Bobby Z.
; Portions copyright(c) 1990 by 2B Programmers
; Portions copyright(c) 1994,95 by Lautenaus
; ----------------------------------------------------------------------------
; Uses:
; UNIDEF.INC universal macros and defines
; LSTRING.ASH Lstring macro
; DOSINOUT.ASH WriteStr routine
; SPEED.ASH CPU MHz computation routine
ifndef __INC__
INCLUDE UNIDEF.INC
endif
ifndef __WriteStr__
__WriteStr = 1
INCLUDE DOSINOUT.ASH
endif
ifndef __Lstring__
INCLUDE LSTRING.ASH
endif
INCLUDE SPEED.ASH
NOMASM51
EF_AC equ 00040000h ; AC bit in EFLAGS register
EF_ID equ 00200000h ; ID bit in EFLAGS register
MSW_ET equ 00000010h ; ET bit in MSW register
MSW_NE equ 00000020h ; NE bit in MSW register
; following constants are returned in AX by CPU_Type routine
cpu8088 equ 0000h ; 8088
cpu8086 equ 0001h ; 8086
cpuNECV20 equ 0002h ; NEC V20
cpuNECV30 equ 0003h ; NEC V30
cpu80188 equ 0004h ; 188
cpu80186 equ 0005h ; 186
cpu80286 equ 0006h ; 286
cpu286 equ 06h ; 286
cpu386 equ 07h ; 386
cpu386sx equ 07h ; 386sx
cpu80386sxv equ 0107h ; 386sx in V86 mode
cpu80386sxr equ 0007h ; 386sx in real mode
cpu386dx equ 08h ; 386dx
cpu80386dxv equ 0108h ; 386dx in V86 mode
cpu80386dxr equ 0008h ; 386dx in real mode
cpu80386slv equ 0109h ; 386sl in V86 mode
cpu80386slr equ 0009h ; 386sl in real mode
cpu486sx equ 0Ah
cpui486sxv equ 010Ah ; 486sx in V86 mode
cpui486sxr equ 000Ah ; 486sx in real mode
cpu486dx equ 0Bh ; 486dx
cpui486dxv equ 010Bh ; 486dx in V86 mode
cpui486dxr equ 000Bh ; 486dx in real mode
cpuCx486 equ 0Ch ; Cyrix 486
cpu486slcv equ 010Ch ; Cyrix 486sx/slc in V86
cpu486slcr equ 000Ch ; Cyrix 486sx/slc in real mode
cpu486dlc equ 0Dh
cpu486dlcv equ 010Dh ; Cyrix 486dx/dlc in V86
cpu486dlcr equ 000Dh ; Cyrix 486dx/dlc in real mode
cpuPentium equ 0Eh
cpuPentiumr equ 000Eh ; Pentium in real mode
cpuPentiumv equ 010Eh ; Pentium in V86 mode
cpuCxM1 equ 0Fh
cpuCxM1r equ 000Fh ; Cyrix M1 (586) in real mode
cpuCxM1v equ 010Fh ; Cyrix M1 (586) in V86 mode
cpuP24T equ 10h
cpuP24Tr equ 0010h ; Intel P24T (Pentium OverDrive)
cpuP24Tv equ 0110h ; Intel P24T in V86 mode
ibm3slc equ 11h
ibm4slc equ 12h
ibm4slc2 equ 13h
cpuIBM386SLCr equ 0011h ; IBM 386SLC
cpuIBM386SLCv equ 0111h
cpuIBM486SLCr equ 0012h ; IBM 486SLC
cpuIBM486SLCv equ 0112h
cpuIBM486SLCr2 equ 0013h ; IBM 486SLC2
cpuIBM486SLCv2 equ 0113h
cpuUMCU5 equ 14h
cpuUMCU5Sr equ 0014h ; U5-S
cpuUMCU5Sv equ 0114h
cpuUMCU5Dr equ 0015h ; U5-D
cpuUMCU5Dv equ 0115h
cpuam386sx equ 16h
cpuam386dx equ 17h
cpuNx586r equ 0018h ; Nx586
cpuNx586v equ 0118h
cpuNx586 equ 18h
ibm4bl3 equ 19h
cpuIBM486BL3r equ 0019h ; IBM 486BL3 Blue Lightning
cpuIBM486BL3v equ 0119h
cpuAm486 equ 1Ah ; AMD Am486xxx
cpuP54 equ 1Bh
cpuP6 equ 1Ch
cpuP6r equ 001Ch ; iP6
cpuP6v equ 011Ch
cpuP7 equ 001Dh ; add new CPUs here
LOCALS @@
IF ??version LT 400h ; if current TASM version is earlier than 4.0 then
; we need macros for P5 instructions
cpuid equ <db 0Fh,0A2h> ; Pentium instruction
ENDIF
.8086
CPU_Type proc
LOCAL hasFPUonChip : BYTE
; entry - none
; returns AL = CPU code (see constants above)
; AH = 1 if in V86, 0 otherwise
; DL = FPU code (see constants below)
mov hasFPUonChip,0
push bx cx si
clr bx
push sp ; this code uses bug in chips prior to
pop ax ; 80286: when push sp performed, value
cmp ax,sp ; of sp is first decremented and then
; placed onto the stack. 286 and up
; handle this instruction correctly,
; saving value which sp have upon issue
; of this command, not after.
jnz @@000 ; if not equal that it is <286
mov ax,7000h
pushf
push ax
popf
pushf
pop ax
popf
mov bl,6
and ah,70h ; check for flags - only 386+ has them
jz @@200 ; if ah=0 than this is 286
inc bx
; distinguish between 386SX/Cx486SX/SLC and 386DX/Cx486DX/DLC chips
; This one uses the fact, that SX/SLC chips has 16-bit data bus and thus
; uses only 16-bit bus interchange format to communicate with coprocessor.
; Due to this limitation the ET bit in MSW is always zero and can't be
; changed, but on DX/DLC it can be flipped.
.386p
clr si
mov eax,cr0
mov ecx,eax
xor eax,MSW_ET ; flipping ET bit
mov cr0,eax
mov eax,cr0
mov cr0,ecx ; restoring previous value of CR0
xor eax,ecx ; did it flip ok?
jz @@L100
inc si ; DX/DLC
@@L100:
;This code that distinguishes a 386 from a 486 depends on
;the 386's inability to toggle the AC bit in the EFLAGS register,
;but the 486 can. This technique is apparently blessed by Intel.
;Distinguish between 386 and 486
;Placed into public domain by Compaq Computers.
.386
mov ax,sp
and sp,0FFFCh ;round down to a dword boundary
pushfd
pushfd
pop edx
mov ecx,edx
xor edx,EF_AC ;toggle AC bit
and ecx,EF_AC
push edx
popfd
pushfd
pop edx
popfd ;restore original flags
mov sp,ax ;restore original stack pointer
and edx,EF_AC
cmp edx,ecx
jnz @@486 ;it's a 486
is0 si,@@386dx ; SX/SLC?
inc bx ; 386DX
jmp @@386dx
@@486:
; distinguish between Cyrix 486 and Intel 486+
mov bx,cpui486sxr
push bx
mov bx,100h
mov ah,7Fh
cwd
sahf
div bx
lahf
xor al,ah
and al,0D5h
pop bx
jnz @@586
inc bx ; Cyrix 486SLC
inc bx
is0 si,@@586
inc bx ; Cyrix 486DLC,486SX or 486DX
@@586:
; Check for Pentium or later by attempting to toggle the Id bit in EFLAGS reg:
; if we can't, it's an i486.
; Pentium detection routine
; Placed in public domain by Dr. Dobbs Journal
pushfd ; get current flags
pop eax
mov ecx,eax
xor eax,EF_ID ; attempt to toggle ID bit
push eax
popfd
pushfd ; get new EFLAGS
pop eax
push ecx ; restore original flags
popfd
and eax,EF_ID ; if we couldn't toggle ID,
and ecx,EF_ID ; then this is i486
cmp eax,ecx
jz @@486sdx ; do not alter BX
; It's Pentium or later. Use CPUID to get processor family.
clr eax ; get processor info
inc al
push bx ; cpuid destroys bx and dx registers!
IF ??version GE 400h
.586
ENDIF
cpuid
pop bx
and dl,1
mov hasFPUonChip,dl
and ah,0Fh ; 5 means Pentium
cmp ah,4
jb @@386dx ; CPUID also works on later models of 486s
je @@486sdx2 ; Though we shouldn't come here on
; a 386 it's better to make an extra check for
; the case we occasionally did.
push bx
push ax
clr eax
cpuid
pop ax
cmp ebx,'iryC' ; M1 has Vendor Id = 'CyrixInstead'
pop bx
jnz @@P5
cmp edx,'snIx'
jnz @@P5
cmp ecx,'daet'
jnz @@P5
mov bl,cpuCxM1
jmp @@L1
@@P5:
mov bl,ah
cmp bl,6
jz @@P6
and ax,10F0h
cmp ah,10h ; Pentium OverDrive
jz @@P24T
cmp al,20h
mov bl,cpuP54 ; P54
jz @@L1
mov bl,cpuPentium ; P5
jmp @@L1
@@P24T:
mov bl,cpuP24T
jmp @@L1
@@P6:
mov bl,cpuP6
jmp @@L1
@@386dx:
call checkIBMmsrs
jmp @@L1
@@486sdx2: ; we got here if cpuid works
clr eax
push bx
IF ??version GE 400h
.586
ENDIF
cpuid ; UMC U5 chips support CPUID instruction
cmp ecx,' CMU' ; returning 'UMC UMC UMC ' as Vendor Id.
jnz @@notUMC
pop bx
clr eax
inc al
cpuid
and al,0F0h
cmp al,10h
mov bl,cpuUMCU5 ; U5-S
jnz @@L1
inc bl ; U5-D
jmp @@L1
@@notUMC:
cmp ebx,'htuA' ; AMD Am486DXx+ has Vendor Id = 'AuthenticAMD'
pop bx
jnz @@notAMD
cmp edx,'itne'
jnz @@notAMD
cmp ecx,'DMAc'
jnz @@notAMD
mov bl,cpuAm486
push bx
clr eax
inc al
cpuid
pop bx
and al,0F0h
or bh,al
jmp @@L1
@@notAMD:
call checkIBMmsrs3 ; check if IBM MSRs present (will only work in
jc @@L1 ; real mode)
mov bl,cpu486sx
clr eax ; get processor info
inc al
push bx ; cpuid destroys bx and dx registers!
IF ??version GE 400h
.586
ENDIF
cpuid
pop bx
isn0 al,@@setNibble ; 0 and 1 both means DX
inc al
@@setNibble:
or bh,al ; put model code into bh's high nibble
jmp @@L1
@@486sdx:
; distinguish between i486dx and i486sx processors
; based on 486sx's inability to toggle NE bit of MSW
.486p
call isInOSZwei ; OS/2 won't allow to flip NE bit anyway
jnz @@L1
cmp bl,cpu486dlc
jae @@L1 ; avoid test on Cyrix 486s
mov eax,cr0
mov ecx,eax
db 66h,83h,0E0h,0DFh
and eax,0FFFFFFDFh ; flip off NE bit of MSW
mov cr0,eax
mov eax,cr0
cmp eax,ecx
jnz @@486dx
or eax,MSW_NE ; flip on NE bit of MSW
mov cr0,eax
mov eax,cr0
cmp eax,ecx
jnz @@486dx
dec bx
@@486dx:
inc bx
mov eax,ecx
mov cr0,eax
call checkIBMmsrs3
@@L1:
; detect a NexGen Nx586 CPU
cmp bl,07h ; should test as 386 only
jb @@L101
cmp bl,08h
ja @@L101
mov ax,5555h
xor dx,dx
mov cx,2
div cx
jnz @@L101 ; Nx586 doesn't change ZF on division while
mov bl,cpuNx586 ; other 386s do.
@@L101:
.286p
smsw ax
and al,1
or bh,al ; get the VM flag into bh
jmp @@200
@@000:
mov bl,4 ; assume this is 186/188
mov cl,33
clr ax
dec ax
shl ax,cl
jnz @@100 ; 186/188 does not actually shift
; more that 32 bits. It shifts only
; n mod 32 bits, where n is number of
; bits to shift.
mov bl,2 ; assume NEC family
clr cx
dec cx
; rep es: lodsb - incorrect order of prefixes and thus would
; not work as repeated command on Intel's CPUs.
; 8086/88 accepts only es: rep lodsb order. But
; NEC Vxx CPUs process multiple prefix repeated
; instructions correctly regardless of their
; order.
db 0F3h,26h,0ACh
; rep es: lodsb
jcxz @@100 ; was repeated cx times -> NEC V20/V30
clr bx ; good old 88/86
@@100:
clr ax ; clear ax, so that test for new CPU won't work
call Test_Buffer ; later...
jcxz @@200 ; prefetch buffer length < 6 bytes -> 88 / V20
inc bx ; prefetch buffer length = 6 bytes -> 86 / V30
@@200:
mov dl,10h
cmp hasFPUonChip,0
jnz @@noCheck
@@checkFPU:
call FPU_Type
@@noCheck:
call checkWeitek
@@Q:
mov ax,bx
pop si cx bx
.8086
ret
endp
isInOSZwei proc near
push ax bx
mov ax,4010h
int 2Fh
cmp ax,4010h
pop bx ax
ret
endp
Test_Buffer proc near ; (C) 2B Programmers
push es di
mov _bpcs[@@0],41h ; to make this routine reentrant
std
push cs
pop es
ldi @@2
mov al,_bpcs[@@1]
mov cx,3
cli
rep stosb
cld ; 1
nop ; 2
nop ; 3
nop ; 4 <- 80x88 will cut here and inc cx instruction
@@0: inc cx ; 5 will be overwritten by sti, else we'll get
@@1: ; cx = 1, which indicates 80x86
sti ; 6
@@2:
sti
pop di es
ret
endp
db 13,10
db ' Too much is not enough...',13,10
db ' (Deep Purple)',13,10
db 13,10
db 'TMi0SDGL(tm) CPU/FPU feature detection library Version 1.17',13,10
db 'Copyright(c) 1992-95 by B-coolWare. Released as freeware.',13,10
checkWeitek proc near
cmp bl,7
jb @@1
.386
clr eax
int 11h
test eax,1000000h
.8086
jz @@1
or dl,1 ; Weitek 1167 present
@@1:
ret
endp
checkEmu proc
; returns CF = 1 if FPU emulator detected, CF = 0 otherwise
.286p
push ax
smsw ax
test al,04
stc
jnz @@1
clc
@@1:
pop ax
ret
endp
.8086
FPU_Type proc near
;
; on entry : BL = CPU code !! Required !!
;
.286p
.287
mov dl,2 ; assume no coprocessor present
fninit
clr cx
jmp $+2 ; just to make sure we have enough time for
; FPU to initialize
mov fpubuf_w,5A5Ah
fnstsw fpubuf_w
mov ax,fpubuf_w
isn0 al,@@L161 ; FPU wasn't initialized - no FPU at all
fnstcw fpubuf_w ; check the control word also
mov ax,fpubuf_w
and ax,103Fh
cmp ax,3Fh
jne @@L161
mov dl,4 ; assume 8087
fstenv fpuenv
and fpubuf_w,0FF7Fh
fldcw fpubuf_w
fdisi
fstcw fpubuf_w
wait
test fpubuf_w,80h
jnz @@L161
mov dl,8 ; assume 80287
fninit ; checking if -Inf <> +Inf
fld1 ; 287 erroneously claim that they are equal
fldz
fdivp st(1),st
fld st
fchs
fcompp
fstsw fpubuf_w
wait
mov ax,fpubuf_w
sahf
jz @@L161 ; -Inf <> +Inf -> 287XL or 387 and up
mov dl,0Ch ; assume 80387
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -