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