⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cpu_type.ash

📁 CPU特性检测程序源代码 1.17。VB编写的对于系统编程感兴趣的朋友
💻 ASH
📖 第 1 页 / 共 3 页
字号:
; ----------------------------------------------------------------------------
; 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 + -