
	 The following text has been copied exactly as is from the
	 _Intel486TM DX Microprocessor Data Book_, including any
	 and all printing errors.  Use at your own risk.  I found
	 a few typos in here while writing my own program!



			Intel486TM DX MICROPROCESSOR

				APPENDIX A
		INTEL RECOMMENDED CPU IDENTIFICATION CODE

 The CPU identification assembly code will determine for the user which 
 Intel microprocessor and if a Intel Math CoProcessor is installed in the 
 system.  If a 486 microprocessor has been installed, the program will 
 determine if the CPU is with/without a floating point unit.  This code 
 should be executed so the system can be configured for a particular 
 application, which may depend on the microprocessor and Math CoProcessor 
 installed in the system.

		TITLE CPUID
		DOSSEG
		.model  small

		.stack  100h

		.data
	fp_status       dw      ?
	id_mess         db      "This system has a$"
	fp_8087         db      "and an 8087 Math CoProcessor$"
	fp_80287        db      "and an 287tm Math CoProcessor$"
	fp_80387        db      "and an 387tm Math CoProcessor$"
	c8086           db      "n8086/8088 microprocessor$"
	c286            db      "n80286 microprocessor$"
	c386            db      "386tm microprocessor$"
	c486            db      "486tm DX microprocessor/487tm SXtm Math
				"CoProcessor$"
	c486nfp         db      "486tm SXtm Microprocessor$"
	period          db      ".$",13,10
	present_86      dw      0
	present_286     dw      0
	present_386     dw      0
	present_486     dw      0

;
;   The purpose of this code is to allow the user the ability to identify
;   the processor and coprocesor that is currently in the system.  The
;   algorithm of the program is to first determine the processor id.
;   When that is accomplished, the program continues to then identify
;   whether a coprocessor exists in the system.  If a coprocessor or
;   integrated coprocessor exists, the program will identify the
;   coprocessor id.  If one does not exist, the program then terminates.
;
	
	     .code
 
 start:
	mov     ax,@data
	mov     ds,ax                   ; set segment register
	mov     dx,offset id_mess       ;print header message
	mov     ah,9h
	int     21h

				     A-1

			Intel486Tm DX MICROPROCESSOR

 ;
 ;      8086 check
 ;      Bits 12-15 are always set on the 8086 processor.
 ;
	pushf                   ;save EFLAGS
	pop     bx              ;store EFLAGS in BX
	mov     ax,0fffh        ;clear bits 12-15
	and     ax,bx           ;in EFLAGS
	push    ax              ;store new EFLAGS value on stack
	popf                    ;replace current EFLAGS value
	pushf                   ;set new EFLAGS
	pop     ax              ;store new EFLAGS in AX
	and     ax,0f000h       ;if bits 12-15 are set, then CPU
	cmp     ax,0f000h       ;is an 8086/8088
	mov     dx,offset c8086 ;store 8086/8088 message
	mov     present_86,1    ;turn on 8086/8088 flag
	je      check_fpu       ;if CPU is 8086/8088, check for
				;8087
 ;
 ;      80286 CPU Check
 ;      Bits 12-15 are always clear on the 80286 processor.
 ;
	or      bx,0f000h       ;try to set bits 12-15
	push    bx
	popf
	pushf
	pop     ax
	and     ax,0f000h       ; if bits 12-15 are cleared, then
	mov     dx,offset c286  ;       CPU is an 80286
	mov     Present_86,0    ; turn off 8086/8088 flag
	mov     present_286,1   ; turn on 80286 flag
	jz      check_fpu       ; if CPU is 80286, check for 80287
;
;       386 CPU check
;
;       The AC bit, bit #18, is a new bit introduced in the EFLAGS
;       on the 486 DX CPU to generate alignment faults.  This bit can be set
;       on the 486 DX CPU, but not on the 386 CPU.
;
	mov     bx,sp           ;save current stack pointer to
				;align it
	and     sp,not 3        ;align stack to avoid AC fault
	db      66h
	pushf                   ;push original EFLAGS
	db      66h
	pop     ax              ;get original EFLAGS
	db      66h
	mov     cx,ax           ;save original EFLAGS
	db      66h             ;xor EAX,40000h
	xor     ax,0            ;flip AC bit in EFLAGS
	dw      4               ;upper 16-bits of xor constant
	db      66h
	push    ax              ;save for EFLAGS
	db      66h
	popf                    ;copy to EFLAGS

				     A-2

			 Intel486Tm DX MICROPROCESSOR

	db      66h
	pushf                   ;push EFLAGS
	db      66h
	POP     ax              ;get new EFLAGS value
	db      66h
	xor     ax,cx           ;if AC bit cannot be changed,
				;CPU is
	mov     dx,offset c386  ;store 386 message
	mov     present_286,0   ;turn off 80286 flag
	mov     present_386,1   ;turn on 386 flag
	Je      check_fpu       ;if CPU is 386, now check for
				;80287/80387
