/*---------------------------------------------------------------------------+
| reg_ld_str.c |
| |
| All of the functions which transfer data between user memory and FPU_REGs.|
| |
| Copyright (C) 1992,1993,1994,1996,1997 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
| E-mail billm@suburbia.net |
| |
| |
+---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------+
| Note: |
| The file contains code which accesses user memory. |
| Emulator static data may change when user memory is accessed, due to |
| other processes using the emulator while swapping is in progress. |
+---------------------------------------------------------------------------*/
#include "fpu_emu.h"
#include <asm/uaccess.h>
#include "fpu_system.h"
#include "exception.h"
#include "reg_constant.h"
#include "control_w.h"
#include "status_w.h"
#define DOUBLE_Emax 1023 /* largest valid exponent */
#define DOUBLE_Ebias 1023
#define DOUBLE_Emin (-1022) /* smallest valid exponent */
#define SINGLE_Emax 127 /* largest valid exponent */
#define SINGLE_Ebias 127
#define SINGLE_Emin (-126) /* smallest valid exponent */
static u_char normalize_no_excep(FPU_REG * r, int exp, int sign)
{
u_char tag;
setexponent16(r, exp);
tag = FPU_normalize_nuo(r);
stdexp(r);
if (sign)
setnegative(r);
return tag;
}
int FPU_tagof(FPU_REG * ptr)
{
int exp;
exp = exponent16(ptr) & 0x7fff;
if (exp == 0) {
if (!(ptr->sigh | ptr->sigl)) {
return TAG_Zero;
}
/* The number is a de-normal or pseudodenormal. */
return TAG_Special;
}
if (exp == 0x7fff) {
/* Is an Infinity, a NaN, or an unsupported data type. */
return TAG_Special;
}
if (!(ptr->sigh & 0x80000000)) {
/* Unsupported data type. */
/* Valid numbers have the ms bit set to 1. */
/* Unnormal. */
return TAG_Special;
}
return TAG_Valid;
}
/* Get a long double from user memory */
int FPU_load_extended(long double __user * s, int stnr)
{
FPU_REG *sti_ptr = &st(stnr);
RE_ENTRANT_CHECK_OFF;
FPU_access_ok(VERIFY_READ, s, 10);
__copy_from_user(sti_ptr, s, 10);
RE_ENTRANT_CHECK_ON;
return FPU_tagof(sti_ptr);
}
/* Get a double from user memory */
int FPU_load_double(double __user * dfloat, FPU_REG * loaded_data)
{
int exp, tag, negative;
unsigned m64, l64;
RE_ENTRANT_CHECK_OFF;
FPU_access_ok(VERIFY_READ, dfloat, 8);
FPU_get_user(m64, 1 + (unsigned long __user *)dfloat);
FPU_get_user(l64, (unsigned long __user *)dfloat);
RE_ENTRANT_CHECK_ON;
negative = (m64 & 0x80000000) ? SIGN_Negative : SIGN_Positive;
exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias + EXTENDED_Ebias;
m64 &= 0xfffff;
if (exp > DOUBLE_Emax + EXTENDED_Ebias) {
/* Infinity or NaN */
if ((