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