home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / cpu / cpu_id / cpuid.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1994-04-24  |  6.2 KB  |  227 lines

  1. {$A+,B-,D+,E+,F-,G-,I+,L+,N+,O-,P-,Q-,R-,S+,T-,V+,X+,Y+}
  2. {
  3. Here is some code that identifies the CPU and FPU of your computer.  It
  4. demonstrates coordination of INLINE, ASM and standard Pascal code.  This
  5. routine uses INTEL recommended CPU identification techniques.  It also
  6. demontrates two techniques that may be used to address the extended 
  7. registers of the 386 and 486.
  8.  
  9. Donated to the public domain.  John D. Leonard II
  10. }
  11.  
  12. unit cpuid;
  13.  
  14. interface
  15.  
  16.  
  17. Procedure CPUFPUID(var CPU,FPU:integer);
  18.  
  19.    {- This routine determine the type of CPU and FPU (Floating Point Unit)
  20.       using INTEL recommended techniques as posted in CPUID.ASM on the
  21.       PCEO Intel Forum.  It has been supplemented with a check for the
  22.       386SX }
  23.  
  24.    {-Returns 1: 8088/8086
  25.              2: 80286
  26.              3: 80386   -3: 80386SX
  27.              4: 80486 -}
  28.  
  29.    {-This routine does not require external OBJ files, all assembler
  30.      calls are implemented using ASM directive or INLINE code. -}
  31.  
  32.    {-Use of INLINE was required, as the TP6 ASM processor does not
  33.      recognize 386/486 specific register addressing -}
  34.  
  35.    {-The procedure first determines the CPU type by filtering through
  36.      a series of tests.  Then, the FPU check is performed. -}
  37.  
  38.    {-This procedure demonstrates the use of ASM directives and INLINE
  39.      code, in conjunction with regular TP assignments and labels. -}
  40.  
  41.    {-This code as been tested with 8088, 80286, 80386, 80386sx and 80486,
  42.      (Yes, Virginia, we have them all sitting around the place.) }
  43.  
  44. { ==================================================================== }
  45.  
  46. implementation
  47.  
  48.  
  49. Procedure CPUFPUID(var CPU,FPU:integer);
  50.    label check_fpu,stop,restore_eflags;
  51.    var fp_status:word;
  52.    begin
  53.  
  54. {- Begin a series of tests to determine CPU type ... -}
  55.  
  56. {- On an 8086/8088 Flag Bits 12-15 are always set -}
  57.       cpu := 1;
  58.       asm
  59.          PUSHF
  60.          POP   BX
  61.          MOV   AX,0FFFH
  62.          AND   AX,BX
  63.          PUSH  AX
  64.          POPF
  65.          PUSHF
  66.          POP   AX
  67.          AND   AX,0F000H
  68.          CMP   AX,0F000H
  69.          JE    CHECK_FPU
  70.       end;
  71.  
  72. {- On a 80286 Flag Bits 12-15 are always clear -}
  73.  
  74.       cpu := 2;
  75.       asm
  76.          OR    BX,0F000H
  77.          PUSH  BX
  78.          POPF
  79.          PUSHF
  80.          POP   AX
  81.          AND   AX,0F000H
  82.          JZ    CHECK_FPU
  83.       end;
  84.  
  85. {- On a 80486, bit 18 of EFLAGS can be set.  It can't be set on 386.
  86.    (This bit relates to generation of alignment faults. )
  87.    Note the use of DB 66H in this code for reference to the
  88.    386 extended registers.  It acts like a SHIFT key, allowing direct
  89.    translation of some addressing commands between the standard
  90.    registers and the 386/486 extended registers. }
  91.  
  92.       cpu := 4;
  93.       asm
  94.  
  95.       {- Align Stack to prevent a fault -}
  96.  
  97.          MOV   DX,SP            { MOV    DX, SP     }
  98.          AND   SP, NOT 3        { AND    SP, NOT 3  }
  99.  
  100.       {- Get EFLAGS and store in ECX for later comparison and restoration }
  101.  
  102.          DB    66H
  103.          PUSHF                  { PUSHFD            }
  104.          DB    66H
  105.          POP   AX               { POP    EAX        }
  106.          DB    66H
  107.          MOV   CX,AX            { MOV    ECX,EAX    }
  108.  
  109.  
  110.       {- Set Bit #18.  Note use of DW to get large integer -}
  111.  
  112.          DB    66H
  113.          XOR   AX,0
  114.          DW    4H               { XOR    EAX,40000H }
  115.  
  116.       {- Stick the result into EFLAGS, and get it back.  Keep in EAX -}
  117.  
  118.          DB    66H
  119.          PUSH  AX               { PUSH   EAX        }
  120.          DB    66H
  121.          POPF                   { POPFD             }
  122.          DB    66H
  123.          PUSHF                  { PUSHFD            }
  124.          DB    66H
  125.          POP   AX               { POP    EAX        }
  126.  
  127.       {- Restore Flags and Stack before making comparison -}
  128.  
  129.          DB    66H
  130.          PUSH  CX               { PUSH   ECX        }
  131.          DB    66H
  132.          POPF                   { POPFD             }
  133.          MOV   SP,DX            { MOV    SP,DX      }
  134.  
  135.          DB    66H
  136.          XOR   AX,CX            { XOR    EAX,ECX    }
  137.          JNZ   CHECK_FPU
  138.  
  139.       end;
  140.  
  141.  
  142. {- On a 386, the coprocessor type bit in CR0 can be set.  On a 386Sx,
  143.    it can not be set.  NOTE: this test is not a part of the recommended
  144.    INTEL CPU check code.  ALSO NOTE: this code can not determine early
  145.    versions of the 386sx, as they allow this bit to be set.  INLINE was
  146.    required, as there is no way to "shift" ala "DB 66H" to access CR0. }
  147.  
  148.  
  149.       cpu := -3;
  150.       inline( $0f/$20/$c0 );         { MOV EAX,CR0 }
  151.       inline( $66/$8b/$c8 );         { MOV ECX,EAX }
  152.       inline( $66/$83/$F0/$10);      { MOV EAX,10H }
  153.       inline( $0f/$22/$c0 );         { MOV CR0,EAX }
  154.       inline( $0f/$20/$c0 );         { MOV EAX,CR0 }
  155.       inline( $0f/$22/$c1 );         { MOV CR0,ECX }
  156.       inline( $66/$33/$c1 );         { XOR EAX,ECX }
  157.       asm
  158.          JZ CHECK_FPU
  159.       end;
  160.  
  161. {- The default CPU type, if all else fails. -}
  162.  
  163.       cpu := 3;
  164.  
  165.  
  166. {- Begin CoProcessor Check.  We first check if the FPU can be initialized.
  167.    If not, there is no FPU.  If we have got one, it will, in general
  168.    match the CPU type, i.e. 8087 goes with 8086/88, 287 goes with 286, etc.
  169.    The only exception is the 386, which may use either the 387 or 287. }
  170.  
  171.  
  172.    CHECK_FPU:
  173.  
  174. {- Can we initialize the CoProcessor? -}
  175.  
  176.       FPU := 0;
  177.       asm
  178.          FNINIT
  179.          MOV    FP_STATUS,5A5AH
  180.          FNSTSW FP_STATUS
  181.          MOV    AX,FP_STATUS
  182.          JNE    STOP
  183.          FNSTCW FP_STATUS
  184.          MOV    AX,FP_STATUS
  185.          AND    AX,103FH
  186.          CMP    AX,3FH
  187.          JNE    STOP
  188.       end;
  189.  
  190. {- Yes!  Assign the corresponding FPU based on CPU -}
  191.  
  192.       FPU := abs(CPU);
  193.  
  194. {- However, if we have a 386/386SX, we must determine 387 or 287.  A 387
  195.    differentiates between positive and negative infinity, a 287 does not. }
  196.  
  197.       if FPU=3 then begin
  198.  
  199.          FPU := 2;
  200.          asm
  201.             FLD1
  202.             FLDZ
  203.             FDIV
  204.             FLD    ST
  205.             FCHS
  206.             FCOMPP
  207.             FSTSW  FP_STATUS
  208.             MOV    AX,FP_STATUS
  209.             SAHF
  210.             JZ     STOP
  211.          end;
  212.  
  213.          fpu := 3;
  214.  
  215.       end;
  216.  
  217.  
  218.    stop:
  219.  
  220.  
  221.    end;
  222.  
  223.  
  224.  
  225.  
  226. end.
  227.