home *** CD-ROM | disk | FTP | other *** search
- ; Created 10/01/90
- ; Updated 03/20/92
- ; To restore status of control word to QBASIC defaults
- ; Revised 10/06/92
- ; Added routine to check for 80C287A
- ; Revised 06/30/93
- ; Better handle old PC's with an 8087
- ; Revised 12/07/93
- ; More info on control flags, results of testing Cyrix 80387SX chip
- ; Revised 03/29/94
- ; More info on control bits, testing Cyrix 486D - 486DX clone
- ; Updated 06/06/94 more info on purpose of port 0F0h
-
- ;======================================================================
- ; Copyright (C) Copr. 1990, 1991, 1992, 93, 94 by Sidney J. Kelly
- ; All Rights Reserved.
- ; Sidney J. Kelly
- ; 150 Woodhaven Drive
- ; Pittsburgh, PA 15228
- ; home phone 412-561-0950 (7pm to 9:30pm EST)
- ;======================================================================
- ;;;;«RM82»«TS8,16,24,32,40,48,56»
-
- DOSSEG
- .MODEL MEDIUM, BASIC
- .CODE
- ;======================================================================
- ; DECLARE FUNCTION CHECK87%()
- ; Returns:
- ; 0 if no 80x87, or system equipment bit not set for 80x87.
- ; 87 if an 8087
- ; -87 if 8087 emulation in use on an 80286 or 80386. Because the
- ; the 80287 has almost exactly the same instruction set as the
- ; 8087 few have felt a need to emulate the 80287. The 80827
- ; just includes one new instruction (protected mode),
- ; nothing for use in real mode. 80387 has transendental
- ; math routines. (Note: real mode software math chip emulators will
- ; not work with protected mode software without hugh speed penalties).
- ; 287 if an 80827 (note on early 386SX, an 80287 was allowed)
- ; 1287 if an 80C287A/80287XL (an 80287 with the 80387 instruction set)
- ; 387 if an 80387, 80387SX or 80486DX.
- ; Because of 486SX not all 486's will have a math chip.
- ; The 80387/80486DX is much faster than an 80287 because it does
- ; not need the FWAIT's before every instruction
- ;
- ; More accurate than just checking the equipment word.
- ; QBX, Version 7 and QBASIC 4.5 both merely check the equipment
- ; word (Int 11h, 0040:0010) to determine if an 80x87 is installed.
- ; Therefore, changing the bit in at 0040:0010 at can be used as a
- ; software toggle.
- ;
- ; Because of complaints about the traditional test with inexpensive clones
- ; (See Jon Waterhouse letter in BYTE, Nov. 1990, page 40) routine first
- ; tests the equipment word in RAM bios. If the equipment bit is clear,
- ; then routine halts. It does not check CMOS equipment word math
- ; chip bit because not all clones properly record in CMOS that a math chip
- ; is installed (e.g. ACER 910 w/ Award BIOS only adjusts Int 11h).
- ;
- ; You should assume that if switch for NDP is not set or Int 11h does not
- ; show an NDP that user wanted it that way.
- ;
- ; Tested: Intel 80287, Cyrix 80387SX, software emulation of 8087, Intel 486DX
- ;======================================================================
- ;
- ; REFERENCES:
- ; basic info is adapted from Ted Forgeron's article in PC
- ; Tech Journal, Aug '87 p43.
- ; Copr. 1987 Pat Shea - Psi! (that Copr. is on there cuz my
- ; lawyer sez I should, but feel
- ; free to hack away!!! pats.)
- ; In the event of subsequent republication of this function,
- ; please carry forward reference to these two gentlemen as
- ; original authors.
- ; Minor beautification, addition of MASM 5.1 simplified
- ; directives, detection of emulation, additional commentary by SJK 12/12/90
- ;
- ; Similar code: Robert Zigon, "Interactive Bezier Curves" Tech Specialist
- ; V2,N3,P53 (March 1991)
- ;
- ; This code is based on code from Intel's "i486 Programmers Reference Manual"
- ; cpuid32.asm - Per file
- ; "This program has been developed by Intel Corporation. You have
- ; Intel's permission to incorporate this source code into your
- ; product royalty free."
- ; as modified by Wayne A. King, [CIS: 70022,2700] 5/24/93 for use w/
- ; MASM 5.1, to correct bugs w/ real mode processors and 32 bit instructions
- ;
- ; The CX loop idea for slow PC's with a math chip is from the public
- ; domain INFOPLUS Version 1.56, Andrew Rossman 12/30/92.
- ;======================================================================
-
- EVEN
- CTRL_Word DW 0 ; CTRL_Word word for the NDP test.
- Orig_CW DW 0 ; original CTRL_Word
- DATA1 DT 0 ; temp storage for 387 testing
-
- ; Please do not remove
- Copyright DB 13,10,'Copyright Copr. (C) 1990, 1991, 1994 Sidney J. Kelly',13,10
- Copyright1 DB 'All Rights Reserved',13,10,26
-
- EVEN
- CHECK87 PROC FAR
- Pushf ; save flags
- ;--------
- ; in response to clone errors, test to see if system knows
- ; if math chip is installed. If Int 11h sez no, then
- ; report no mathchip. Can't check AT CMOS mathchip bit
- ; because some clones do not set the bit in the CMOS, but
- ; only set the bit in the Int 11h equipment word, e.g. ACER 910, during
- ; boot up.
- ;--------
- Int 11h
- Test AL,10b ; is mathchip bit Set?
- JZ No_Math_Chip ; no mathchip
- ; Test for any mathchip
- Xor AX,AX ; make AX = 0
- Mov Word Ptr CS:[CTRL_Word],AX ; clear CTRL_Word
- Out 0F0h,AX ; clear busy bit on 80287+
- ; w/o changing (real/protected) mode of NDP by writing 0 to the port.
- ; Per "Intel486 SX Microprocessor Intel487 SX Math CoProcessor Data Book"
- ; (Intel 1991) ISBN 1-55512-158-6, pages 140-141, a write to this port
- ; acts as external device reset to clear IRQ 13 error on 80287+ chip
- ; an internal device reset for 80287+ requires a FNINIT
- ; Load a sensible default control value so NDP handles all
- ; exceptions. This should help prevent errors because of slow
- ; chips (affine, even, 64 bit precision)
- Mov Word Ptr CS:[Orig_CW],13BFh ; store a reasonable value
- ; default after FINIT on 80387 is 037Fh. After QBASIC
- ; tests math chip, the control word becomes 1370h
- ;-------
- ; The next 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. This
- ; allow use of routine on an old PC with an 8087.
- ;-------
- FNSTCW Word Ptr CS:[Orig_CW] ; save original value
- ; it takes about 24 clocks for a real NDP to do this
- ; (about 3-5 clocks on a 486)
- ; it do have a chip, our "reasonable value" will be overwritten
- Mov CX,14h ; time waste loop
- Loop $ ; to substitute for a FWAIT
- JMP $+2 ; waste time and flush que
- JMP $+2 ; waste time and flush que
- FNINIT ; try to initialize the NDP
- ; it takes about 8 clocks for a real NDP to do this, 33 clocks
- ; for 80387, 17 clocks on a 486
- ;------
- ; use the no-wait state version of the op code so will not
- ; hang a machine without a NDP. Loop allows test of a PC that
- ; does have an 8087.
- ;------
- Mov CX,14h ; a time waste loop
- Loop $ ; allow 8087 time to react
- JMP $+2 ; waste time and flush que
- FNSTCW CS:[CTRL_Word] ; put CTRL_Word in memory
- ; it takes about 24 clocks for a real NDP to do this
- ; 3 to 5 clocks on a 486
- ;-------
- ; use the no-wait state version of the op code so will not
- ; hang a machine without a NDP. Loop allows test of a PC that
- ; does have an 8087.
- ;-------
- Mov CX,14h
- Loop $
- JMP $+2 ; waste time and flush que
- Cmp BYTE PTR CS:[CTRL_Word+1],3 ; if high byte = 3h have NDP
- Je Chk_87 ; found something, so keep going
- No_Math_Chip:
- Xor AX,AX ; else zero AX to show
- Popf ; restore flags
- Ret ; end, return to main routine
- Chk_87: ; Test for 8087
- ; we know we have a math chip now, so test if
- ; CPU is old 808x, 8018x, NEC V series chip
- Push SP
- Pop AX
- Cmp AX,SP ; SP = AX if have 80286+ chip
- Jne Have_87 ; else old mode chip, no emulation possible
- ; we now have a math chip and an 80286+ CPU
- And CS:[CTRL_Word],NOT 080h ; turn ON interrupts (IEM = 0)
- ; IEM is bit 7 of control word
- FLDCW CS:[CTRL_Word] ; load CTRL_Word word
- FDISI ; turn OFF interrupts (IEM = 1)
- FSTCW CS:[CTRL_Word] ; store CTRL_Word word
- FWAIT ; allow time for update to occur
- ; if IEM=1, 8087 (only 8087 pays attention to IEM)
- Test CS:[CTRL_Word],80h ; test IEM
- Jz Chk_287 ; not an 8087, test for 80287
- Report_Emulation:
- ;-----------
- ; Report have 8087 emulation by software. Emulation only can be done on an
- ; 80286 or 80386. To get this far, CPU must be 80286+, emulating 8087
- ; There is no particular advantage to emulating 80287. In addition, some
- ; early 80386DX and 80386SX CPU's used the 80287 chip, so can't easily test
- ; for emulation of an 80287 on a 386 machine.
- ;-----------
- ;--- not necessary, already tested for above
- ; Xor AX,AX ; clear AX
- ; Push AX ; put on stack
- ; Popf ; put in flags
- ; Pushf ; put back on stack
- ; Pop AX ; get flags back in AX
- ; And AX,0F000h ; clear all but upper 4 bits
- ; Cmp AX,0F000h ; if bits 12-15 are set then CPU
- ; JE Have_87 ; is not an 80286, 80386 or 80486
- Mov AX,-87 ; put -87 in AX to show that
- Jmp SHORT Chk_87_END ; emulation is detected
- ;-----------
- ; I haven't tested the software that emulates the 80287/80387 so this is
- ; not tested for. Emulation of an x87 is possible
- ; because of a special bit (EM or Bit 2) in the 80286 machine status
- ; word and the use of a specific interrupt generated by 80826/80386 if
- ; coprocessor is not available. The 80386 also can do emulation
- ; using Bit 2 in register CR0 along with the use of a special interrupt
- ; if the coprocessor is not available.
- ;
- ; Emulators of 80387 have also become available, though not tested.
- ; The only reason for testing for emulation is to suggest to user that he
- ; would get faster results if he relied on MS QuickBasic built in
- ; software emulation rather than other forms of software emulation.
- ; Moreover, because many software emulators do not work with
- ; protected mode (otherwise speed penalty would be huge), emulators
- ; would take up space on a fast 386 machine. SJK
- ;-----------
- Have_87:
- ; CPU is a NEC, 8086/88 or 80186/88
- Mov AX,87 ; put 87 in AX to show
- Jmp SHORT Chk_87_END ; no emulation is detected
- Chk_287: ; Test for 80287
- ; if any of the following instructions is not available, Int 07h
- ; will call a BIOS routine that ignores the error on 80286+ in real mode
- ; This has been tested. Though, should only get here if have a 8087 chip
- ; Should not get an error in protected mode w/ 80386+ chip, because
- ; math chip either must exist or it must be emulated to get this far.
- FINIT ; set default infinity mode
- FLD1 ; push 1 on stack
- FLDZ ; push 0 on stack
- FDIV ; then divide. Make infinity
- ; by dividing 1 by zero
- FLD ST ; push back on stack. Change
- FCHS ; sign & make negative infinity
- FCOMPP ; compare the two infinities
- ; pops stack and eliminates 2 pushes
- ;--------
- ; Default after FINIT for 80287 & 8087 is projective infinity where
- ; both positive and negative infinity are equal. The 80C287A
- ; (a faster 80287 chip with all the features of the 80387), the 80387 and
- ; and the 80486DX use affine infinity, and ignore projective infinity.
- ; Under affine infinity positive and negative infinity are at opposite
- ; ends of the number line and are not equal.
- ; (SJK - Who thinks of these things???)
- ;--------
- FSTSW CS:[CTRL_Word] ; store status for result
- FWAIT ; wait until status word is stored
- Mov AX,CS:[CTRL_Word] ; get CTRL_Word word
- SAHF ; put highbyte (AH) status in flags
- Jnz Test_4_387 ; If bit 6 (infinity control)
- ; not set then it is a 80387 or 80C287A
- Have_287:
- Mov AX,287 ; else report that it is an 80287
- ; since we tested for an 8087
- Jmp SHORT Chk_87_END
- ;------------
- ; NDP not an 8087 or an 80287 so it must be an 80387(80486DX) or 80C287A.
- ; The 80486DX/80387/80C287A ignore the infinity control (IC) flag,
- ; while the 80287/8087 do not. SJK
- ;------------
- Test_4_387:
- ;.387 ; allows assembly of 387 instructions
- ; and cuts out many of the FWAITs
- ; if your assembler wont handle .387 then the DB equivalents
- ; are shown below the .387 instruction
- ; .387 mode code wont run on a 286 because .387 drops the FWAIT that
- ; preceed all the NDP instructions, a 286 needs the syncronization
- ; that the FWAITs provide.
- FLDPI ; load Pi (value in radians)
- ; FSIN ; take the Sin(Pi)
- DB 0D9h,0FEh ; the code for FSIN
- ; if NDP wont support op codes, 80286+ bios will capture error and
- ; ignore it
- FSTP TByte Ptr DATA1 ; store and Pop
- FWAIT ; wait for memory to catch up
- FLD TByte Ptr DATA1 ; get value back
- FWAIT ; wait for memory to catch up
- ; FCOS ; now take Cos(Sin(PI))
- DB 0D9h,0FFh ; the code for FCOS
- ; if COS(SIN(Pi)) is calculated correctly it = 1.00, if FSIN and FCOS
- ; not available or don't work, then COS(SIN(Pi)) will = Pi
- FLD1 ; load 1
- FCOMPP ; compare ST(0) with ST(1)
- ; pops stack and eliminates 2 pushes
- FSTSW CS:[CTRL_Word] ; store status for result
- FWAIT ; wait until status word is stored
- Mov AX,CS:[CTRL_Word] ; get CTRL_Word word
- SAHF ; place in flags
- JNZ Have_287 ; if not equal then have 287 chip
- ; distinguish between 80386 and 80286 based on flags
- Mov AX,0F000h ; see if 80286 or 80386
- Push AX
- PopF
- PushF
- Pop AX
- And AX,0F000h
- JNZ Have_387 ; if not clear, quit, have 80387
- Mov AX,1287 ; report have 80C287A/80287XL
- Jmp Short Chk_87_END
- Have_387:
- Mov AX,387 ; report have 80387
- Chk_87_END:
- Mov Byte Ptr CS:[Orig_CW+1],00010011b
- ; select affine infinity, even rouding, 64 bit precision
- ; but don't touch lower byte since QB sets it to control
- ; its own exception handling
- FLDCW Word Ptr CS:[Orig_CW] ; re-load modified original word
- Popf ; restore flags
- Ret ; end, return to main routine
- CHECK87 ENDP
- END
-
- Math chip control word, high byte
- ┌──┬──┬──┬──┬──┬──┬──┬──┐
- │F │E │D │C │B │A │9 │8 │ bits within high byte
- └┬─┴┬─┴┬─┴┬─┴┬─┴┬─┴┬─┴┬─┘
- │ │ │ │ │ │ └──┴───Precision Control
- │ │ │ │ │ │ (00 = 24 bits)
- │ │ │ │ │ │ (01 = undefined)
- │ │ │ │ │ │ (10 = 53 bits)
- │ │ │ │ │ │ (11 = 64 bits) DEFAULT
- │ │ │ │ └──┴─────────Rounding Control
- │ │ │ │ (00 = Nearest or Even) DEFAULT
- │ │ │ │ (01 = Round Down to minus infinity)
- │ │ │ │ (10 = Round Up to positive infinity)
- │ │ │ │ (11 = Chop/truncate toward 0)
- │ │ │ └───────────────Infinity Control
- │ │ │ (0 = Projective infinity)
- │ │ │ Default on FINIT on 8087/80287
- │ │ │ (1 = Affine infinity) QBASIC default
- └──┴──┴──────────────────Reserved
- (All 0)
-
- After FINIT, the default high byte is 03h, or
- Projective infinity, round nearest, 64 bits of precision
- QBASIC uses 13h for high byte or
- Affine infinity, round nearest, 64 bits of precision
-
- Low byte of control word
- ┌──┬──┬──┬──┬──┬──┬──┬──┐
- │7 │6 │5 │4 │3 │2 │1 │0 │ bits within low byte
- └┬─┴┬─┴┬─┴┬─┴┬─┴┬─┴┬─┴┬─┘
- │ │ │ │ │ │ │ └─── Invalid operation (IM)
- │ │ │ │ │ │ └────── Denormalized operation (DM)
- │ │ │ │ │ └───────── Divide by zero error (ZM)
- │ │ │ │ └──────────── Overflow (UM)
- │ │ │ └─────────────── Underflow (UM)
- │ │ └────────────────── Precision error (PM)
- │ └───────────────────── Reserved
- └──────────────────────── Interrupt enable mask (IEM) 0 = enabled
- 1 = disabled.
- Busy bit on 80287+
-
- After FINIT, the default low byte is 7Fh, or
- Exceptions disabled, Interrupt mask (IEM) disabled.
- QBASIC uses 70h for low byte or
- Exceptions enabled (all but PM), Interrupt mask (IEM) disabled
-
-