?? reg_ld_str.c
字號:
/* * reg_ld_str.c * * All of the functions which transfer data between user memory and FPU_REGs. * * * Copyright (C) 1992,1993,1994 * W. Metzenthen, 22 Parker St, Ormond, Vic 3163, * Australia. E-mail billm@vaxc.cc.monash.edu.au * All rights reserved. * * This copyright notice covers the redistribution and use of the * FPU emulator developed by W. Metzenthen. It covers only its use * in the 386BSD, FreeBSD and NetBSD operating systems. Any other * use is not permitted under this copyright. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must include information specifying * that source code for the emulator is freely available and include * either: * a) an offer to provide the source code for a nominal distribution * fee, or * b) list at least two alternative methods whereby the source * can be obtained, e.g. a publically accessible bulletin board * and an anonymous ftp site from which the software can be * downloaded. * 3. All advertising materials specifically mentioning features or use of * this emulator must acknowledge that it was developed by W. Metzenthen. * 4. The name of W. Metzenthen may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * * The purpose of this copyright, based upon the Berkeley copyright, is to * ensure that the covered software remains freely available to everyone. * * The software (with necessary differences) is also available, but under * the terms of the GNU copyleft, for the Linux operating system and for * the djgpp ms-dos extender. * * W. Metzenthen June 1994. * * * $FreeBSD: src/sys/gnu/i386/fpemul/reg_ld_str.c,v 1.7.2.1 1999/09/05 08:09:52 peter Exp $ * *//*---------------------------------------------------------------------------+ | 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 <sys/param.h>#include <sys/proc.h>#include <sys/systm.h>#include <machine/cpu.h>#include <machine/md_var.h>#include <machine/pcb.h>#include <gnu/i386/fpemul/fpu_emu.h>#include <gnu/i386/fpemul/fpu_system.h>#include <gnu/i386/fpemul/exception.h>#include <gnu/i386/fpemul/reg_constant.h>#include <gnu/i386/fpemul/control_w.h>#include <gnu/i386/fpemul/status_w.h>#define EXTENDED_Emax 0x3fff /* largest valid exponent */#define EXTENDED_Ebias 0x3fff#define EXTENDED_Emin (-0x3ffe) /* smallest valid exponent */#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 */#define LOST_UP (EX_Precision | SW_C1)#define LOST_DOWN EX_PrecisionFPU_REG FPU_loaded_data;/* Get a long double from user memory */voidreg_load_extended(void){ long double *s = (long double *) FPU_data_address; unsigned long sigl, sigh, exp; REENTRANT_CHECK(OFF); /* Use temporary variables here because FPU_loaded data is static and * hence re-entrancy problems can arise */ sigl = fuword((unsigned long *) s); sigh = fuword(1 + (unsigned long *) s); exp = fusword(4 + (unsigned short *) s); REENTRANT_CHECK(ON); FPU_loaded_data.sigl = sigl; FPU_loaded_data.sigh = sigh; FPU_loaded_data.exp = exp; if (FPU_loaded_data.exp & 0x8000) FPU_loaded_data.sign = SIGN_NEG; else FPU_loaded_data.sign = SIGN_POS; if ((FPU_loaded_data.exp &= 0x7fff) == 0) { if (!(FPU_loaded_data.sigl | FPU_loaded_data.sigh)) { FPU_loaded_data.tag = TW_Zero; return; } /* The number is a de-normal or pseudodenormal. */ /* The 80486 doesn't regard pseudodenormals as denormals here. */ if (!(FPU_loaded_data.sigh & 0x80000000)) EXCEPTION(EX_Denormal); FPU_loaded_data.exp++; /* The default behaviour will now take care of it. */ } else if (FPU_loaded_data.exp == 0x7fff) { FPU_loaded_data.exp = EXTENDED_Emax; if ((FPU_loaded_data.sigh == 0x80000000) && (FPU_loaded_data.sigl == 0)) { FPU_loaded_data.tag = TW_Infinity; return; } else if (!(FPU_loaded_data.sigh & 0x80000000)) { /* Unsupported NaN data type */ EXCEPTION(EX_Invalid); FPU_loaded_data.tag = TW_NaN; return; } FPU_loaded_data.tag = TW_NaN; return; } FPU_loaded_data.exp = (FPU_loaded_data.exp & 0x7fff) - EXTENDED_Ebias + EXP_BIAS; FPU_loaded_data.tag = TW_Valid; if (!(sigh & 0x80000000)) { /* Unsupported data type */ EXCEPTION(EX_Invalid); normalize_nuo(&FPU_loaded_data); }}/* Get a double from user memory */voidreg_load_double(void){ double *dfloat = (double *) FPU_data_address; int exp; unsigned m64, l64; REENTRANT_CHECK(OFF); m64 = fuword(1 + (unsigned long *) dfloat); l64 = fuword((unsigned long *) dfloat); REENTRANT_CHECK(ON); if (m64 & 0x80000000) FPU_loaded_data.sign = SIGN_NEG; else FPU_loaded_data.sign = SIGN_POS; exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias; m64 &= 0xfffff; if (exp > DOUBLE_Emax) { /* Infinity or NaN */ if ((m64 == 0) && (l64 == 0)) { /* +- infinity */ FPU_loaded_data.exp = EXTENDED_Emax; FPU_loaded_data.tag = TW_Infinity; return; } else { /* Must be a signaling or quiet NaN */ FPU_loaded_data.exp = EXTENDED_Emax; FPU_loaded_data.tag = TW_NaN; FPU_loaded_data.sigh = (m64 << 11) | 0x80000000; FPU_loaded_data.sigh |= l64 >> 21; FPU_loaded_data.sigl = l64 << 11; return; } } else if (exp < DOUBLE_Emin) { /* Zero or de-normal */ if ((m64 == 0) && (l64 == 0)) { /* Zero */ int c = FPU_loaded_data.sign; reg_move(&CONST_Z, &FPU_loaded_data); FPU_loaded_data.sign = c; return; } else { /* De-normal */ EXCEPTION(EX_Denormal); FPU_loaded_data.exp = DOUBLE_Emin + EXP_BIAS; FPU_loaded_data.tag = TW_Valid; FPU_loaded_data.sigh = m64 << 11; FPU_loaded_data.sigh |= l64 >> 21; FPU_loaded_data.sigl = l64 << 11; normalize_nuo(&FPU_loaded_data); return; } } else { FPU_loaded_data.exp = exp + EXP_BIAS; FPU_loaded_data.tag = TW_Valid; FPU_loaded_data.sigh = (m64 << 11) | 0x80000000; FPU_loaded_data.sigh |= l64 >> 21; FPU_loaded_data.sigl = l64 << 11; return; }}/* Get a float from user memory */voidreg_load_single(void){ float *single = (float *) FPU_data_address; unsigned m32; int exp; REENTRANT_CHECK(OFF); m32 = fuword((unsigned long *) single); REENTRANT_CHECK(ON); if (m32 & 0x80000000) FPU_loaded_data.sign = SIGN_NEG; else FPU_loaded_data.sign = SIGN_POS; if (!(m32 & 0x7fffffff)) { /* Zero */ int c = FPU_loaded_data.sign; reg_move(&CONST_Z, &FPU_loaded_data); FPU_loaded_data.sign = c; return; } exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias; m32 = (m32 & 0x7fffff) << 8; if (exp < SINGLE_Emin) { /* De-normals */ EXCEPTION(EX_Denormal); FPU_loaded_data.exp = SINGLE_Emin + EXP_BIAS; FPU_loaded_data.tag = TW_Valid; FPU_loaded_data.sigh = m32; FPU_loaded_data.sigl = 0; normalize_nuo(&FPU_loaded_data); return; } else if (exp > SINGLE_Emax) { /* Infinity or NaN */ if (m32 == 0) { /* +- infinity */ FPU_loaded_data.exp = EXTENDED_Emax; FPU_loaded_data.tag = TW_Infinity; return; } else { /* Must be a signaling or quiet NaN */ FPU_loaded_data.exp = EXTENDED_Emax; FPU_loaded_data.tag = TW_NaN; FPU_loaded_data.sigh = m32 | 0x80000000; FPU_loaded_data.sigl = 0; return; } } else { FPU_loaded_data.exp = exp + EXP_BIAS; FPU_loaded_data.sigh = m32 | 0x80000000; FPU_loaded_data.sigl = 0; FPU_loaded_data.tag = TW_Valid; }}/* Get a long long from user memory */voidreg_load_int64(void){ long long *_s = (long long *) FPU_data_address; int e; long long s; REENTRANT_CHECK(OFF); ((unsigned long *) &s)[0] = fuword((unsigned long *) _s); ((unsigned long *) &s)[1] = fuword(1 + (unsigned long *) _s); REENTRANT_CHECK(ON); if (s == 0) { reg_move(&CONST_Z, &FPU_loaded_data); return; } if (s > 0) FPU_loaded_data.sign = SIGN_POS; else { s = -s; FPU_loaded_data.sign = SIGN_NEG; } e = EXP_BIAS + 63; *((long long *) &FPU_loaded_data.sigl) = s; FPU_loaded_data.exp = e; FPU_loaded_data.tag = TW_Valid; normalize_nuo(&FPU_loaded_data);}/* Get a long from user memory */voidreg_load_int32(void){ long *_s = (long *) FPU_data_address; long s; int e; REENTRANT_CHECK(OFF); s = (long) fuword((unsigned long *) _s); REENTRANT_CHECK(ON); if (s == 0) { reg_move(&CONST_Z, &FPU_loaded_data); return; } if (s > 0) FPU_loaded_data.sign = SIGN_POS; else { s = -s; FPU_loaded_data.sign = SIGN_NEG; } e = EXP_BIAS + 31; FPU_loaded_data.sigh = s; FPU_loaded_data.sigl = 0; FPU_loaded_data.exp = e; FPU_loaded_data.tag = TW_Valid; normalize_nuo(&FPU_loaded_data);}/* Get a short from user memory */voidreg_load_int16(void){ short *_s = (short *) FPU_data_address; int s, e; REENTRANT_CHECK(OFF); /* Cast as short to get the sign extended. */ s = (short) fusword((unsigned short *) _s); REENTRANT_CHECK(ON); if (s == 0) { reg_move(&CONST_Z, &FPU_loaded_data); return; } if (s > 0) FPU_loaded_data.sign = SIGN_POS; else { s = -s; FPU_loaded_data.sign = SIGN_NEG; } e = EXP_BIAS + 15; FPU_loaded_data.sigh = s << 16; FPU_loaded_data.sigl = 0; FPU_loaded_data.exp = e; FPU_loaded_data.tag = TW_Valid; normalize_nuo(&FPU_loaded_data);}/* Get a packed bcd array from user memory */voidreg_load_bcd(void){ char *s = (char *) FPU_data_address; int pos; unsigned char bcd; long long l = 0; for (pos = 8; pos >= 0; pos--) { l *= 10; REENTRANT_CHECK(OFF); bcd = (unsigned char) fubyte((unsigned char *) s + pos); REENTRANT_CHECK(ON); l += bcd >> 4; l *= 10; l += bcd & 0x0f; } /* Finish all access to user memory before putting stuff into the * static FPU_loaded_data */ REENTRANT_CHECK(OFF); FPU_loaded_data.sign = ((unsigned char) fubyte((unsigned char *) s + 9)) & 0x80 ? SIGN_NEG : SIGN_POS; REENTRANT_CHECK(ON); if (l == 0) { char sign = FPU_loaded_data.sign; reg_move(&CONST_Z, &FPU_loaded_data); FPU_loaded_data.sign = sign; } else { *((long long *) &FPU_loaded_data.sigl) = l; FPU_loaded_data.exp = EXP_BIAS + 63; FPU_loaded_data.tag = TW_Valid; normalize_nuo(&FPU_loaded_data); }}/*===========================================================================*//* Put a long double into user memory */intreg_store_extended(void){ long double *d = (long double *) FPU_data_address; long e = FPU_st0_ptr->exp - EXP_BIAS + EXTENDED_Ebias; unsigned short sign = FPU_st0_ptr->sign * 0x8000; unsigned long ls, ms; if (FPU_st0_tag == TW_Valid) { if (e >= 0x7fff) { EXCEPTION(EX_Overflow); /* Overflow */ /* This is a special case: see sec 16.2.5.1 of the * 80486 book */ if (control_word & EX_Overflow) { /* Overflow to infinity */ ls = 0; ms = 0x80000000; e = 0x7fff; } else return 0; } else if (e <= 0) { if (e > -63) { /* Correctly format the de-normal */ int precision_loss; FPU_REG tmp; EXCEPTION(EX_Denormal); reg_move(FPU_st0_ptr, &tmp); tmp.exp += -EXTENDED_Emin + 63; /* largest exp to be 62 */ if ((precision_loss = round_to_int(&tmp))) { EXCEPTION(EX_Underflow | precision_loss);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -