Subversion Repositories Kolibri OS

Rev

Rev 1075 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
703 serge 1
;*****************************************************************************
2
;*
3
;*                            Open Watcom Project
4
;*
5
;*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
6
;*
7
;*  ========================================================================
8
;*
9
;*    This file contains Original Code and/or Modifications of Original
10
;*    Code as defined in and that are subject to the Sybase Open Watcom
11
;*    Public License version 1.0 (the 'License'). You may not use this file
12
;*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
13
;*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
14
;*    provided with the Original Code and Modifications, and is also
15
;*    available at www.sybase.com/developer/opensource.
16
;*
17
;*    The Original Code and all software distributed under the License are
18
;*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
19
;*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
20
;*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
21
;*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
22
;*    NON-INFRINGEMENT. Please see the License for the specific language
23
;*    governing rights and limitations under the License.
24
;*
25
;*  ========================================================================
26
;*
27
;* Description:  80x87 interrupt handler.
28
;*
29
;*****************************************************************************
30
 
31
 
32
;;; //e:\watcom\src\bld\watcom\h;E:\WATCOM\H;E:\WATCOM\H\NT
33
 
34
.8087
35
.386p
36
 
37
include struct.inc
38
include mdef.inc
39
include stword.inc
40
include env387.inc
41
include fstatus.inc
42
 
43
        xref            __8087  ; indicate that NDP instructions are present
44
 
45
        modstart        fpeinth
46
 
47
        datasegment
48
 
49
        extrn   __FPE_exception_: proc
50
        extrn   "C",_STACKLOW   : dword
51
 
52
TInf    db 00h,00h,00h,00h,00h,00h,00h,80h,0ffh,7fh
53
F8Inf   db 0ffh,0ffh,0ffh,0ffh,0ffh,0ffh,0efh,7fh
54
F4Inf   db 0ffh,0ffh,7fh,7fh
55
        enddata
56
 
57
; User handler for 80x87 exceptions.
58
 
59
xdefp   __FPEHandler_
60
defp    __FPEHandler_
61
 
62
public  __FPE2Handler_
1075 Galkov 63
__FPE2Handler_ label byte
703 serge 64
 
65
        push    EAX                     ; save regs
66
        push    EBX                     ; ...
67
        push    ECX                     ; ...
68
        push    EDX                     ; ...
69
        push    ESI                     ; ...
70
        push    EDI                     ; ...
71
        push    EBP                     ; ...
72
        sub     ESP,ENV_SIZE            ; make room for environment information
73
        mov     EBP,ESP                 ; point to buffer for 80x87 environment
1075 Galkov 74
  ; Now EXC_NUM is located in [EBP+ENV_SIZE+32]
75
  ; but it isn't necessary to testing EXC_NUM,
76
  ; because only #MF is unmasked now
703 serge 77
        fnstenv [EBP]                   ; get 80x87 environment
78
        fwait                           ; wait for 80x87
79
        mov     EDX,ENV_CW[EBP]         ; get control word
80
        not     EDX                     ; flip the mask bits
81
        mov     DH,0FFh                 ; turn on top byte
82
        and     EDX,ENV_SW[EBP]         ; get status word
83
        mov     EDI,ENV_IP[EBP]         ; ...
84
opcode:
85
        mov     BX,[EDI]                ; get opcode
86
        inc     EDI                     ; point to next opcode
87
        cmp     BL,0d8h                 ; check if its the opcode
88
        jb      opcode                  ; ...
89
        cmp     BL,0dfh                 ; ...
90
        ja      opcode                  ; ...
91
        mov     EDI,ENV_OP[EBP]         ; ...
92
        xchg    BL,BH                   ; get opcode in right position
93
        mov     CL,FPE_OK               ; assume exception to be ignored
94
        _guess                          ; guess precision exception
95
          test  DL,ST_EF_PR             ; - check for precision exception
96
          _quif e                       ; - quit if not precision exception
