home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TopWare 18: Liquid
/
Image.iso
/
liquid
/
top1077
/
cpu.asm
< prev
next >
Wrap
Assembly Source File
|
1993-03-05
|
9KB
|
271 lines
;****************************************************************************
;*
;* The MegaToolbox
;*
;* Copyright (C) 1993 Kendall Bennett.
;* All rights reserved.
;*
;* Filename: $RCSfile: cpu.asm $
;* Version: $Revision: 1.4 $
;*
;* Language: 8086 Assembler
;* Environment: IBM PC (MS DOS)
;*
;* Description: Autodetection routine to determine the type of CPU installed
;* in the system.
;*
;* $Id: cpu.asm 1.4 1992/09/09 09:57:57 kjb Exp $
;*
;* Revision History:
;* -----------------
;*
;* $Log: cpu.asm $
;* Revision 1.4 1992/09/09 09:57:57 kjb
;* Fixed to only check for emulation on > 80286 machines.
;*
;* Revision 1.3 1992/09/08 09:36:25 kjb
;* Added code to check for 80x87 emulation software.
;*
;* Revision 1.2 1992/04/13 18:53:43 kjb
;* Added support for detecting the numeric co-processor
;*
;* Revision 1.1 91/11/28 01:52:21 kjb
;* Initial revision
;*
;****************************************************************************
IDEAL
INCLUDE "model.mac" ; Memory model macros
header cpu ; Set up memory model
;****************************************************************************
;
; Equates used by queryCPU routine.
;
;****************************************************************************
; Central Processing Unit type codes
CPU86 = 0 ; 8086/88 type processor
CPU186 = 1 ; 80186 type processor
CPU286 = 2 ; 80286 type processor
CPU286p = 3 ; 80286 type processor in protected mode
CPU386 = 4 ; 80386 type processor
CPU386p = 5 ; 80386 type processor in protected mode
CPU486 = 6 ; 80486 type processor
CPU486p = 7 ; 80486 type processor in protected mode
; Floating Point Unit type codes
FPUNONE = 0 ; No coprocessor present
FPU87 = 1 ; 8087 coprocessor
FPU287 = 2 ; 80287 coprocessor
FPU387 = 3 ; 80387 coprocessor
FPU487 = 4 ; 80487 coprocessor
begcodeseg cpu ; Start of code segment
P386 ; Enable all '386 instructions
P387 ; Enable all '387 instructions
; Save the type of CPU detected so we can determine the co-processor
; type correctly. This means that we MUST call queryCpu() BEFORE calling
; queryFpu() to obtain correct results.
cpu dw CPU86
;----------------------------------------------------------------------------
; cpu_type queryCpu(void)
;----------------------------------------------------------------------------
; Determine type of processor present.
;----------------------------------------------------------------------------
procstart _queryCpu
push bp ; We MUST save bp for initialization code...
mov ax,CPU86 ; Default to 8086/8088 processor
push sp
pop bx ; BX holds the value of SP or SP-2
cmp bx,sp ; 88/86/186 pushes the value of SP-2
je @@Check286 ; Must be a 286/386/486 type processor
mov cl,32 ; 186 uses count mod 32 = 0
shl bx,cl ; 86 shifts 32 bits left so ax = 0
jz @@Done ; zero: shifted out all bits so 86/88
mov ax,CPU186 ; nonzero: no shift, so 186
jz @@Done
@@Check286: ; First check for 386/486 in 32 bit mode
pushf ; Test for 16 or 32 operand size:
mov bx,sp ; pushed 2 or 4 bytes of flags
popf
inc bx
inc bx
cmp bx,sp ; did pushf change sp by 2?
jnz @@Check486 ; 32 bit push, so it is a 386/486
sub sp,6 ; Is it a 286/386/486 in 16 bit mode?
mov bp,sp
sgdt [QWORD ptr bp] ; 80286/386/486 specific instrucion
add sp,4 ; Get global descriptor table
pop bx
inc bh ; Third word of GDT = -1 for 286
jnz @@Check486 ; We have a 386/486
mov ax,CPU286 ; We have a 286
jmp @@TestPROT
@@Check486:
; Distinguish an 80386 from an 80486. Bit 18 (40000H) of EFLAGS register
; is used only in the 486. This code flips it and tests if anything happened.
mov edx,esp ; Save stack pointer
and esp,not 3 ; Align stack pointer to prevent a fault
; when we set the AC flag on a 486
pushfd ; Copy the EFLAGS register
pop eax ; into register eax
mov ecx,eax ; Save the original EFLAGS value
xor eax,40000H ; Flip the AC flag bit
push eax ; Try to put the modified value back
popfd ; into the EFLAGS register
pushfd ; Copy the EFLAGS register again
pop eax ; into eax
xor eax,ecx ; Compare the old and new AC bits
shr eax,18 ; Shift and mask to get the AC comparison bit
and eax,1 ; in the low order position of eax
push ecx
popfd ; Restore EFLAGS that were saved on entry
mov esp,edx ; And restore stack pointer to saved value
mov bx,ax ; and move into bx
; At this point ax = 0 for a 386, or ax = 1 for a 486
mov ax,CPU386 ; Assume a 386
test bx,bx
jz @@TestPROT ; We have a 386
mov ax,CPU486 ; We have a 486
@@TestPROT:
smsw cx ; protected? machine status -> cx
ror cx,1 ; protection bit -> carry flag
jnc @@Done ; Real mode if no carry
inc ax ; Protected: return value + 1
@@Done:
mov [cpu],ax ; Save CPU type in code segment variable
pop bp ; Restore bp
ret ; We are done
procend _queryCpu
ndp_cw dw ?
ndp_sw dw ?
;----------------------------------------------------------------------------
; fpu_type queryFpu(void)
;----------------------------------------------------------------------------
; Determine type of floating point coprocessor present in the system.
; The idea is to determine whether or not the floating-point control word
; can be successfully read. If it cannot, then no coprocessor exists.
; If it can the correct coprocessor is then determined depending on the
; main CPU id.
;----------------------------------------------------------------------------
procstart _queryFpu
push bp
mov bx,FPUNONE ; Default to no FPU present
; The next two 80x87 instructions cannot carry the WAIT prefix,
; because there may not be an 80x87 for which to wait. The WAIT is
; therefore emulated with a MOV CX,<value> LOOP $ combination.
mov [ndp_cw],0 ; Clear the control word in memory
cli ; Interrupts must be off during test
fninit ; reset NDP status word
mov cx,2 ; Wait for co-pro to complete operation
loop $
fnstcw [ndp_cw] ; Obtain the processor control word
mov cx,14h ; Wait for co-pro to complete operation
loop $
sti ; Re-enable interrupts
; We check to see that the precison control bits of the control word
; indicate 64 bit internal precision (bits 8 & 9 set) which is the default
; set up by the fninit instruction above. We also test that the exception
; masks are properly set.
mov ax,[ndp_cw] ; AX := NDP control word
and ax,033fh ; Mask out the precision control bits etc.
cmp ax,033fh ; is the NDP present?
jne @@Done ; No, we are all done... (must be a 3)
; Determine the type of NDP from the main CPU type
mov bx,FPU87 ; Start with the 8087 NDP
mov ax,[cpu] ; Get current cpu type
cmp ax,CPU286 ; >= 80286 type processor?
jge @@80286 ; Yes, check for 287/387/487
jmp @@Done ; No, we are done
; Now that we know we have a possible co-processor and the processor is
; at least an 80286, we can check to se if coprocessor emulation software
; is installed in the system. Some emulators such as FRANKIE.387 emulate
; the co-processor so well that the above checks believe a co-pro is
; actually out there.
@@80286:
smsw ax ; AX := machine status word
test al,4 ; Check the EM bit status
jnz @@Done ; Software emulation installed on INT 7!
cmp ax,CPU386 ; Do we have a 386 or above?
jge @@80386 ; Yes, check for it
mov bx,FPU287 ; We have a 80287 co-pro
jmp @@Done
@@80386:
cmp ax,CPU486 ; Do we have a 486 or above?
jge @@80486 ; Yes, check for it
; The i386 processor can work with either an 80287 or 80387 co processor
; so we must check for that here. The 387 says that +inf <> -inf while
; the 287 says that they are the same.
fld1 ; Load +1.0 onto NDP stack
fldz ; Load +0.0 onto NDP stack
fdiv ; do +1/0 (create +inf)
fld1 ; Load +1.0 onto NDP stack
fchs ; Change to -1.0
fldz ; Load +0.0 onto NDP stack
fdiv ; do -1/0 (create -inf)
fcompp ; compare and pop values from stack
fstsw [ndp_sw] ; Get the status word from the co pro
mov ax,[ndp_sw] ; AX := Status word
and ah,41h ; Mask out C3 and C0 condition codes
cmp ah,40h ; C3 = 1, C0 = 0 means ST(0) == ST(1)
mov bx,FPU287 ; Set up for a 287 co pro
je @@Done ; Yes, we were correct
mov bx,FPU387 ; No, it was an 80387
jmp @@Done
@@80486:
mov bx,FPU487 ; We must have a 487 co pro.
@@Done:
mov ax,bx ; Return FPU type in AX
pop bp ; Restore bp
ret ; We are done
procend _queryFpu
endcodeseg cpu
END ; End of module