]> Git Repo - qemu.git/blobdiff - target-i386/op.c
NaN support in FPU comparisons
[qemu.git] / target-i386 / op.c
index f81d59b16172b3dd6b8bcb4fe59f6c0c49c4753a..c157b120b0f444df5b357c3c752c8a924a258aba 100644 (file)
@@ -286,8 +286,8 @@ void OPPROTO op_imull_EAX_T0(void)
 {
     int64_t res;
     res = (int64_t)((int32_t)EAX) * (int64_t)((int32_t)T0);
-    EAX = res;
-    EDX = res >> 32;
+    EAX = (uint32_t)(res);
+    EDX = (uint32_t)(res >> 32);
     CC_DST = res;
     CC_SRC = (res != (int32_t)res);
 }
@@ -517,6 +517,11 @@ void OPPROTO op_movq_T0_im64(void)
     T0 = PARAMQ1;
 }
 
+void OPPROTO op_movq_T1_im64(void)
+{
+    T1 = PARAMQ1;
+}
+
 void OPPROTO op_movq_A0_im(void)
 {
     A0 = (int32_t)PARAM1;
@@ -611,11 +616,10 @@ void OPPROTO op_debug(void)
 
 void OPPROTO op_raise_interrupt(void)
 {
-    int intno;
-    unsigned int next_eip;
+    int intno, next_eip_addend;
     intno = PARAM1;
-    next_eip = PARAM2;
-    raise_interrupt(intno, 1, 0, next_eip);
+    next_eip_addend = PARAM2;
+    raise_interrupt(intno, 1, 0, next_eip_addend);
 }
 
 void OPPROTO op_raise_exception(void)
@@ -753,11 +757,6 @@ void OPPROTO op_movswl_T0_T0(void)
     T0 = (int16_t)T0;
 }
 
-void OPPROTO op_movslq_T0_T0(void)
-{
-    T0 = (int32_t)T0;
-}
-
 void OPPROTO op_movzwl_T0_T0(void)
 {
     T0 = (uint16_t)T0;
@@ -769,6 +768,11 @@ void OPPROTO op_movswl_EAX_AX(void)
 }
 
 #ifdef TARGET_X86_64
+void OPPROTO op_movslq_T0_T0(void)
+{
+    T0 = (int32_t)T0;
+}
+
 void OPPROTO op_movslq_RAX_EAX(void)
 {
     EAX = (int32_t)EAX;
@@ -1199,6 +1203,13 @@ void OPPROTO op_movl_crN_T0(void)
     helper_movl_crN_T0(PARAM1);
 }
 
+#if !defined(CONFIG_USER_ONLY) 
+void OPPROTO op_movtl_T0_cr8(void)
+{
+    T0 = cpu_get_apic_tpr(env);
+}
+#endif
+
 /* DR registers access */
 void OPPROTO op_movl_drN_T0(void)
 {
@@ -1263,12 +1274,12 @@ void OPPROTO op_clts(void)
 
 void OPPROTO op_goto_tb0(void)
 {
-    GOTO_TB(op_goto_tb0, 0);
+    GOTO_TB(op_goto_tb0, PARAM1, 0);
 }
 
 void OPPROTO op_goto_tb1(void)
 {
-    GOTO_TB(op_goto_tb1, 1);
+    GOTO_TB(op_goto_tb1, PARAM1, 1);
 }
 
 void OPPROTO op_jmp_label(void)
@@ -1280,12 +1291,14 @@ void OPPROTO op_jnz_T0_label(void)
 {
     if (T0)
         GOTO_LABEL_PARAM(1);
+    FORCE_RET();
 }
 
 void OPPROTO op_jz_T0_label(void)
 {
     if (!T0)
         GOTO_LABEL_PARAM(1);
+    FORCE_RET();
 }
 
 /* slow set cases (compute x86 flags) */
@@ -1353,6 +1366,11 @@ void OPPROTO op_set_cc_op(void)
     CC_OP = PARAM1;
 }
 
+void OPPROTO op_mov_T0_cc(void)
+{
+    T0 = cc_table[CC_OP].compute_all();
+}
+
 /* XXX: clear VIF/VIP in all ops ? */
 
 void OPPROTO op_movl_eflags_T0(void)