97
          mov   CL,FPE_INEXACT          ; - indicate precision exception
98
        _admit                          ; guess stack under/overflow
99
          test  DL,ST_EF_SF             ; - check for stack under/overflow
100
          _quif e                       ; - quit if not stack under/overflow
101
          test  DX,ST_C1                ; - check if underflow
102
          _if   e                       ; - if underflow
103
            mov CL,FPE_STACKUNDERFLOW   ; - - indicate stack underflow
104
          _else                         ; - else
105
            mov CL,FPE_STACKOVERFLOW    ; - - indicate stack overflow
106
          _endif                        ; - endif
107
        _admit                          ; guess invalid operation
108
          test  DL,ST_EF_IO             ; - check for invalid operation
109
          _quif e                       ; - quit if not invalid operation
110
          call  InvalidOp               ; - process invalid operation
111
        _admit                          ; guess denormal operand
112
          test  DL,ST_EF_DO             ; - check for denormal operand
113
          _quif e                       ; - quit if not denormal operand
114
          mov   CL,FPE_DENORMAL         ; - indicate underflow
115
        _admit                          ; guess overflow
116
          test  DL,ST_EF_OF             ; - check for overflow
117
          _quif e                       ; - quit if not overflow
118
          call  KOOverFlow              ; - process overflow exception
119
          mov   CL,FPE_OVERFLOW         ; - set floating point error code
120
        _admit                          ; guess underflow
121
          test  DL,ST_EF_UF             ; - check for underflow
122
          _quif e                       ; - quit if not underflow
123
          mov   CL,FPE_UNDERFLOW        ; - indicate underflow
124
        _admit                          ; guess divide by 0
125
          test  DL,ST_EF_ZD             ; - check for divide by zero
126
          _quif e                       ; - quit if not divide by zero
127
          call  GetInf                  ; - process divide by zero
128
          mov   CL,FPE_ZERODIVIDE       ; - indicate divide by zero
129
        _endguess                       ; endguess
1075 Galkov 130
   ; More correctly to rise this mask bit - is on end of __FPE_exception_
131
   ; but it may not returned at all...
132
        push    ECX
133
        mov     EAX, 68
1077 Galkov 134
        mov     EBX, 25                 ;
1075 Galkov 135
        mov     ECX, 16                 ; #MF
136
        mov     EDX, 1                  ; rise activity
137
        int     40h                     ; change state of signal activity
138
        pop     ECX
703 serge 139
        _guess                          ; guess exception to be handled
140
          cmp   CL,FPE_OK               ; - check if exception allowed
141
          _quif e                       ; - quit if exception not allowed
142
          movzx EAX,CL                  ; - set floating point status
143
          call  __FPE_exception_        ; - call user's handler
144
        _endguess                       ; endguess
145
        fclex                           ; clear exceptions that may have
146
                                        ; occurred as a result of handling the
147
                                        ; exception
148
        and     word ptr ENV_CW[EBP],0FF72h
149
        fldcw   word ptr ENV_CW[EBP]    ; enable interrupts
150
        fwait                           ; ...
151
        add     ESP,ENV_SIZE            ; clean up stack
152
        pop     EBP                     ; ...
153
        pop     EDI                     ; ...
154
        pop     ESI                     ; ...
155
        pop     EDX                     ; ...
156
        pop     ECX                     ; ...
157
        pop     EBX                     ; ...
158
        pop     EAX                     ; ...
1075 Galkov 159
        ret     4                       ; return from interrupt handler
160
                                        ; with removing EXC_NUM
703 serge 161
 
162
endproc __FPEHandler_
163
 
164
; Process invalid operation.
165
 
166
InvalidOp proc near
167
        mov   CL,FPE_INVALID            ; assume invalid operation
168
        _guess                          ; guess it's square root
169
          cmp   BX,0D9FAh               ; - ...
170
          _quif ne                      ; - quit if it's not that instruction
