home *** CD-ROM | disk | FTP | other *** search
- ;-----------------------------------------------------------------------------
- ; CPU_Type determines the CPU type in the system.
- ;-----------------------------------------------------------------------------
- ; Written by:
- ; Robert Collins
- ; 3361 Keys Lane
- ; Anaheim, CA 92804
- ;-----------------------------------------------------------------------------
- ; Input: None
- ; Output: AX = CPU type
- ; 0 = 8086/8088
- ; 1 = 80186/80188
- ; 2 = 80286
- ; 3 = 80386
- ; 4 = 80486
- ; FFFF = Unknown CPU type
- ;-----------------------------------------------------------------------------
-
- .radix 16 ; anybody that programs in base 10 is a wimp!
- .386P ; MASM 5.1 directive
-
- ;-----------------------------------------------------------------------------
- ; PUBLIC statements here
- ;-----------------------------------------------------------------------------
- Public sl_CPU_Type
-
- ;-----------------------------------------------------------------------------
- ; Local variable definitions
- ;-----------------------------------------------------------------------------
-
- INT6 equ [bp-4]
-
- ;-----------------------------------------------------------------------------
- ; Interrupt vector segment
- ;-----------------------------------------------------------------------------
-
- ABS0 segment use16 at 0
-
- org 6*4
-
- Orig_INT6 dd ?
-
- ABS0 ends
-
-
- ;-----------------------------------------------------------------------------
- ; 80486 instruction macro -- because MASM 5.1 doesn't support the 80486!
- ;-----------------------------------------------------------------------------
-
- XADD macro
- db 0fh,0C0h,0D2h ; 80486 instruction macro
- ENDM
-
-
- stdlib segment para use16 public 'slcode'
- assume cs:cseg
-
- sl_CPU_Type proc near
- push bx
- push cx
- push dx
- ;
- ;-----------------------------------------------------------------------------
- ; Determine the CPU type by testing for differences in the CPU in the system.
- ;-----------------------------------------------------------------------------
- ; To test for the 8086/8088, test the value of SP after it is placed on the
- ; stack. The 8086/8088 increments this value before pushing it on the stack,
- ; all other CPU's increment SP after pushing it on the stack.
- ;-----------------------------------------------------------------------------
- xor ax,ax ; clear CPU type return register
- push sp ; save SP on stack to look at
- pop bx ; get SP saved on stack
- cmp bx,sp ; if 8086/8088, these values will differ
- jnz CPU_8086_exit ; yep
- ;-----------------------------------------------------------------------------
- ; When we get here, we know that we aren't a 8086/8088. And since all
- ; subsequent processors will trap invalid opcodes via INT6, we will determine
- ; which CPU we are by trapping an invalid opcode.
- ; We are an 80486 if: XADD DX,DX executes correctly
- ; 80386 if: MOV EDX,CR0 executes correctly
- ; 80286 if: SMSW DX executes correctly
- ; 80186 if: SHL DX,5 executes correctly
- ;-----------------------------------------------------------------------------
- ; Setup INT6 handler
- ;-----------------------------------------------------------------------------
-
- enter 4,0 ; create stack frame
- mov word ptr INT6, offset INT6_handler
- mov INT6+2,cs
- call set_INT6_vector ; set pointer to our INT6 handler
- mov ax,4 ; initialize CPU flag=4 (80486)
- xor cx,cx ; initialize semaphore
-
- ;-----------------------------------------------------------------------------
- ; Now, try and determine which CPU we are by executing invalid opcodes.
- ; The instructions I chose to invoke invalid opcodes, are themselves rather
- ; benign. In each case, the chosen instruction modifies the DX register,
- ; and nothing else. No system parameters are changed, e.g. protected mode,
- ; or other CPU dependant features.
- ;-----------------------------------------------------------------------------
- ; The 80486 instruction 'XADD' xchanges the registers, then adds them.
- ; The exact syntax for a '486 compiler would be: XADD DX,DX.
- ;-----------------------------------------------------------------------------
-
- XADD ;DX,DX ; 80486
- jcxz CPU_exit
- dec ax ; set 80386 semaphore
- inc cx ; CX=0
-
- ;-----------------------------------------------------------------------------
- ; For a description on the effects of the following instructions, look in
- ; the Intel Programmers Reference Manual's for the 80186, 80286, or 80386.
- ;-----------------------------------------------------------------------------
- mov edx,cr0 ; 80386
- jcxz CPU_exit
- dec ax ; set 80286 semaphore
- inc cx ; CX=0
-
- smsw dx ; 80286
- jcxz CPU_exit
- dec ax ; set 80186 semaphore
- inc cx ; CX=0
-
- shl dx,5 ; 80186/80188
- jcxz CPU_exit
- dec ax ; set UNKNOWN_CPU semaphore
-
- CPU_exit:
- call set_INT6_vector
- leave
-
- CPU_8086_exit: pop dx
- pop cx
- pop bx
- ret
-
-
- ;-----------------------------------------------------------------------------
- ; Set the INT6 vector by exchanging it with the one currently on the stack.
- ;-----------------------------------------------------------------------------
-
- set_INT6_vector:
- push ds
- push ABS0 ; save interrupt vector segment
- pop ds ; make DS=INT vector segment
- mov dx,word ptr ds:Orig_INT6; ; get offset if INT6 handler
- xchg INT6,dx ; set new INT6 offset
- mov word ptr ds:Orig_INT6,dx
- mov dx,word ptr ds:Orig_INT6+2 ; get segment of INT6 handler
- xchg INT6+2,dx ; set new INT6 segment
- mov word ptr ds:Orig_INT6+2,dx
- pop ds ; restore segment register
- ret ; split
-
-
- ;-----------------------------------------------------------------------------
- ; INT6 handler sets a semaphore (CX=FFFF) and adjusts the return address to
- ; point past the invalid opcode.
- ;-----------------------------------------------------------------------------
-
- INT6_handler:
- enter 0,0 ; create new stack frame
- dec cx ; make CX=FFFF
- add word ptr ss:[bp][2],3 ; point past invalid opcode
- leave
- iret
- ;
- ;
- CPU_Type endp
- cseg ends
- end
-