@@ -1580,26 +1598,6 @@ CCTable cc_table[CC_OP_NB] = {
    functions comes from the LGPL'ed x86 emulator found in the Willows
    TWIN windows emulator. */
 
-#if defined(__powerpc__)
-extern CPU86_LDouble copysign(CPU86_LDouble, CPU86_LDouble);
-
-/* correct (but slow) PowerPC rint() (glibc version is incorrect) */
-double qemu_rint(double x)
-{
-    double y = 4503599627370496.0;
-    if (fabs(x) >= y)
-        return x;
-    if (x < 0) 
-        y = -y;
-    y = (x + y) - y;
-    if (y == 0.0)
-        y = copysign(y, x);
-    return y;
-}
-
-#define rint qemu_rint
-#endif
-
 /* fp load FT0 */
 
 void OPPROTO op_flds_FT0_A0(void)
@@ -1696,9 +1694,9 @@ void OPPROTO op_flds_ST0_A0(void)
     new_fpstt = (env->fpstt - 1) & 7;
 #ifdef USE_FP_CONVERT
     FP_CONVERT.i32 = ldl(A0);
-    env->fpregs[new_fpstt] = FP_CONVERT.f;
+    env->fpregs[new_fpstt].d = FP_CONVERT.f;
 #else
-    env->fpregs[new_fpstt] = ldfl(A0);
+    env->fpregs[new_fpstt].d = ldfl(A0);
 #endif
     env->fpstt = new_fpstt;
     env->fptags[new_fpstt] = 0; /* validate stack entry */
@@ -1710,9 +1708,9 @@ void OPPROTO op_fldl_ST0_A0(void)
     new_fpstt = (env->fpstt - 1) & 7;
 #ifdef USE_FP_CONVERT
     FP_CONVERT.i64 = ldq(A0);
-    env->fpregs[new_fpstt] = FP_CONVERT.d;
+    env->fpregs[new_fpstt].d = FP_CONVERT.d;
 #else
-    env->fpregs[new_fpstt] = ldfq(A0);
+    env->fpregs[new_fpstt].d = ldfq(A0);
 #endif
     env->fpstt = new_fpstt;
     env->fptags[new_fpstt] = 0; /* validate stack entry */
@@ -1730,7 +1728,7 @@ void helper_fild_ST0_A0(void)
 {
     int new_fpstt;
     new_fpstt = (env->fpstt - 1) & 7;
-    env->fpregs[new_fpstt] = (CPU86_LDouble)ldsw(A0);
+    env->fpregs[new_fpstt].d = (CPU86_LDouble)ldsw(A0);
     env->fpstt = new_fpstt;
     env->fptags[new_fpstt] = 0; /* validate stack entry */
 }
@@ -1739,7 +1737,7 @@ void helper_fildl_ST0_A0(void)
 {
     int new_fpstt;
     new_fpstt = (env->fpstt - 1) & 7;
-    env->fpregs[new_fpstt] = (CPU86_LDouble)((int32_t)ldl(A0));
+    env->fpregs[new_fpstt].d = (CPU86_LDouble)((int32_t)ldl(A0));
     env->fpstt = new_fpstt;
     env->fptags[new_fpstt] = 0; /* validate stack entry */
 }
@@ -1748,7 +1746,7 @@ void helper_fildll_ST0_A0(void)
 {
     int new_fpstt;
     new_fpstt = (env->fpstt - 1) & 7;
-    env->fpregs[new_fpstt] = (CPU86_LDouble)((int64_t)ldq(A0));
+    env->fpregs[new_fpstt].d = (CPU86_LDouble)((int64_t)ldq(A0));
     env->fpstt = new_fpstt;
     env->fptags[new_fpstt] = 0; /* validate stack entry */
 }
@@ -1776,9 +1774,9 @@ void OPPROTO op_fild_ST0_A0(void)
     new_fpstt = (env->fpstt - 1) & 7;
 #ifdef USE_FP_CONVERT
     FP_CONVERT.i32 = ldsw(A0);
-    env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i32;
+    env->fpregs[new_fpstt].d = (CPU86_LDouble)FP_CONVERT.i32;
 #else
-    env->fpregs[new_fpstt] = (CPU86_LDouble)ldsw(A0);
+    env->fpregs[new_fpstt].d = (CPU86_LDouble)ldsw(A0);
 #endif
     env->fpstt = new_fpstt;
     env->fptags[new_fpstt] = 0; /* validate stack entry */
@@ -1790,9 +1788,9 @@ void OPPROTO op_fildl_ST0_A0(void)
     new_fpstt = (env->fpstt - 1) & 7;
 #ifdef USE_FP_CONVERT
     FP_CONVERT.i32 = (int32_t) ldl(A0);
-    env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i32;
+    env->fpregs[new_fpstt].d = (CPU86_LDouble)FP_CONVERT.i32;
 #else
-    env->fpregs[new_fpstt] = (CPU86_LDouble)((int32_t)ldl(A0));
+    env->fpregs[new_fpstt].d = (CPU86_LDouble)((int32_t)ldl(A0));
 #endif
     env->fpstt = new_fpstt;
     env->fptags[new_fpstt] = 0; /* validate stack entry */
@@ -1804,9 +1802,9 @@ void OPPROTO op_fildll_ST0_A0(void)
     new_fpstt = (env->fpstt - 1) & 7;
 #ifdef USE_FP_CONVERT
     FP_CONVERT.i64 = (int64_t) ldq(A0);
-    env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i64;
+    env->fpregs[new_fpstt].d = (CPU86_LDouble)FP_CONVERT.i64;
 #else
-    env->fpregs[new_fpstt] = (CPU86_LDouble)((int64_t)ldq(A0));
+    env->fpregs[new_fpstt].d = (CPU86_LDouble)((int64_t)ldq(A0));
 #endif
     env->fpstt = new_fpstt;
     env->fptags[new_fpstt] = 0; /* validate stack entry */
@@ -1824,11 +1822,13 @@ void OPPROTO op_fsts_ST0_A0(void)
 #else
     stfl(A0, (float)ST0);
 #endif
+    FORCE_RET();
 }
 
 void OPPROTO op_fstl_ST0_A0(void)
 {
     stfq(A0, (double)ST0);
+    FORCE_RET();
 }
 
 void OPPROTO op_fstt_ST0_A0(void)