171
          mov   CL,FPE_SQRTNEG          ; - indicate sqrt(negative number)
172
          ret                           ; - return
173
        _endguess                       ; endguess
174
        _guess                          ; guess it's square root
175
          cmp   BX,0D9F1h               ; - ...
176
          _quif ne                      ; - quit if it's not that instruction
177
          mov   CL,FPE_LOGERR           ; - indicate sqrt(negative number)
178
          ret                           ; - return
179
        _endguess                       ; endguess
180
        _guess                          ; guess: 'fprem' instruction
181
          cmp   BX,0D9F8h               ; - check for 'fprem'   10-may-90
182
          _if   ne                      ; - if not 'fprem'
183
            cmp   BX,0D9F5h             ; - - check for 'fprem1'
184
          _endif                        ; - endif
185
          _quif ne                      ; - quit if not 'fprem' or 'fprem1'
186
          mov   CL,FPE_MODERR           ; - indicate mod(negative number)
187
        _admit                          ; guess: integer overflow
188
          mov   DX,BX                   ; - save op code
189
          and   DX,0310h                ; - check for fist/fistp instruction
190
          cmp   DX,0310h                ; - ...
191
          _quif ne                      ; - quit if its not that instruction
192
          mov   CL,FPE_IOVERFLOW        ; - indicate integer overflow
193
        _admit                          ; guess it's floating point underflow
194
;;        mov   DX,BX                   ; - save op code
195
          and   DX,0110h                ; - check if fst or fstp instruction
196
          cmp   DX,0110h                ; - ...
197
          _quif ne                      ; - quit if it's not that instruction
198
; Destination is short or long real and source register is an unnormal
199
; with exponent in range.
200
          fstp  st(0)                   ; - pop old result
201
          fldz                          ; - load zero
202
          mov   DL,BL                   ; - save op code
203
          and   DL,0C0h                 ; - check the MOD bits of instruction
204
          cmp   DL,0C0h                 ; - ...
205
          _if   ne                      ; - if result to be placed in memory
206
            call  Store                 ; - - store result in memory
207
          _endif                        ; - endif
208
          test  BL,08h                  ; - check if result to be popped
209
          _if   ne                      ; - if result to be popped
210
            fstp  st(0)                 ; - - pop the result
211
          _endif                        ; - endif
212
          mov   CL,FPE_UNDERFLOW        ; - indicate underflow
213
        _admit                          ; guess it's divide
214
          mov   DX,BX                   ; - save op code
215
          and   DX,0130h                ; - check for fdiv/fidiv instruction
216
          cmp   DX,0030h                ; - ...
217
          _quif ne                      ; - quit if it's not that instruction
218
          mov   DX,ENV_TW[EBP]          ; - get tag word
219
          mov   CL,AH                   ; - get stack pointer
220
          and   CL,38h                  ; - ...
221
          shr   CL,2                    ; - ...
222
          ror   DX,CL                   ; - make stack top low order bits
223
          and   DL,05h                  ; - check if top two elements are 0
224
          cmp   DL,05h                  ; - ...
225
          _quif ne                      ; - quif if they are not 0
226
          mov   CL,FPE_ZERODIVIDE       ; - indicate divide by zero
227
        _endguess                       ; endguess
228
        ret
229
endproc InvalidOp
230
 
231
 
232
; Process overflow exception (note that only floating point overflows
233
; are handled - integer overflows are invalid operations).
234
 
235
KOOverFlow proc near
236
        _guess                  ; guess: fscale instruction     10-may-90
237
          cmp   BX,0D9FDh       ; - quit if not 'fscale' instruction
238
          _quif ne              ; - ...
239
        _admit                  ; guess: fst/fstp instruction
240
          mov   DX,BX           ; - save op code
241
          and   DX,0110h        ; - check if fst or fstp instruction
242
          cmp   DX,0110h        ; - ...
243
          _quif ne              ; - quit if not an fst/fstp instr.