;
;       486 DX CPU and 486 DX CPU w/o FPU checking
;
	
	mov     dx,offset c486nfp       ;store 486NFP message
	mov     present_386,0           ;turn off 386 flag
	mov     present_486,1           ;turn on 486 flag

;
;    Co-processor checking begins here for the 8086/80286/386 CPUS.
;    The algorithm is to determine whether or not the floating-point
;    status and control words can be written to, the correct coprocessor
;    is then determined depending on the processor id. Coprocessor checks
;    are first performed for an 8086, 80286 and a 486 DX CPU.  If the
;    coprocessor id is still undetermined, the system must contain a 386
;    CPU. The 386 CPU may work with either an 80287 or an 80387.  The
;    infinity of the coprocessor must be checked to determine the correct
;    coprocessor id.
;

check_fpu:                      ;check for 8087/80287/80387
	
	fninit                  ; reset FP status word
	mov    fp_status.5a5ah  ;initialize temp word to non-zero
				;value
	fnstsw fp_status        ;save FP status word
	mov    ax,fp_status     ;check FP status word
	cmp    al,0             ; see if correct status with
				; written
	jne    print_one        ;jump if not Valid, no NPX
				;installed
	fnstcw  fp_status       ;save FP control word
	mov    ax,fp_status     ;check FP control word
	and    ax,103fh         ;see if selected parts looks OX
	cmp    ax,3fh           ;check that ones and zeroes
				;correctly read
	jne    print_one        ;jump if not Valid, no NPX
				;installed
	cmp    present_486,1    ;check if 486 flag is on
	je     is_486           ;if so, jump to print 486 message
	jmp    not_486          ;else continue with 386 checking

is_486:
	mov    dx,offset c486   ;store 486 message
	jmp    print_one

				   A-3

			Intel486Tm DX MICROPROCESSOR

not_486:        
	cmp     present_386,1   ; check if 386 flag is on
	jne     print_87_287    ; if 386 flag not on, check NPX for
				;       8086/8088/80286
	mov     ah,9h           ;       print out 386 CPU ID first
	int     21h
;
;       80287/80387 check for the 386 CPU
;
	fldl                    ;must use default control from
				;FNINIT
	fldz                    ;form infinity
	fdiv                    ;8087/80287 says +inf = inf
	fld     st              ;form negative infinity
	fchs                    ;80387 says +inf < > -inf
	fcompp                  ;see if they are the same and
				;remove them
	fstsw   fp_status       ;look at status from FCOMPP
	
	mov     ax,fp_status
	mov     dx,offset fp_80287      ;store 80287 message
	sahf                            ;see if infinities matched
	jz      restore_EFLAGS          ;jump if 8087/80287 is present
	mov     dx,offset fp_80387      ;store 80387 message

 restore_EFLAGS:
		
	finit                   ;clear any pending fp exception
	mov     ah,9h           ;print NPX message
	int     21h
	db      66h
	push    cx              ;push ECX
	db      66h
	popf                    ;restore original EFLAGS register
	mov     sp,bx           ;restore original stack pointer
	jmp     exit

 print_one:

	mov     ah,9h           ;print Out CPU ID with no NPX
	int     21h
	jmp     exit

 print_87_287:

	mov     ah,9h           ;print out 8086/8088/80286 first
	int     21h
	cmp     present_86,1        ;if 8086/8088 flag is on
	mov     dx,offset fp_8087   ;store 8087 message
	je      print_fpu
	mov     dx,offset fp_80287  ;else CPU = 80286, store 80287
				    ;message
 print_fpu:
  
	mov     ah,9h           ;print out NPX
	int     21h
	jmp     exit

exit:
	mov     dx,offset period    ;print out a period of end message
	mov     ah,9h
	int     21h
	mov     ax,4c00h        ;terminate program
	int     21h

	end     start

				    A-4

