home *** CD-ROM | disk | FTP | other *** search
- page 60,132
- ;-----------------------------------------------------------------------------
- ;
- ; FISTBUG
- ;
- ; Copyright (c) 1997-Present Robert Collins
- ;
- ; You have my permission to copy and distribute this software for
- ; non-commercial purposes. Any commercial use of this software or
- ; source code is allowed, so long as the appropriate copyright
- ; attributions (to me) are intact, *AND* my email address is properly
- ; displayed.
- ;
- ; Basically, give me credit, where credit is due, and show my email
- ; address.
- ;
- ;-----------------------------------------------------------------------------
- ;
- ; Robert R. Collins email: rcollins@x86.org
- ;
- ;-----------------------------------------------------------------------------
- ;
- ; FISTBUG --
- ;
- ; If all you're interested in seeing is the source code which should be
- ; offered for academic and peer review, please refer to the subrutines
- ; 'FistTest16' and 'FistTest32.'
- ;
- ; Synopsis:
- ; This program tests for a bug in the Pentium Pro and Pentium II floating
- ; point unit. This program may be run on a variety of microprocessors
- ; from the 80286 on up. For a complete description of the bug, please refer
- ; to http://www.x86.org/secrets/Dan0411.html.
- ;
- ; To assemble this source code:
- ; * You will need Microsoft Macro Assembler, version 6.11d (though just about
- ; any other version of MASM will probably work). Borland TASM will probably
- ; work also.
- ; * Run the makefile using the 'nmake' utility supplied with MASM.
- ; * You may compile this without the nmake utility by invoking the command
- ; line:
- ; C: > ml /Fl fistbug.asm - to generate non-verbose version
- ; C: > ml /Fl /DVERBOSE fistbug.asm - to genrate verbose version
- ;
- ;-----------------------------------------------------------------------------
-
-
- ;-----------------------------------------------------------------------------
- ; Assembler directives
- ;-----------------------------------------------------------------------------
- .xlist ; disable list file
- .286
-
- ;-----------------------------------------------------------------------------
- ; Include file section
- ;-----------------------------------------------------------------------------
-
- ;-----------------------------------------------------------------------------
- ; Equates
- ;-----------------------------------------------------------------------------
- FSW_IE equ 1 ; Status Word IE bit
-
- ;-----------------------------------------------------------------------------
- ; Macros
- ;-----------------------------------------------------------------------------
- PRINT_PASS_FAIL MACRO
- ifdef VERBOSE
- pushf ; save results of comparison
- mov ah,9 ; print string function ID
- mov dx,offset PassMsg ; prepare for test passed
- jnz @F ; test did pass
- mov dx,offset FailMsg ; get address of failed message
- @@: int 21h ; print message
- popf ; restore flags
- endif ; VERBOSE
- ENDM
-
-
- PRINT_MSG MACRO MSG
- ifdef VERBOSE
- mov ah,9
- mov dx,offset MSG
- int 21h
- endif ; VERBOSE
- ENDM
-
-
- ;-----------------------------------------------------------------------------
- ; 16-bit Floating point environment
- ;
- ; I intentionally chose a 16-bit floating point environment to allow this
- ; program to be run on the 80286 microprocessor.
- ;-----------------------------------------------------------------------------
- FPU_Struct STRUCT
- FCW dw ? ; Control word
- FSW dw ? ; Status word
- FTW dw ? ; Tag word
- dw ? ; Floating point IP
- dw ? ; Floating point CS
- dw ? ; Operand offset
- dw ? ; Operand selector
- ST0 dt ? ; ST0
- ST1 dt ? ; ST1
- ST2 dt ? ; ST2
- ST3 dt ? ; ST3
- ST4 dt ? ; ST4
- ST5 dt ? ; ST5
- ST6 dt ? ; ST6
- ST7 dt ? ; ST7
- FPU_Struct ENDS
-
-
- .list
- ;-----------------------------------------------------------------------------
- ; Dummy segments
- ;-----------------------------------------------------------------------------
- INTSEG segment at 0
-
- org 6*4
- INT06 dd ?
- INTSEG ends
-
-
- ;-----------------------------------------------------------------------------
- ; Data segment
- ;-----------------------------------------------------------------------------
- _DATA segment use16 para public 'DATA'
-
- ;-----------------------------------------------------------------------------
- ; Instantiate the floating point environment structure. I might as well make
- ; this appear at the paragraph boundary of the data segment.
- ;-----------------------------------------------------------------------------
- FENV FPU_Struct <>
-
- ;-----------------------------------------------------------------------------
- ; This is where the list of floating point numbers is stored. If you want
- ; to add to this list, simply insert a floating point number in the 16-bit
- ; section, or the 32-bit section, depending on what your needs are. For
- ; example, you may want to verify that positive numbers aren't affected by
- ; this bug. To do so, you could simply insert a line such as:
- ; dt 65536.0
- ; The operand doesn't need to be given in hex as my examples were. My
- ; examples were choosen in hex to easily demonstrate the boundary conditions
- ; of the Dan-0411 bug.
- ;
- ; If you insert new operands, you don't need to make any other program
- ; changes, but you will need to reassemble the source code. The program
- ; automatically adjust the nuber of test cases according to how many
- ; operands appear in the Op16 or Op32 list.
- ;-----------------------------------------------------------------------------
- Op16 dt 0c06e8000000000000001h
- dt 0c06e8000000000000010h
- dt 0c06e8000000000000100h
- dt 0c06e8000000000001000h
- dt 0c06e8000000000010000h
- dt 0c06e8000000000100000h
- dt 0c06e8000000001000000h
- dt 0c06e8000000010000000h
- dt 0c06e8000000100000000h
- dt 0c06e8000001000000000h
- dt 0c06e8000010000000000h
- dt 0c06e8000100000000000h
- dt 0c06e80007fffffffffffh
- N16 equ ($-Op16) / sizeof Op16
-
- Op32 dt 0c05e8000000000000001h
- dt 0c05e8000000000000010h
- dt 0c05e8000000000000100h
- dt 0c05e8000000000001000h
- dt 0c05e8000000000010000h
- dt 0c05e8000000000100000h
- dt 0c05e8000000001000000h
- dt 0c05e8000000010000000h
- dt 0c05e800000007fffffffh
- N32 equ ($-Op32) / sizeof Op32
-
- ;-----------------------------------------------------------------------------
- ; D16 and D32 listed below are the destinations for the FIST and FISTP
- ; (Floating-to-Integer Store) instructions. The StatusWord variable is used
- ; to collect the resultant status words for the four different test cases on
- ; each floating point operand. 'Results' is used to accumulate the results.
- ; At the end of this test, if any bit is set in 'Results' then the test is
- ; considered a failure, and you've got the Dan-0411 bug.
- ;-----------------------------------------------------------------------------
- D16 dw 55aah
- D32 dd 55aa55aah
- StatusWord dw 4 dup (0)
- Results dw 0 ; Cumulative results
-
-
- ;-----------------------------------------------------------------------------
- ; Misc data storage.
- ;-----------------------------------------------------------------------------
- CPUIDVal dd 0 ; Results of CPUID instruction
- OrigINT06 dd 0 ; Temp holding spot for INT06 vector
-
-
- ;-----------------------------------------------------------------------------
- ; String messages used for formatting the screen output
- ;-----------------------------------------------------------------------------
- ; 16-bit Value FLD/FIST FRSTOR/FIST FLD/FISTP FRSTOR/FISTP
- ; xxxxxxxxxxxxxxxxxx PASS PASS PASS PASS
- HeaderMsg16 db " 16-bit Value FLD/FIST FRSTOR/FIST FLD/FISTP FRSTOR/FISTP",0dh,0ah,24h
- HeaderMsg32 db " 32-bit Value FLD/FIST FRSTOR/FIST FLD/FISTP FRSTOR/FISTP",0dh,0ah,24h
- ValueBuf db " ",24h
- Spaces db " ",24h
- PassMsg db " PASS ",24h
- FailMsg db "**FAIL**",24h
- CRLFMsg db 0dh,0ah,24h
-
- PMMsg db "Running in protected mode (probably Windows). Results are most",0dh,0ah
- db "reliable while running in real mode (booting clean to DOS).",0dh,0ah
- db "I'll try running anyways.",0dh,0ah,24h
-
- CPUIDMsg db "Microprocessor ID: "
- FamilyString db "Unknown "
- db " Vendor String: "
- IDString db "Not Detected",0dh,0ah,24h
-
- Dan0411Failed db "*** Dan-0411 bug found. ***",0dh,0ah,24h
- Dan0411Passed db "Dan-0411 not found.",0dh,0ah,24h
- _DATA ENDS
-
-
- ;-----------------------------------------------------------------------------
- ; Beginning of main code segment
- ;-----------------------------------------------------------------------------
- _TEXT segment para public use16 'CODE'
- ASSUME CS:_TEXT, DS:_DATA, ES:_DATA, SS:STACK
- ;-----------------------------------------------------------------------------
- ; Code starts here
- ; * Set up stack
- ;-----------------------------------------------------------------------------
- FISTBUG proc far
- mov ax,seg STACK ; setup stack segment
- mov ss,ax
- mov sp,sizeof StackPtr
- xor ax,ax ; clear it
- pushf
- push ds ; save far return on stack
- push ax
-
- ;-----------------------------------------------------------------------------
- ; * Disable interrupts during this test
- ; * Set up data segments
- ;-----------------------------------------------------------------------------
- cli ; disable interrupts
- mov ax,seg _DATA ; get data segment
- mov ds,ax
- mov es,ax
-
- ifdef VERBOSE
- ;-----------------------------------------------------------------------------
- ; The purpoase of this section of code is to determine a few things about
- ; the target computer. I'll detect whether or not we're in protected mode
- ; (like running in a DOS-box of Windows) and print a message accordingly.
- ; Whether or not we're in protected mode shouldn't make any difference, as
- ; I'm not executing any priviledged instryctions.
- ;
- ; Also in this section, I check for the processor stepping information and
- ; vendor string. If present, I'll print this information to the screen.
- ;-----------------------------------------------------------------------------
- ; Test for protected mode
- ;-----------------------------------------------------------------------------
- smsw ax ; get lower bits of CR0
- test al,1 ; in protected mode?
- jz @F ; nope
- PRINT_MSG PMMsg ; print protected mode message
- PRINT_MSG CRLFMsg ; print <CRLF>
-
- ;-----------------------------------------------------------------------------
- ; Install INT06 (Invalid opcode) exception handler
- ;-----------------------------------------------------------------------------
- @@: push es ; save
- mov ax,seg INTSEG
- mov es,ax
- mov ax,offset OurINT6 ; get pointer to our INT6 handler
- mov dx,cs ; get our code segment
- xchg ax,word ptr es:INT06 ; swap 'em
- xchg dx,word ptr es:INT06[2] ; swap vector
- mov word ptr OrigINT06,ax ; save original vector
- mov word ptr OrigINT06[2],dx; vector now saved
- pop es ; restore original segment
-
- ;-----------------------------------------------------------------------------
- ; Execute CPUID instruction and print results on string
- ;
- ; This is a real down-and-dirty way to detect CPUID. I've installed an
- ; invalid exception handler, and pointed DX to a return address in the case
- ; that an invalid opcode exception occurs. If we're an 80286, then the
- ; 'xor eax,eax' instruction will cause the invalid opcode fault. If we're
- ; running on a processor that doesn't support CPUID, the 'cpuid' instruction
- ; will cause the invalid opcode fault. In either case, if the fault occurs,
- ; execution continues beyond the processor detection code. At that point,
- ; the processor stepping information is printed anyways with a default
- ; response. If CPUID does work, then the default results are filled in with
- ; the appropriate CPUID return values.
- ;-----------------------------------------------------------------------------
- .586
- mov dx,offset @NoCPUID ; set destination location
- xor eax,eax ; real dirty way to detect 80386+
- cpuid ; try CPUID instruction
- mov dword ptr IDString[0],ebx
- mov dword ptr IDString[4],edx
- mov dword ptr IDString[8],ecx
- mov eax,1 ; do next level of CPUID
- cpuid ; get processor stepping
- mov CPUIDVal,eax ; save it
- mov si,offset CPUIDVal ; get source of CPUID stepping
- mov di,offset FamilyString ; get destination of string
- mov cx,4 ; # of bytes to convert
- call hex_string ; convert data
-
- @NoCPUID:
- .286
- PRINT_MSG CPUIDMsg ; print CPUID message
- PRINT_MSG CRLFMsg ; print <CRLF>
-
- ;-----------------------------------------------------------------------------
- ; Restore invalid opcode interrupt handler
- ;-----------------------------------------------------------------------------
- push es ; save
- mov ax,seg INTSEG
- mov es,ax
- mov ax,word ptr OrigINT06[0]; get pointer to our INT6 handler
- mov dx,word ptr OrigINT06[2]; get our code segment
- xchg ax,word ptr es:INT06 ; swap 'em
- xchg dx,word ptr es:INT06[2] ; swap vector
- pop es ; restore original segment
-
- ;-----------------------------------------------------------------------------
- ; Print header message
- ;-----------------------------------------------------------------------------
- PRINT_MSG HeaderMsg16 ; print beginning header message
- endif
-
- ;-----------------------------------------------------------------------------
- ; Time to start test
- ;-----------------------------------------------------------------------------
- mov cx,N16 ; # of 16-bit operands to test
- xor si,si ; Initialize index pointer to operands
-
- @FistLoop16:
-
- ifdef VERBOSE
- ;-----------------------------------------------------------------------------
- ; The purpose of this section is printing the 80-bit hex operands to the
- ; screen. Each 80-bit operand is converted to ASCII and printed on the
- ; screen.
- ;-----------------------------------------------------------------------------
- push cx
- push si
-
- ;-----------------------------------------------------------------------------
- ; * Convert data to ASCII
- ; * Print value on screen
- ;-----------------------------------------------------------------------------
- lea si,Op16[si] ; get pointer to data
- mov di,offset ValueBuf ; get output buffer
- mov cx,sizeof Op16 ; get # of bytes to convert
- call hex_string
- PRINT_MSG ValueBuf ; print 10-byte hex value on screen
- pop si
- pop cx
- endif ; VERBOSE
-
-
- ;-----------------------------------------------------------------------------
- ; Start test
- ;-----------------------------------------------------------------------------
- call FistTest16 ; Check various form of executing
- ; FIST[P] and saving FSW
-
- ;-----------------------------------------------------------------------------
- ; This section tests for the results of each of the operand test cases.
- ; Each test case is checked for the FSW.IE flag set. A pass/fail message is
- ; printed if running in VERBOSE mode. Otherwise, results are collected in
- ; the 'Results' variable for processing at the end of the test.
- ;-----------------------------------------------------------------------------
- ; Check for results
- ;-----------------------------------------------------------------------------
- push cx ; save current count
- xor di,di
- mov cx,4 ; # of results to check
-
- ;-----------------------------------------------------------------------------
- ; Check for FSW.IE. If set, indicate results. If VERBOSE, print to the
- ; screen (macros handle verbose mode printing). Iterate through each test
- ; case until finished.
- ;-----------------------------------------------------------------------------
- Check16:
- test StatusWord[di],FSW_IE ; check for correct exception
- PRINT_PASS_FAIL
- jnz @F ; yes, behavior correct
- or Results,-1 ; set results to indicate failure
- @@: add di,2 ; point to next datum
- dec cx ; are we done yet?
- jz @F ; yes
- PRINT_MSG Spaces
- jmp Check16
-
- @@: PRINT_MSG CRLFMsg ; print <CRLF>
- pop cx
- add si,sizeof Op16
- loop @FistLoop16
-
- ;-----------------------------------------------------------------------------
- ; Now done testing all 16-bit operands.
- ; Time to test 32-bit operands.
- ;-----------------------------------------------------------------------------
- ; Print header message
- ;-----------------------------------------------------------------------------
- PRINT_MSG CRLFMsg ; print <CRLF>
- PRINT_MSG HeaderMsg32 ; print header message for 32-bit test
-
- ;-----------------------------------------------------------------------------
- ; Put code here...
- ;-----------------------------------------------------------------------------
- mov cx,N32 ; # of 32-bit operands to test
- xor si,si ; Initialize index pointer to operands
-
- @FistLoop32:
-
- ifdef VERBOSE
- ;-----------------------------------------------------------------------------
- ; The purpose of this section is printing the 80-bit hex operands to the
- ; screen. Each 80-bit operand is converted to ASCII and printed on the
- ; screen.
- ;-----------------------------------------------------------------------------
- push cx
- push si
-
- ;-----------------------------------------------------------------------------
- ; * Convert data to ASCII
- ; * Print value on screen
- ;-----------------------------------------------------------------------------
- lea si,Op32[si] ; get pointer to data
- mov di,offset ValueBuf ; get output buffer
- mov cx,sizeof Op32 ; get # of bytes to convert
- call hex_string
- PRINT_MSG ValueBuf ; print 10-byte data on screen
- pop si
- pop cx
- endif ; VERBOSE
-
- ;-----------------------------------------------------------------------------
- ; Start test
- ;-----------------------------------------------------------------------------
- call FistTest32 ; Check various form of executing
- ; FIST[P] and saving FSW
-
- ;-----------------------------------------------------------------------------
- ; This section tests for the results of each of the operand test cases.
- ; Each test case is checked for the FSW.IE flag set. A pass/fail message is
- ; printed if running in VERBOSE mode. Otherwise, results are collected in
- ; the 'Results' variable for processing at the end of the test.
- ;-----------------------------------------------------------------------------
- ; Check for results
- ;-----------------------------------------------------------------------------
- push cx ; save current count
- xor di,di
- mov cx,4 ; # of results to check
-
- ;-----------------------------------------------------------------------------
- ; Check for FSW.IE. If set, indicate results. If VERBOSE, print to the
- ; screen (macros handle verbose mode printing). Iterate through each test
- ; case until finished.
- ;-----------------------------------------------------------------------------
- Check32:
- test StatusWord[di],FSW_IE ; check for correct exception
- PRINT_PASS_FAIL
- jnz @F ; yes, behavior correct
- or Results,-1 ; set results to indicate failure
- @@: add di,2 ; point to next datum
- dec cx ; are we done yet?
- jz @F ; yes
- PRINT_MSG Spaces
- jmp Check32
-
- @@: PRINT_MSG CRLFMsg ; print <CRLF>
- pop cx
- add si,sizeof Op32
- loop @FistLoop32
-
- ;-----------------------------------------------------------------------------
- ; Now done testing all 32-bit operands.
- ; Now let's print the final results of the test. Does your processor have
- ; the 'Dan-0411' bug? If so, the results are printed here.
- ;-----------------------------------------------------------------------------
- mov ah,9 ; get function to print string
- mov dx,offset CRLFMsg ; get pointer to CRLF message
- int 21h
- mov dx,offset Dan0411Passed ; prepare to pass
- test Results,-1 ; anything fail?
- jz @F ; nope
- mov dx,offset Dan0411Failed ; get failed message
- @@: int 21h
-
- ;-----------------------------------------------------------------------------
- ; Terminate and return to DOS.
- ;-----------------------------------------------------------------------------
- iret ; return to DOS
- FISTBUG endp
-
-
- ;-----------------------------------------------------------------------------
- FistTest16 proc near
- ;-----------------------------------------------------------------------------
- ; FistTest16 checks four different ways of executing the FIST[P] instruction
- ; and storing the status word to memory. Before each sub-test is attempted,
- ; the floating point unit is re-initialized with the fninit instruction.
- ; The FPU re-initialization ensures that any pending ("sticky") floating point
- ; errors from the previous test will be cleared. This also guarantees that
- ; the each sub-tests is performed on a pristine FPU environment.
- ;
- ; The four test cases are as follows:
- ; 1) * Floating point load using FLD instruction
- ; * Floating point store using FIST instruction
- ; * Store status word using FNSTSW instruction.
- ;
- ; 2) * Floating point load using FLD instruction
- ; * Save floating point environment with FNSAVE instruction. This
- ; instruction has the side-effect of re-initializing the FPU state (a
- ; good thing).
- ; * Restore the FPU state with FRSTOR instruction. This ensures that
- ; the Dan-0411 error wasn't a byproduct of the FLD instruction.
- ; * Floating point store using FIST instruction
- ; * Store status word using FNSTSW instruction.
- ;
- ; 3) * Floating point load using FLD instruction
- ; * Floating point store using FISTP instruction
- ; * Store status word using FNSTSW instruction.
- ;
- ; 4) * Floating point load using FLD instruction
- ; * Save floating point environment with FNSAVE instruction. This
- ; instruction has the side-effect of re-initializing the FPU state (a
- ; good thing).
- ; * Restore the FPU state with FRSTOR instruction. This ensures that
- ; the Dan-0411 error wasn't a byproduct of the FLD instruction.
- ; * Floating point store using FISTP instruction
- ; * Store status word using FNSTSW instruction.
- ;
- ;-----------------------------------------------------------------------------
- ; Input: DS:SI = Index pointer to 80-bit floating point operand
- ; Output: StatusWord filled in with FPU status words for each test case.
- ;-----------------------------------------------------------------------------
- ; Restore pristine environment.
- ;-----------------------------------------------------------------------------
- xor di,di ; initialize pointer to results
- fninit ; initialize floating point unit
-
- ;-----------------------------------------------------------------------------
- ; 1) * Floating point load using FLD instruction
- ; * Floating point store using FIST instruction
- ; * Store status word using FNSTSW instruction.
- ;-----------------------------------------------------------------------------
- fld Op16[si] ; load a value
- fist D16
- fnstsw StatusWord[di] ; save results
-
- ;-----------------------------------------------------------------------------
- ; Restore pristine environment.
- ;-----------------------------------------------------------------------------
- add di,2 ; point to next FSW results datum
- fninit ; initialize floating point unit
-
- ;-----------------------------------------------------------------------------
- ; 2) * Floating point load using FLD instruction
- ; * Save floating point environment with FNSAVE instruction. This
- ; instruction has the side-effect of re-initializing the FPU state (a
- ; good thing).
- ; * Restore the FPU state with FRSTOR instruction. This ensures that
- ; the Dan-0411 error wasn't a byproduct of the FLD instruction.
- ; * Floating point store using FIST instruction
- ; * Store status word using FNSTSW instruction.
- ;-----------------------------------------------------------------------------
- fld Op16[si] ; load a value
- fnsave FENV ; save a copy of environment
- ; does implicit fninit
- frstor FENV ; restore FPU environment
- fist D16
- fnstsw StatusWord[di] ; save results
-
- ;-----------------------------------------------------------------------------
- ; Restore pristine environment.
- ;-----------------------------------------------------------------------------
- add di,2 ; point to next data value
- fninit ; initialize floating point unit
-
- ;-----------------------------------------------------------------------------
- ; 3) * Floating point load using FLD instruction
- ; * Floating point store using FISTP instruction
- ; * Store status word using FNSTSW instruction.
- ;
- ;-----------------------------------------------------------------------------
- fld Op16[si] ; load a value
- fistp D16
- fnstsw StatusWord[di] ; save results
-
- ;-----------------------------------------------------------------------------
- ; Restore pristine environment.
- ;-----------------------------------------------------------------------------
- add di,2 ; point to next data value
- fninit ; initialize floating point unit
-
- ;-----------------------------------------------------------------------------
- ; 4) * Floating point load using FLD instruction
- ; * Save floating point environment with FNSAVE instruction. This
- ; instruction has the side-effect of re-initializing the FPU state (a
- ; good thing).
- ; * Restore the FPU state with FRSTOR instruction. This ensures that
- ; the Dan-0411 error wasn't a byproduct of the FLD instruction.
- ; * Floating point store using FISTP instruction
- ; * Store status word using FNSTSW instruction.
- ;-----------------------------------------------------------------------------
- fld Op16[si] ; load a value
- fnsave FENV ; save a copy of environment
- ; does implicit fninit
- frstor FENV ; restore FPU environment
- fistp D16
- fnstsw StatusWord[di] ; save results
- ret
- FistTest16 endp
-
-
- ;-----------------------------------------------------------------------------
- FistTest32 proc near
- ;-----------------------------------------------------------------------------
- ;
- ; FistTest32 checks four different ways of executing the FIST[P] instruction
- ; and storing the status word to memory. Before each sub-test is attempted,
- ; the floating point unit is re-initialized with the fninit instruction.
- ; The FPU re-initialization ensures that any pending ("sticky") floating point
- ; errors from the previous test will be cleared. This also guarantees that
- ; the each sub-tests is performed on a pristine FPU environment.
- ;
- ; The four test cases are as follows:
- ; 1) * Floating point load using FLD instruction
- ; * Floating point store using FIST instruction
- ; * Store status word using FNSTSW instruction.
- ;
- ; 2) * Floating point load using FLD instruction
- ; * Save floating point environment with FNSAVE instruction. This
- ; instruction has the side-effect of re-initializing the FPU state (a
- ; good thing).
- ; * Restore the FPU state with FRSTOR instruction. This ensures that
- ; the Dan-0411 error wasn't a byproduct of the FLD instruction.
- ; * Floating point store using FIST instruction
- ; * Store status word using FNSTSW instruction.
- ;
- ; 3) * Floating point load using FLD instruction
- ; * Floating point store using FISTP instruction
- ; * Store status word using FNSTSW instruction.
- ;
- ; 4) * Floating point load using FLD instruction
- ; * Save floating point environment with FNSAVE instruction. This
- ; instruction has the side-effect of re-initializing the FPU state (a
- ; good thing).
- ; * Restore the FPU state with FRSTOR instruction. This ensures that
- ; the Dan-0411 error wasn't a byproduct of the FLD instruction.
- ; * Floating point store using FISTP instruction
- ; * Store status word using FNSTSW instruction.
- ;
- ;-----------------------------------------------------------------------------
- ; Input: DS:SI = Index pointer to 80-bit floating point operand
- ; Output: StatusWord filled in with FPU status words for each test case.
- ;-----------------------------------------------------------------------------
- ; Restore pristine environment.
- ;-----------------------------------------------------------------------------
- xor di,di ; initialize pointer to results
- fninit ; initialize floating point unit
-
- ;-----------------------------------------------------------------------------
- ; 1) * Floating point load using FLD instruction
- ; * Floating point store using FIST instruction
- ; * Store status word using FNSTSW instruction.
- ;-----------------------------------------------------------------------------
- fld Op32[si] ; load a value
- fist D32
- fnstsw StatusWord[di] ; save results
-
- ;-----------------------------------------------------------------------------
- ; Restore pristine environment.
- ;-----------------------------------------------------------------------------
- add di,2 ; point to next data value
- fninit ; initialize floating point unit
-
- ;-----------------------------------------------------------------------------
- ; 2) * Floating point load using FLD instruction
- ; * Save floating point environment with FNSAVE instruction. This
- ; instruction has the side-effect of re-initializing the FPU state (a
- ; good thing).
- ; * Restore the FPU state with FRSTOR instruction. This ensures that
- ; the Dan-0411 error wasn't a byproduct of the FLD instruction.
- ; * Floating point store using FIST instruction
- ; * Store status word using FNSTSW instruction.
- ;-----------------------------------------------------------------------------
- fld Op32[si] ; load a value
- fnsave FENV ; save a copy of environment
- ; does implicit fninit
- frstor FENV ; restore FPU environment
- fist D32
- fnstsw StatusWord[di] ; save results
-
- ;-----------------------------------------------------------------------------
- ; Restore pristine environment.
- ;-----------------------------------------------------------------------------
- add di,2 ; point to next data value
- fninit ; initialize floating point unit
-
- ;-----------------------------------------------------------------------------
- ; 3) * Floating point load using FLD instruction
- ; * Floating point store using FISTP instruction
- ; * Store status word using FNSTSW instruction.
- ;
- ;-----------------------------------------------------------------------------
- fld Op32[si] ; load a value
- fistp D32
- fnstsw StatusWord[di] ; save results
-
- ;-----------------------------------------------------------------------------
- ; Restore pristine environment.
- ;-----------------------------------------------------------------------------
- add di,2 ; point to next data value
- fninit ; initialize floating point unit
-
- ;-----------------------------------------------------------------------------
- ; 4) * Floating point load using FLD instruction
- ; * Save floating point environment with FNSAVE instruction. This
- ; instruction has the side-effect of re-initializing the FPU state (a
- ; good thing).
- ; * Restore the FPU state with FRSTOR instruction. This ensures that
- ; the Dan-0411 error wasn't a byproduct of the FLD instruction.
- ; * Floating point store using FISTP instruction
- ; * Store status word using FNSTSW instruction.
- ;-----------------------------------------------------------------------------
- fld Op32[si] ; load a value
- fnsave FENV ; save a copy of environment
- ; does implicit fninit
- frstor FENV ; restore FPU environment
- fistp D32
- fnstsw StatusWord[di] ; save results
- ret
- FistTest32 endp
-
-
- ;-----------------------------------------------------------------------------
- ; HEX_STRING: Convert a string of 8-bit hex numbers to ASCII.
- ; Input: DS:SI = Pointer to hex data
- ; ES:DI = Buffer to get output
- ; CX = # of bytes to convert
- ; Output: ES:DI = Filled in w/ ASCII hex#
- ;-----------------------------------------------------------------------------
- Hex_String proc near
- ;-----------------------------------------------------------------------------
- jcxz @Hex_str_exit ; go split
- push ax ; [bp][0ah]
- push cx ; [bp][8]
- push dx ; [bp][6]
- push si ; [bp][4]
- push di ; [bp][2]
- push bp ; [bp]
- mov bp,sp
- add si,cx
-
- @@: dec si
- mov al,ds:[si] ; get hex digit
- mov dl,al
- mov cl,4 ; shift count
- rol dl,cl
- mov al,dl ; save it
- and al,0fh ; keep low nibble
- daa
- add al,0f0h
- adc al,40h ; here is the ASCII
- stosb ; save it
- mov cl,4 ; shift count
- rol dl,cl
- mov al,dl ; save it
- and al,0fh ; keep low nibble
- daa
- add al,0f0h
- adc al,40h ; here is the ASCII
- stosb ; save it
- dec word ptr [bp][8] ; are we done yet?
- jnz @B
- pop bp
- pop di
- pop si
- pop dx
- pop cx
- pop ax
-
- @Hex_str_exit:
- ret
- Hex_String endp
-
-
- ;-----------------------------------------------------------------------------
- ; This is a real down-and-dirty invalid opcode exception handler. All this
- ; handler does, is take the value in DX and use it as the return address.
- ;-----------------------------------------------------------------------------
- ; Input: DX = Return address
- ; Output: None
- ;-----------------------------------------------------------------------------
- OurINT6 proc far
- pop ax ; get IP from stack
- mov ax,dx ; point to return address
- push ax ; save it
- iret ; go split
- OurINT6 endp
-
- _TEXT ENDS
-
-
- STACK segment para public 'STACK'
- ;-----------------------------------------------------------------------------
- ; Stack segment
- ;-----------------------------------------------------------------------------
- StackPtr db 400h dup (?)
- STACK ends
-
- end FISTBUG
-