244
          call  GetInf          ; - load infinity
245
          mov   DL,BL           ; - save op code
246
          and   DL,0C0h         ; - check the MOD bits of instruction
247
          cmp   DL,0C0h         ; - ...
248
          _if   ne              ; - if result to be placed in memory
249
            call Store          ; - - store infinity
250
          _endif                ; - endif
251
          test  BL,08h          ; - check if result to be popped
252
          _if   ne              ; - if result to be popped
253
            fstp  st(0)         ; - - pop result
254
          _endif                ; - endif
255
        _admit                  ; admit arithmetic operation
256
          mov   DL,BL           ; - save op code
257
          and   DL,0C0h         ; - check if both operands on stack
258
          cmp   DL,0C0h         ; - ...
259
          _quif ne              ; - quif both operands not on stack
260
;
261
; This code handles overflow on the following intructions:
262
;    fxxx   ST,ST(i)
263
;    fxxx   ST(i),ST    where xxx is one of mul,div,sub or add
264
;    fxxxp  ST(i),ST
265
;
266
          lea   ESI,TInf        ; - load internal infinity
267
          call  Load            ; - ...
268
        _admit                  ; admit
269
;
270
; This admit block is to handle overflow on the following intructions:
271
;    fxxx   short real
272
;    fxxx   long real   where xxx is one of mul,div,sub or add
273
;
274
          call  GetInf          ; - load infinity
275
        _endguess               ; endguess
276
        ret                     ; return
277
endproc KOOverFlow
278
 
279
 
280
; Replace the top element of the stack with the appropriate signed
281
; infinity.
282
 
283
GetInf  proc    near
284
        ftst                    ; get sign of result
285
        fstsw   word ptr ENV_OP[EBP]
286
        fstp    st(0)           ; pop argument off stack (does fwait)
287
        test    BH,04h          ; check if single or double
288
        _if     ne              ; if double
289
          fld   qword ptr F8Inf ; - load double precision infinity
290
        _else                   ; else
291
          fld   dword ptr F4Inf ; - load single precision infinity
292
        _endif                  ; endif
293
        test    word ptr ENV_OP[EBP],ST_C0
294
        _if     ne              ; if argument is negative
295
          fchs                  ; - return negative infinity
296
        _endif                  ; endif
297
        ret                     ; return
298
endproc GetInf
299
 
300
 
301
; Replace an element on the stack with internal zero or infinity.
302
 
303
Load    proc    near
304
        test    BH,04h          ; check if result is top element
305
        _if     e               ; if result is not top element
306
          mov   DL,0            ; - indicate we are at the top
307
        _else                   ; else
308
          mov   DL,BL           ; - get st(i)
309
          and   DL,07h          ; - . . .
310
        _endif                  ; endif
311
        push    EDX             ; save st(i)
312
        _loop                   ; loop
313
          dec   DL              ; - decrement counter
314
          _quif l               ; - quit if we are at st(i)
315
          fincstp               ; - increment stack pointer
316
        _endloop                ; endloop
317
        fstp    st(0)           ; free the stack element
318
        fld     tbyte ptr [ESI] ; load internal zero
319
        pop     EDX             ; get st(i)
320
        _loop                   ; loop
321
          dec   DL              ; - decrement counter
322
          _quif l               ; - quit if we are at st(i)
323
          fdecstp               ; - decrement stack pointer
324
        _endloop                ; endloop
325
        ret                     ; return
326
endproc Load
327
 
328
 
329
; Store the top element of the stack at ES:EDI.
330
 
331
Store   proc    near
332
        test    BH,04h
333
        _if     ne                      ; if double
334
          fst   qword ptr [EDI]         ; - store as double precision result
335
        _else                           ; else
336
          fst   dword ptr [EDI]         ; - store as single precision result
337
        _endif                          ; endif
338
        ret                             ; return
339
endproc Store
340
 
341
        endmod
342
        end