1 /*---------------------------------------------------------------------------+
2 | reg_ld_str.c |
3 | |
4 | All of the functions which transfer data between user memory and FPU_REGs.|
5 | |
6 | Copyright (C) 1992,1993,1994,1996,1997 |
7 | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
8 | E-mail billm@suburbia.net |
9 | |
10 | |
11 +---------------------------------------------------------------------------*/
12
13 /*---------------------------------------------------------------------------+
14 | Note: |
15 | The file contains code which accesses user memory. |
16 | Emulator static data may change when user memory is accessed, due to |
17 | other processes using the emulator while swapping is in progress. |
18 +---------------------------------------------------------------------------*/
19
20 #include "fpu_emu.h"
21
22 #include <asm/uaccess.h>
23
24 #include "fpu_system.h"
25 #include "exception.h"
26 #include "reg_constant.h"
27 #include "control_w.h"
28 #include "status_w.h"
29
30
31 #define DOUBLE_Emax 1023 /* largest valid exponent */
32 #define DOUBLE_Ebias 1023
33 #define DOUBLE_Emin (-1022) /* smallest valid exponent */
34
35 #define SINGLE_Emax 127 /* largest valid exponent */
36 #define SINGLE_Ebias 127
37 #define SINGLE_Emin (-126) /* smallest valid exponent */
38
39
normalize_no_excep(FPU_REG * r,int exp,int sign)40 static u_char normalize_no_excep(FPU_REG *r, int exp, int sign)
41 {
42 u_char tag;
43
44 setexponent16(r, exp);
45
46 tag = FPU_normalize_nuo(r);
47 stdexp(r);
48 if ( sign )
49 setnegative(r);
50
51 return tag;
52 }
53
54
FPU_tagof(FPU_REG * ptr)55 int FPU_tagof(FPU_REG *ptr)
56 {
57 int exp;
58
59 exp = exponent16(ptr) & 0x7fff;
60 if ( exp == 0 )
61 {
62 if ( !(ptr->sigh | ptr->sigl) )
63 {
64 return TAG_Zero;
65 }
66 /* The number is a de-normal or pseudodenormal. */
67 return TAG_Special;
68 }
69
70 if ( exp == 0x7fff )
71 {
72 /* Is an Infinity, a NaN, or an unsupported data type. */
73 return TAG_Special;
74 }
75
76 if ( !(ptr->sigh & 0x80000000) )
77 {
78 /* Unsupported data type. */
79 /* Valid numbers have the ms bit set to 1. */
80 /* Unnormal. */
81 return TAG_Special;
82 }
83
84 return TAG_Valid;
85 }
86
87
88 /* Get a long double from user memory */
FPU_load_extended(long double * s,int stnr)89 int FPU_load_extended(long double *s, int stnr)
90 {
91 FPU_REG *sti_ptr = &st(stnr);
92
93 RE_ENTRANT_CHECK_OFF;
94 FPU_verify_area(VERIFY_READ, s, 10);
95 __copy_from_user(sti_ptr, s, 10);
96 RE_ENTRANT_CHECK_ON;
97
98 return FPU_tagof(sti_ptr);
99 }
100
101
102 /* Get a double from user memory */
FPU_load_double(double * dfloat,FPU_REG * loaded_data)103 int FPU_load_double(double *dfloat, FPU_REG *loaded_data)
104 {
105 int exp, tag, negative;
106 unsigned m64, l64;
107
108 RE_ENTRANT_CHECK_OFF;
109 FPU_verify_area(VERIFY_READ, dfloat, 8);
110 FPU_get_user(m64, 1 + (unsigned long *) dfloat);
111 FPU_get_user(l64, (unsigned long *) dfloat);
112 RE_ENTRANT_CHECK_ON;
113
114 negative = (m64 & 0x80000000) ? SIGN_Negative : SIGN_Positive;
115 exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias + EXTENDED_Ebias;
116 m64 &= 0xfffff;
117 if ( exp > DOUBLE_Emax + EXTENDED_Ebias )
118 {
119 /* Infinity or NaN */
120 if ((m64 == 0) && (l64 == 0))
121 {
122 /* +- infinity */
123 loaded_data->sigh = 0x80000000;
124 loaded_data->sigl = 0x00000000;
125 exp = EXP_Infinity + EXTENDED_Ebias;
126 tag = TAG_Special;
127 }
128 else
129 {
130 /* Must be a signaling or quiet NaN */
131 exp = EXP_NaN + EXTENDED_Ebias;
132 loaded_data->sigh = (m64 << 11) | 0x80000000;
133 loaded_data->sigh |= l64 >> 21;
134 loaded_data->sigl = l64 << 11;
135 tag = TAG_Special; /* The calling function must look for NaNs */
136 }
137 }
138 else if ( exp < DOUBLE_Emin + EXTENDED_Ebias )
139 {
140 /* Zero or de-normal */
141 if ((m64 == 0) && (l64 == 0))
142 {
143 /* Zero */
144 reg_copy(&CONST_Z, loaded_data);
145 exp = 0;
146 tag = TAG_Zero;
147 }
148 else
149 {
150 /* De-normal */
151 loaded_data->sigh = m64 << 11;
152 loaded_data->sigh |= l64 >> 21;
153 loaded_data->sigl = l64 << 11;
154
155 return normalize_no_excep(loaded_data, DOUBLE_Emin, negative)
156 | (denormal_operand() < 0 ? FPU_Exception : 0);
157 }
158 }
159 else
160 {
161 loaded_data->sigh = (m64 << 11) | 0x80000000;
162 loaded_data->sigh |= l64 >> 21;
163 loaded_data->sigl = l64 << 11;
164
165 tag = TAG_Valid;
166 }
167
168 setexponent16(loaded_data, exp | negative);
169
170 return tag;
171 }
172
173
174 /* Get a float from user memory */
FPU_load_single(float * single,FPU_REG * loaded_data)175 int FPU_load_single(float *single, FPU_REG *loaded_data)
176 {
177 unsigned m32;
178 int exp, tag, negative;
179
180 RE_ENTRANT_CHECK_OFF;
181 FPU_verify_area(VERIFY_READ, single, 4);
182 FPU_get_user(m32, (unsigned long *) single);
183 RE_ENTRANT_CHECK_ON;
184
185 negative = (m32 & 0x80000000) ? SIGN_Negative : SIGN_Positive;
186
187 if (!(m32 & 0x7fffffff))
188 {
189 /* Zero */
190 reg_copy(&CONST_Z, loaded_data);
191 addexponent(loaded_data, negative);
192 return TAG_Zero;
193 }
194 exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias + EXTENDED_Ebias;
195 m32 = (m32 & 0x7fffff) << 8;
196 if ( exp < SINGLE_Emin + EXTENDED_Ebias )
197 {
198 /* De-normals */
199 loaded_data->sigh = m32;
200 loaded_data->sigl = 0;
201
202 return normalize_no_excep(loaded_data, SINGLE_Emin, negative)
203 | (denormal_operand() < 0 ? FPU_Exception : 0);
204 }
205 else if ( exp > SINGLE_Emax + EXTENDED_Ebias )
206 {
207 /* Infinity or NaN */
208 if ( m32 == 0 )
209 {
210 /* +- infinity */
211 loaded_data->sigh = 0x80000000;
212 loaded_data->sigl = 0x00000000;
213 exp = EXP_Infinity + EXTENDED_Ebias;
214 tag = TAG_Special;
215 }
216 else
217 {
218 /* Must be a signaling or quiet NaN */
219 exp = EXP_NaN + EXTENDED_Ebias;
220 loaded_data->sigh = m32 | 0x80000000;
221 loaded_data->sigl = 0;
222 tag = TAG_Special; /* The calling function must look for NaNs */
223 }
224 }
225 else
226 {
227 loaded_data->sigh = m32 | 0x80000000;
228 loaded_data->sigl = 0;
229 tag = TAG_Valid;
230 }
231
232 setexponent16(loaded_data, exp | negative); /* Set the sign. */
233
234 return tag;
235 }
236
237
238 /* Get a long long from user memory */
FPU_load_int64(long long * _s)239 int FPU_load_int64(long long *_s)
240 {
241 long long s;
242 int sign;
243 FPU_REG *st0_ptr = &st(0);
244
245 RE_ENTRANT_CHECK_OFF;
246 FPU_verify_area(VERIFY_READ, _s, 8);
247 copy_from_user(&s,_s,8);
248 RE_ENTRANT_CHECK_ON;
249
250 if (s == 0)
251 {
252 reg_copy(&CONST_Z, st0_ptr);
253 return TAG_Zero;
254 }
255
256 if (s > 0)
257 sign = SIGN_Positive;
258 else
259 {
260 s = -s;
261 sign = SIGN_Negative;
262 }
263
264 significand(st0_ptr) = s;
265
266 return normalize_no_excep(st0_ptr, 63, sign);
267 }
268
269
270 /* Get a long from user memory */
FPU_load_int32(long * _s,FPU_REG * loaded_data)271 int FPU_load_int32(long *_s, FPU_REG *loaded_data)
272 {
273 long s;
274 int negative;
275
276 RE_ENTRANT_CHECK_OFF;
277 FPU_verify_area(VERIFY_READ, _s, 4);
278 FPU_get_user(s, _s);
279 RE_ENTRANT_CHECK_ON;
280
281 if (s == 0)
282 { reg_copy(&CONST_Z, loaded_data); return TAG_Zero; }
283
284 if (s > 0)
285 negative = SIGN_Positive;
286 else
287 {
288 s = -s;
289 negative = SIGN_Negative;
290 }
291
292 loaded_data->sigh = s;
293 loaded_data->sigl = 0;
294
295 return normalize_no_excep(loaded_data, 31, negative);
296 }
297
298
299 /* Get a short from user memory */
FPU_load_int16(short * _s,FPU_REG * loaded_data)300 int FPU_load_int16(short *_s, FPU_REG *loaded_data)
301 {
302 int s, negative;
303
304 RE_ENTRANT_CHECK_OFF;
305 FPU_verify_area(VERIFY_READ, _s, 2);
306 /* Cast as short to get the sign extended. */
307 FPU_get_user(s, _s);
308 RE_ENTRANT_CHECK_ON;
309
310 if (s == 0)
311 { reg_copy(&CONST_Z, loaded_data); return TAG_Zero; }
312
313 if (s > 0)
314 negative = SIGN_Positive;
315 else
316 {
317 s = -s;
318 negative = SIGN_Negative;
319 }
320
321 loaded_data->sigh = s << 16;
322 loaded_data->sigl = 0;
323
324 return normalize_no_excep(loaded_data, 15, negative);
325 }
326
327
328 /* Get a packed bcd array from user memory */
FPU_load_bcd(u_char * s)329 int FPU_load_bcd(u_char *s)
330 {
331 FPU_REG *st0_ptr = &st(0);
332 int pos;
333 u_char bcd;
334 long long l=0;
335 int sign;
336
337 RE_ENTRANT_CHECK_OFF;
338 FPU_verify_area(VERIFY_READ, s, 10);
339 RE_ENTRANT_CHECK_ON;
340 for ( pos = 8; pos >= 0; pos--)
341 {
342 l *= 10;
343 RE_ENTRANT_CHECK_OFF;
344 FPU_get_user(bcd, (u_char *) s+pos);
345 RE_ENTRANT_CHECK_ON;
346 l += bcd >> 4;
347 l *= 10;
348 l += bcd & 0x0f;
349 }
350
351 RE_ENTRANT_CHECK_OFF;
352 FPU_get_user(sign, (u_char *) s+9);
353 sign = sign & 0x80 ? SIGN_Negative : SIGN_Positive;
354 RE_ENTRANT_CHECK_ON;
355
356 if ( l == 0 )
357 {
358 reg_copy(&CONST_Z, st0_ptr);
359 addexponent(st0_ptr, sign); /* Set the sign. */
360 return TAG_Zero;
361 }
362 else
363 {
364 significand(st0_ptr) = l;
365 return normalize_no_excep(st0_ptr, 63, sign);
366 }
367 }
368
369 /*===========================================================================*/
370
371 /* Put a long double into user memory */
FPU_store_extended(FPU_REG * st0_ptr,u_char st0_tag,long double * d)372 int FPU_store_extended(FPU_REG *st0_ptr, u_char st0_tag, long double *d)
373 {
374 /*
375 The only exception raised by an attempt to store to an
376 extended format is the Invalid Stack exception, i.e.
377 attempting to store from an empty register.
378 */
379
380 if ( st0_tag != TAG_Empty )
381 {
382 RE_ENTRANT_CHECK_OFF;
383 FPU_verify_area(VERIFY_WRITE, d, 10);
384
385 FPU_put_user(st0_ptr->sigl, (unsigned long *) d);
386 FPU_put_user(st0_ptr->sigh, (unsigned long *) ((u_char *)d + 4));
387 FPU_put_user(exponent16(st0_ptr), (unsigned short *) ((u_char *)d + 8));
388 RE_ENTRANT_CHECK_ON;
389
390 return 1;
391 }
392
393 /* Empty register (stack underflow) */
394 EXCEPTION(EX_StackUnder);
395 if ( control_word & CW_Invalid )
396 {
397 /* The masked response */
398 /* Put out the QNaN indefinite */
399 RE_ENTRANT_CHECK_OFF;
400 FPU_verify_area(VERIFY_WRITE,d,10);
401 FPU_put_user(0, (unsigned long *) d);
402 FPU_put_user(0xc0000000, 1 + (unsigned long *) d);
403 FPU_put_user(0xffff, 4 + (short *) d);
404 RE_ENTRANT_CHECK_ON;
405 return 1;
406 }
407 else
408 return 0;
409
410 }
411
412
413 /* Put a double into user memory */
FPU_store_double(FPU_REG * st0_ptr,u_char st0_tag,double * dfloat)414 int FPU_store_double(FPU_REG *st0_ptr, u_char st0_tag, double *dfloat)
415 {
416 unsigned long l[2];
417 unsigned long increment = 0; /* avoid gcc warnings */
418 int precision_loss;
419 int exp;
420 FPU_REG tmp;
421
422 if ( st0_tag == TAG_Valid )
423 {
424 reg_copy(st0_ptr, &tmp);
425 exp = exponent(&tmp);
426
427 if ( exp < DOUBLE_Emin ) /* It may be a denormal */
428 {
429 addexponent(&tmp, -DOUBLE_Emin + 52); /* largest exp to be 51 */
430
431 denormal_arg:
432
433 if ( (precision_loss = FPU_round_to_int(&tmp, st0_tag)) )
434 {
435 #ifdef PECULIAR_486
436 /* Did it round to a non-denormal ? */
437 /* This behaviour might be regarded as peculiar, it appears
438 that the 80486 rounds to the dest precision, then
439 converts to decide underflow. */
440 if ( !((tmp.sigh == 0x00100000) && (tmp.sigl == 0) &&
441 (st0_ptr->sigl & 0x000007ff)) )
442 #endif /* PECULIAR_486 */
443 {
444 EXCEPTION(EX_Underflow);
445 /* This is a special case: see sec 16.2.5.1 of
446 the 80486 book */
447 if ( !(control_word & CW_Underflow) )
448 return 0;
449 }
450 EXCEPTION(precision_loss);
451 if ( !(control_word & CW_Precision) )
452 return 0;
453 }
454 l[0] = tmp.sigl;
455 l[1] = tmp.sigh;
456 }
457 else
458 {
459 if ( tmp.sigl & 0x000007ff )
460 {
461 precision_loss = 1;
462 switch (control_word & CW_RC)
463 {
464 case RC_RND:
465 /* Rounding can get a little messy.. */
466 increment = ((tmp.sigl & 0x7ff) > 0x400) | /* nearest */
467 ((tmp.sigl & 0xc00) == 0xc00); /* odd -> even */
468 break;
469 case RC_DOWN: /* towards -infinity */
470 increment = signpositive(&tmp) ? 0 : tmp.sigl & 0x7ff;
471 break;
472 case RC_UP: /* towards +infinity */
473 increment = signpositive(&tmp) ? tmp.sigl & 0x7ff : 0;
474 break;
475 case RC_CHOP:
476 increment = 0;
477 break;
478 }
479
480 /* Truncate the mantissa */
481 tmp.sigl &= 0xfffff800;
482
483 if ( increment )
484 {
485 if ( tmp.sigl >= 0xfffff800 )
486 {
487 /* the sigl part overflows */
488 if ( tmp.sigh == 0xffffffff )
489 {
490 /* The sigh part overflows */
491 tmp.sigh = 0x80000000;
492 exp++;
493 if (exp >= EXP_OVER)
494 goto overflow;
495 }
496 else
497 {
498 tmp.sigh ++;
499 }
500 tmp.sigl = 0x00000000;
501 }
502 else
503 {
504 /* We only need to increment sigl */
505 tmp.sigl += 0x00000800;
506 }
507 }
508 }
509 else
510 precision_loss = 0;
511
512 l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21);
513 l[1] = ((tmp.sigh >> 11) & 0xfffff);
514
515 if ( exp > DOUBLE_Emax )
516 {
517 overflow:
518 EXCEPTION(EX_Overflow);
519 if ( !(control_word & CW_Overflow) )
520 return 0;
521 set_precision_flag_up();
522 if ( !(control_word & CW_Precision) )
523 return 0;
524
525 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
526 /* Overflow to infinity */
527 l[0] = 0x00000000; /* Set to */
528 l[1] = 0x7ff00000; /* + INF */
529 }
530 else
531 {
532 if ( precision_loss )
533 {
534 if ( increment )
535 set_precision_flag_up();
536 else
537 set_precision_flag_down();
538 }
539 /* Add the exponent */
540 l[1] |= (((exp+DOUBLE_Ebias) & 0x7ff) << 20);
541 }
542 }
543 }
544 else if (st0_tag == TAG_Zero)
545 {
546 /* Number is zero */
547 l[0] = 0;
548 l[1] = 0;
549 }
550 else if ( st0_tag == TAG_Special )
551 {
552 st0_tag = FPU_Special(st0_ptr);
553 if ( st0_tag == TW_Denormal )
554 {
555 /* A denormal will always underflow. */
556 #ifndef PECULIAR_486
557 /* An 80486 is supposed to be able to generate
558 a denormal exception here, but... */
559 /* Underflow has priority. */
560 if ( control_word & CW_Underflow )
561 denormal_operand();
562 #endif /* PECULIAR_486 */
563 reg_copy(st0_ptr, &tmp);
564 goto denormal_arg;
565 }
566 else if (st0_tag == TW_Infinity)
567 {
568 l[0] = 0;
569 l[1] = 0x7ff00000;
570 }
571 else if (st0_tag == TW_NaN)
572 {
573 /* Is it really a NaN ? */
574 if ( (exponent(st0_ptr) == EXP_OVER)
575 && (st0_ptr->sigh & 0x80000000) )
576 {
577 /* See if we can get a valid NaN from the FPU_REG */
578 l[0] = (st0_ptr->sigl >> 11) | (st0_ptr->sigh << 21);
579 l[1] = ((st0_ptr->sigh >> 11) & 0xfffff);
580 if ( !(st0_ptr->sigh & 0x40000000) )
581 {
582 /* It is a signalling NaN */
583 EXCEPTION(EX_Invalid);
584 if ( !(control_word & CW_Invalid) )
585 return 0;
586 l[1] |= (0x40000000 >> 11);
587 }
588 l[1] |= 0x7ff00000;
589 }
590 else
591 {
592 /* It is an unsupported data type */
593 EXCEPTION(EX_Invalid);
594 if ( !(control_word & CW_Invalid) )
595 return 0;
596 l[0] = 0;
597 l[1] = 0xfff80000;
598 }
599 }
600 }
601 else if ( st0_tag == TAG_Empty )
602 {
603 /* Empty register (stack underflow) */
604 EXCEPTION(EX_StackUnder);
605 if ( control_word & CW_Invalid )
606 {
607 /* The masked response */
608 /* Put out the QNaN indefinite */
609 RE_ENTRANT_CHECK_OFF;
610 FPU_verify_area(VERIFY_WRITE,(void *)dfloat,8);
611 FPU_put_user(0, (unsigned long *) dfloat);
612 FPU_put_user(0xfff80000, 1 + (unsigned long *) dfloat);
613 RE_ENTRANT_CHECK_ON;
614 return 1;
615 }
616 else
617 return 0;
618 }
619 if ( getsign(st0_ptr) )
620 l[1] |= 0x80000000;
621
622 RE_ENTRANT_CHECK_OFF;
623 FPU_verify_area(VERIFY_WRITE,(void *)dfloat,8);
624 FPU_put_user(l[0], (unsigned long *)dfloat);
625 FPU_put_user(l[1], 1 + (unsigned long *)dfloat);
626 RE_ENTRANT_CHECK_ON;
627
628 return 1;
629 }
630
631
632 /* Put a float into user memory */
FPU_store_single(FPU_REG * st0_ptr,u_char st0_tag,float * single)633 int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float *single)
634 {
635 long templ = 0;
636 unsigned long increment = 0; /* avoid gcc warnings */
637 int precision_loss;
638 int exp;
639 FPU_REG tmp;
640
641 if ( st0_tag == TAG_Valid )
642 {
643
644 reg_copy(st0_ptr, &tmp);
645 exp = exponent(&tmp);
646
647 if ( exp < SINGLE_Emin )
648 {
649 addexponent(&tmp, -SINGLE_Emin + 23); /* largest exp to be 22 */
650
651 denormal_arg:
652
653 if ( (precision_loss = FPU_round_to_int(&tmp, st0_tag)) )
654 {
655 #ifdef PECULIAR_486
656 /* Did it round to a non-denormal ? */
657 /* This behaviour might be regarded as peculiar, it appears
658 that the 80486 rounds to the dest precision, then
659 converts to decide underflow. */
660 if ( !((tmp.sigl == 0x00800000) &&
661 ((st0_ptr->sigh & 0x000000ff) || st0_ptr->sigl)) )
662 #endif /* PECULIAR_486 */
663 {
664 EXCEPTION(EX_Underflow);
665 /* This is a special case: see sec 16.2.5.1 of
666 the 80486 book */
667 if ( !(control_word & CW_Underflow) )
668 return 0;
669 }
670 EXCEPTION(precision_loss);
671 if ( !(control_word & CW_Precision) )
672 return 0;
673 }
674 templ = tmp.sigl;
675 }
676 else
677 {
678 if ( tmp.sigl | (tmp.sigh & 0x000000ff) )
679 {
680 unsigned long sigh = tmp.sigh;
681 unsigned long sigl = tmp.sigl;
682
683 precision_loss = 1;
684 switch (control_word & CW_RC)
685 {
686 case RC_RND:
687 increment = ((sigh & 0xff) > 0x80) /* more than half */
688 || (((sigh & 0xff) == 0x80) && sigl) /* more than half */
689 || ((sigh & 0x180) == 0x180); /* round to even */
690 break;
691 case RC_DOWN: /* towards -infinity */
692 increment = signpositive(&tmp)
693 ? 0 : (sigl | (sigh & 0xff));
694 break;
695 case RC_UP: /* towards +infinity */
696 increment = signpositive(&tmp)
697 ? (sigl | (sigh & 0xff)) : 0;
698 break;
699 case RC_CHOP:
700 increment = 0;
701 break;
702 }
703
704 /* Truncate part of the mantissa */
705 tmp.sigl = 0;
706
707 if (increment)
708 {
709 if ( sigh >= 0xffffff00 )
710 {
711 /* The sigh part overflows */
712 tmp.sigh = 0x80000000;
713 exp++;
714 if ( exp >= EXP_OVER )
715 goto overflow;
716 }
717 else
718 {
719 tmp.sigh &= 0xffffff00;
720 tmp.sigh += 0x100;
721 }
722 }
723 else
724 {
725 tmp.sigh &= 0xffffff00; /* Finish the truncation */
726 }
727 }
728 else
729 precision_loss = 0;
730
731 templ = (tmp.sigh >> 8) & 0x007fffff;
732
733 if ( exp > SINGLE_Emax )
734 {
735 overflow:
736 EXCEPTION(EX_Overflow);
737 if ( !(control_word & CW_Overflow) )
738 return 0;
739 set_precision_flag_up();
740 if ( !(control_word & CW_Precision) )
741 return 0;
742
743 /* This is a special case: see sec 16.2.5.1 of the 80486 book. */
744 /* Masked response is overflow to infinity. */
745 templ = 0x7f800000;
746 }
747 else
748 {
749 if ( precision_loss )
750 {
751 if ( increment )
752 set_precision_flag_up();
753 else
754 set_precision_flag_down();
755 }
756 /* Add the exponent */
757 templ |= ((exp+SINGLE_Ebias) & 0xff) << 23;
758 }
759 }
760 }
761 else if (st0_tag == TAG_Zero)
762 {
763 templ = 0;
764 }
765 else if ( st0_tag == TAG_Special )
766 {
767 st0_tag = FPU_Special(st0_ptr);
768 if (st0_tag == TW_Denormal)
769 {
770 reg_copy(st0_ptr, &tmp);
771
772 /* A denormal will always underflow. */
773 #ifndef PECULIAR_486
774 /* An 80486 is supposed to be able to generate
775 a denormal exception here, but... */
776 /* Underflow has priority. */
777 if ( control_word & CW_Underflow )
778 denormal_operand();
779 #endif /* PECULIAR_486 */
780 goto denormal_arg;
781 }
782 else if (st0_tag == TW_Infinity)
783 {
784 templ = 0x7f800000;
785 }
786 else if (st0_tag == TW_NaN)
787 {
788 /* Is it really a NaN ? */
789 if ( (exponent(st0_ptr) == EXP_OVER) && (st0_ptr->sigh & 0x80000000) )
790 {
791 /* See if we can get a valid NaN from the FPU_REG */
792 templ = st0_ptr->sigh >> 8;
793 if ( !(st0_ptr->sigh & 0x40000000) )
794 {
795 /* It is a signalling NaN */
796 EXCEPTION(EX_Invalid);
797 if ( !(control_word & CW_Invalid) )
798 return 0;
799 templ |= (0x40000000 >> 8);
800 }
801 templ |= 0x7f800000;
802 }
803 else
804 {
805 /* It is an unsupported data type */
806 EXCEPTION(EX_Invalid);
807 if ( !(control_word & CW_Invalid) )
808 return 0;
809 templ = 0xffc00000;
810 }
811 }
812 #ifdef PARANOID
813 else
814 {
815 EXCEPTION(EX_INTERNAL|0x164);
816 return 0;
817 }
818 #endif
819 }
820 else if ( st0_tag == TAG_Empty )
821 {
822 /* Empty register (stack underflow) */
823 EXCEPTION(EX_StackUnder);
824 if ( control_word & EX_Invalid )
825 {
826 /* The masked response */
827 /* Put out the QNaN indefinite */
828 RE_ENTRANT_CHECK_OFF;
829 FPU_verify_area(VERIFY_WRITE,(void *)single,4);
830 FPU_put_user(0xffc00000, (unsigned long *) single);
831 RE_ENTRANT_CHECK_ON;
832 return 1;
833 }
834 else
835 return 0;
836 }
837 #ifdef PARANOID
838 else
839 {
840 EXCEPTION(EX_INTERNAL|0x163);
841 return 0;
842 }
843 #endif
844 if ( getsign(st0_ptr) )
845 templ |= 0x80000000;
846
847 RE_ENTRANT_CHECK_OFF;
848 FPU_verify_area(VERIFY_WRITE,(void *)single,4);
849 FPU_put_user(templ,(unsigned long *) single);
850 RE_ENTRANT_CHECK_ON;
851
852 return 1;
853 }
854
855
856 /* Put a long long into user memory */
FPU_store_int64(FPU_REG * st0_ptr,u_char st0_tag,long long * d)857 int FPU_store_int64(FPU_REG *st0_ptr, u_char st0_tag, long long *d)
858 {
859 FPU_REG t;
860 long long tll;
861 int precision_loss;
862
863 if ( st0_tag == TAG_Empty )
864 {
865 /* Empty register (stack underflow) */
866 EXCEPTION(EX_StackUnder);
867 goto invalid_operand;
868 }
869 else if ( st0_tag == TAG_Special )
870 {
871 st0_tag = FPU_Special(st0_ptr);
872 if ( (st0_tag == TW_Infinity) ||
873 (st0_tag == TW_NaN) )
874 {
875 EXCEPTION(EX_Invalid);
876 goto invalid_operand;
877 }
878 }
879
880 reg_copy(st0_ptr, &t);
881 precision_loss = FPU_round_to_int(&t, st0_tag);
882 ((long *)&tll)[0] = t.sigl;
883 ((long *)&tll)[1] = t.sigh;
884 if ( (precision_loss == 1) ||
885 ((t.sigh & 0x80000000) &&
886 !((t.sigh == 0x80000000) && (t.sigl == 0) &&
887 signnegative(&t))) )
888 {
889 EXCEPTION(EX_Invalid);
890 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
891 invalid_operand:
892 if ( control_word & EX_Invalid )
893 {
894 /* Produce something like QNaN "indefinite" */
895 tll = 0x8000000000000000LL;
896 }
897 else
898 return 0;
899 }
900 else
901 {
902 if ( precision_loss )
903 set_precision_flag(precision_loss);
904 if ( signnegative(&t) )
905 tll = - tll;
906 }
907
908 RE_ENTRANT_CHECK_OFF;
909 FPU_verify_area(VERIFY_WRITE,(void *)d,8);
910 copy_to_user(d, &tll, 8);
911 RE_ENTRANT_CHECK_ON;
912
913 return 1;
914 }
915
916
917 /* Put a long into user memory */
FPU_store_int32(FPU_REG * st0_ptr,u_char st0_tag,long * d)918 int FPU_store_int32(FPU_REG *st0_ptr, u_char st0_tag, long *d)
919 {
920 FPU_REG t;
921 int precision_loss;
922
923 if ( st0_tag == TAG_Empty )
924 {
925 /* Empty register (stack underflow) */
926 EXCEPTION(EX_StackUnder);
927 goto invalid_operand;
928 }
929 else if ( st0_tag == TAG_Special )
930 {
931 st0_tag = FPU_Special(st0_ptr);
932 if ( (st0_tag == TW_Infinity) ||
933 (st0_tag == TW_NaN) )
934 {
935 EXCEPTION(EX_Invalid);
936 goto invalid_operand;
937 }
938 }
939
940 reg_copy(st0_ptr, &t);
941 precision_loss = FPU_round_to_int(&t, st0_tag);
942 if (t.sigh ||
943 ((t.sigl & 0x80000000) &&
944 !((t.sigl == 0x80000000) && signnegative(&t))) )
945 {
946 EXCEPTION(EX_Invalid);
947 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
948 invalid_operand:
949 if ( control_word & EX_Invalid )
950 {
951 /* Produce something like QNaN "indefinite" */
952 t.sigl = 0x80000000;
953 }
954 else
955 return 0;
956 }
957 else
958 {
959 if ( precision_loss )
960 set_precision_flag(precision_loss);
961 if ( signnegative(&t) )
962 t.sigl = -(long)t.sigl;
963 }
964
965 RE_ENTRANT_CHECK_OFF;
966 FPU_verify_area(VERIFY_WRITE,d,4);
967 FPU_put_user(t.sigl, (unsigned long *) d);
968 RE_ENTRANT_CHECK_ON;
969
970 return 1;
971 }
972
973
974 /* Put a short into user memory */
FPU_store_int16(FPU_REG * st0_ptr,u_char st0_tag,short * d)975 int FPU_store_int16(FPU_REG *st0_ptr, u_char st0_tag, short *d)
976 {
977 FPU_REG t;
978 int precision_loss;
979
980 if ( st0_tag == TAG_Empty )
981 {
982 /* Empty register (stack underflow) */
983 EXCEPTION(EX_StackUnder);
984 goto invalid_operand;
985 }
986 else if ( st0_tag == TAG_Special )
987 {
988 st0_tag = FPU_Special(st0_ptr);
989 if ( (st0_tag == TW_Infinity) ||
990 (st0_tag == TW_NaN) )
991 {
992 EXCEPTION(EX_Invalid);
993 goto invalid_operand;
994 }
995 }
996
997 reg_copy(st0_ptr, &t);
998 precision_loss = FPU_round_to_int(&t, st0_tag);
999 if (t.sigh ||
1000 ((t.sigl & 0xffff8000) &&
1001 !((t.sigl == 0x8000) && signnegative(&t))) )
1002 {
1003 EXCEPTION(EX_Invalid);
1004 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
1005 invalid_operand:
1006 if ( control_word & EX_Invalid )
1007 {
1008 /* Produce something like QNaN "indefinite" */
1009 t.sigl = 0x8000;
1010 }
1011 else
1012 return 0;
1013 }
1014 else
1015 {
1016 if ( precision_loss )
1017 set_precision_flag(precision_loss);
1018 if ( signnegative(&t) )
1019 t.sigl = -t.sigl;
1020 }
1021
1022 RE_ENTRANT_CHECK_OFF;
1023 FPU_verify_area(VERIFY_WRITE,d,2);
1024 FPU_put_user((short)t.sigl,(short *) d);
1025 RE_ENTRANT_CHECK_ON;
1026
1027 return 1;
1028 }
1029
1030
1031 /* Put a packed bcd array into user memory */
FPU_store_bcd(FPU_REG * st0_ptr,u_char st0_tag,u_char * d)1032 int FPU_store_bcd(FPU_REG *st0_ptr, u_char st0_tag, u_char *d)
1033 {
1034 FPU_REG t;
1035 unsigned long long ll;
1036 u_char b;
1037 int i, precision_loss;
1038 u_char sign = (getsign(st0_ptr) == SIGN_NEG) ? 0x80 : 0;
1039
1040 if ( st0_tag == TAG_Empty )
1041 {
1042 /* Empty register (stack underflow) */
1043 EXCEPTION(EX_StackUnder);
1044 goto invalid_operand;
1045 }
1046 else if ( st0_tag == TAG_Special )
1047 {
1048 st0_tag = FPU_Special(st0_ptr);
1049 if ( (st0_tag == TW_Infinity) ||
1050 (st0_tag == TW_NaN) )
1051 {
1052 EXCEPTION(EX_Invalid);
1053 goto invalid_operand;
1054 }
1055 }
1056
1057 reg_copy(st0_ptr, &t);
1058 precision_loss = FPU_round_to_int(&t, st0_tag);
1059 ll = significand(&t);
1060
1061 /* Check for overflow, by comparing with 999999999999999999 decimal. */
1062 if ( (t.sigh > 0x0de0b6b3) ||
1063 ((t.sigh == 0x0de0b6b3) && (t.sigl > 0xa763ffff)) )
1064 {
1065 EXCEPTION(EX_Invalid);
1066 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
1067 invalid_operand:
1068 if ( control_word & CW_Invalid )
1069 {
1070 /* Produce the QNaN "indefinite" */
1071 RE_ENTRANT_CHECK_OFF;
1072 FPU_verify_area(VERIFY_WRITE,d,10);
1073 for ( i = 0; i < 7; i++)
1074 FPU_put_user(0, (u_char *) d+i); /* These bytes "undefined" */
1075 FPU_put_user(0xc0, (u_char *) d+7); /* This byte "undefined" */
1076 FPU_put_user(0xff, (u_char *) d+8);
1077 FPU_put_user(0xff, (u_char *) d+9);
1078 RE_ENTRANT_CHECK_ON;
1079 return 1;
1080 }
1081 else
1082 return 0;
1083 }
1084 else if ( precision_loss )
1085 {
1086 /* Precision loss doesn't stop the data transfer */
1087 set_precision_flag(precision_loss);
1088 }
1089
1090 RE_ENTRANT_CHECK_OFF;
1091 FPU_verify_area(VERIFY_WRITE,d,10);
1092 RE_ENTRANT_CHECK_ON;
1093 for ( i = 0; i < 9; i++)
1094 {
1095 b = FPU_div_small(&ll, 10);
1096 b |= (FPU_div_small(&ll, 10)) << 4;
1097 RE_ENTRANT_CHECK_OFF;
1098 FPU_put_user(b,(u_char *) d+i);
1099 RE_ENTRANT_CHECK_ON;
1100 }
1101 RE_ENTRANT_CHECK_OFF;
1102 FPU_put_user(sign,(u_char *) d+9);
1103 RE_ENTRANT_CHECK_ON;
1104
1105 return 1;
1106 }
1107
1108 /*===========================================================================*/
1109
1110 /* r gets mangled such that sig is int, sign:
1111 it is NOT normalized */
1112 /* The return value (in eax) is zero if the result is exact,
1113 if bits are changed due to rounding, truncation, etc, then
1114 a non-zero value is returned */
1115 /* Overflow is signalled by a non-zero return value (in eax).
1116 In the case of overflow, the returned significand always has the
1117 largest possible value */
FPU_round_to_int(FPU_REG * r,u_char tag)1118 int FPU_round_to_int(FPU_REG *r, u_char tag)
1119 {
1120 u_char very_big;
1121 unsigned eax;
1122
1123 if (tag == TAG_Zero)
1124 {
1125 /* Make sure that zero is returned */
1126 significand(r) = 0;
1127 return 0; /* o.k. */
1128 }
1129
1130 if (exponent(r) > 63)
1131 {
1132 r->sigl = r->sigh = ~0; /* The largest representable number */
1133 return 1; /* overflow */
1134 }
1135
1136 eax = FPU_shrxs(&r->sigl, 63 - exponent(r));
1137 very_big = !(~(r->sigh) | ~(r->sigl)); /* test for 0xfff...fff */
1138 #define half_or_more (eax & 0x80000000)
1139 #define frac_part (eax)
1140 #define more_than_half ((eax & 0x80000001) == 0x80000001)
1141 switch (control_word & CW_RC)
1142 {
1143 case RC_RND:
1144 if ( more_than_half /* nearest */
1145 || (half_or_more && (r->sigl & 1)) ) /* odd -> even */
1146 {
1147 if ( very_big ) return 1; /* overflow */
1148 significand(r) ++;
1149 return PRECISION_LOST_UP;
1150 }
1151 break;
1152 case RC_DOWN:
1153 if (frac_part && getsign(r))
1154 {
1155 if ( very_big ) return 1; /* overflow */
1156 significand(r) ++;
1157 return PRECISION_LOST_UP;
1158 }
1159 break;
1160 case RC_UP:
1161 if (frac_part && !getsign(r))
1162 {
1163 if ( very_big ) return 1; /* overflow */
1164 significand(r) ++;
1165 return PRECISION_LOST_UP;
1166 }
1167 break;
1168 case RC_CHOP:
1169 break;
1170 }
1171
1172 return eax ? PRECISION_LOST_DOWN : 0;
1173
1174 }
1175
1176 /*===========================================================================*/
1177
fldenv(fpu_addr_modes addr_modes,u_char * s)1178 u_char *fldenv(fpu_addr_modes addr_modes, u_char *s)
1179 {
1180 unsigned short tag_word = 0;
1181 u_char tag;
1182 int i;
1183
1184 if ( (addr_modes.default_mode == VM86) ||
1185 ((addr_modes.default_mode == PM16)
1186 ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX)) )
1187 {
1188 RE_ENTRANT_CHECK_OFF;
1189 FPU_verify_area(VERIFY_READ, s, 0x0e);
1190 FPU_get_user(control_word, (unsigned short *) s);
1191 FPU_get_user(partial_status, (unsigned short *) (s+2));
1192 FPU_get_user(tag_word, (unsigned short *) (s+4));
1193 FPU_get_user(instruction_address.offset, (unsigned short *) (s+6));
1194 FPU_get_user(instruction_address.selector, (unsigned short *) (s+8));
1195 FPU_get_user(operand_address.offset, (unsigned short *) (s+0x0a));
1196 FPU_get_user(operand_address.selector, (unsigned short *) (s+0x0c));
1197 RE_ENTRANT_CHECK_ON;
1198 s += 0x0e;
1199 if ( addr_modes.default_mode == VM86 )
1200 {
1201 instruction_address.offset
1202 += (instruction_address.selector & 0xf000) << 4;
1203 operand_address.offset += (operand_address.selector & 0xf000) << 4;
1204 }
1205 }
1206 else
1207 {
1208 RE_ENTRANT_CHECK_OFF;
1209 FPU_verify_area(VERIFY_READ, s, 0x1c);
1210 FPU_get_user(control_word, (unsigned short *) s);
1211 FPU_get_user(partial_status, (unsigned short *) (s+4));
1212 FPU_get_user(tag_word, (unsigned short *) (s+8));
1213 FPU_get_user(instruction_address.offset, (unsigned long *) (s+0x0c));
1214 FPU_get_user(instruction_address.selector, (unsigned short *) (s+0x10));
1215 FPU_get_user(instruction_address.opcode, (unsigned short *) (s+0x12));
1216 FPU_get_user(operand_address.offset, (unsigned long *) (s+0x14));
1217 FPU_get_user(operand_address.selector, (unsigned long *) (s+0x18));
1218 RE_ENTRANT_CHECK_ON;
1219 s += 0x1c;
1220 }
1221
1222 #ifdef PECULIAR_486
1223 control_word &= ~0xe080;
1224 #endif /* PECULIAR_486 */
1225
1226 top = (partial_status >> SW_Top_Shift) & 7;
1227
1228 if ( partial_status & ~control_word & CW_Exceptions )
1229 partial_status |= (SW_Summary | SW_Backward);
1230 else
1231 partial_status &= ~(SW_Summary | SW_Backward);
1232
1233 for ( i = 0; i < 8; i++ )
1234 {
1235 tag = tag_word & 3;
1236 tag_word >>= 2;
1237
1238 if ( tag == TAG_Empty )
1239 /* New tag is empty. Accept it */
1240 FPU_settag(i, TAG_Empty);
1241 else if ( FPU_gettag(i) == TAG_Empty )
1242 {
1243 /* Old tag is empty and new tag is not empty. New tag is determined
1244 by old reg contents */
1245 if ( exponent(&fpu_register(i)) == - EXTENDED_Ebias )
1246 {
1247 if ( !(fpu_register(i).sigl | fpu_register(i).sigh) )
1248 FPU_settag(i, TAG_Zero);
1249 else
1250 FPU_settag(i, TAG_Special);
1251 }
1252 else if ( exponent(&fpu_register(i)) == 0x7fff - EXTENDED_Ebias )
1253 {
1254 FPU_settag(i, TAG_Special);
1255 }
1256 else if ( fpu_register(i).sigh & 0x80000000 )
1257 FPU_settag(i, TAG_Valid);
1258 else
1259 FPU_settag(i, TAG_Special); /* An Un-normal */
1260 }
1261 /* Else old tag is not empty and new tag is not empty. Old tag
1262 remains correct */
1263 }
1264
1265 return s;
1266 }
1267
1268
frstor(fpu_addr_modes addr_modes,u_char * data_address)1269 void frstor(fpu_addr_modes addr_modes, u_char *data_address)
1270 {
1271 int i, regnr;
1272 u_char *s = fldenv(addr_modes, data_address);
1273 int offset = (top & 7) * 10, other = 80 - offset;
1274
1275 /* Copy all registers in stack order. */
1276 RE_ENTRANT_CHECK_OFF;
1277 FPU_verify_area(VERIFY_READ,s,80);
1278 __copy_from_user(register_base+offset, s, other);
1279 if ( offset )
1280 __copy_from_user(register_base, s+other, offset);
1281 RE_ENTRANT_CHECK_ON;
1282
1283 for ( i = 0; i < 8; i++ )
1284 {
1285 regnr = (i+top) & 7;
1286 if ( FPU_gettag(regnr) != TAG_Empty )
1287 /* The loaded data over-rides all other cases. */
1288 FPU_settag(regnr, FPU_tagof(&st(i)));
1289 }
1290
1291 }
1292
1293
fstenv(fpu_addr_modes addr_modes,u_char * d)1294 u_char *fstenv(fpu_addr_modes addr_modes, u_char *d)
1295 {
1296 if ( (addr_modes.default_mode == VM86) ||
1297 ((addr_modes.default_mode == PM16)
1298 ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX)) )
1299 {
1300 RE_ENTRANT_CHECK_OFF;
1301 FPU_verify_area(VERIFY_WRITE,d,14);
1302 #ifdef PECULIAR_486
1303 FPU_put_user(control_word & ~0xe080, (unsigned long *) d);
1304 #else
1305 FPU_put_user(control_word, (unsigned short *) d);
1306 #endif /* PECULIAR_486 */
1307 FPU_put_user(status_word(), (unsigned short *) (d+2));
1308 FPU_put_user(fpu_tag_word, (unsigned short *) (d+4));
1309 FPU_put_user(instruction_address.offset, (unsigned short *) (d+6));
1310 FPU_put_user(operand_address.offset, (unsigned short *) (d+0x0a));
1311 if ( addr_modes.default_mode == VM86 )
1312 {
1313 FPU_put_user((instruction_address.offset & 0xf0000) >> 4,
1314 (unsigned short *) (d+8));
1315 FPU_put_user((operand_address.offset & 0xf0000) >> 4,
1316 (unsigned short *) (d+0x0c));
1317 }
1318 else
1319 {
1320 FPU_put_user(instruction_address.selector, (unsigned short *) (d+8));
1321 FPU_put_user(operand_address.selector, (unsigned short *) (d+0x0c));
1322 }
1323 RE_ENTRANT_CHECK_ON;
1324 d += 0x0e;
1325 }
1326 else
1327 {
1328 RE_ENTRANT_CHECK_OFF;
1329 FPU_verify_area(VERIFY_WRITE, d, 7*4);
1330 #ifdef PECULIAR_486
1331 control_word &= ~0xe080;
1332 /* An 80486 sets nearly all of the reserved bits to 1. */
1333 control_word |= 0xffff0040;
1334 partial_status = status_word() | 0xffff0000;
1335 fpu_tag_word |= 0xffff0000;
1336 I387.soft.fcs &= ~0xf8000000;
1337 I387.soft.fos |= 0xffff0000;
1338 #endif /* PECULIAR_486 */
1339 __copy_to_user(d, &control_word, 7*4);
1340 RE_ENTRANT_CHECK_ON;
1341 d += 0x1c;
1342 }
1343
1344 control_word |= CW_Exceptions;
1345 partial_status &= ~(SW_Summary | SW_Backward);
1346
1347 return d;
1348 }
1349
1350
fsave(fpu_addr_modes addr_modes,u_char * data_address)1351 void fsave(fpu_addr_modes addr_modes, u_char *data_address)
1352 {
1353 u_char *d;
1354 int offset = (top & 7) * 10, other = 80 - offset;
1355
1356 d = fstenv(addr_modes, data_address);
1357
1358 RE_ENTRANT_CHECK_OFF;
1359 FPU_verify_area(VERIFY_WRITE,d,80);
1360
1361 /* Copy all registers in stack order. */
1362 __copy_to_user(d, register_base+offset, other);
1363 if ( offset )
1364 __copy_to_user(d+other, register_base, offset);
1365 RE_ENTRANT_CHECK_ON;
1366
1367 finit();
1368 }
1369
1370 /*===========================================================================*/
1371