home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / basic / library / qb_pds / dcpu / masm / equip2.asm < prev   
Encoding:
Assembly Source File  |  1994-06-17  |  16.6 KB  |  366 lines

  1. ; Created 10/01/90
  2. ; Updated 03/20/92
  3. ;    To restore status of control word to QBASIC defaults
  4. ; Revised 10/06/92
  5. ;    Added routine to check for 80C287A
  6. ; Revised 06/30/93
  7. ;    Better handle old PC's with an 8087
  8. ; Revised 12/07/93
  9. ;    More info on control flags, results of testing Cyrix 80387SX chip
  10. ; Revised 03/29/94
  11. ;    More info on control bits, testing Cyrix 486D - 486DX clone
  12. ;    Updated 06/06/94 more info on purpose of port 0F0h
  13.  
  14. ;======================================================================
  15. ;   Copyright (C) Copr. 1990, 1991, 1992, 93, 94 by Sidney J. Kelly
  16. ;           All Rights Reserved.
  17. ;           Sidney J. Kelly
  18. ;           150 Woodhaven Drive
  19. ;           Pittsburgh, PA 15228
  20. ;           home phone 412-561-0950 (7pm to 9:30pm EST)
  21. ;======================================================================
  22. ;;;;«RM82»«TS8,16,24,32,40,48,56»
  23.  
  24. DOSSEG
  25. .MODEL MEDIUM, BASIC
  26. .CODE
  27. ;======================================================================
  28. ; DECLARE FUNCTION CHECK87%()
  29. ; Returns:
  30. ;        0 if no 80x87, or system equipment bit not set for 80x87.
  31. ;       87 if an 8087
  32. ;      -87 if 8087 emulation in use on an 80286 or 80386.  Because the
  33. ;           the 80287 has almost exactly the same instruction set as the
  34. ;           8087 few have felt a need to emulate the 80287.  The 80827
  35. ;           just includes one new instruction (protected mode),
  36. ;           nothing for use in real mode.  80387 has transendental
  37. ;           math routines.  (Note: real mode software math chip emulators will 
  38. ;        not work with protected mode software without hugh speed penalties).
  39. ;      287 if an 80827 (note on early 386SX, an 80287 was allowed)
  40. ;     1287 if an 80C287A/80287XL (an 80287 with the 80387 instruction set)
  41. ;      387 if an 80387, 80387SX or 80486DX.
  42. ;          Because of 486SX not all 486's will have a math chip.
  43. ;          The 80387/80486DX is much faster than an 80287 because it does
  44. ;          not need the FWAIT's before every instruction
  45. ;
  46. ; More accurate than just checking the equipment word.
  47. ; QBX, Version 7 and QBASIC 4.5 both merely check the equipment
  48. ; word (Int 11h, 0040:0010) to determine if an 80x87 is installed.
  49. ; Therefore, changing the bit in at 0040:0010 at can be used as a
  50. ; software toggle.
  51. ;
  52. ; Because of complaints about the traditional test with inexpensive clones
  53. ; (See Jon Waterhouse letter in BYTE, Nov. 1990, page 40) routine first
  54. ; tests the equipment word in RAM bios.  If the equipment bit is clear,
  55. ; then routine halts.   It does not check CMOS equipment word math
  56. ; chip bit because not all clones properly record in CMOS that a math chip
  57. ; is installed (e.g. ACER 910 w/ Award BIOS only adjusts Int 11h).
  58. ;
  59. ; You should assume that if switch for NDP is not set or Int 11h does not
  60. ; show an NDP that user wanted it that way.
  61. ;
  62. ; Tested: Intel 80287, Cyrix 80387SX, software emulation of 8087, Intel 486DX
  63. ;======================================================================
  64. ;
  65. ;   REFERENCES:
  66. ;       basic info is adapted from Ted Forgeron's article in PC
  67. ;         Tech Journal, Aug '87 p43.
  68. ;       Copr. 1987      Pat Shea - Psi! (that Copr. is on there cuz my
  69. ;                                        lawyer sez I should, but feel
  70. ;                                        free to hack away!!!    pats.)
  71. ;     In the event of subsequent republication of this function,
  72. ;       please carry forward reference to these two gentlemen as
  73. ;       original authors.
  74. ; Minor beautification, addition of MASM 5.1 simplified
  75. ;    directives, detection of emulation, additional commentary by SJK 12/12/90
  76. ;
  77. ; Similar code: Robert Zigon, "Interactive Bezier Curves" Tech Specialist
  78. ;  V2,N3,P53 (March 1991)
  79. ;
  80. ; This code is based on code from Intel's "i486 Programmers Reference Manual"
  81. ; cpuid32.asm  - Per file
  82. ;  "This program has been developed by Intel Corporation.  You have
  83. ;   Intel's permission to incorporate this source code into your
  84. ;   product royalty free."
  85. ;  as modified by Wayne A. King, [CIS: 70022,2700] 5/24/93 for use w/ 
  86. ;  MASM 5.1, to correct bugs w/ real mode processors and 32 bit instructions
  87. ;
  88. ; The CX loop idea for slow PC's with a math chip is from the public
  89. ; domain INFOPLUS Version 1.56, Andrew Rossman 12/30/92.  
  90. ;======================================================================
  91.  
  92. EVEN
  93. CTRL_Word       DW      0       ; CTRL_Word word for the NDP test.
  94. Orig_CW         DW      0       ; original CTRL_Word
  95. DATA1           DT      0       ; temp storage for 387 testing
  96.  
  97. ; Please do not remove
  98. Copyright       DB    13,10,'Copyright Copr. (C) 1990, 1991, 1994 Sidney J. Kelly',13,10
  99. Copyright1      DB    'All Rights Reserved',13,10,26
  100.  
  101. EVEN
  102. CHECK87 PROC FAR
  103.     Pushf                   ; save flags
  104. ;--------
  105. ; in response to clone errors, test to see if system knows
  106. ; if math chip is installed. If Int 11h sez no, then
  107. ; report no mathchip.  Can't check AT CMOS mathchip bit
  108. ; because some clones do not set the bit in the CMOS, but
  109. ; only set the bit in the Int 11h equipment word, e.g. ACER 910, during
  110. ; boot up.
  111. ;--------
  112.     Int     11h
  113.     Test    AL,10b          ; is mathchip bit Set?
  114.     JZ      No_Math_Chip    ; no mathchip
  115. ; Test for any mathchip
  116.     Xor     AX,AX           ; make AX = 0
  117.     Mov     Word Ptr CS:[CTRL_Word],AX       ; clear CTRL_Word
  118.     Out     0F0h,AX         ; clear busy bit on 80287+
  119.     ; w/o changing (real/protected) mode of NDP by writing 0 to the port.
  120. ; Per "Intel486 SX Microprocessor Intel487 SX Math CoProcessor Data Book" 
  121. ; (Intel 1991) ISBN 1-55512-158-6, pages 140-141, a write to this port
  122. ; acts as external device reset to clear IRQ 13 error on  80287+ chip
  123. ; an internal device reset for 80287+ requires a FNINIT
  124.     ; Load a sensible default control value so NDP handles all
  125.     ; exceptions.  This should help prevent errors because of slow
  126.     ; chips (affine, even, 64 bit precision)
  127.     Mov     Word Ptr CS:[Orig_CW],13BFh     ; store a reasonable value
  128.     ; default after FINIT on 80387 is 037Fh.  After QBASIC
  129.     ; tests math chip, the control word becomes 1370h
  130. ;-------
  131. ; The next 80x87 instructions cannot carry the WAIT prefix,
  132. ; because there may not be an 80x87 for which to wait.  The WAIT is
  133. ; therefore emulated with a MOV CX,<value>! LOOP $ combination.  This
  134. ; allow use of routine on an old PC with an 8087.
  135. ;-------
  136.     FNSTCW  Word Ptr CS:[Orig_CW]   ; save original value
  137.     ; it takes about 24 clocks for a real NDP to do this
  138.     ; (about 3-5 clocks on a 486)
  139.     ; it do have a chip, our "reasonable value" will be overwritten
  140.     Mov     CX,14h          ; time waste loop
  141.     Loop    $               ; to substitute for a FWAIT
  142.     JMP     $+2             ; waste time and flush que
  143.     JMP     $+2             ; waste time and flush que
  144.     FNINIT                  ; try to initialize the NDP
  145.     ; it takes about 8 clocks for a real NDP to do this, 33 clocks
  146.     ; for 80387, 17 clocks on a 486
  147. ;------
  148. ; use the no-wait state version of the op code so will not
  149. ; hang a machine without a NDP.  Loop allows test of a PC that
  150. ; does have an 8087.
  151. ;------
  152.     Mov     CX,14h          ; a time waste loop
  153.     Loop    $               ; allow 8087 time to react
  154.     JMP     $+2             ; waste time and flush que
  155.     FNSTCW  CS:[CTRL_Word]  ; put CTRL_Word in memory
  156.     ; it takes about 24 clocks for a real NDP to do this
  157.     ; 3 to 5 clocks on a 486
  158. ;-------
  159. ; use the no-wait state version of the op code so will not
  160. ; hang a machine without a NDP.  Loop allows test of a PC that
  161. ; does have an 8087.
  162. ;-------
  163.     Mov     CX,14h
  164.     Loop    $
  165.     JMP     $+2             ; waste time and flush que
  166.     Cmp     BYTE PTR CS:[CTRL_Word+1],3  ; if high byte = 3h have NDP
  167.     Je      Chk_87          ; found something, so keep going
  168. No_Math_Chip:
  169.     Xor     AX,AX           ; else zero AX to show
  170.     Popf                    ; restore flags
  171.     Ret                     ; end, return to main routine
  172. Chk_87:                         ; Test for 8087
  173.     ; we know we have a math chip now, so test if 
  174.     ; CPU is old 808x, 8018x, NEC V series chip
  175.     Push    SP
  176.     Pop    AX
  177.     Cmp    AX,SP        ; SP = AX if have 80286+ chip
  178.     Jne    Have_87        ; else old mode chip, no emulation possible
  179. ; we now have a math chip and an 80286+ CPU
  180.     And     CS:[CTRL_Word],NOT 080h      ; turn ON interrupts (IEM = 0)
  181.     ; IEM is bit 7 of control word
  182.     FLDCW   CS:[CTRL_Word]  ; load CTRL_Word word
  183.     FDISI                   ; turn OFF interrupts (IEM = 1)
  184.     FSTCW   CS:[CTRL_Word]  ; store CTRL_Word word
  185.     FWAIT                   ; allow time for update to occur
  186.     ; if IEM=1, 8087 (only 8087 pays attention to IEM)
  187.     Test    CS:[CTRL_Word],80h  ; test IEM
  188.     Jz     Chk_287          ; not an 8087, test for 80287
  189. Report_Emulation:
  190. ;-----------
  191. ; Report have 8087 emulation by software.  Emulation only can be done on an
  192. ; 80286 or 80386.   To get this far, CPU must be 80286+, emulating 8087
  193. ; There is no particular advantage to emulating 80287.  In addition, some
  194. ; early 80386DX and 80386SX CPU's used the 80287 chip, so can't easily test
  195. ; for emulation of an 80287 on a 386 machine.
  196. ;-----------
  197.   ;--- not necessary, already tested for above
  198.   ;    Xor    AX,AX            ; clear AX
  199.   ;    Push   AX               ; put on stack
  200.   ;    Popf                    ; put in flags
  201.   ;    Pushf                   ; put back on stack
  202.   ;     Pop    AX               ; get flags back in AX
  203.   ;    And    AX,0F000h        ; clear all but upper 4 bits
  204.   ;    Cmp    AX,0F000h        ; if bits 12-15 are set then CPU
  205.   ;    JE     Have_87          ; is not an 80286, 80386 or 80486
  206.     Mov    AX,-87           ; put -87 in AX to show that
  207.     Jmp    SHORT Chk_87_END ;  emulation is detected
  208.  ;-----------
  209.   ; I haven't tested the software that emulates the 80287/80387 so this is
  210.   ; not tested for.  Emulation of an x87 is possible
  211.   ; because of  a special  bit (EM or Bit 2) in the 80286 machine status
  212.   ; word and the use of a specific interrupt generated by 80826/80386 if
  213.   ; coprocessor is not available.  The 80386 also can do emulation
  214.   ; using Bit 2 in register CR0 along with the use of a  special interrupt
  215.   ; if the coprocessor is not available.
  216.   ;
  217.   ; Emulators of 80387 have also become available, though not tested.
  218.   ; The only reason for testing for emulation is to suggest to user that he
  219.   ; would get faster results if he relied on MS QuickBasic built in
  220.   ; software emulation rather than other forms of software emulation.
  221.   ; Moreover, because many software emulators do not work with
  222.   ; protected mode (otherwise speed penalty would be huge), emulators
  223.   ; would take up space on a fast 386 machine.   SJK
  224.  ;-----------
  225. Have_87:
  226.                 ; CPU is a NEC, 8086/88 or 80186/88
  227.     Mov    AX,87            ; put 87 in AX to show
  228.     Jmp    SHORT Chk_87_END ; no emulation is detected
  229. Chk_287:                        ; Test for 80287
  230. ; if any of the following instructions is not available, Int 07h
  231. ; will call a BIOS routine that ignores the error on 80286+ in real mode
  232. ; This has been tested.  Though, should only get here if have a 8087 chip
  233. ; Should not get an error in protected mode w/ 80386+ chip, because
  234. ; math chip either must exist or it must be emulated to get this far.
  235.     FINIT                   ; set default infinity mode
  236.     FLD1                    ; push 1 on stack
  237.     FLDZ                    ; push 0 on stack
  238.     FDIV                    ; then divide. Make infinity
  239.                 ; by dividing 1 by zero
  240.     FLD    ST               ; push back on stack.   Change
  241.     FCHS                    ; sign & make negative infinity
  242.     FCOMPP                  ; compare the two infinities
  243.                 ; pops stack and eliminates 2 pushes
  244. ;--------
  245.  ; Default after FINIT for 80287 & 8087 is projective infinity where
  246.  ; both positive and negative infinity are equal.  The 80C287A
  247.  ; (a faster 80287 chip with all the features of the 80387), the 80387 and
  248.  ; and the 80486DX use  affine infinity, and ignore projective infinity.
  249.  ; Under affine infinity positive and negative infinity are at opposite
  250.  ; ends of the  number line and are not equal.  
  251.  ;      (SJK - Who thinks of these things???)
  252. ;--------
  253.     FSTSW  CS:[CTRL_Word]   ; store status for result
  254.     FWAIT                   ; wait until status word is stored
  255.     Mov    AX,CS:[CTRL_Word] ; get CTRL_Word word
  256.     SAHF                    ; put highbyte (AH) status in flags
  257.     Jnz    Test_4_387       ; If bit 6 (infinity control)
  258.                 ; not set then it is a 80387 or 80C287A
  259. Have_287:
  260.     Mov    AX,287           ; else report that it is an 80287
  261.                 ; since we tested for an 8087
  262.     Jmp    SHORT Chk_87_END
  263. ;------------
  264. ; NDP not an 8087 or an 80287 so it must be an 80387(80486DX) or 80C287A.
  265. ; The 80486DX/80387/80C287A ignore the infinity control (IC) flag,
  266. ; while the 80287/8087 do not. SJK
  267. ;------------
  268. Test_4_387:
  269. ;.387                           ; allows assembly of 387 instructions
  270.                 ; and cuts out many of the FWAITs
  271. ; if your assembler wont handle .387 then the DB equivalents
  272. ; are shown below the .387 instruction
  273. ; .387 mode code wont run on a 286 because .387 drops the FWAIT that
  274. ; preceed all the NDP instructions, a 286 needs the syncronization
  275. ; that the FWAITs provide.
  276.     FLDPI                   ; load Pi (value in radians)
  277. ;       FSIN                    ; take the Sin(Pi)
  278.     DB      0D9h,0FEh       ; the code for FSIN
  279. ; if NDP wont support op codes, 80286+ bios will capture error and
  280. ; ignore it
  281.     FSTP    TByte Ptr DATA1 ; store and Pop
  282.     FWAIT                   ; wait for memory to catch up
  283.     FLD     TByte Ptr DATA1 ; get value back
  284.     FWAIT                   ; wait for memory to catch up
  285. ;       FCOS                    ; now take Cos(Sin(PI))
  286.     DB      0D9h,0FFh       ; the code for FCOS
  287. ; if COS(SIN(Pi)) is calculated correctly it = 1.00, if FSIN and FCOS 
  288. ; not available or don't work, then COS(SIN(Pi)) will = Pi
  289.     FLD1                    ; load 1
  290.     FCOMPP                  ; compare ST(0) with ST(1)
  291.                 ; pops stack and eliminates 2 pushes
  292.     FSTSW  CS:[CTRL_Word]   ; store status for result
  293.     FWAIT                   ; wait until status word is stored
  294.     Mov    AX,CS:[CTRL_Word] ; get CTRL_Word word
  295.     SAHF                    ; place in flags
  296.     JNZ     Have_287        ; if not equal then have 287 chip
  297. ; distinguish between 80386 and 80286 based on flags
  298.     Mov     AX,0F000h       ; see if 80286 or 80386
  299.     Push    AX
  300.     PopF
  301.     PushF
  302.     Pop     AX
  303.     And     AX,0F000h
  304.     JNZ     Have_387        ; if not clear, quit, have 80387
  305.     Mov     AX,1287         ; report have 80C287A/80287XL
  306.     Jmp     Short  Chk_87_END
  307. Have_387:
  308.     Mov     AX,387          ; report have 80387
  309. Chk_87_END:
  310.     Mov     Byte Ptr CS:[Orig_CW+1],00010011b
  311.     ; select affine infinity, even rouding, 64 bit precision
  312.     ; but don't touch lower byte since QB sets it to control
  313.     ; its own exception handling
  314.     FLDCW   Word Ptr CS:[Orig_CW]   ; re-load modified original word
  315.     Popf                            ; restore flags
  316.     Ret                             ; end, return to main routine
  317. CHECK87 ENDP
  318. END
  319.  
  320. Math chip control word, high byte
  321. ┌──┬──┬──┬──┬──┬──┬──┬──┐
  322. │F │E │D │C │B │A │9 │8 │  bits within high byte
  323. └┬─┴┬─┴┬─┴┬─┴┬─┴┬─┴┬─┴┬─┘
  324.  │  │  │  │  │  │  └──┴───Precision Control
  325.  │  │  │  │  │  │            (00 = 24 bits)
  326.  │  │  │  │  │  │            (01 = undefined)
  327.  │  │  │  │  │  │            (10 = 53 bits)
  328.  │  │  │  │  │  │            (11 = 64 bits) DEFAULT
  329.  │  │  │  │  └──┴─────────Rounding Control
  330.  │  │  │  │                  (00 = Nearest or Even) DEFAULT
  331.  │  │  │  │                  (01 = Round Down to minus infinity)
  332.  │  │  │  │                  (10 = Round Up to positive infinity)
  333.  │  │  │  │                  (11 = Chop/truncate toward 0)
  334.  │  │  │  └───────────────Infinity Control
  335.  │  │  │                     (0 = Projective infinity)
  336.  │  │  │                     Default on FINIT on 8087/80287
  337.  │  │  │                     (1 = Affine infinity)   QBASIC default
  338.  └──┴──┴──────────────────Reserved
  339.                  (All 0)
  340.  
  341. After FINIT, the default high byte is 03h, or
  342.     Projective infinity, round nearest, 64 bits of precision
  343. QBASIC uses 13h for high byte or
  344.     Affine infinity, round nearest, 64 bits of precision
  345.  
  346. Low byte of control word
  347. ┌──┬──┬──┬──┬──┬──┬──┬──┐
  348. │7 │6 │5 │4 │3 │2 │1 │0 │  bits within low byte
  349. └┬─┴┬─┴┬─┴┬─┴┬─┴┬─┴┬─┴┬─┘
  350.  │  │  │  │  │  │  │  └─── Invalid operation (IM)
  351.  │  │  │  │  │  │  └────── Denormalized operation (DM)
  352.  │  │  │  │  │  └───────── Divide by zero error (ZM)
  353.  │  │  │  │  └──────────── Overflow (UM)
  354.  │  │  │  └─────────────── Underflow (UM)
  355.  │  │  └────────────────── Precision error (PM)
  356.  │  └───────────────────── Reserved
  357.  └──────────────────────── Interrupt enable mask (IEM)  0 = enabled
  358.                                                     1 = disabled.
  359.                            Busy bit on 80287+
  360.  
  361. After FINIT, the default low byte is 7Fh, or
  362.     Exceptions disabled, Interrupt mask (IEM) disabled.
  363. QBASIC uses 70h for low byte or
  364.     Exceptions enabled (all but PM), Interrupt mask (IEM) disabled
  365.  
  366.