@@ -1846,10 +1846,11 @@ void OPPROTO op_fist_ST0_A0(void)
     int val;
 
     d = ST0;
-    val = lrint(d);
+    val = floatx_to_int32(d, &env->fp_status);
     if (val != (int16_t)val)
         val = -32768;
     stw(A0, val);
+    FORCE_RET();
 }
 
 void OPPROTO op_fistl_ST0_A0(void)
@@ -1862,8 +1863,9 @@ void OPPROTO op_fistl_ST0_A0(void)
     int val;
 
     d = ST0;
-    val = lrint(d);
+    val = floatx_to_int32(d, &env->fp_status);
     stl(A0, val);
+    FORCE_RET();
 }
 
 void OPPROTO op_fistll_ST0_A0(void)
@@ -1876,8 +1878,9 @@ void OPPROTO op_fistll_ST0_A0(void)
     int64_t val;
 
     d = ST0;
-    val = llrint(d);
+    val = floatx_to_int64(d, &env->fp_status);
     stq(A0, val);
+    FORCE_RET();
 }
 
 void OPPROTO op_fbld_ST0_A0(void)
@@ -1949,52 +1952,94 @@ void OPPROTO op_fxchg_ST0_STN(void)
 
 /* FPU operations */
 
-/* XXX: handle nans */
 void OPPROTO op_fcom_ST0_FT0(void)
 {
-    env->fpus &= (~0x4500);    /* (C3,C2,C0) <-- 000 */
-    if (ST0 < FT0)
-        env->fpus |= 0x100;    /* (C3,C2,C0) <-- 001 */
-    else if (ST0 == FT0)
-        env->fpus |= 0x4000; /* (C3,C2,C0) <-- 100 */
+    int cc;
+    switch(floatx_compare(ST0, FT0, &env->fp_status)) {
+    case -1:
+        cc = 0x0100;
+        break;
+    case 0:
+        cc = 0x4000;
+        break;
+    case 1:
+        cc = 0x0000;
+        break;
+    case 2:
+    default:
+        cc = 0x4500;
+        break;
+    }
+    env->fpus = (env->fpus & ~0x4500) | cc;
     FORCE_RET();
 }
 
-/* XXX: handle nans */
 void OPPROTO op_fucom_ST0_FT0(void)
 {
-    env->fpus &= (~0x4500);    /* (C3,C2,C0) <-- 000 */
-    if (ST0 < FT0)
-        env->fpus |= 0x100;    /* (C3,C2,C0) <-- 001 */
-    else if (ST0 == FT0)
-        env->fpus |= 0x4000; /* (C3,C2,C0) <-- 100 */
+    int cc;
+    switch(floatx_compare_quiet(ST0, FT0, &env->fp_status)) {
+    case -1:
+        cc = 0x0100;
+        break;
+    case 0:
+        cc = 0x4000;
+        break;
+    case 1:
+        cc = 0x0000;
+        break;
+    case 2:
+    default:
+        cc = 0x4500;
+        break;
+    }
+    env->fpus = (env->fpus & ~0x4500) | cc;
     FORCE_RET();
 }
 
