aboutsummaryrefslogtreecommitdiff
path: root/op-i386.c
diff options
context:
space:
mode:
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2003-05-29 20:04:28 +0000
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2003-05-29 20:04:28 +0000
commitd0a1ffc9573b15997ecdfbc9ec5ec2fc1403d0f1 (patch)
tree3cf9a2bb49e6104b2bf27904475ff45c9ebf9f84 /op-i386.c
parentdf0f11a03b5bda2a16b8fd9530b1feeef93da8e5 (diff)
added fsave/frstor/fstenv/fldenv/fcomi - fixed cpuid - make lret/iret restartable
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@198 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'op-i386.c')
-rw-r--r--op-i386.c200
1 files changed, 191 insertions, 9 deletions
diff --git a/op-i386.c b/op-i386.c
index 69bd4cffca..befa39f4df 100644
--- a/op-i386.c
+++ b/op-i386.c
@@ -1073,7 +1073,7 @@ void helper_cpuid(void)
EBX = 0x756e6547;
ECX = 0x6c65746e;
EDX = 0x49656e69;
- } else {
+ } else if (EAX == 1) {
/* EAX = 1 info */
EAX = 0x52b;
EBX = 0;
@@ -1899,17 +1899,22 @@ void OPPROTO op_fldt_ST0_A0(void)
ST0 = *(long double *)A0;
}
#else
-void helper_fldt_ST0_A0(void)
+static inline CPU86_LDouble helper_fldt(uint8_t *ptr)
{
CPU86_LDoubleU temp;
int upper, e;
/* mantissa */
- upper = lduw((uint8_t *)A0 + 8);
+ upper = lduw(ptr + 8);
/* XXX: handle overflow ? */
e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */
e |= (upper >> 4) & 0x800; /* sign */
- temp.ll = ((ldq((void *)A0) >> 11) & ((1LL << 52) - 1)) | ((uint64_t)e << 52);
- ST0 = temp.d;
+ temp.ll = ((ldq(ptr) >> 11) & ((1LL << 52) - 1)) | ((uint64_t)e << 52);
+ return temp.d;
+}
+
+void helper_fldt_ST0_A0(void)
+{
+ ST0 = helper_fldt((uint8_t *)A0);
}
void OPPROTO op_fldt_ST0_A0(void)
@@ -2008,17 +2013,23 @@ void OPPROTO op_fstt_ST0_A0(void)
*(long double *)A0 = ST0;
}
#else
-void helper_fstt_ST0_A0(void)
+
+static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr)
{
CPU86_LDoubleU temp;
int e;
- temp.d = ST0;
+ temp.d = f;
/* mantissa */
- stq((void *)A0, (MANTD(temp) << 11) | (1LL << 63));
+ stq(ptr, (MANTD(temp) << 11) | (1LL << 63));
/* exponent + sign */
e = EXPD(temp) - EXPBIAS + 16383;
e |= SIGND(temp) >> 16;
- stw((uint8_t *)A0 + 8, e);
+ stw(ptr + 8, e);
+}
+
+void helper_fstt_ST0_A0(void)
+{
+ helper_fstt(ST0, (uint8_t *)A0);
}
void OPPROTO op_fstt_ST0_A0(void)
@@ -2254,6 +2265,34 @@ void OPPROTO op_fucom_ST0_FT0(void)
FORCE_RET();
}
+/* XXX: handle nans */
+void OPPROTO op_fcomi_ST0_FT0(void)
+{
+ int eflags;
+ eflags = cc_table[CC_OP].compute_all();
+ eflags &= ~(CC_Z | CC_P | CC_C);
+ if (ST0 < FT0)
+ eflags |= CC_C;
+ else if (ST0 == FT0)
+ eflags |= CC_Z;
+ CC_SRC = eflags;
+ FORCE_RET();
+}
+
+/* XXX: handle nans */
+void OPPROTO op_fucomi_ST0_FT0(void)
+{
+ int eflags;
+ eflags = cc_table[CC_OP].compute_all();
+ eflags &= ~(CC_Z | CC_P | CC_C);
+ if (ST0 < FT0)
+ eflags |= CC_C;
+ else if (ST0 == FT0)
+ eflags |= CC_Z;
+ CC_SRC = eflags;
+ FORCE_RET();
+}
+
void OPPROTO op_fadd_ST0_FT0(void)
{
ST0 += FT0;
@@ -2750,6 +2789,149 @@ void OPPROTO op_fninit(void)
env->fptags[7] = 1;
}
+void helper_fstenv(uint8_t *ptr, int data32)
+{
+ int fpus, fptag, exp, i;
+ uint64_t mant;
+ CPU86_LDoubleU tmp;
+
+ fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
+ fptag = 0;
+ for (i=7; i>=0; i--) {
+ fptag <<= 2;
+ if (env->fptags[i]) {
+ fptag |= 3;
+ } else {
+ tmp.d = env->fpregs[i];
+ exp = EXPD(tmp);
+ mant = MANTD(tmp);
+ if (exp == 0 && mant == 0) {
+ /* zero */
+ fptag |= 1;
+ } else if (exp == 0 || exp == MAXEXPD
+#ifdef USE_X86LDOUBLE
+ || (mant & (1LL << 63)) == 0
+#endif
+ ) {
+ /* NaNs, infinity, denormal */
+ fptag |= 2;
+ }
+ }
+ }
+ if (data32) {
+ /* 32 bit */
+ stl(ptr, env->fpuc);
+ stl(ptr + 4, fpus);
+ stl(ptr + 8, fptag);
+ stl(ptr + 12, 0);
+ stl(ptr + 16, 0);
+ stl(ptr + 20, 0);
+ stl(ptr + 24, 0);
+ } else {
+ /* 16 bit */
+ stw(ptr, env->fpuc);
+ stw(ptr + 2, fpus);
+ stw(ptr + 4, fptag);
+ stw(ptr + 6, 0);
+ stw(ptr + 8, 0);
+ stw(ptr + 10, 0);
+ stw(ptr + 12, 0);
+ }
+}
+
+void helper_fldenv(uint8_t *ptr, int data32)
+{
+ int i, fpus, fptag;
+
+ if (data32) {
+ env->fpuc = lduw(ptr);
+ fpus = lduw(ptr + 4);
+ fptag = lduw(ptr + 8);
+ }
+ else {
+ env->fpuc = lduw(ptr);
+ fpus = lduw(ptr + 2);
+ fptag = lduw(ptr + 4);
+ }
+ env->fpstt = (fpus >> 11) & 7;
+ env->fpus = fpus & ~0x3800;
+ for(i = 0;i < 7; i++) {
+ env->fptags[i] = ((fptag & 3) == 3);
+ fptag >>= 2;
+ }
+}
+
+void helper_fsave(uint8_t *ptr, int data32)
+{
+ CPU86_LDouble tmp;
+ int i;
+
+ helper_fstenv(ptr, data32);
+
+ ptr += (14 << data32);
+ for(i = 0;i < 8; i++) {
+ tmp = ST(i);
+#ifdef USE_X86LDOUBLE
+ *(long double *)ptr = tmp;
+#else
+ helper_fstt(tmp, ptr);
+#endif
+ ptr += 10;
+ }
+
+ /* fninit */
+ env->fpus = 0;
+ env->fpstt = 0;
+ env->fpuc = 0x37f;
+ env->fptags[0] = 1;
+ env->fptags[1] = 1;
+ env->fptags[2] = 1;
+ env->fptags[3] = 1;
+ env->fptags[4] = 1;
+ env->fptags[5] = 1;
+ env->fptags[6] = 1;
+ env->fptags[7] = 1;
+}
+
+void helper_frstor(uint8_t *ptr, int data32)
+{
+ CPU86_LDouble tmp;
+ int i;
+
+ helper_fldenv(ptr, data32);
+ ptr += (14 << data32);
+
+ for(i = 0;i < 8; i++) {
+#ifdef USE_X86LDOUBLE
+ tmp = *(long double *)ptr;
+#else
+ tmp = helper_fldt(ptr);
+#endif
+ ST(i) = tmp;
+ ptr += 10;
+ }
+}
+
+void OPPROTO op_fnstenv_A0(void)
+{
+ helper_fstenv((uint8_t *)A0, PARAM1);
+}
+
+void OPPROTO op_fldenv_A0(void)
+{
+ helper_fldenv((uint8_t *)A0, PARAM1);
+}
+
+void OPPROTO op_fnsave_A0(void)
+{
+ helper_fsave((uint8_t *)A0, PARAM1);
+}
+
+void OPPROTO op_frstor_A0(void)
+{
+ helper_frstor((uint8_t *)A0, PARAM1);
+}
+
/* threading support */
void OPPROTO op_lock(void)
{