📄 cpu_hl.asm
字号:
; -----------------------------------------------------------------------------
; CPU_HL.ASM CPU Type detection routine for hi-level languages Version 1.17
;
; Too-Much-In-One-So-Don't-Get-Lost(tm) CPU/FPU feature detection library
;
; Copyright(c) 1992-95 by B-coolWare. Written by Bobby Z.
; -----------------------------------------------------------------------------
; This is a port from CPU_TYPE.ASH - the assembler version of TMi0SDGL(tm)
; See file CPU_TYPE.ASH for extensive comments and all.
INCLUDE HEADER.ASH
.DATA
EXTRN FPUType:BYTE
.CODE
PUBLIC CPU_Type
PUBLIC checkEmu
; TP/BP:
; function CPU_Type : Word;
;
; C/C++:
; word CPU_Type(void);
;
; returns current CPU code (see CPUTYPE.PAS or CPUTYPE.H for details) and sets
; current FPU code in FPUType variable.
EF_AC equ 00040000h ; AC bit in EFLAGS register
EF_ID equ 00200000h ; ID bit in EFLAGS register
MSW_NE equ 00000020h ; NE bit in MSW register
IF ??version LT 400h
cpuid equ <db 0Fh,0A2h> ; new i486 & Pentium instruction
ENDIF
.8086
CPU_Type proc
LOCAL hasFPUonChip:BYTE
mov hasFPUonChip,0
push bx cx si
sub bx,bx
push sp
pop ax
cmp ax,sp
jnz @@Ct_000
mov ax,7000h
pushf
push ax
popf
pushf
pop ax
popf
mov bl,6
and ax,7000h
jz @@Ct_200
inc bx
.386p
clr si
mov eax,cr0
mov ecx,eax
xor eax,10h
mov cr0,eax
mov eax,cr0
mov cr0,ecx
xor eax,ecx
jz @@L100
inc si
@@L100:
.386
mov ax,sp
and sp,0FFFCh
pushfd
pushfd
pop edx
mov ecx,edx
xor edx,EF_AC
and ecx,EF_AC
push edx
popfd
pushfd
pop edx
popfd
mov sp,ax
and edx,EF_AC
cmp edx,ecx
jnz @@486
or si,si
jz @@386dx
inc bx
jmp @@386dx
@@486:
mov bx,0Ah
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
inc bx
or si,si
jz @@586
inc bx
@@586:
pushfd
pop eax
mov ecx,eax
xor eax,EF_ID
push eax
popfd
pushfd
pop eax
push ecx
popfd
and eax,EF_ID
and ecx,EF_ID
cmp eax,ecx
jz @@486sdx
clr eax
inc al
push bx
IF ??version GE 400h
.586
ENDIF
cpuid
pop bx
and dl,1
mov hasFPUonChip,dl
and ah,0Fh
cmp ah,4
jb @@386dx
je @@486sdx2
push bx
push ax
clr eax
cpuid
pop ax
cmp ebx,'iryC'
pop bx
jnz @@P5
cmp edx,'snIx'
jnz @@P5
cmp ecx,'daet'
jnz @@P5
mov bl,0Fh ; CxM1
jmp @@L1
@@P5:
mov bl,ah
cmp bl,6
jz @@P6
and ax,10F0h
cmp ah,10h
jz @@P24T
cmp al,20h
mov bl,1Bh
jz @@L1
mov bl,0Eh
jmp @@L1
@@P24T:
mov bl,10h
jmp @@L1
@@P6:
mov bl,1Ch
jmp @@L1
@@386dx:
call checkIBMmsrs
jmp @@L1
@@486sdx2:
push bx
clr eax
cpuid
cmp ebx,'htuA'
pop bx
jnz @@notAMD
cmp edx,'itne'
jnz @@notAMD
cmp ecx,'DMAc'
jnz @@notAMD
mov bl,1Ah
jmp @@L1
@@notAMD:
call checkIBMmsrs3
jc @@L1
mov bl,0Ah
push bx
clr eax
inc al
IF ??version GE 400h
.586
ENDIF
cpuid
pop bx
test al,al
jnz @@setNibble
inc al
@@setNibble:
or bh,al
jmp @@L1
@@486sdx:
.486p
call isInOSZwei
jnz @@L1
cmp bl,0Ch
jae @@L1
mov eax,cr0
mov ecx,eax
db 66h,83h,0E0h,0DFh
mov cr0,eax
mov eax,cr0
cmp eax,ecx
jnz @@486dx
or eax,MSW_NE
mov cr0,eax
mov eax,cr0 ; this instruction causes the host to clear EBX ???!!!
cmp eax,ecx
jnz @@486dx
dec bx
@@486dx:
inc bx
mov eax,ecx
mov cr0,eax
call checkIBMmsrs3
@@L1:
cmp bl,07h
jb @@L101
cmp bl,08h
ja @@L101
mov ax,5555h
xor dx,dx
mov cx,2
div cx
jnz @@L101
mov bl,18h
@@L101:
.286p
smsw ax
and al,1
or bh,al
jmp @@Ct_200
@@Ct_000:
mov bl,4
mov cl,33
clr ax
dec ax
shl ax,cl
jnz @@Ct_100
mov bl,2
clr cx
dec cx
db 0F3h,26h,0ACh
jcxz @@Ct_100
clr bx
@@Ct_100:
clr ax
call Test_Buffer
jcxz @@Ct_200
inc bx
@@Ct_200:
mov dl,10h
cmp hasFPUonChip,1
jz @@noCheck
@@checkFPU:
call FPU_Type
@@noCheck:
call checkWeitek
mov FPUType,dl
mov ax,bx
pop si cx bx
.8086
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
Test_Buffer proc near
; this routine will never be called in DPMI applications for they won't run
; on CPU less that 286. Thus we need no precautions about writing to code
; segment.
push es di
std
mov _bpcs[@@0],41h
push cs
pop es
ldi @@2
mov al,_bpcs[@@1]
mov cx,3
cli
rep stosb
cld
nop
nop
nop
@@0: inc cx
@@1:
sti
@@2:
sti
pop di es
ret
endp
.386p
IF ??version LT 400h
rdmsr macro Reg
mov ecx,Reg
db 0Fh,32h
endm
wrmsr macro Reg
mov ecx,Reg
db 0Fh,30h
endm
ENDIF
checkIBMmsrs proc near
; we'll get here only on 386 with CPUID support
; returns CF=1 if IBM MSRs found and sets BL in this case
push dx
smsw ax
test al,1 ; we can only do this nasty code in real mode...
jnz @@Qs1
; jz @@OkWRMSR
; call checkQEMM ; ...or under QEMM 7.04 and up.
; jnc @@Qs1
;@@OkWRMSR:
push bx
push ds
mov ax,350Dh
int 21h
push es
push bx
push cs
pop ds
mov dx,offset @@trap0D
mov ax,250Dh ; intercept GPF exception
int 21h
mov ax,3506h
int 21h
push es
push bx
mov dx,offset @@trap06
mov ax,2506h ; and Invalid Instruction exception
int 21h
IF ??version LT 400h
rdmsr 1000h ; we'll get Exception 13 if this MSR is not
ELSE
.586p
mov ecx,1000h
rdmsr
ENDIF
stc ; valid or Exception 06 if this is not IBM386.
mov bl,11h ; IBM 386SLC
jmp @@Qs
@@trap06:
add sp,4
popf
clc
jmp @@Qs
@@trap0D:
add sp,4
popf
clc
@@Qs:
pop dx
pop ds
pushf
mov ax,2506h
int 21h
popf
pop dx
pop ds
pushf
mov ax,250Dh
int 21h
popf
pop ds
pop bx
@@Qs1:
pop dx
ret
endp
checkIBMmsrs2 proc near
; we'll get here only on 486 with CPUID support
push dx
call checkIBMmsrs ; first check if this is IBM 486SLC chip
jnc @@Qi
push bx
push ds
mov ax,350Dh
int 21h
push es
push bx
push cs
pop ds
mov dx,offset @@trap0D2
mov ax,250Dh
int 21h
IF ??version LT 400h
rdmsr 1002h ; try to read 486SLC2 specific MSR
ELSE
.586p
mov ecx,1002h
rdmsr
ENDIF
mov bl,13h ; IBM 486SLC2
jmp @@Qi2
@@trap0D2:
add sp,4
popf
stc
mov bl,12h ; IBM 486SLC
@@Qi2:
pop dx
pop ds
pushf
mov ax,250Dh
int 21h
popf
pop bx
@@Qi:
pop dx
ret
endp
checkIBMmsrs3 proc near
; we'll get here only on 486 with CPUID support
push dx
call checkIBMmsrs2 ; first check if this is IBM 486SLC chip
jnc @@Qi4
push bx
push ds
mov ax,350Dh
int 21h
push es
push bx
push cs
pop ds
mov dx,offset @@trap0D3
mov ax,250Dh
int 21h
IF ??version LT 400h
rdmsr 1004h ; try to read 486BL3 specific MSR
ELSE
.586p
mov ecx,1004h
rdmsr
ENDIF
mov bl,19h ; IBM 486BL3
jmp @@Qi3
@@trap0D3:
add sp,4
popf
stc
@@Qi3:
pop dx
pop ds
pushf
mov ax,250Dh
int 21h
popf
pop bx
@@Qi4:
pop dx
ret
endp
.8086
isInOSZwei proc near
push ax bx
mov ax,4010h
int 2Fh
cmp ax,4010h
pop bx ax
ret
endp
checkWeitek proc near
cmp bl,7
jb @@1
.386
clr eax
int 11h
test eax,1000000h
.8086
jz @@1
or dl,1
@@1:
ret
endp
.8086
FPU_Type proc near
.286p
.287
push ds
ifdef __DPMI__
push ax bx
mov ax,dpmiCreateCodeAlias
mov bx,cs
int 31h
mov ds,ax
pop bx ax
else
push cs
pop ds
ASSUME DS:@code
endif
mov dl,2
fninit
xor cx,cx
jmp $+2
mov ds:fpudata1,5A5Ah
fnstsw ds:fpudata1
mov ax,ds:fpudata1
or al,al
jnz @@L161
fnstcw ds:fpudata1
mov ax,ds:fpudata1
and ax,103Fh
cmp ax,3Fh
jne @@L161
mov dl,4
fstenv ds:fpudata3
wait
and ds:fpudata1,0FF7Fh
fldcw ds:fpudata1
fdisi
fstcw ds:fpudata1
wait
test ds:fpudata1,80h
jnz @@L161
mov dl,8
fninit
fld1
fldz
fdivp st(1),st
fld st
fchs
fcompp
fstsw ds:fpudata1
wait
mov ax,ds:fpudata1
sahf
jz @@L161
mov dl,0Ch
cmp bl,09h
jae @@50
cmp bl,06h
jb @@50
@@checkIIT:
fld ds:[denormal]
fadd st(0),st
fnstsw ax
test al,02h
jnz @@50
cmp dl,0Ch
jz @@300
mov dl,22
jmp @@L161
@@300:
cmp bl,0Ah
jb @@301
mov dl,22h
jmp @@L161
@@301:
mov dl,24
jmp @@L161
@@50:
fninit
fldpi
f2xm1
fstp ds:fpudata2
wait
cmp _wp ds:[fpudata2+2],3FC9h
jne @@L15
or dl,2
@@L15:
fninit
fldcw ds:_53bit_prec
fld tbyte ptr ds:op1
fld1
faddp st(1),st
fstp ds:tera
fnstsw ax
wait
test al,20h
jnz @@L16
cmp byte ptr ds:tera,0F8h
jnz @@L16
cmp byte ptr ds:tera[9],40h
jnz @@L16
mov dl,1Ah
jmp @@L161
@@L16:
fnstcw ds:fpudata1
or byte ptr ds:fpudata1[1],80h
fldcw ds:fpudata1
fstcw ds:fpudata1
wait
test byte ptr ds:fpudata1[1],80h
jz @@L162
mov dl,1Ch
jmp @@L161
@@L162:
cmp bl,7
jb @@L161
fninit
fldpi
f2xm1
fld1
fchs
fldpi
fscale
fstp st(1)
fcompp
fstsw ax
wait
sahf
jnz @@L161
mov dl,1Eh
@@L161:
cmp bl,0Eh
jb @@17
and dl,3
or dl,10h
jmp @@30
@@17:
cmp bl,0Bh
jnz @@nobuilt
fninit
fstcw ds:fpudata1
cmp ds:fpudata1,037Fh
jz @@builtin
dec bl
jmp @@31
@@builtin:
and dl,1
or dl,10h
jmp @@nobuilt
@@nobuilt:
cmp bl,06
jnz @@30
cmp dl,0Ch
jz @@XL
cmp dl,0Dh
jnz @@30
@@XL:
add dl,8
@@30:
cmp bl,0Ah
jnz @@31
cmp dl,0Ch
jz @@487sx
cmp dl,0Dh
jnz @@31
@@487sx:
inc bl
mov dl,10h
@@31:
cmp bl,18h
jnz @@32
cmp dl,0Ch
jz @@nx587
cmp dl,0Dh
jnz @@32
@@nx587:
and dl,1
add dl,20h
@@32:
cmp dl,4
jb @@L18
fldenv ds:fpudata3
@@L18:
ifdef __DPMI__
push ax bx
mov ax,dpmiFreeLDTDesc
mov bx,ds
int 31h
pop bx ax
endif
pop ds
ASSUME DS:@data
ret
endp
fpudata1 dw ?
fpudata2 dd ?
fpudata3 db 14 dup(?)
tera dt ?
_53bit_prec dw 027Fh
denormal dt 1
op1 db 0F0h,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,03Fh
checkEmu proc
.286p
smsw ax
test al,04
mov al,1
jnz @@1
clr al
@@1:
ret
endp
;getQEMMAPI proc near
;; get QEMM API entry point
;; returns CF=1 if QEMM found and API entry point got OK.
; ldx QEMMId
; mov ax,3D00h
; clr cx
; int 21h
; jc @@Q
; mov bx,ax
; mov ax,4402h
; mov cx,4
; ldx QEMMEntry
; int 21h
; mov ah,3Eh
; int 21h
; clc
;@@Q:
; ret
; endp
;
;checkQEMM proc near
;; get and check QEMM version. Only QEMM v7.04 and up enables WRMSR from V86.
;; returns CF=1 if QEMM found and version is OK.
; push bx
; call getQEMMAPI
; jc @@tooearly
; mov ah,3
; call dword ptr ds:QEMMEntry
; cmp bx,0704h
; pop bx
; jb @@tooearly
; stc
; ret
;@@tooearly:
; clc
; ret
; endp
;
; EXTRN QEMMEntry : DWORD
; EXTRN QEMMId : BYTE
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -