diff options
Diffstat (limited to 'arch/i386/math-emu/reg_round.S')
-rw-r--r-- | arch/i386/math-emu/reg_round.S | 708 |
1 files changed, 708 insertions, 0 deletions
diff --git a/arch/i386/math-emu/reg_round.S b/arch/i386/math-emu/reg_round.S new file mode 100644 index 00000000000..d1d4e48b4f6 --- /dev/null +++ b/arch/i386/math-emu/reg_round.S | |||
@@ -0,0 +1,708 @@ | |||
1 | .file "reg_round.S" | ||
2 | /*---------------------------------------------------------------------------+ | ||
3 | | reg_round.S | | ||
4 | | | | ||
5 | | Rounding/truncation/etc for FPU basic arithmetic functions. | | ||
6 | | | | ||
7 | | Copyright (C) 1993,1995,1997 | | ||
8 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | | ||
9 | | Australia. E-mail billm@suburbia.net | | ||
10 | | | | ||
11 | | This code has four possible entry points. | | ||
12 | | The following must be entered by a jmp instruction: | | ||
13 | | fpu_reg_round, fpu_reg_round_sqrt, and fpu_Arith_exit. | | ||
14 | | | | ||
15 | | The FPU_round entry point is intended to be used by C code. | | ||
16 | | From C, call as: | | ||
17 | | int FPU_round(FPU_REG *arg, unsigned int extent, unsigned int control_w) | | ||
18 | | | | ||
19 | | Return value is the tag of the answer, or-ed with FPU_Exception if | | ||
20 | | one was raised, or -1 on internal error. | | ||
21 | | | | ||
22 | | For correct "up" and "down" rounding, the argument must have the correct | | ||
23 | | sign. | | ||
24 | | | | ||
25 | +---------------------------------------------------------------------------*/ | ||
26 | |||
27 | /*---------------------------------------------------------------------------+ | ||
28 | | Four entry points. | | ||
29 | | | | ||
30 | | Needed by both the fpu_reg_round and fpu_reg_round_sqrt entry points: | | ||
31 | | %eax:%ebx 64 bit significand | | ||
32 | | %edx 32 bit extension of the significand | | ||
33 | | %edi pointer to an FPU_REG for the result to be stored | | ||
34 | | stack calling function must have set up a C stack frame and | | ||
35 | | pushed %esi, %edi, and %ebx | | ||
36 | | | | ||
37 | | Needed just for the fpu_reg_round_sqrt entry point: | | ||
38 | | %cx A control word in the same format as the FPU control word. | | ||
39 | | Otherwise, PARAM4 must give such a value. | | ||
40 | | | | ||
41 | | | | ||
42 | | The significand and its extension are assumed to be exact in the | | ||
43 | | following sense: | | ||
44 | | If the significand by itself is the exact result then the significand | | ||
45 | | extension (%edx) must contain 0, otherwise the significand extension | | ||
46 | | must be non-zero. | | ||
47 | | If the significand extension is non-zero then the significand is | | ||
48 | | smaller than the magnitude of the correct exact result by an amount | | ||
49 | | greater than zero and less than one ls bit of the significand. | | ||
50 | | The significand extension is only required to have three possible | | ||
51 | | non-zero values: | | ||
52 | | less than 0x80000000 <=> the significand is less than 1/2 an ls | | ||
53 | | bit smaller than the magnitude of the | | ||
54 | | true exact result. | | ||
55 | | exactly 0x80000000 <=> the significand is exactly 1/2 an ls bit | | ||
56 | | smaller than the magnitude of the true | | ||
57 | | exact result. | | ||
58 | | greater than 0x80000000 <=> the significand is more than 1/2 an ls | | ||
59 | | bit smaller than the magnitude of the | | ||
60 | | true exact result. | | ||
61 | | | | ||
62 | +---------------------------------------------------------------------------*/ | ||
63 | |||
64 | /*---------------------------------------------------------------------------+ | ||
65 | | The code in this module has become quite complex, but it should handle | | ||
66 | | all of the FPU flags which are set at this stage of the basic arithmetic | | ||
67 | | computations. | | ||
68 | | There are a few rare cases where the results are not set identically to | | ||
69 | | a real FPU. These require a bit more thought because at this stage the | | ||
70 | | results of the code here appear to be more consistent... | | ||
71 | | This may be changed in a future version. | | ||
72 | +---------------------------------------------------------------------------*/ | ||
73 | |||
74 | |||
75 | #include "fpu_emu.h" | ||
76 | #include "exception.h" | ||
77 | #include "control_w.h" | ||
78 | |||
79 | /* Flags for FPU_bits_lost */ | ||
80 | #define LOST_DOWN $1 | ||
81 | #define LOST_UP $2 | ||
82 | |||
83 | /* Flags for FPU_denormal */ | ||
84 | #define DENORMAL $1 | ||
85 | #define UNMASKED_UNDERFLOW $2 | ||
86 | |||
87 | |||
88 | #ifndef NON_REENTRANT_FPU | ||
89 | /* Make the code re-entrant by putting | ||
90 | local storage on the stack: */ | ||
91 | #define FPU_bits_lost (%esp) | ||
92 | #define FPU_denormal 1(%esp) | ||
93 | |||
94 | #else | ||
95 | /* Not re-entrant, so we can gain speed by putting | ||
96 | local storage in a static area: */ | ||
97 | .data | ||
98 | .align 4,0 | ||
99 | FPU_bits_lost: | ||
100 | .byte 0 | ||
101 | FPU_denormal: | ||
102 | .byte 0 | ||
103 | #endif /* NON_REENTRANT_FPU */ | ||
104 | |||
105 | |||
106 | .text | ||
107 | .globl fpu_reg_round | ||
108 | .globl fpu_Arith_exit | ||
109 | |||
110 | /* Entry point when called from C */ | ||
111 | ENTRY(FPU_round) | ||
112 | pushl %ebp | ||
113 | movl %esp,%ebp | ||
114 | pushl %esi | ||
115 | pushl %edi | ||
116 | pushl %ebx | ||
117 | |||
118 | movl PARAM1,%edi | ||
119 | movl SIGH(%edi),%eax | ||
120 | movl SIGL(%edi),%ebx | ||
121 | movl PARAM2,%edx | ||
122 | |||
123 | fpu_reg_round: /* Normal entry point */ | ||
124 | movl PARAM4,%ecx | ||
125 | |||
126 | #ifndef NON_REENTRANT_FPU | ||
127 | pushl %ebx /* adjust the stack pointer */ | ||
128 | #endif /* NON_REENTRANT_FPU */ | ||
129 | |||
130 | #ifdef PARANOID | ||
131 | /* Cannot use this here yet */ | ||
132 | /* orl %eax,%eax */ | ||
133 | /* jns L_entry_bugged */ | ||
134 | #endif /* PARANOID */ | ||
135 | |||
136 | cmpw EXP_UNDER,EXP(%edi) | ||
137 | jle L_Make_denorm /* The number is a de-normal */ | ||
138 | |||
139 | movb $0,FPU_denormal /* 0 -> not a de-normal */ | ||
140 | |||
141 | Denorm_done: | ||
142 | movb $0,FPU_bits_lost /* No bits yet lost in rounding */ | ||
143 | |||
144 | movl %ecx,%esi | ||
145 | andl CW_PC,%ecx | ||
146 | cmpl PR_64_BITS,%ecx | ||
147 | je LRound_To_64 | ||
148 | |||
149 | cmpl PR_53_BITS,%ecx | ||
150 | je LRound_To_53 | ||
151 | |||
152 | cmpl PR_24_BITS,%ecx | ||
153 | je LRound_To_24 | ||
154 | |||
155 | #ifdef PECULIAR_486 | ||
156 | /* With the precision control bits set to 01 "(reserved)", a real 80486 | ||
157 | behaves as if the precision control bits were set to 11 "64 bits" */ | ||
158 | cmpl PR_RESERVED_BITS,%ecx | ||
159 | je LRound_To_64 | ||
160 | #ifdef PARANOID | ||
161 | jmp L_bugged_denorm_486 | ||
162 | #endif /* PARANOID */ | ||
163 | #else | ||
164 | #ifdef PARANOID | ||
165 | jmp L_bugged_denorm /* There is no bug, just a bad control word */ | ||
166 | #endif /* PARANOID */ | ||
167 | #endif /* PECULIAR_486 */ | ||
168 | |||
169 | |||
170 | /* Round etc to 24 bit precision */ | ||
171 | LRound_To_24: | ||
172 | movl %esi,%ecx | ||
173 | andl CW_RC,%ecx | ||
174 | cmpl RC_RND,%ecx | ||
175 | je LRound_nearest_24 | ||
176 | |||
177 | cmpl RC_CHOP,%ecx | ||
178 | je LCheck_truncate_24 | ||
179 | |||
180 | cmpl RC_UP,%ecx /* Towards +infinity */ | ||
181 | je LUp_24 | ||
182 | |||
183 | cmpl RC_DOWN,%ecx /* Towards -infinity */ | ||
184 | je LDown_24 | ||
185 | |||
186 | #ifdef PARANOID | ||
187 | jmp L_bugged_round24 | ||
188 | #endif /* PARANOID */ | ||
189 | |||
190 | LUp_24: | ||
191 | cmpb SIGN_POS,PARAM5 | ||
192 | jne LCheck_truncate_24 /* If negative then up==truncate */ | ||
193 | |||
194 | jmp LCheck_24_round_up | ||
195 | |||
196 | LDown_24: | ||
197 | cmpb SIGN_POS,PARAM5 | ||
198 | je LCheck_truncate_24 /* If positive then down==truncate */ | ||
199 | |||
200 | LCheck_24_round_up: | ||
201 | movl %eax,%ecx | ||
202 | andl $0x000000ff,%ecx | ||
203 | orl %ebx,%ecx | ||
204 | orl %edx,%ecx | ||
205 | jnz LDo_24_round_up | ||
206 | jmp L_Re_normalise | ||
207 | |||
208 | LRound_nearest_24: | ||
209 | /* Do rounding of the 24th bit if needed (nearest or even) */ | ||
210 | movl %eax,%ecx | ||
211 | andl $0x000000ff,%ecx | ||
212 | cmpl $0x00000080,%ecx | ||
213 | jc LCheck_truncate_24 /* less than half, no increment needed */ | ||
214 | |||
215 | jne LGreater_Half_24 /* greater than half, increment needed */ | ||
216 | |||
217 | /* Possibly half, we need to check the ls bits */ | ||
218 | orl %ebx,%ebx | ||
219 | jnz LGreater_Half_24 /* greater than half, increment needed */ | ||
220 | |||
221 | orl %edx,%edx | ||
222 | jnz LGreater_Half_24 /* greater than half, increment needed */ | ||
223 | |||
224 | /* Exactly half, increment only if 24th bit is 1 (round to even) */ | ||
225 | testl $0x00000100,%eax | ||
226 | jz LDo_truncate_24 | ||
227 | |||
228 | LGreater_Half_24: /* Rounding: increment at the 24th bit */ | ||
229 | LDo_24_round_up: | ||
230 | andl $0xffffff00,%eax /* Truncate to 24 bits */ | ||
231 | xorl %ebx,%ebx | ||
232 | movb LOST_UP,FPU_bits_lost | ||
233 | addl $0x00000100,%eax | ||
234 | jmp LCheck_Round_Overflow | ||
235 | |||
236 | LCheck_truncate_24: | ||
237 | movl %eax,%ecx | ||
238 | andl $0x000000ff,%ecx | ||
239 | orl %ebx,%ecx | ||
240 | orl %edx,%ecx | ||
241 | jz L_Re_normalise /* No truncation needed */ | ||
242 | |||
243 | LDo_truncate_24: | ||
244 | andl $0xffffff00,%eax /* Truncate to 24 bits */ | ||
245 | xorl %ebx,%ebx | ||
246 | movb LOST_DOWN,FPU_bits_lost | ||
247 | jmp L_Re_normalise | ||
248 | |||
249 | |||
250 | /* Round etc to 53 bit precision */ | ||
251 | LRound_To_53: | ||
252 | movl %esi,%ecx | ||
253 | andl CW_RC,%ecx | ||
254 | cmpl RC_RND,%ecx | ||
255 | je LRound_nearest_53 | ||
256 | |||
257 | cmpl RC_CHOP,%ecx | ||
258 | je LCheck_truncate_53 | ||
259 | |||
260 | cmpl RC_UP,%ecx /* Towards +infinity */ | ||
261 | je LUp_53 | ||
262 | |||
263 | cmpl RC_DOWN,%ecx /* Towards -infinity */ | ||
264 | je LDown_53 | ||
265 | |||
266 | #ifdef PARANOID | ||
267 | jmp L_bugged_round53 | ||
268 | #endif /* PARANOID */ | ||
269 | |||
270 | LUp_53: | ||
271 | cmpb SIGN_POS,PARAM5 | ||
272 | jne LCheck_truncate_53 /* If negative then up==truncate */ | ||
273 | |||
274 | jmp LCheck_53_round_up | ||
275 | |||
276 | LDown_53: | ||
277 | cmpb SIGN_POS,PARAM5 | ||
278 | je LCheck_truncate_53 /* If positive then down==truncate */ | ||
279 | |||
280 | LCheck_53_round_up: | ||
281 | movl %ebx,%ecx | ||
282 | andl $0x000007ff,%ecx | ||
283 | orl %edx,%ecx | ||
284 | jnz LDo_53_round_up | ||
285 | jmp L_Re_normalise | ||
286 | |||
287 | LRound_nearest_53: | ||
288 | /* Do rounding of the 53rd bit if needed (nearest or even) */ | ||
289 | movl %ebx,%ecx | ||
290 | andl $0x000007ff,%ecx | ||
291 | cmpl $0x00000400,%ecx | ||
292 | jc LCheck_truncate_53 /* less than half, no increment needed */ | ||
293 | |||
294 | jnz LGreater_Half_53 /* greater than half, increment needed */ | ||
295 | |||
296 | /* Possibly half, we need to check the ls bits */ | ||
297 | orl %edx,%edx | ||
298 | jnz LGreater_Half_53 /* greater than half, increment needed */ | ||
299 | |||
300 | /* Exactly half, increment only if 53rd bit is 1 (round to even) */ | ||
301 | testl $0x00000800,%ebx | ||
302 | jz LTruncate_53 | ||
303 | |||
304 | LGreater_Half_53: /* Rounding: increment at the 53rd bit */ | ||
305 | LDo_53_round_up: | ||
306 | movb LOST_UP,FPU_bits_lost | ||
307 | andl $0xfffff800,%ebx /* Truncate to 53 bits */ | ||
308 | addl $0x00000800,%ebx | ||
309 | adcl $0,%eax | ||
310 | jmp LCheck_Round_Overflow | ||
311 | |||
312 | LCheck_truncate_53: | ||
313 | movl %ebx,%ecx | ||
314 | andl $0x000007ff,%ecx | ||
315 | orl %edx,%ecx | ||
316 | jz L_Re_normalise | ||
317 | |||
318 | LTruncate_53: | ||
319 | movb LOST_DOWN,FPU_bits_lost | ||
320 | andl $0xfffff800,%ebx /* Truncate to 53 bits */ | ||
321 | jmp L_Re_normalise | ||
322 | |||
323 | |||
324 | /* Round etc to 64 bit precision */ | ||
325 | LRound_To_64: | ||
326 | movl %esi,%ecx | ||
327 | andl CW_RC,%ecx | ||
328 | cmpl RC_RND,%ecx | ||
329 | je LRound_nearest_64 | ||
330 | |||
331 | cmpl RC_CHOP,%ecx | ||
332 | je LCheck_truncate_64 | ||
333 | |||
334 | cmpl RC_UP,%ecx /* Towards +infinity */ | ||
335 | je LUp_64 | ||
336 | |||
337 | cmpl RC_DOWN,%ecx /* Towards -infinity */ | ||
338 | je LDown_64 | ||
339 | |||
340 | #ifdef PARANOID | ||
341 | jmp L_bugged_round64 | ||
342 | #endif /* PARANOID */ | ||
343 | |||
344 | LUp_64: | ||
345 | cmpb SIGN_POS,PARAM5 | ||
346 | jne LCheck_truncate_64 /* If negative then up==truncate */ | ||
347 | |||
348 | orl %edx,%edx | ||
349 | jnz LDo_64_round_up | ||
350 | jmp L_Re_normalise | ||
351 | |||
352 | LDown_64: | ||
353 | cmpb SIGN_POS,PARAM5 | ||
354 | je LCheck_truncate_64 /* If positive then down==truncate */ | ||
355 | |||
356 | orl %edx,%edx | ||
357 | jnz LDo_64_round_up | ||
358 | jmp L_Re_normalise | ||
359 | |||
360 | LRound_nearest_64: | ||
361 | cmpl $0x80000000,%edx | ||
362 | jc LCheck_truncate_64 | ||
363 | |||
364 | jne LDo_64_round_up | ||
365 | |||
366 | /* Now test for round-to-even */ | ||
367 | testb $1,%bl | ||
368 | jz LCheck_truncate_64 | ||
369 | |||
370 | LDo_64_round_up: | ||
371 | movb LOST_UP,FPU_bits_lost | ||
372 | addl $1,%ebx | ||
373 | adcl $0,%eax | ||
374 | |||
375 | LCheck_Round_Overflow: | ||
376 | jnc L_Re_normalise | ||
377 | |||
378 | /* Overflow, adjust the result (significand to 1.0) */ | ||
379 | rcrl $1,%eax | ||
380 | rcrl $1,%ebx | ||
381 | incw EXP(%edi) | ||
382 | jmp L_Re_normalise | ||
383 | |||
384 | LCheck_truncate_64: | ||
385 | orl %edx,%edx | ||
386 | jz L_Re_normalise | ||
387 | |||
388 | LTruncate_64: | ||
389 | movb LOST_DOWN,FPU_bits_lost | ||
390 | |||
391 | L_Re_normalise: | ||
392 | testb $0xff,FPU_denormal | ||
393 | jnz Normalise_result | ||
394 | |||
395 | L_Normalised: | ||
396 | movl TAG_Valid,%edx | ||
397 | |||
398 | L_deNormalised: | ||
399 | cmpb LOST_UP,FPU_bits_lost | ||
400 | je L_precision_lost_up | ||
401 | |||
402 | cmpb LOST_DOWN,FPU_bits_lost | ||
403 | je L_precision_lost_down | ||
404 | |||
405 | L_no_precision_loss: | ||
406 | /* store the result */ | ||
407 | |||
408 | L_Store_significand: | ||
409 | movl %eax,SIGH(%edi) | ||
410 | movl %ebx,SIGL(%edi) | ||
411 | |||
412 | cmpw EXP_OVER,EXP(%edi) | ||
413 | jge L_overflow | ||
414 | |||
415 | movl %edx,%eax | ||
416 | |||
417 | /* Convert the exponent to 80x87 form. */ | ||
418 | addw EXTENDED_Ebias,EXP(%edi) | ||
419 | andw $0x7fff,EXP(%edi) | ||
420 | |||
421 | fpu_reg_round_signed_special_exit: | ||
422 | |||
423 | cmpb SIGN_POS,PARAM5 | ||
424 | je fpu_reg_round_special_exit | ||
425 | |||
426 | orw $0x8000,EXP(%edi) /* Negative sign for the result. */ | ||
427 | |||
428 | fpu_reg_round_special_exit: | ||
429 | |||
430 | #ifndef NON_REENTRANT_FPU | ||
431 | popl %ebx /* adjust the stack pointer */ | ||
432 | #endif /* NON_REENTRANT_FPU */ | ||
433 | |||
434 | fpu_Arith_exit: | ||
435 | popl %ebx | ||
436 | popl %edi | ||
437 | popl %esi | ||
438 | leave | ||
439 | ret | ||
440 | |||
441 | |||
442 | /* | ||
443 | * Set the FPU status flags to represent precision loss due to | ||
444 | * round-up. | ||
445 | */ | ||
446 | L_precision_lost_up: | ||
447 | push %edx | ||
448 | push %eax | ||
449 | call set_precision_flag_up | ||
450 | popl %eax | ||
451 | popl %edx | ||
452 | jmp L_no_precision_loss | ||
453 | |||
454 | /* | ||
455 | * Set the FPU status flags to represent precision loss due to | ||
456 | * truncation. | ||
457 | */ | ||
458 | L_precision_lost_down: | ||
459 | push %edx | ||
460 | push %eax | ||
461 | call set_precision_flag_down | ||
462 | popl %eax | ||
463 | popl %edx | ||
464 | jmp L_no_precision_loss | ||
465 | |||
466 | |||
467 | /* | ||
468 | * The number is a denormal (which might get rounded up to a normal) | ||
469 | * Shift the number right the required number of bits, which will | ||
470 | * have to be undone later... | ||
471 | */ | ||
472 | L_Make_denorm: | ||
473 | /* The action to be taken depends upon whether the underflow | ||
474 | exception is masked */ | ||
475 | testb CW_Underflow,%cl /* Underflow mask. */ | ||
476 | jz Unmasked_underflow /* Do not make a denormal. */ | ||
477 | |||
478 | movb DENORMAL,FPU_denormal | ||
479 | |||
480 | pushl %ecx /* Save */ | ||
481 | movw EXP_UNDER+1,%cx | ||
482 | subw EXP(%edi),%cx | ||
483 | |||
484 | cmpw $64,%cx /* shrd only works for 0..31 bits */ | ||
485 | jnc Denorm_shift_more_than_63 | ||
486 | |||
487 | cmpw $32,%cx /* shrd only works for 0..31 bits */ | ||
488 | jnc Denorm_shift_more_than_32 | ||
489 | |||
490 | /* | ||
491 | * We got here without jumps by assuming that the most common requirement | ||
492 | * is for a small de-normalising shift. | ||
493 | * Shift by [1..31] bits | ||
494 | */ | ||
495 | addw %cx,EXP(%edi) | ||
496 | orl %edx,%edx /* extension */ | ||
497 | setne %ch /* Save whether %edx is non-zero */ | ||
498 | xorl %edx,%edx | ||
499 | shrd %cl,%ebx,%edx | ||
500 | shrd %cl,%eax,%ebx | ||
501 | shr %cl,%eax | ||
502 | orb %ch,%dl | ||
503 | popl %ecx | ||
504 | jmp Denorm_done | ||
505 | |||
506 | /* Shift by [32..63] bits */ | ||
507 | Denorm_shift_more_than_32: | ||
508 | addw %cx,EXP(%edi) | ||
509 | subb $32,%cl | ||
510 | orl %edx,%edx | ||
511 | setne %ch | ||
512 | orb %ch,%bl | ||
513 | xorl %edx,%edx | ||
514 | shrd %cl,%ebx,%edx | ||
515 | shrd %cl,%eax,%ebx | ||
516 | shr %cl,%eax | ||
517 | orl %edx,%edx /* test these 32 bits */ | ||
518 | setne %cl | ||
519 | orb %ch,%bl | ||
520 | orb %cl,%bl | ||
521 | movl %ebx,%edx | ||
522 | movl %eax,%ebx | ||
523 | xorl %eax,%eax | ||
524 | popl %ecx | ||
525 | jmp Denorm_done | ||
526 | |||
527 | /* Shift by [64..) bits */ | ||
528 | Denorm_shift_more_than_63: | ||
529 | cmpw $64,%cx | ||
530 | jne Denorm_shift_more_than_64 | ||
531 | |||
532 | /* Exactly 64 bit shift */ | ||
533 | addw %cx,EXP(%edi) | ||
534 | xorl %ecx,%ecx | ||
535 | orl %edx,%edx | ||
536 | setne %cl | ||
537 | orl %ebx,%ebx | ||
538 | setne %ch | ||
539 | orb %ch,%cl | ||
540 | orb %cl,%al | ||
541 | movl %eax,%edx | ||
542 | xorl %eax,%eax | ||
543 | xorl %ebx,%ebx | ||
544 | popl %ecx | ||
545 | jmp Denorm_done | ||
546 | |||
547 | Denorm_shift_more_than_64: | ||
548 | movw EXP_UNDER+1,EXP(%edi) | ||
549 | /* This is easy, %eax must be non-zero, so.. */ | ||
550 | movl $1,%edx | ||
551 | xorl %eax,%eax | ||
552 | xorl %ebx,%ebx | ||
553 | popl %ecx | ||
554 | jmp Denorm_done | ||
555 | |||
556 | |||
557 | Unmasked_underflow: | ||
558 | movb UNMASKED_UNDERFLOW,FPU_denormal | ||
559 | jmp Denorm_done | ||
560 | |||
561 | |||
562 | /* Undo the de-normalisation. */ | ||
563 | Normalise_result: | ||
564 | cmpb UNMASKED_UNDERFLOW,FPU_denormal | ||
565 | je Signal_underflow | ||
566 | |||
567 | /* The number must be a denormal if we got here. */ | ||
568 | #ifdef PARANOID | ||
569 | /* But check it... just in case. */ | ||
570 | cmpw EXP_UNDER+1,EXP(%edi) | ||
571 | jne L_norm_bugged | ||
572 | #endif /* PARANOID */ | ||
573 | |||
574 | #ifdef PECULIAR_486 | ||
575 | /* | ||
576 | * This implements a special feature of 80486 behaviour. | ||
577 | * Underflow will be signalled even if the number is | ||
578 | * not a denormal after rounding. | ||
579 | * This difference occurs only for masked underflow, and not | ||
580 | * in the unmasked case. | ||
581 | * Actual 80486 behaviour differs from this in some circumstances. | ||
582 | */ | ||
583 | orl %eax,%eax /* ms bits */ | ||
584 | js LPseudoDenormal /* Will be masked underflow */ | ||
585 | #else | ||
586 | orl %eax,%eax /* ms bits */ | ||
587 | js L_Normalised /* No longer a denormal */ | ||
588 | #endif /* PECULIAR_486 */ | ||
589 | |||
590 | jnz LDenormal_adj_exponent | ||
591 | |||
592 | orl %ebx,%ebx | ||
593 | jz L_underflow_to_zero /* The contents are zero */ | ||
594 | |||
595 | LDenormal_adj_exponent: | ||
596 | decw EXP(%edi) | ||
597 | |||
598 | LPseudoDenormal: | ||
599 | testb $0xff,FPU_bits_lost /* bits lost == underflow */ | ||
600 | movl TAG_Special,%edx | ||
601 | jz L_deNormalised | ||
602 | |||
603 | /* There must be a masked underflow */ | ||
604 | push %eax | ||
605 | pushl EX_Underflow | ||
606 | call EXCEPTION | ||
607 | popl %eax | ||
608 | popl %eax | ||
609 | movl TAG_Special,%edx | ||
610 | jmp L_deNormalised | ||
611 | |||
612 | |||
613 | /* | ||
614 | * The operations resulted in a number too small to represent. | ||
615 | * Masked response. | ||
616 | */ | ||
617 | L_underflow_to_zero: | ||
618 | push %eax | ||
619 | call set_precision_flag_down | ||
620 | popl %eax | ||
621 | |||
622 | push %eax | ||
623 | pushl EX_Underflow | ||
624 | call EXCEPTION | ||
625 | popl %eax | ||
626 | popl %eax | ||
627 | |||
628 | /* Reduce the exponent to EXP_UNDER */ | ||
629 | movw EXP_UNDER,EXP(%edi) | ||
630 | movl TAG_Zero,%edx | ||
631 | jmp L_Store_significand | ||
632 | |||
633 | |||
634 | /* The operations resulted in a number too large to represent. */ | ||
635 | L_overflow: | ||
636 | addw EXTENDED_Ebias,EXP(%edi) /* Set for unmasked response. */ | ||
637 | push %edi | ||
638 | call arith_overflow | ||
639 | pop %edi | ||
640 | jmp fpu_reg_round_signed_special_exit | ||
641 | |||
642 | |||
643 | Signal_underflow: | ||
644 | /* The number may have been changed to a non-denormal */ | ||
645 | /* by the rounding operations. */ | ||
646 | cmpw EXP_UNDER,EXP(%edi) | ||
647 | jle Do_unmasked_underflow | ||
648 | |||
649 | jmp L_Normalised | ||
650 | |||
651 | Do_unmasked_underflow: | ||
652 | /* Increase the exponent by the magic number */ | ||
653 | addw $(3*(1<<13)),EXP(%edi) | ||
654 | push %eax | ||
655 | pushl EX_Underflow | ||
656 | call EXCEPTION | ||
657 | popl %eax | ||
658 | popl %eax | ||
659 | jmp L_Normalised | ||
660 | |||
661 | |||
662 | #ifdef PARANOID | ||
663 | #ifdef PECULIAR_486 | ||
664 | L_bugged_denorm_486: | ||
665 | pushl EX_INTERNAL|0x236 | ||
666 | call EXCEPTION | ||
667 | popl %ebx | ||
668 | jmp L_exception_exit | ||
669 | #else | ||
670 | L_bugged_denorm: | ||
671 | pushl EX_INTERNAL|0x230 | ||
672 | call EXCEPTION | ||
673 | popl %ebx | ||
674 | jmp L_exception_exit | ||
675 | #endif /* PECULIAR_486 */ | ||
676 | |||
677 | L_bugged_round24: | ||
678 | pushl EX_INTERNAL|0x231 | ||
679 | call EXCEPTION | ||
680 | popl %ebx | ||
681 | jmp L_exception_exit | ||
682 | |||
683 | L_bugged_round53: | ||
684 | pushl EX_INTERNAL|0x232 | ||
685 | call EXCEPTION | ||
686 | popl %ebx | ||
687 | jmp L_exception_exit | ||
688 | |||
689 | L_bugged_round64: | ||
690 | pushl EX_INTERNAL|0x233 | ||
691 | call EXCEPTION | ||
692 | popl %ebx | ||
693 | jmp L_exception_exit | ||
694 | |||
695 | L_norm_bugged: | ||
696 | pushl EX_INTERNAL|0x234 | ||
697 | call EXCEPTION | ||
698 | popl %ebx | ||
699 | jmp L_exception_exit | ||
700 | |||
701 | L_entry_bugged: | ||
702 | pushl EX_INTERNAL|0x235 | ||
703 | call EXCEPTION | ||
704 | popl %ebx | ||
705 | L_exception_exit: | ||
706 | mov $-1,%eax | ||
707 | jmp fpu_reg_round_special_exit | ||
708 | #endif /* PARANOID */ | ||