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 |