home *** CD-ROM | disk | FTP | other *** search
/ World of Graphics / WOGRAPH.BIN / 457.CPU.ASM < prev    next >
Assembly Source File  |  1993-03-05  |  9KB  |  271 lines

  1. ;****************************************************************************
  2. ;*
  3. ;*                              The MegaToolbox
  4. ;*
  5. ;*                    Copyright (C) 1993 Kendall Bennett.
  6. ;*                            All rights reserved.
  7. ;*
  8. ;* Filename:    $RCSfile: cpu.asm $
  9. ;* Version:        $Revision: 1.4 $
  10. ;*
  11. ;* Language:    8086 Assembler
  12. ;* Environment:    IBM PC (MS DOS)
  13. ;*
  14. ;* Description:    Autodetection routine to determine the type of CPU installed
  15. ;*                in the system.
  16. ;*
  17. ;* $Id: cpu.asm 1.4 1992/09/09 09:57:57 kjb Exp $
  18. ;*
  19. ;* Revision History:
  20. ;* -----------------
  21. ;*
  22. ;* $Log: cpu.asm $
  23. ;* Revision 1.4  1992/09/09  09:57:57  kjb
  24. ;* Fixed to only check for emulation on > 80286 machines.
  25. ;*
  26. ;* Revision 1.3  1992/09/08  09:36:25  kjb
  27. ;* Added code to check for 80x87 emulation software.
  28. ;*
  29. ;* Revision 1.2  1992/04/13  18:53:43  kjb
  30. ;* Added support for detecting the numeric co-processor
  31. ;*
  32. ;* Revision 1.1  91/11/28  01:52:21  kjb
  33. ;* Initial revision
  34. ;* 
  35. ;****************************************************************************
  36.  
  37.         IDEAL
  38.  
  39. INCLUDE "model.mac"                ; Memory model macros
  40.  
  41. header    cpu                        ; Set up memory model
  42.  
  43. ;****************************************************************************
  44. ;
  45. ; Equates used by queryCPU routine.
  46. ;
  47. ;****************************************************************************
  48.  
  49. ; Central Processing Unit type codes
  50.  
  51. CPU86        =     0                ; 8086/88 type processor
  52. CPU186        =    1                ; 80186 type processor
  53. CPU286        =    2                ; 80286 type processor
  54. CPU286p        =    3                ; 80286 type processor in protected mode
  55. CPU386        =    4                ; 80386 type processor
  56. CPU386p        =    5                ; 80386 type processor in protected mode
  57. CPU486        =    6                ; 80486 type processor
  58. CPU486p        =    7                ; 80486 type processor in protected mode
  59.  
  60. ; Floating Point Unit type codes
  61.  
  62. FPUNONE        =    0                ; No coprocessor present
  63. FPU87        =    1                ; 8087 coprocessor
  64. FPU287        =    2                ; 80287 coprocessor
  65. FPU387        =    3                ; 80387 coprocessor
  66. FPU487        =    4                ; 80487 coprocessor
  67.  
  68. begcodeseg    cpu                    ; Start of code segment
  69.  
  70. P386                            ; Enable all '386 instructions
  71. P387                            ; Enable all '387 instructions
  72.  
  73. ; Save the type of CPU detected so we can determine the co-processor
  74. ; type correctly. This means that we MUST call queryCpu() BEFORE calling
  75. ; queryFpu() to obtain correct results.
  76.  
  77. cpu            dw    CPU86
  78.  
  79. ;----------------------------------------------------------------------------
  80. ; cpu_type queryCpu(void)
  81. ;----------------------------------------------------------------------------
  82. ; Determine type of processor present.
  83. ;----------------------------------------------------------------------------
  84. procstart    _queryCpu
  85.  
  86.         push    bp                ; We MUST save bp for initialization code...
  87.  
  88.         mov        ax,CPU86        ; Default to 8086/8088 processor
  89.         push    sp
  90.         pop        bx                ; BX holds the value of SP or SP-2
  91.         cmp        bx,sp            ; 88/86/186 pushes the value of SP-2
  92.         je        @@Check286        ; Must be a 286/386/486 type processor
  93.         mov        cl,32            ; 186 uses count mod 32 = 0
  94.         shl        bx,cl            ; 86 shifts 32 bits left so ax = 0
  95.         jz        @@Done            ; zero: shifted out all bits so 86/88
  96.         mov        ax,CPU186        ; nonzero: no shift, so 186
  97.         jz        @@Done
  98.  
  99. @@Check286:                        ; First check for 386/486 in 32 bit mode
  100.         pushf                    ; Test for 16 or 32 operand size:
  101.         mov        bx,sp            ;  pushed 2 or 4 bytes of flags
  102.         popf
  103.         inc        bx
  104.         inc        bx
  105.         cmp        bx,sp            ; did pushf change sp by 2?
  106.         jnz        @@Check486        ; 32 bit push, so it is a 386/486
  107.  
  108.         sub        sp,6            ; Is it a 286/386/486 in 16 bit mode?
  109.         mov        bp,sp
  110.         sgdt    [QWORD ptr bp]    ; 80286/386/486 specific instrucion
  111.         add        sp,4            ; Get global descriptor table
  112.         pop        bx
  113.         inc        bh                ; Third word of GDT = -1 for 286
  114.         jnz        @@Check486        ; We have a 386/486
  115.  
  116.         mov        ax,CPU286        ; We have a 286
  117.         jmp        @@TestPROT
  118.  
  119. @@Check486:
  120.  
  121. ; Distinguish an 80386 from an 80486. Bit 18 (40000H) of EFLAGS register
  122. ; is used only in the 486. This code flips it and tests if anything happened.
  123.  
  124.         mov        edx,esp            ; Save stack pointer
  125.         and        esp,not 3        ; Align stack pointer to prevent a fault
  126.                                 ;  when we set the AC flag on a 486
  127.         pushfd                    ; Copy the EFLAGS register
  128.         pop        eax                ;   into register eax
  129.         mov        ecx,eax            ; Save the original EFLAGS value
  130.         xor        eax,40000H        ; Flip the AC flag bit
  131.         push    eax                ; Try to put the modified value back
  132.         popfd                    ;   into the EFLAGS register
  133.         pushfd                    ; Copy the EFLAGS register again
  134.         pop        eax                ;   into eax
  135.         xor        eax,ecx            ; Compare the old and new AC bits
  136.         shr        eax,18            ; Shift and mask to get the AC comparison bit
  137.         and        eax,1            ;   in the low order position of eax
  138.         push    ecx
  139.         popfd                    ; Restore EFLAGS that were saved on entry
  140.         mov        esp,edx            ; And restore stack pointer to saved value
  141.         mov        bx,ax            ; and move into bx
  142.  
  143. ; At this point ax = 0 for a 386, or ax = 1 for a 486
  144.  
  145.         mov        ax,CPU386        ; Assume a 386
  146.         test    bx,bx
  147.         jz        @@TestPROT        ; We have a 386
  148.         mov        ax,CPU486        ; We have a 486
  149.  
  150. @@TestPROT:
  151.         smsw    cx                ; protected? machine status -> cx
  152.         ror        cx,1            ; protection bit -> carry flag
  153.         jnc        @@Done            ; Real mode if no carry
  154.         inc        ax                ; Protected: return value + 1
  155.  
  156. @@Done:
  157.         mov        [cpu],ax        ; Save CPU type in code segment variable
  158.         pop        bp                ; Restore bp
  159.         ret                        ; We are done
  160.  
  161. procend        _queryCpu
  162.  
  163. ndp_cw    dw    ?
  164. ndp_sw    dw    ?
  165.  
  166. ;----------------------------------------------------------------------------
  167. ; fpu_type queryFpu(void)
  168. ;----------------------------------------------------------------------------
  169. ; Determine type of floating point coprocessor present in the system.
  170. ; The idea is to determine whether or not the floating-point control word
  171. ; can be successfully read. If it cannot, then no coprocessor exists.
  172. ; If it can the correct coprocessor is then determined depending on the
  173. ; main CPU id.
  174. ;----------------------------------------------------------------------------
  175. procstart    _queryFpu
  176.  
  177.         push    bp
  178.  
  179.         mov        bx,FPUNONE        ; Default to no FPU present
  180.  
  181. ; The next two 80x87 instructions cannot carry the WAIT prefix,
  182. ; because there may not be an 80x87 for which to wait.  The WAIT is
  183. ; therefore emulated with a MOV CX,<value> LOOP $ combination.
  184.  
  185.         mov        [ndp_cw],0        ; Clear the control word in memory
  186.         cli                        ; Interrupts must be off during test
  187.  
  188.         fninit                    ; reset NDP status word
  189.         mov        cx,2            ; Wait for co-pro to complete operation
  190.         loop    $
  191.  
  192.         fnstcw    [ndp_cw]        ; Obtain the processor control word
  193.         mov        cx,14h            ; Wait for co-pro to complete operation
  194.         loop    $
  195.  
  196.         sti                        ; Re-enable interrupts
  197.  
  198. ; We check to see that the precison control bits of the control word
  199. ; indicate 64 bit internal precision (bits 8 & 9 set) which is the default
  200. ; set up by the fninit instruction above. We also test that the exception
  201. ; masks are properly set.
  202.  
  203.         mov        ax,[ndp_cw]        ; AX := NDP control word
  204.         and        ax,033fh        ; Mask out the precision control bits etc.
  205.         cmp        ax,033fh        ; is the NDP present?
  206.         jne        @@Done            ; No, we are all done... (must be a 3)
  207.  
  208. ; Determine the type of NDP from the main CPU type
  209.  
  210.         mov        bx,FPU87        ; Start with the 8087 NDP
  211.         mov        ax,[cpu]        ; Get current cpu type
  212.         cmp        ax,CPU286        ; >= 80286 type processor?
  213.         jge        @@80286            ; Yes, check for 287/387/487
  214.         jmp        @@Done            ; No, we are done
  215.  
  216. ; Now that we know we have a possible co-processor and the processor is
  217. ; at least an 80286, we can check to se if coprocessor emulation software
  218. ; is installed in the system. Some emulators such as FRANKIE.387 emulate
  219. ; the co-processor so well that the above checks believe a co-pro is
  220. ; actually out there.
  221.  
  222. @@80286:
  223.         smsw    ax                ; AX := machine status word
  224.         test    al,4            ; Check the EM bit status
  225.         jnz        @@Done            ; Software emulation installed on INT 7!
  226.  
  227.         cmp        ax,CPU386        ; Do we have a 386 or above?
  228.         jge        @@80386            ; Yes, check for it
  229.         mov        bx,FPU287        ; We have a 80287 co-pro
  230.         jmp        @@Done
  231.  
  232. @@80386:
  233.         cmp        ax,CPU486        ; Do we have a 486 or above?
  234.         jge        @@80486            ; Yes, check for it
  235.  
  236. ; The i386 processor can work with either an 80287 or 80387 co processor
  237. ; so we must check for that here. The 387 says that +inf <> -inf while
  238. ; the 287 says that they are the same.
  239.  
  240.         fld1                    ; Load +1.0 onto NDP stack
  241.         fldz                    ; Load +0.0 onto NDP stack
  242.         fdiv                    ; do +1/0 (create +inf)
  243.         fld1                    ; Load +1.0 onto NDP stack
  244.         fchs                    ; Change to -1.0
  245.         fldz                    ; Load +0.0 onto NDP stack
  246.         fdiv                    ; do -1/0 (create -inf)
  247.         fcompp                    ; compare and pop values from stack
  248.         fstsw    [ndp_sw]        ; Get the status word from the co pro
  249.         mov        ax,[ndp_sw]        ; AX := Status word
  250.         and        ah,41h            ; Mask out C3 and C0 condition codes
  251.         cmp        ah,40h            ; C3 = 1, C0 = 0 means ST(0) == ST(1)
  252.         mov        bx,FPU287        ; Set up for a 287 co pro
  253.         je        @@Done            ; Yes, we were correct
  254.  
  255.         mov        bx,FPU387        ; No, it was an 80387
  256.         jmp        @@Done
  257.  
  258. @@80486:
  259.         mov        bx,FPU487        ; We must have a 487 co pro.
  260.  
  261. @@Done:
  262.         mov        ax,bx            ; Return FPU type in AX
  263.         pop        bp                ; Restore bp
  264.         ret                        ; We are done
  265.  
  266. procend        _queryFpu
  267.  
  268. endcodeseg    cpu
  269.  
  270.         END                        ; End of module
  271.