#include "emu.h" #include "const.h" #include "rmov.h" extern "C" void shld(void *v); extern "C" void shrd(void *v); void normalize(reg& r) { if (!(r.sigl | r.sigh)) { r.exp = 0; r.tag = TW_Z; return; } if (r.exp >= EXP_MAX) { r.tag = TW_S; return; } while (!(r.sigh & 0x80000000)) { if (r.exp == 0) return; shld(&r.sigl); r.exp--; } } void r_mov(long double *s, reg& d) { unsigned long *sp = (unsigned long *)s; if (sp[2] & 0x8000) d.sign = SIGN_NEG; else d.sign = SIGN_POS; d.exp = sp[2] & 0x7fff; d.sigh = sp[1]; d.sigl = sp[0]; d.tag = TW_V; normalize(d); } void r_mov(double *s, reg& d) { unsigned m64 = ((unsigned *)s)[1]; unsigned l64 = ((unsigned *)s)[0]; if (m64 & 0x80000000) d.sign = SIGN_NEG; else d.sign = SIGN_POS; if (!((m64 & 0x7fffffff) | (l64))) { int c = d.sign; r_mov(CONST_Z, d); d.sign = c; return; } d.exp = (int)((m64>>20)&0x7ff) - 1023 + EXP_BIAS; d.sigh = ((m64 & 0xfffff)<<11) | 0x80000000; d.sigh |= l64 >> 21; d.sigl = l64 << 11; d.tag = TW_V; if ((m64 & 0x7ff00000) == 0x7ff00000) d.exp = EXP_MAX; normalize(d); } void r_mov(float *s, reg& d) { unsigned m32 = *(unsigned *)s; if (m32 & 0x80000000) d.sign = SIGN_NEG; else d.sign = SIGN_POS; if (!(m32 & 0x7fffffff)) { int c = d.sign; r_mov(CONST_Z, d); d.sign = c; return; } d.exp = (int)((m32>>23)&0xff) - 127 + EXP_BIAS; d.sigh = ((m32 & 0x7fffff)<<8) | 0x80000000; d.sigl = 0; d.tag = TW_V; if ((m32 & 0x7f800000) == 0x7f800000) d.exp = EXP_MAX; normalize(d); } void r_mov(long long *_s, reg& d) { long long s = *_s; if (s == 0) return r_mov(CONST_Z, d); if (s > 0) d.sign = SIGN_POS; else { s = -s; d.sign = SIGN_NEG; } int e = EXP_BIAS + 63; while (s >= 0) { shld(&s); e -= 1; } d.sigh = s >> 32; d.sigl = s; d.exp = e; d.tag = TW_V; normalize(d); } void r_mov(long *_s, reg& d) { long s = *_s; if (s == 0) return r_mov(CONST_Z, d); if (s > 0) d.sign = SIGN_POS; else { s = -s; d.sign = SIGN_NEG; } int e = EXP_BIAS + 31; while (!(s & 0x80000000)) { s <<= 1; e -= 1; } d.sigh = s; d.sigl = 0; d.exp = e; d.tag = TW_V; normalize(d); } void r_mov(short *_s, reg& d) { int s = *_s; if (s == 0) return r_mov(CONST_Z, d); if (s > 0) d.sign = SIGN_POS; else { s = -s; d.sign = SIGN_NEG; } int e = EXP_BIAS + 15; while (!(s & 0x8000)) { s <<= 1; e -= 1; } d.sigh = s << 16; d.sigl = 0; d.exp = e; d.tag = TW_V; normalize(d); } void r_mov(char *s, reg& d) { int side=1, pos=8; long long l; l = 0; for (int i=0; i<18; i++) { l *= 10; switch (side) { case 0: l += s[pos] & 0x0f; side = 1; pos--; break; case 1: l += s[pos] >> 4; side = 0; break; } } r_mov(&l, d); if (s[9] & 0x80) d.sign = SIGN_NEG; } //============================================================================= static void round_to_int(reg& r) // r gets mangled such that sig is int, sign { reg t; int more_than_half = 0; int half_or_more = 0; if (r.tag == TW_Z) { return; } while (r.exp < EXP_BIAS+62) { if (r.sigl & 1) more_than_half = 1; shrd(&r.sigl); r.exp++; } while (r.exp < EXP_BIAS+63) { if (r.sigl & 1) half_or_more = 1; shrd(&r.sigl); r.exp++; } if (r.exp > EXP_BIAS+63) { r.sigl = r.sigh = ~0; return; } switch (control_word & CW_RC) { case RC_RND: if (half_or_more) if (more_than_half) // nearest (*(long long *)(&r.sigl)) ++; else if (r.sigl & 1) // odd? (*(long long *)(&r.sigl)) ++; break; case RC_DOWN: if ((half_or_more||more_than_half) && r.sign) (*(long long *)(&r.sigl)) ++; break; case RC_UP: if ((half_or_more||more_than_half) && !r.sign) (*(long long *)(&r.sigl)) ++; break; case RC_CHOP: break; } } void r_mov(reg& s, long double *d) { ((short *)d)[2] = s.exp + s.sign*0x8000; ((long *)d)[0] = s.sigl; ((long *)d)[1] = s.sigh; } void r_mov(reg& s, double *d) { unsigned long *l = (unsigned long *)d; if (s.tag == TW_Z) { l[0] = 0; l[1] = 0; } else { l[0] = (s.sigl >> 11) | (s.sigh << 21); l[1] = ((s.sigh >> 11) & 0xfffff) | (((s.exp-EXP_BIAS+1023) & 0x7ff) << 20); } if (s.sign) l[1] |= 0x80000000; } void r_mov(reg& s, float *d) { long f; if (s.tag == TW_Z) { f = 0; } else { f = (s.sigh >> 8) & 0x007fffff; f |= ((s.exp-EXP_BIAS+127) & 0xff) << 23; } if (s.sign) f |= 0x80000000; *(long *)d = f; } void r_mov(reg& s, long long *d) { reg t; r_mov(s, t); round_to_int(t); ((long *)d)[0] = t.sigl; ((long *)d)[1] = t.sigh; if (t.sign) *d = - *d; } void r_mov(reg& s, long *d) { reg t; r_mov(s, t); round_to_int(t); if (t.sigh || (t.sigl & 0x80000000)) *d = -1; else *d = s.sign ? -t.sigl : t.sigl; } void r_mov(reg& s, short *d) { reg t; r_mov(s, t); round_to_int(t); if (t.sigh || (t.sigl & 0xFFFF8000)) *d = -1; else *d = s.sign ? -t.sigl : t.sigl; } void r_mov(reg& s, char *d) { reg t; r_mov(s, t); round_to_int(t); long long ll = *(long long *)(&t.sigl); int side = 0; int r, i; for (i=0; i<10; i++) d[i] = 0; int pos=0; for (i=0; i<18; i++) { r = ll % 10; ll /= 10; if (side) { d[pos] |= r << 4; side = 0; pos++; } else { d[pos] |= r; side = 1; } } if (s.sign == SIGN_NEG) d[9] = 0x80; }