-/* XXX: handle nans */
 void OPPROTO op_fcomi_ST0_FT0(void)
 {
-    int eflags;
+    int eflags, cc;
+    switch(floatx_compare(ST0, FT0, &env->fp_status)) {
+    case -1:
+        cc = CC_C;
+        break;
+    case 0:
+        cc = CC_Z;
+        break;
+    case 1:
+        cc = 0;
+        break;
+    case 2:
+    default:
+        cc = CC_Z | CC_P | CC_C;
+        break;
+    }
     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;
+    eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | cc;
     CC_SRC = eflags;
     FORCE_RET();
 }
 
-/* XXX: handle nans */
 void OPPROTO op_fucomi_ST0_FT0(void)
 {
-    int eflags;
+    int eflags, cc;
+    switch(floatx_compare_quiet(ST0, FT0, &env->fp_status)) {
+    case -1:
+        cc = CC_C;
+        break;
+    case 0:
+        cc = CC_Z;
+        break;
+    case 1:
+        cc = 0;
+        break;
+    case 2:
+    default:
+        cc = CC_Z | CC_P | CC_C;
+        break;
+    }
     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;
+    eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | cc;
     CC_SRC = eflags;
     FORCE_RET();
 }
@@ -2078,12 +2123,12 @@ void OPPROTO op_fdivr_STN_ST0(void)
 /* misc FPU operations */
 void OPPROTO op_fchs_ST0(void)
 {
-    ST0 = -ST0;
+    ST0 = floatx_chs(ST0);
 }
 
 void OPPROTO op_fabs_ST0(void)
 {
-    ST0 = fabs(ST0);
+    ST0 = floatx_abs(ST0);
 }
 
 void OPPROTO op_fxam_ST0(void)
@@ -2210,6 +2255,7 @@ void OPPROTO op_fnstsw_A0(void)
     int fpus;
     fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
     stw(A0, fpus);
+    FORCE_RET();
 }
 
 void OPPROTO op_fnstsw_EAX(void)
@@ -2222,29 +2268,13 @@ void OPPROTO op_fnstsw_EAX(void)
 void OPPROTO op_fnstcw_A0(void)
 {
     stw(A0, env->fpuc);
+    FORCE_RET();
 }
 
 void OPPROTO op_fldcw_A0(void)
 {
-    int rnd_type;
     env->fpuc = lduw(A0);
-    /* set rounding mode */
-    switch(env->fpuc & RC_MASK) {
-    default:
-    case RC_NEAR:
-        rnd_type = FE_TONEAREST;
-        break;
-    case RC_DOWN:
-        rnd_type = FE_DOWNWARD;
-        break;
-    case RC_UP:
-        rnd_type = FE_UPWARD;
-        break;
-    case RC_CHOP:
-        rnd_type = FE_TOWARDZERO;
-        break;
-    }
-    fesetround(rnd_type);
+    update_fp_status();
 }
 
 void OPPROTO op_fclex(void)
@@ -2323,6 +2353,29 @@ void OPPROTO op_movo(void)
     memcpy16(d, s);
 }
 
+void OPPROTO op_movq(void)
+{
+    uint64_t *d, *s;
+    d = (uint64_t *)((char *)env + PARAM1);
+    s = (uint64_t *)((char *)env + PARAM2);
+    *d = *s;
+}
+
+void OPPROTO op_movl(void)
+{
+    uint32_t *d, *s;
+    d = (uint32_t *)((char *)env + PARAM1);
+    s = (uint32_t *)((char *)env + PARAM2);
+    *d = *s;
+}
+
+void OPPROTO op_movq_env_0(void)
+{
+    uint64_t *d;
+    d = (uint64_t *)((char *)env + PARAM1);
+    *d = 0;
+}
+
 void OPPROTO op_fxsave_A0(void)
 {
     helper_fxsave(A0, PARAM1);
@@ -2332,3 +2385,24 @@ void OPPROTO op_fxrstor_A0(void)
 {
     helper_fxrstor(A0, PARAM1);
 }
+
+/* XXX: optimize by storing fptt and fptags in the static cpu state */
+void OPPROTO op_enter_mmx(void)
+{
+    env->fpstt = 0;
+    *(uint32_t *)(env->fptags) = 0;
+    *(uint32_t *)(env->fptags + 4) = 0;
+}
+
+void OPPROTO op_emms(void)
+{
+    /* set to empty state */
+    *(uint32_t *)(env->fptags) = 0x01010101;
+    *(uint32_t *)(env->fptags + 4) = 0x01010101;
+}
+
+#define SHIFT 0
+#include "ops_sse.h"
+
+#define SHIFT 1
+#include "ops_sse.h"
This page took 0.036178 seconds and 4 git commands to generate.