📄 reg_ld_s.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 | | | | | +---------------------------------------------------------------------------*//*---------------------------------------------------------------------------+ | 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 <asm/segment.h>#include "fpu_system.h"#include "exception.h"#include "reg_constant.h"#include "fpu_emu.h"#include "control_w.h"#include "status_w.h"#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 */static void write_to_extended(FPU_REG *rp, char *d);FPU_REG FPU_loaded_data;/* Get a long double from user memory */int reg_load_extended(void){ long double *s = (long double *)FPU_data_address; unsigned long sigl, sigh, exp; RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_READ, s, 10); /* Use temporary variables here because FPU_loaded data is static and hence re-entrancy problems can arise */ sigl = get_fs_long((unsigned long *) s); sigh = get_fs_long(1 + (unsigned long *) s); exp = get_fs_word(4 + (unsigned short *) s); RE_ENTRANT_CHECK_ON; FPU_loaded_data.tag = TW_Valid; /* Default */ FPU_loaded_data.sigl = sigl; FPU_loaded_data.sigh = sigh; if (exp & 0x8000) FPU_loaded_data.sign = SIGN_NEG; else FPU_loaded_data.sign = SIGN_POS; exp &= 0x7fff; FPU_loaded_data.exp = exp - EXTENDED_Ebias + EXP_BIAS; /* Assume that optimisation can keep sigl, sigh, and exp in registers, otherwise it would be more efficient to work with FPU_loaded_data (which is static) here. */ if ( exp == 0 ) { if ( !(sigh | sigl) ) { FPU_loaded_data.tag = TW_Zero; return 0; } /* The number is a de-normal or pseudodenormal. */ if (sigh & 0x80000000) { /* Is a pseudodenormal. */ /* Convert it for internal use. */ /* This is non-80486 behaviour because the number loses its 'denormal' identity. */ FPU_loaded_data.exp++; return 1; } else { /* Is a denormal. */ /* Convert it for internal use. */ FPU_loaded_data.exp++; normalize_nuo(&FPU_loaded_data); return 0; } } else if ( exp == 0x7fff ) { if ( !((sigh ^ 0x80000000) | sigl) ) { /* Matches the bit pattern for Infinity. */ FPU_loaded_data.exp = EXP_Infinity; FPU_loaded_data.tag = TW_Infinity; return 0; } FPU_loaded_data.exp = EXP_NaN; FPU_loaded_data.tag = TW_NaN; if ( !(sigh & 0x80000000) ) { /* NaNs have the ms bit set to 1. */ /* This is therefore an Unsupported NaN data type. */ /* This is non 80486 behaviour */ /* This should generate an Invalid Operand exception later, so we convert it to a SNaN */ FPU_loaded_data.sigh = 0x80000000; FPU_loaded_data.sigl = 0x00000001; FPU_loaded_data.sign = SIGN_NEG; return 1; } return 0; } if ( !(sigh & 0x80000000) ) { /* Unsupported data type. */ /* Valid numbers have the ms bit set to 1. */ /* Unnormal. */ /* Convert it for internal use. */ /* This is non-80486 behaviour */ /* This should generate an Invalid Operand exception later, so we convert it to a SNaN */ FPU_loaded_data.sigh = 0x80000000; FPU_loaded_data.sigl = 0x00000001; FPU_loaded_data.sign = SIGN_NEG; FPU_loaded_data.exp = EXP_NaN; FPU_loaded_data.tag = TW_NaN; return 1; } return 0;}/* Get a double from user memory */int reg_load_double(void){ double *dfloat = (double *)FPU_data_address; int exp; unsigned m64, l64; RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_READ, dfloat, 8); m64 = get_fs_long(1 + (unsigned long *) dfloat); l64 = get_fs_long((unsigned long *) dfloat); RE_ENTRANT_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.sigh = 0x80000000; FPU_loaded_data.sigl = 0x00000000; FPU_loaded_data.exp = EXP_Infinity; FPU_loaded_data.tag = TW_Infinity; return 0; } else { /* Must be a signaling or quiet NaN */ FPU_loaded_data.exp = EXP_NaN; 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 0; /* The calling function must look for NaNs */ } } 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 0; } else { /* De-normal */ 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 denormal_operand(); } } 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 0; }}/* Get a float from user memory */int reg_load_single(void){ float *single = (float *)FPU_data_address; unsigned m32; int exp; RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_READ, single, 4); m32 = get_fs_long((unsigned long *) single); RE_ENTRANT_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 0; } exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias; m32 = (m32 & 0x7fffff) << 8; if ( exp < SINGLE_Emin ) { /* De-normals */ 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 denormal_operand(); } else if ( exp > SINGLE_Emax ) { /* Infinity or NaN */ if ( m32 == 0 ) { /* +- infinity */ FPU_loaded_data.sigh = 0x80000000; FPU_loaded_data.sigl = 0x00000000; FPU_loaded_data.exp = EXP_Infinity; FPU_loaded_data.tag = TW_Infinity; return 0; } else { /* Must be a signaling or quiet NaN */ FPU_loaded_data.exp = EXP_NaN; FPU_loaded_data.tag = TW_NaN; FPU_loaded_data.sigh = m32 | 0x80000000; FPU_loaded_data.sigl = 0; return 0; /* The calling function must look for NaNs */ } } 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; return 0; }}/* Get a long long from user memory */void reg_load_int64(void){ long long *_s = (long long *)FPU_data_address; int e; long long s; RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_READ, _s, 8); ((unsigned long *)&s)[0] = get_fs_long((unsigned long *) _s); ((unsigned long *)&s)[1] = get_fs_long(1 + (unsigned long *) _s); RE_ENTRANT_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; significand(&FPU_loaded_data) = s; FPU_loaded_data.exp = e; FPU_loaded_data.tag = TW_Valid; normalize_nuo(&FPU_loaded_data);}/* Get a long from user memory */void reg_load_int32(void){ long *_s = (long *)FPU_data_address; long s; int e; RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_READ, _s, 4); s = (long)get_fs_long((unsigned long *) _s); RE_ENTRANT_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 */void reg_load_int16(void){ short *_s = (short *)FPU_data_address; int s, e; RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_READ, _s, 2); /* Cast as short to get the sign extended. */ s = (short)get_fs_word((unsigned short *) _s); RE_ENTRANT_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 */void reg_load_bcd(void){ char *s = (char *)FPU_data_address; int pos; unsigned char bcd; long long l=0; RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_READ, s, 10); RE_ENTRANT_CHECK_ON; for ( pos = 8; pos >= 0; pos--) { l *= 10; RE_ENTRANT_CHECK_OFF; bcd = (unsigned char)get_fs_byte((unsigned char *) s+pos); RE_ENTRANT_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 */ RE_ENTRANT_CHECK_OFF; FPU_loaded_data.sign = ((unsigned char)get_fs_byte((unsigned char *) s+9)) & 0x80 ? SIGN_NEG : SIGN_POS; RE_ENTRANT_CHECK_ON; if (l == 0) { char sign = FPU_loaded_data.sign; reg_move(&CONST_Z, &FPU_loaded_data); FPU_loaded_data.sign = sign; } else { significand(&FPU_loaded_data) = 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 */int reg_store_extended(void){ /* The only exception raised by an attempt to store to an extended format is the Invalid Stack exception, i.e. attempting to store from an empty register. */ long double *d = (long double *)FPU_data_address; if ( FPU_st0_tag != TW_Empty ) { RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_WRITE, d, 10); RE_ENTRANT_CHECK_ON; write_to_extended(FPU_st0_ptr, (char *) FPU_data_address); return 1; } /* Empty register (stack underflow) */ EXCEPTION(EX_StackUnder); if ( control_word & CW_Invalid ) { /* The masked response */ /* Put out the QNaN indefinite */ RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_WRITE,d,10); put_fs_long(0, (unsigned long *) d); put_fs_long(0xc0000000, 1 + (unsigned long *) d); put_fs_word(0xffff, 4 + (short *) d); RE_ENTRANT_CHECK_ON; return 1; } else return 0;}/* Put a double into user memory */int reg_store_double(void){ double *dfloat = (double *)FPU_data_address; unsigned long l[2]; unsigned long increment = 0; /* avoid gcc warnings */ if (FPU_st0_tag == TW_Valid) { int exp; FPU_REG tmp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -