Revision f299f437 target-i386/op_helper.c

b/target-i386/op_helper.c
17 17
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 18
 */
19 19

  
20
#include <math.h>
21 20
#include "cpu.h"
22 21
#include "dyngen-exec.h"
23 22
#include "host-utils.h"
......
52 51
    }
53 52
}
54 53

  
55
#define FPU_RC_MASK         0xc00
56
#define FPU_RC_NEAR         0x000
57
#define FPU_RC_DOWN         0x400
58
#define FPU_RC_UP           0x800
59
#define FPU_RC_CHOP         0xc00
60

  
61
#define MAXTAN 9223372036854775808.0
62

  
63
/* the following deal with x86 long double-precision numbers */
64
#define MAXEXPD 0x7fff
65
#define EXPBIAS 16383
66
#define EXPD(fp)        (fp.l.upper & 0x7fff)
67
#define SIGND(fp)       ((fp.l.upper) & 0x8000)
68
#define MANTD(fp)       (fp.l.lower)
69
#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7fff)) | EXPBIAS
70

  
71
static inline void fpush(void)
72
{
73
    env->fpstt = (env->fpstt - 1) & 7;
74
    env->fptags[env->fpstt] = 0; /* validate stack entry */
75
}
76

  
77
static inline void fpop(void)
78
{
79
    env->fptags[env->fpstt] = 1; /* invalidate stack entry */
80
    env->fpstt = (env->fpstt + 1) & 7;
81
}
82

  
83
static inline floatx80 helper_fldt(target_ulong ptr)
84
{
85
    CPU_LDoubleU temp;
86

  
87
    temp.l.lower = ldq(ptr);
88
    temp.l.upper = lduw(ptr + 8);
89
    return temp.d;
90
}
91

  
92
static inline void helper_fstt(floatx80 f, target_ulong ptr)
93
{
94
    CPU_LDoubleU temp;
95

  
96
    temp.d = f;
97
    stq(ptr, temp.l.lower);
98
    stw(ptr + 8, temp.l.upper);
99
}
100

  
101
#define FPUS_IE (1 << 0)
102
#define FPUS_DE (1 << 1)
103
#define FPUS_ZE (1 << 2)
104
#define FPUS_OE (1 << 3)
105
#define FPUS_UE (1 << 4)
106
#define FPUS_PE (1 << 5)
107
#define FPUS_SF (1 << 6)
108
#define FPUS_SE (1 << 7)
109
#define FPUS_B  (1 << 15)
110

  
111
#define FPUC_EM 0x3f
112

  
113 54
static inline uint32_t compute_eflags(void)
114 55
{
115 56
    return env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
......
189 130
    6, 7, 8, 0, 1, 2, 3, 4,
190 131
};
191 132

  
192
#define floatx80_lg2 make_floatx80(0x3ffd, 0x9a209a84fbcff799LL)
193
#define floatx80_l2e make_floatx80(0x3fff, 0xb8aa3b295c17f0bcLL)
194
#define floatx80_l2t make_floatx80(0x4000, 0xd49a784bcd1b8afeLL)
195

  
196 133
/* broken thread support */
197 134

  
198 135
static spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
......
3750 3687
    CC_SRC = eflags | CC_Z;
3751 3688
}
3752 3689

  
3753
/* x87 FPU helpers */
3754

  
3755
static inline double floatx80_to_double(floatx80 a)
3756
{
3757
    union {
3758
        float64 f64;
3759
        double d;
3760
    } u;
3761

  
3762
    u.f64 = floatx80_to_float64(a, &env->fp_status);
3763
    return u.d;
3764
}
3765

  
3766
static inline floatx80 double_to_floatx80(double a)
3767
{
3768
    union {
3769
        float64 f64;
3770
        double d;
3771
    } u;
3772

  
3773
    u.d = a;
3774
    return float64_to_floatx80(u.f64, &env->fp_status);
3775
}
3776

  
3777
static void fpu_set_exception(int mask)
3690
#if defined(CONFIG_USER_ONLY)
3691
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
3778 3692
{
3779
    env->fpus |= mask;
3780
    if (env->fpus & (~env->fpuc & FPUC_EM)) {
3781
        env->fpus |= FPUS_SE | FPUS_B;
3782
    }
3783
}
3693
    CPUX86State *saved_env;
3784 3694

  
3785
static inline floatx80 helper_fdiv(floatx80 a, floatx80 b)
3786
{
3787
    if (floatx80_is_zero(b)) {
3788
        fpu_set_exception(FPUS_ZE);
3695
    saved_env = env;
3696
    env = s;
3697
    if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
3698
        selector &= 0xffff;
3699
        cpu_x86_load_seg_cache(env, seg_reg, selector,
3700
                               (selector << 4), 0xffff, 0);
3701
    } else {
3702
        helper_load_seg(seg_reg, selector);
3789 3703
    }
3790
    return floatx80_div(a, b, &env->fp_status);
3704
    env = saved_env;
3791 3705
}
3792

  
3793
static void fpu_raise_exception(void)
3794
{
3795
    if (env->cr[0] & CR0_NE_MASK) {
3796
        raise_exception(env, EXCP10_COPR);
3797
    }
3798
#if !defined(CONFIG_USER_ONLY)
3799
    else {
3800
        cpu_set_ferr(env);
3801
    }
3802 3706
#endif
3803
}
3804

  
3805
void helper_flds_FT0(uint32_t val)
3806
{
3807
    union {
3808
        float32 f;
3809
        uint32_t i;
3810
    } u;
3811 3707

  
3812
    u.i = val;
3813
    FT0 = float32_to_floatx80(u.f, &env->fp_status);
3814
}
3815

  
3816
void helper_fldl_FT0(uint64_t val)
3708
#ifdef TARGET_X86_64
3709
static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
3817 3710
{
3818
    union {
3819
        float64 f;
3820
        uint64_t i;
3821
    } u;
3822

  
3823
    u.i = val;
3824
    FT0 = float64_to_floatx80(u.f, &env->fp_status);
3711
    *plow += a;
3712
    /* carry test */
3713
    if (*plow < a) {
3714
        (*phigh)++;
3715
    }
3716
    *phigh += b;
3825 3717
}
3826 3718

  
3827
void helper_fildl_FT0(int32_t val)
3719
static void neg128(uint64_t *plow, uint64_t *phigh)
3828 3720
{
3829
    FT0 = int32_to_floatx80(val, &env->fp_status);
3721
    *plow = ~*plow;
3722
    *phigh = ~*phigh;
3723
    add128(plow, phigh, 1, 0);
3830 3724
}
3831 3725

  
3832
void helper_flds_ST0(uint32_t val)
3726
/* return TRUE if overflow */
3727
static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
3833 3728
{
3834
    int new_fpstt;
3835
    union {
3836
        float32 f;
3837
        uint32_t i;
3838
    } u;
3729
    uint64_t q, r, a1, a0;
3730
    int i, qb, ab;
3839 3731

  
3840
    new_fpstt = (env->fpstt - 1) & 7;
3841
    u.i = val;
3842
    env->fpregs[new_fpstt].d = float32_to_floatx80(u.f, &env->fp_status);
3843
    env->fpstt = new_fpstt;
3844
    env->fptags[new_fpstt] = 0; /* validate stack entry */
3732
    a0 = *plow;
3733
    a1 = *phigh;
3734
    if (a1 == 0) {
3735
        q = a0 / b;
3736
        r = a0 % b;
3737
        *plow = q;
3738
        *phigh = r;
3739
    } else {
3740
        if (a1 >= b) {
3741
            return 1;
3742
        }
3743
        /* XXX: use a better algorithm */
3744
        for (i = 0; i < 64; i++) {
3745
            ab = a1 >> 63;
3746
            a1 = (a1 << 1) | (a0 >> 63);
3747
            if (ab || a1 >= b) {
3748
                a1 -= b;
3749
                qb = 1;
3750
            } else {
3751
                qb = 0;
3752
            }
3753
            a0 = (a0 << 1) | qb;
3754
        }
3755
#if defined(DEBUG_MULDIV)
3756
        printf("div: 0x%016" PRIx64 "%016" PRIx64 " / 0x%016" PRIx64
3757
               ": q=0x%016" PRIx64 " r=0x%016" PRIx64 "\n",
3758
               *phigh, *plow, b, a0, a1);
3759
#endif
3760
        *plow = a0;
3761
        *phigh = a1;
3762
    }
3763
    return 0;
3845 3764
}
3846 3765

  
3847
void helper_fldl_ST0(uint64_t val)
3766
/* return TRUE if overflow */
3767
static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
3848 3768
{
3849
    int new_fpstt;
3850
    union {
3851
        float64 f;
3852
        uint64_t i;
3853
    } u;
3769
    int sa, sb;
3854 3770

  
3855
    new_fpstt = (env->fpstt - 1) & 7;
3856
    u.i = val;
3857
    env->fpregs[new_fpstt].d = float64_to_floatx80(u.f, &env->fp_status);
3858
    env->fpstt = new_fpstt;
3859
    env->fptags[new_fpstt] = 0; /* validate stack entry */
3771
    sa = ((int64_t)*phigh < 0);
3772
    if (sa) {
3773
        neg128(plow, phigh);
3774
    }
3775
    sb = (b < 0);
3776
    if (sb) {
3777
        b = -b;
3778
    }
3779
    if (div64(plow, phigh, b) != 0) {
3780
        return 1;
3781
    }
3782
    if (sa ^ sb) {
3783
        if (*plow > (1ULL << 63)) {
3784
            return 1;
3785
        }
3786
        *plow = -*plow;
3787
    } else {
3788
        if (*plow >= (1ULL << 63)) {
3789
            return 1;
3790
        }
3791
    }
3792
    if (sa) {
3793
        *phigh = -*phigh;
3794
    }
3795
    return 0;
3860 3796
}
3861 3797

  
3862
void helper_fildl_ST0(int32_t val)
3798
void helper_mulq_EAX_T0(target_ulong t0)
3863 3799
{
3864
    int new_fpstt;
3800
    uint64_t r0, r1;
3865 3801

  
3866
    new_fpstt = (env->fpstt - 1) & 7;
3867
    env->fpregs[new_fpstt].d = int32_to_floatx80(val, &env->fp_status);
3868
    env->fpstt = new_fpstt;
3869
    env->fptags[new_fpstt] = 0; /* validate stack entry */
3802
    mulu64(&r0, &r1, EAX, t0);
3803
    EAX = r0;
3804
    EDX = r1;
3805
    CC_DST = r0;
3806
    CC_SRC = r1;
3870 3807
}
3871 3808

  
3872
void helper_fildll_ST0(int64_t val)
3809
void helper_imulq_EAX_T0(target_ulong t0)
3873 3810
{
3874
    int new_fpstt;
3811
    uint64_t r0, r1;
3875 3812

  
3876
    new_fpstt = (env->fpstt - 1) & 7;
3877
    env->fpregs[new_fpstt].d = int64_to_floatx80(val, &env->fp_status);
3878
    env->fpstt = new_fpstt;
3879
    env->fptags[new_fpstt] = 0; /* validate stack entry */
3813
    muls64(&r0, &r1, EAX, t0);
3814
    EAX = r0;
3815
    EDX = r1;
3816
    CC_DST = r0;
3817
    CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
3880 3818
}
3881 3819

  
3882
uint32_t helper_fsts_ST0(void)
3820
target_ulong helper_imulq_T0_T1(target_ulong t0, target_ulong t1)
3883 3821
{
3884
    union {
3885
        float32 f;
3886
        uint32_t i;
3887
    } u;
3822
    uint64_t r0, r1;
3888 3823

  
3889
    u.f = floatx80_to_float32(ST0, &env->fp_status);
3890
    return u.i;
3824
    muls64(&r0, &r1, t0, t1);
3825
    CC_DST = r0;
3826
    CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
3827
    return r0;
3891 3828
}
3892 3829

  
3893
uint64_t helper_fstl_ST0(void)
3830
void helper_divq_EAX(target_ulong t0)
3894 3831
{
3895
    union {
3896
        float64 f;
3897
        uint64_t i;
3898
    } u;
3832
    uint64_t r0, r1;
3899 3833

  
3900
    u.f = floatx80_to_float64(ST0, &env->fp_status);
3901
    return u.i;
3834
    if (t0 == 0) {
3835
        raise_exception(env, EXCP00_DIVZ);
3836
    }
3837
    r0 = EAX;
3838
    r1 = EDX;
3839
    if (div64(&r0, &r1, t0)) {
3840
        raise_exception(env, EXCP00_DIVZ);
3841
    }
3842
    EAX = r0;
3843
    EDX = r1;
3902 3844
}
3903 3845

  
3904
int32_t helper_fist_ST0(void)
3846
void helper_idivq_EAX(target_ulong t0)
3905 3847
{
3906
    int32_t val;
3848
    uint64_t r0, r1;
3907 3849

  
3908
    val = floatx80_to_int32(ST0, &env->fp_status);
3909
    if (val != (int16_t)val) {
3910
        val = -32768;
3850
    if (t0 == 0) {
3851
        raise_exception(env, EXCP00_DIVZ);
3911 3852
    }
3912
    return val;
3853
    r0 = EAX;
3854
    r1 = EDX;
3855
    if (idiv64(&r0, &r1, t0)) {
3856
        raise_exception(env, EXCP00_DIVZ);
3857
    }
3858
    EAX = r0;
3859
    EDX = r1;
3913 3860
}
3861
#endif
3914 3862

  
3915
int32_t helper_fistl_ST0(void)
3863
static void do_hlt(void)
3916 3864
{
3917
    int32_t val;
3918

  
3919
    val = floatx80_to_int32(ST0, &env->fp_status);
3920
    return val;
3865
    env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
3866
    env->halted = 1;
3867
    env->exception_index = EXCP_HLT;
3868
    cpu_loop_exit(env);
3921 3869
}
3922 3870

  
3923
int64_t helper_fistll_ST0(void)
3871
void helper_hlt(int next_eip_addend)
3924 3872
{
3925
    int64_t val;
3873
    helper_svm_check_intercept_param(SVM_EXIT_HLT, 0);
3874
    EIP += next_eip_addend;
3926 3875

  
3927
    val = floatx80_to_int64(ST0, &env->fp_status);
3928
    return val;
3876
    do_hlt();
3929 3877
}
3930 3878

  
3931
int32_t helper_fistt_ST0(void)
3879
void helper_monitor(target_ulong ptr)
3932 3880
{
3933
    int32_t val;
3934

  
3935
    val = floatx80_to_int32_round_to_zero(ST0, &env->fp_status);
3936
    if (val != (int16_t)val) {
3937
        val = -32768;
3881
    if ((uint32_t)ECX != 0) {
3882
        raise_exception(env, EXCP0D_GPF);
3938 3883
    }
3939
    return val;
3884
    /* XXX: store address? */
3885
    helper_svm_check_intercept_param(SVM_EXIT_MONITOR, 0);
3940 3886
}
3941 3887

  
3942
int32_t helper_fisttl_ST0(void)
3888
void helper_mwait(int next_eip_addend)
3943 3889
{
3944
    int32_t val;
3890
    if ((uint32_t)ECX != 0) {
3891
        raise_exception(env, EXCP0D_GPF);
3892
    }
3893
    helper_svm_check_intercept_param(SVM_EXIT_MWAIT, 0);
3894
    EIP += next_eip_addend;
3945 3895

  
3946
    val = floatx80_to_int32_round_to_zero(ST0, &env->fp_status);
3947
    return val;
3896
    /* XXX: not complete but not completely erroneous */
3897
    if (env->cpu_index != 0 || env->next_cpu != NULL) {
3898
        /* more than one CPU: do not sleep because another CPU may
3899
           wake this one */
3900
    } else {
3901
        do_hlt();
3902
    }
3948 3903
}
3949 3904

  
3950
int64_t helper_fisttll_ST0(void)
3905
void helper_debug(void)
3951 3906
{
3952
    int64_t val;
3953

  
3954
    val = floatx80_to_int64_round_to_zero(ST0, &env->fp_status);
3955
    return val;
3907
    env->exception_index = EXCP_DEBUG;
3908
    cpu_loop_exit(env);
3956 3909
}
3957 3910

  
3958
void helper_fldt_ST0(target_ulong ptr)
3911
void helper_reset_rf(void)
3959 3912
{
3960
    int new_fpstt;
3961

  
3962
    new_fpstt = (env->fpstt - 1) & 7;
3963
    env->fpregs[new_fpstt].d = helper_fldt(ptr);
3964
    env->fpstt = new_fpstt;
3965
    env->fptags[new_fpstt] = 0; /* validate stack entry */
3913
    env->eflags &= ~RF_MASK;
3966 3914
}
3967 3915

  
3968
void helper_fstt_ST0(target_ulong ptr)
3916
void helper_cli(void)
3969 3917
{
3970
    helper_fstt(ST0, ptr);
3918
    env->eflags &= ~IF_MASK;
3971 3919
}
3972 3920

  
3973
void helper_fpush(void)
3921
void helper_sti(void)
3974 3922
{
3975
    fpush();
3923
    env->eflags |= IF_MASK;
3976 3924
}
3977 3925

  
3978
void helper_fpop(void)
3926
#if 0
3927
/* vm86plus instructions */
3928
void helper_cli_vm(void)
3979 3929
{
3980
    fpop();
3930
    env->eflags &= ~VIF_MASK;
3981 3931
}
3982 3932

  
3983
void helper_fdecstp(void)
3933
void helper_sti_vm(void)
3984 3934
{
3985
    env->fpstt = (env->fpstt - 1) & 7;
3986
    env->fpus &= ~0x4700;
3935
    env->eflags |= VIF_MASK;
3936
    if (env->eflags & VIP_MASK) {
3937
        raise_exception(env, EXCP0D_GPF);
3938
    }
3987 3939
}
3940
#endif
3988 3941

  
3989
void helper_fincstp(void)
3942
void helper_set_inhibit_irq(void)
3990 3943
{
3991
    env->fpstt = (env->fpstt + 1) & 7;
3992
    env->fpus &= ~0x4700;
3944
    env->hflags |= HF_INHIBIT_IRQ_MASK;
3993 3945
}
3994 3946

  
3995
/* FPU move */
3996

  
3997
void helper_ffree_STN(int st_index)
3947
void helper_reset_inhibit_irq(void)
3998 3948
{
3999
    env->fptags[(env->fpstt + st_index) & 7] = 1;
3949
    env->hflags &= ~HF_INHIBIT_IRQ_MASK;
4000 3950
}
4001 3951

  
4002
void helper_fmov_ST0_FT0(void)
3952
void helper_boundw(target_ulong a0, int v)
4003 3953
{
4004
    ST0 = FT0;
4005
}
3954
    int low, high;
4006 3955

  
4007
void helper_fmov_FT0_STN(int st_index)
4008
{
4009
    FT0 = ST(st_index);
3956
    low = ldsw(a0);
3957
    high = ldsw(a0 + 2);
3958
    v = (int16_t)v;
3959
    if (v < low || v > high) {
3960
        raise_exception(env, EXCP05_BOUND);
3961
    }
4010 3962
}
4011 3963

  
4012
void helper_fmov_ST0_STN(int st_index)
3964
void helper_boundl(target_ulong a0, int v)
4013 3965
{
4014
    ST0 = ST(st_index);
4015
}
3966
    int low, high;
4016 3967

  
4017
void helper_fmov_STN_ST0(int st_index)
4018
{
4019
    ST(st_index) = ST0;
4020
}
4021

  
4022
void helper_fxchg_ST0_STN(int st_index)
4023
{
4024
    floatx80 tmp;
4025

  
4026
    tmp = ST(st_index);
4027
    ST(st_index) = ST0;
4028
    ST0 = tmp;
4029
}
4030

  
4031
/* FPU operations */
4032

  
4033
static const int fcom_ccval[4] = {0x0100, 0x4000, 0x0000, 0x4500};
4034

  
4035
void helper_fcom_ST0_FT0(void)
4036
{
4037
    int ret;
4038

  
4039
    ret = floatx80_compare(ST0, FT0, &env->fp_status);
4040
    env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1];
4041
}
4042

  
4043
void helper_fucom_ST0_FT0(void)
4044
{
4045
    int ret;
4046

  
4047
    ret = floatx80_compare_quiet(ST0, FT0, &env->fp_status);
4048
    env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1];
4049
}
4050

  
4051
static const int fcomi_ccval[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C};
4052

  
4053
void helper_fcomi_ST0_FT0(void)
4054
{
4055
    int eflags;
4056
    int ret;
4057

  
4058
    ret = floatx80_compare(ST0, FT0, &env->fp_status);
4059
    eflags = helper_cc_compute_all(CC_OP);
4060
    eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
4061
    CC_SRC = eflags;
4062
}
4063

  
4064
void helper_fucomi_ST0_FT0(void)
4065
{
4066
    int eflags;
4067
    int ret;
4068

  
4069
    ret = floatx80_compare_quiet(ST0, FT0, &env->fp_status);
4070
    eflags = helper_cc_compute_all(CC_OP);
4071
    eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
4072
    CC_SRC = eflags;
4073
}
4074

  
4075
void helper_fadd_ST0_FT0(void)
4076
{
4077
    ST0 = floatx80_add(ST0, FT0, &env->fp_status);
4078
}
4079

  
4080
void helper_fmul_ST0_FT0(void)
4081
{
4082
    ST0 = floatx80_mul(ST0, FT0, &env->fp_status);
4083
}
4084

  
4085
void helper_fsub_ST0_FT0(void)
4086
{
4087
    ST0 = floatx80_sub(ST0, FT0, &env->fp_status);
4088
}
4089

  
4090
void helper_fsubr_ST0_FT0(void)
4091
{
4092
    ST0 = floatx80_sub(FT0, ST0, &env->fp_status);
4093
}
4094

  
4095
void helper_fdiv_ST0_FT0(void)
4096
{
4097
    ST0 = helper_fdiv(ST0, FT0);
4098
}
4099

  
4100
void helper_fdivr_ST0_FT0(void)
4101
{
4102
    ST0 = helper_fdiv(FT0, ST0);
4103
}
4104

  
4105
/* fp operations between STN and ST0 */
4106

  
4107
void helper_fadd_STN_ST0(int st_index)
4108
{
4109
    ST(st_index) = floatx80_add(ST(st_index), ST0, &env->fp_status);
4110
}
4111

  
4112
void helper_fmul_STN_ST0(int st_index)
4113
{
4114
    ST(st_index) = floatx80_mul(ST(st_index), ST0, &env->fp_status);
4115
}
4116

  
4117
void helper_fsub_STN_ST0(int st_index)
4118
{
4119
    ST(st_index) = floatx80_sub(ST(st_index), ST0, &env->fp_status);
4120
}
4121

  
4122
void helper_fsubr_STN_ST0(int st_index)
4123
{
4124
    ST(st_index) = floatx80_sub(ST0, ST(st_index), &env->fp_status);
4125
}
4126

  
4127
void helper_fdiv_STN_ST0(int st_index)
4128
{
4129
    floatx80 *p;
4130

  
4131
    p = &ST(st_index);
4132
    *p = helper_fdiv(*p, ST0);
4133
}
4134

  
4135
void helper_fdivr_STN_ST0(int st_index)
4136
{
4137
    floatx80 *p;
4138

  
4139
    p = &ST(st_index);
4140
    *p = helper_fdiv(ST0, *p);
4141
}
4142

  
4143
/* misc FPU operations */
4144
void helper_fchs_ST0(void)
4145
{
4146
    ST0 = floatx80_chs(ST0);
4147
}
4148

  
4149
void helper_fabs_ST0(void)
4150
{
4151
    ST0 = floatx80_abs(ST0);
4152
}
4153

  
4154
void helper_fld1_ST0(void)
4155
{
4156
    ST0 = floatx80_one;
4157
}
4158

  
4159
void helper_fldl2t_ST0(void)
4160
{
4161
    ST0 = floatx80_l2t;
4162
}
4163

  
4164
void helper_fldl2e_ST0(void)
4165
{
4166
    ST0 = floatx80_l2e;
4167
}
4168

  
4169
void helper_fldpi_ST0(void)
4170
{
4171
    ST0 = floatx80_pi;
4172
}
4173

  
4174
void helper_fldlg2_ST0(void)
4175
{
4176
    ST0 = floatx80_lg2;
4177
}
4178

  
4179
void helper_fldln2_ST0(void)
4180
{
4181
    ST0 = floatx80_ln2;
4182
}
4183

  
4184
void helper_fldz_ST0(void)
4185
{
4186
    ST0 = floatx80_zero;
4187
}
4188

  
4189
void helper_fldz_FT0(void)
4190
{
4191
    FT0 = floatx80_zero;
4192
}
4193

  
4194
uint32_t helper_fnstsw(void)
4195
{
4196
    return (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
4197
}
4198

  
4199
uint32_t helper_fnstcw(void)
4200
{
4201
    return env->fpuc;
4202
}
4203

  
4204
static void update_fp_status(void)
4205
{
4206
    int rnd_type;
4207

  
4208
    /* set rounding mode */
4209
    switch (env->fpuc & FPU_RC_MASK) {
4210
    default:
4211
    case FPU_RC_NEAR:
4212
        rnd_type = float_round_nearest_even;
4213
        break;
4214
    case FPU_RC_DOWN:
4215
        rnd_type = float_round_down;
4216
        break;
4217
    case FPU_RC_UP:
4218
        rnd_type = float_round_up;
4219
        break;
4220
    case FPU_RC_CHOP:
4221
        rnd_type = float_round_to_zero;
4222
        break;
4223
    }
4224
    set_float_rounding_mode(rnd_type, &env->fp_status);
4225
    switch ((env->fpuc >> 8) & 3) {
4226
    case 0:
4227
        rnd_type = 32;
4228
        break;
4229
    case 2:
4230
        rnd_type = 64;
4231
        break;
4232
    case 3:
4233
    default:
4234
        rnd_type = 80;
4235
        break;
4236
    }
4237
    set_floatx80_rounding_precision(rnd_type, &env->fp_status);
4238
}
4239

  
4240
void helper_fldcw(uint32_t val)
4241
{
4242
    env->fpuc = val;
4243
    update_fp_status();
4244
}
4245

  
4246
void helper_fclex(void)
4247
{
4248
    env->fpus &= 0x7f00;
4249
}
4250

  
4251
void helper_fwait(void)
4252
{
4253
    if (env->fpus & FPUS_SE) {
4254
        fpu_raise_exception();
4255
    }
4256
}
4257

  
4258
void helper_fninit(void)
4259
{
4260
    env->fpus = 0;
4261
    env->fpstt = 0;
4262
    env->fpuc = 0x37f;
4263
    env->fptags[0] = 1;
4264
    env->fptags[1] = 1;
4265
    env->fptags[2] = 1;
4266
    env->fptags[3] = 1;
4267
    env->fptags[4] = 1;
4268
    env->fptags[5] = 1;
4269
    env->fptags[6] = 1;
4270
    env->fptags[7] = 1;
4271
}
4272

  
4273
/* BCD ops */
4274

  
4275
void helper_fbld_ST0(target_ulong ptr)
4276
{
4277
    floatx80 tmp;
4278
    uint64_t val;
4279
    unsigned int v;
4280
    int i;
4281

  
4282
    val = 0;
4283
    for (i = 8; i >= 0; i--) {
4284
        v = ldub(ptr + i);
4285
        val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
4286
    }
4287
    tmp = int64_to_floatx80(val, &env->fp_status);
4288
    if (ldub(ptr + 9) & 0x80) {
4289
        floatx80_chs(tmp);
4290
    }
4291
    fpush();
4292
    ST0 = tmp;
4293
}
4294

  
4295
void helper_fbst_ST0(target_ulong ptr)
4296
{
4297
    int v;
4298
    target_ulong mem_ref, mem_end;
4299
    int64_t val;
4300

  
4301
    val = floatx80_to_int64(ST0, &env->fp_status);
4302
    mem_ref = ptr;
4303
    mem_end = mem_ref + 9;
4304
    if (val < 0) {
4305
        stb(mem_end, 0x80);
4306
        val = -val;
4307
    } else {
4308
        stb(mem_end, 0x00);
4309
    }
4310
    while (mem_ref < mem_end) {
4311
        if (val == 0) {
4312
            break;
4313
        }
4314
        v = val % 100;
4315
        val = val / 100;
4316
        v = ((v / 10) << 4) | (v % 10);
4317
        stb(mem_ref++, v);
4318
    }
4319
    while (mem_ref < mem_end) {
4320
        stb(mem_ref++, 0);
4321
    }
4322
}
4323

  
4324
void helper_f2xm1(void)
4325
{
4326
    double val = floatx80_to_double(ST0);
4327

  
4328
    val = pow(2.0, val) - 1.0;
4329
    ST0 = double_to_floatx80(val);
4330
}
4331

  
4332
void helper_fyl2x(void)
4333
{
4334
    double fptemp = floatx80_to_double(ST0);
4335

  
4336
    if (fptemp > 0.0) {
4337
        fptemp = log(fptemp) / log(2.0); /* log2(ST) */
4338
        fptemp *= floatx80_to_double(ST1);
4339
        ST1 = double_to_floatx80(fptemp);
4340
        fpop();
4341
    } else {
4342
        env->fpus &= ~0x4700;
4343
        env->fpus |= 0x400;
4344
    }
4345
}
4346

  
4347
void helper_fptan(void)
4348
{
4349
    double fptemp = floatx80_to_double(ST0);
4350

  
4351
    if ((fptemp > MAXTAN) || (fptemp < -MAXTAN)) {
4352
        env->fpus |= 0x400;
4353
    } else {
4354
        fptemp = tan(fptemp);
4355
        ST0 = double_to_floatx80(fptemp);
4356
        fpush();
4357
        ST0 = floatx80_one;
4358
        env->fpus &= ~0x400; /* C2 <-- 0 */
4359
        /* the above code is for |arg| < 2**52 only */
4360
    }
4361
}
4362

  
4363
void helper_fpatan(void)
4364
{
4365
    double fptemp, fpsrcop;
4366

  
4367
    fpsrcop = floatx80_to_double(ST1);
4368
    fptemp = floatx80_to_double(ST0);
4369
    ST1 = double_to_floatx80(atan2(fpsrcop, fptemp));
4370
    fpop();
4371
}
4372

  
4373
void helper_fxtract(void)
4374
{
4375
    CPU_LDoubleU temp;
4376

  
4377
    temp.d = ST0;
4378

  
4379
    if (floatx80_is_zero(ST0)) {
4380
        /* Easy way to generate -inf and raising division by 0 exception */
4381
        ST0 = floatx80_div(floatx80_chs(floatx80_one), floatx80_zero,
4382
                           &env->fp_status);
4383
        fpush();
4384
        ST0 = temp.d;
4385
    } else {
4386
        int expdif;
4387

  
4388
        expdif = EXPD(temp) - EXPBIAS;
4389
        /* DP exponent bias */
4390
        ST0 = int32_to_floatx80(expdif, &env->fp_status);
4391
        fpush();
4392
        BIASEXPONENT(temp);
4393
        ST0 = temp.d;
4394
    }
4395
}
4396

  
4397
void helper_fprem1(void)
4398
{
4399
    double st0, st1, dblq, fpsrcop, fptemp;
4400
    CPU_LDoubleU fpsrcop1, fptemp1;
4401
    int expdif;
4402
    signed long long int q;
4403

  
4404
    st0 = floatx80_to_double(ST0);
4405
    st1 = floatx80_to_double(ST1);
4406

  
4407
    if (isinf(st0) || isnan(st0) || isnan(st1) || (st1 == 0.0)) {
4408
        ST0 = double_to_floatx80(0.0 / 0.0); /* NaN */
4409
        env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
4410
        return;
4411
    }
4412

  
4413
    fpsrcop = st0;
4414
    fptemp = st1;
4415
    fpsrcop1.d = ST0;
4416
    fptemp1.d = ST1;
4417
    expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
4418

  
4419
    if (expdif < 0) {
4420
        /* optimisation? taken from the AMD docs */
4421
        env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
4422
        /* ST0 is unchanged */
4423
        return;
4424
    }
4425

  
4426
    if (expdif < 53) {
4427
        dblq = fpsrcop / fptemp;
4428
        /* round dblq towards nearest integer */
4429
        dblq = rint(dblq);
4430
        st0 = fpsrcop - fptemp * dblq;
4431

  
4432
        /* convert dblq to q by truncating towards zero */
4433
        if (dblq < 0.0) {
4434
            q = (signed long long int)(-dblq);
4435
        } else {
4436
            q = (signed long long int)dblq;
4437
        }
4438

  
4439
        env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
4440
        /* (C0,C3,C1) <-- (q2,q1,q0) */
4441
        env->fpus |= (q & 0x4) << (8 - 2);  /* (C0) <-- q2 */
4442
        env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */
4443
        env->fpus |= (q & 0x1) << (9 - 0);  /* (C1) <-- q0 */
4444
    } else {
4445
        env->fpus |= 0x400;  /* C2 <-- 1 */
4446
        fptemp = pow(2.0, expdif - 50);
4447
        fpsrcop = (st0 / st1) / fptemp;
4448
        /* fpsrcop = integer obtained by chopping */
4449
        fpsrcop = (fpsrcop < 0.0) ?
4450
                  -(floor(fabs(fpsrcop))) : floor(fpsrcop);
4451
        st0 -= (st1 * fpsrcop * fptemp);
4452
    }
4453
    ST0 = double_to_floatx80(st0);
4454
}
4455

  
4456
void helper_fprem(void)
4457
{
4458
    double st0, st1, dblq, fpsrcop, fptemp;
4459
    CPU_LDoubleU fpsrcop1, fptemp1;
4460
    int expdif;
4461
    signed long long int q;
4462

  
4463
    st0 = floatx80_to_double(ST0);
4464
    st1 = floatx80_to_double(ST1);
4465

  
4466
    if (isinf(st0) || isnan(st0) || isnan(st1) || (st1 == 0.0)) {
4467
        ST0 = double_to_floatx80(0.0 / 0.0); /* NaN */
4468
        env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
4469
        return;
4470
    }
4471

  
4472
    fpsrcop = st0;
4473
    fptemp = st1;
4474
    fpsrcop1.d = ST0;
4475
    fptemp1.d = ST1;
4476
    expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
4477

  
4478
    if (expdif < 0) {
4479
        /* optimisation? taken from the AMD docs */
4480
        env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
4481
        /* ST0 is unchanged */
4482
        return;
4483
    }
4484

  
4485
    if (expdif < 53) {
4486
        dblq = fpsrcop / fptemp; /* ST0 / ST1 */
4487
        /* round dblq towards zero */
4488
        dblq = (dblq < 0.0) ? ceil(dblq) : floor(dblq);
4489
        st0 = fpsrcop - fptemp * dblq; /* fpsrcop is ST0 */
4490

  
4491
        /* convert dblq to q by truncating towards zero */
4492
        if (dblq < 0.0) {
4493
            q = (signed long long int)(-dblq);
4494
        } else {
4495
            q = (signed long long int)dblq;
4496
        }
4497

  
4498
        env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
4499
        /* (C0,C3,C1) <-- (q2,q1,q0) */
4500
        env->fpus |= (q & 0x4) << (8 - 2);  /* (C0) <-- q2 */
4501
        env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */
4502
        env->fpus |= (q & 0x1) << (9 - 0);  /* (C1) <-- q0 */
4503
    } else {
4504
        int N = 32 + (expdif % 32); /* as per AMD docs */
4505

  
4506
        env->fpus |= 0x400;  /* C2 <-- 1 */
4507
        fptemp = pow(2.0, (double)(expdif - N));
4508
        fpsrcop = (st0 / st1) / fptemp;
4509
        /* fpsrcop = integer obtained by chopping */
4510
        fpsrcop = (fpsrcop < 0.0) ?
4511
                  -(floor(fabs(fpsrcop))) : floor(fpsrcop);
4512
        st0 -= (st1 * fpsrcop * fptemp);
4513
    }
4514
    ST0 = double_to_floatx80(st0);
4515
}
4516

  
4517
void helper_fyl2xp1(void)
4518
{
4519
    double fptemp = floatx80_to_double(ST0);
4520

  
4521
    if ((fptemp + 1.0) > 0.0) {
4522
        fptemp = log(fptemp + 1.0) / log(2.0); /* log2(ST + 1.0) */
4523
        fptemp *= floatx80_to_double(ST1);
4524
        ST1 = double_to_floatx80(fptemp);
4525
        fpop();
4526
    } else {
4527
        env->fpus &= ~0x4700;
4528
        env->fpus |= 0x400;
4529
    }
4530
}
4531

  
4532
void helper_fsqrt(void)
4533
{
4534
    if (floatx80_is_neg(ST0)) {
4535
        env->fpus &= ~0x4700;  /* (C3,C2,C1,C0) <-- 0000 */
4536
        env->fpus |= 0x400;
4537
    }
4538
    ST0 = floatx80_sqrt(ST0, &env->fp_status);
4539
}
4540

  
4541
void helper_fsincos(void)
4542
{
4543
    double fptemp = floatx80_to_double(ST0);
4544

  
4545
    if ((fptemp > MAXTAN) || (fptemp < -MAXTAN)) {
4546
        env->fpus |= 0x400;
4547
    } else {
4548
        ST0 = double_to_floatx80(sin(fptemp));
4549
        fpush();
4550
        ST0 = double_to_floatx80(cos(fptemp));
4551
        env->fpus &= ~0x400;  /* C2 <-- 0 */
4552
        /* the above code is for |arg| < 2**63 only */
4553
    }
4554
}
4555

  
4556
void helper_frndint(void)
4557
{
4558
    ST0 = floatx80_round_to_int(ST0, &env->fp_status);
4559
}
4560

  
4561
void helper_fscale(void)
4562
{
4563
    if (floatx80_is_any_nan(ST1)) {
4564
        ST0 = ST1;
4565
    } else {
4566
        int n = floatx80_to_int32_round_to_zero(ST1, &env->fp_status);
4567
        ST0 = floatx80_scalbn(ST0, n, &env->fp_status);
4568
    }
4569
}
4570

  
4571
void helper_fsin(void)
4572
{
4573
    double fptemp = floatx80_to_double(ST0);
4574

  
4575
    if ((fptemp > MAXTAN) || (fptemp < -MAXTAN)) {
4576
        env->fpus |= 0x400;
4577
    } else {
4578
        ST0 = double_to_floatx80(sin(fptemp));
4579
        env->fpus &= ~0x400;  /* C2 <-- 0 */
4580
        /* the above code is for |arg| < 2**53 only */
4581
    }
4582
}
4583

  
4584
void helper_fcos(void)
4585
{
4586
    double fptemp = floatx80_to_double(ST0);
4587

  
4588
    if ((fptemp > MAXTAN) || (fptemp < -MAXTAN)) {
4589
        env->fpus |= 0x400;
4590
    } else {
4591
        ST0 = double_to_floatx80(cos(fptemp));
4592
        env->fpus &= ~0x400;  /* C2 <-- 0 */
4593
        /* the above code is for |arg| < 2**63 only */
4594
    }
4595
}
4596

  
4597
void helper_fxam_ST0(void)
4598
{
4599
    CPU_LDoubleU temp;
4600
    int expdif;
4601

  
4602
    temp.d = ST0;
4603

  
4604
    env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
4605
    if (SIGND(temp)) {
4606
        env->fpus |= 0x200; /* C1 <-- 1 */
4607
    }
4608

  
4609
    /* XXX: test fptags too */
4610
    expdif = EXPD(temp);
4611
    if (expdif == MAXEXPD) {
4612
        if (MANTD(temp) == 0x8000000000000000ULL) {
4613
            env->fpus |= 0x500; /* Infinity */
4614
        } else {
4615
            env->fpus |= 0x100; /* NaN */
4616
        }
4617
    } else if (expdif == 0) {
4618
        if (MANTD(temp) == 0) {
4619
            env->fpus |=  0x4000; /* Zero */
4620
        } else {
4621
            env->fpus |= 0x4400; /* Denormal */
4622
        }
4623
    } else {
4624
        env->fpus |= 0x400;
4625
    }
4626
}
4627

  
4628
void helper_fstenv(target_ulong ptr, int data32)
4629
{
4630
    int fpus, fptag, exp, i;
4631
    uint64_t mant;
4632
    CPU_LDoubleU tmp;
4633

  
4634
    fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
4635
    fptag = 0;
4636
    for (i = 7; i >= 0; i--) {
4637
        fptag <<= 2;
4638
        if (env->fptags[i]) {
4639
            fptag |= 3;
4640
        } else {
4641
            tmp.d = env->fpregs[i].d;
4642
            exp = EXPD(tmp);
4643
            mant = MANTD(tmp);
4644
            if (exp == 0 && mant == 0) {
4645
                /* zero */
4646
                fptag |= 1;
4647
            } else if (exp == 0 || exp == MAXEXPD
4648
                       || (mant & (1LL << 63)) == 0) {
4649
                /* NaNs, infinity, denormal */
4650
                fptag |= 2;
4651
            }
4652
        }
4653
    }
4654
    if (data32) {
4655
        /* 32 bit */
4656
        stl(ptr, env->fpuc);
4657
        stl(ptr + 4, fpus);
4658
        stl(ptr + 8, fptag);
4659
        stl(ptr + 12, 0); /* fpip */
4660
        stl(ptr + 16, 0); /* fpcs */
4661
        stl(ptr + 20, 0); /* fpoo */
4662
        stl(ptr + 24, 0); /* fpos */
4663
    } else {
4664
        /* 16 bit */
4665
        stw(ptr, env->fpuc);
4666
        stw(ptr + 2, fpus);
4667
        stw(ptr + 4, fptag);
4668
        stw(ptr + 6, 0);
4669
        stw(ptr + 8, 0);
4670
        stw(ptr + 10, 0);
4671
        stw(ptr + 12, 0);
4672
    }
4673
}
4674

  
4675
void helper_fldenv(target_ulong ptr, int data32)
4676
{
4677
    int i, fpus, fptag;
4678

  
4679
    if (data32) {
4680
        env->fpuc = lduw(ptr);
4681
        fpus = lduw(ptr + 4);
4682
        fptag = lduw(ptr + 8);
4683
    } else {
4684
        env->fpuc = lduw(ptr);
4685
        fpus = lduw(ptr + 2);
4686
        fptag = lduw(ptr + 4);
4687
    }
4688
    env->fpstt = (fpus >> 11) & 7;
4689
    env->fpus = fpus & ~0x3800;
4690
    for (i = 0; i < 8; i++) {
4691
        env->fptags[i] = ((fptag & 3) == 3);
4692
        fptag >>= 2;
4693
    }
4694
}
4695

  
4696
void helper_fsave(target_ulong ptr, int data32)
4697
{
4698
    floatx80 tmp;
4699
    int i;
4700

  
4701
    helper_fstenv(ptr, data32);
4702

  
4703
    ptr += (14 << data32);
4704
    for (i = 0; i < 8; i++) {
4705
        tmp = ST(i);
4706
        helper_fstt(tmp, ptr);
4707
        ptr += 10;
4708
    }
4709

  
4710
    /* fninit */
4711
    env->fpus = 0;
4712
    env->fpstt = 0;
4713
    env->fpuc = 0x37f;
4714
    env->fptags[0] = 1;
4715
    env->fptags[1] = 1;
4716
    env->fptags[2] = 1;
4717
    env->fptags[3] = 1;
4718
    env->fptags[4] = 1;
4719
    env->fptags[5] = 1;
4720
    env->fptags[6] = 1;
4721
    env->fptags[7] = 1;
4722
}
4723

  
4724
void helper_frstor(target_ulong ptr, int data32)
4725
{
4726
    floatx80 tmp;
4727
    int i;
4728

  
4729
    helper_fldenv(ptr, data32);
4730
    ptr += (14 << data32);
4731

  
4732
    for (i = 0; i < 8; i++) {
4733
        tmp = helper_fldt(ptr);
4734
        ST(i) = tmp;
4735
        ptr += 10;
4736
    }
4737
}
4738

  
4739

  
4740
#if defined(CONFIG_USER_ONLY)
4741
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
4742
{
4743
    CPUX86State *saved_env;
4744

  
4745
    saved_env = env;
4746
    env = s;
4747
    if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
4748
        selector &= 0xffff;
4749
        cpu_x86_load_seg_cache(env, seg_reg, selector,
4750
                               (selector << 4), 0xffff, 0);
4751
    } else {
4752
        helper_load_seg(seg_reg, selector);
4753
    }
4754
    env = saved_env;
4755
}
4756

  
4757
void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
4758
{
4759
    CPUX86State *saved_env;
4760

  
4761
    saved_env = env;
4762
    env = s;
4763

  
4764
    helper_fsave(ptr, data32);
4765

  
4766
    env = saved_env;
4767
}
4768

  
4769
void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
4770
{
4771
    CPUX86State *saved_env;
4772

  
4773
    saved_env = env;
4774
    env = s;
4775

  
4776
    helper_frstor(ptr, data32);
4777

  
4778
    env = saved_env;
4779
}
4780
#endif
4781

  
4782
void helper_fxsave(target_ulong ptr, int data64)
4783
{
4784
    int fpus, fptag, i, nb_xmm_regs;
4785
    floatx80 tmp;
4786
    target_ulong addr;
4787

  
4788
    /* The operand must be 16 byte aligned */
4789
    if (ptr & 0xf) {
4790
        raise_exception(env, EXCP0D_GPF);
4791
    }
4792

  
4793
    fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
4794
    fptag = 0;
4795
    for (i = 0; i < 8; i++) {
4796
        fptag |= (env->fptags[i] << i);
4797
    }
4798
    stw(ptr, env->fpuc);
4799
    stw(ptr + 2, fpus);
4800
    stw(ptr + 4, fptag ^ 0xff);
4801
#ifdef TARGET_X86_64
4802
    if (data64) {
4803
        stq(ptr + 0x08, 0); /* rip */
4804
        stq(ptr + 0x10, 0); /* rdp */
4805
    } else
4806
#endif
4807
    {
4808
        stl(ptr + 0x08, 0); /* eip */
4809
        stl(ptr + 0x0c, 0); /* sel  */
4810
        stl(ptr + 0x10, 0); /* dp */
4811
        stl(ptr + 0x14, 0); /* sel  */
4812
    }
4813

  
4814
    addr = ptr + 0x20;
4815
    for (i = 0; i < 8; i++) {
4816
        tmp = ST(i);
4817
        helper_fstt(tmp, addr);
4818
        addr += 16;
4819
    }
4820

  
4821
    if (env->cr[4] & CR4_OSFXSR_MASK) {
4822
        /* XXX: finish it */
4823
        stl(ptr + 0x18, env->mxcsr); /* mxcsr */
4824
        stl(ptr + 0x1c, 0x0000ffff); /* mxcsr_mask */
4825
        if (env->hflags & HF_CS64_MASK) {
4826
            nb_xmm_regs = 16;
4827
        } else {
4828
            nb_xmm_regs = 8;
4829
        }
4830
        addr = ptr + 0xa0;
4831
        /* Fast FXSAVE leaves out the XMM registers */
4832
        if (!(env->efer & MSR_EFER_FFXSR)
4833
            || (env->hflags & HF_CPL_MASK)
4834
            || !(env->hflags & HF_LMA_MASK)) {
4835
            for (i = 0; i < nb_xmm_regs; i++) {
4836
                stq(addr, env->xmm_regs[i].XMM_Q(0));
4837
                stq(addr + 8, env->xmm_regs[i].XMM_Q(1));
4838
                addr += 16;
4839
            }
4840
        }
4841
    }
4842
}
4843

  
4844
void helper_fxrstor(target_ulong ptr, int data64)
4845
{
4846
    int i, fpus, fptag, nb_xmm_regs;
4847
    floatx80 tmp;
4848
    target_ulong addr;
4849

  
4850
    /* The operand must be 16 byte aligned */
4851
    if (ptr & 0xf) {
4852
        raise_exception(env, EXCP0D_GPF);
4853
    }
4854

  
4855
    env->fpuc = lduw(ptr);
4856
    fpus = lduw(ptr + 2);
4857
    fptag = lduw(ptr + 4);
4858
    env->fpstt = (fpus >> 11) & 7;
4859
    env->fpus = fpus & ~0x3800;
4860
    fptag ^= 0xff;
4861
    for (i = 0; i < 8; i++) {
4862
        env->fptags[i] = ((fptag >> i) & 1);
4863
    }
4864

  
4865
    addr = ptr + 0x20;
4866
    for (i = 0; i < 8; i++) {
4867
        tmp = helper_fldt(addr);
4868
        ST(i) = tmp;
4869
        addr += 16;
4870
    }
4871

  
4872
    if (env->cr[4] & CR4_OSFXSR_MASK) {
4873
        /* XXX: finish it */
4874
        env->mxcsr = ldl(ptr + 0x18);
4875
        /* ldl(ptr + 0x1c); */
4876
        if (env->hflags & HF_CS64_MASK) {
4877
            nb_xmm_regs = 16;
4878
        } else {
4879
            nb_xmm_regs = 8;
4880
        }
4881
        addr = ptr + 0xa0;
4882
        /* Fast FXRESTORE leaves out the XMM registers */
4883
        if (!(env->efer & MSR_EFER_FFXSR)
4884
            || (env->hflags & HF_CPL_MASK)
4885
            || !(env->hflags & HF_LMA_MASK)) {
4886
            for (i = 0; i < nb_xmm_regs; i++) {
4887
                env->xmm_regs[i].XMM_Q(0) = ldq(addr);
4888
                env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8);
4889
                addr += 16;
4890
            }
4891
        }
4892
    }
4893
}
4894

  
4895
void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, floatx80 f)
4896
{
4897
    CPU_LDoubleU temp;
4898

  
4899
    temp.d = f;
4900
    *pmant = temp.l.lower;
4901
    *pexp = temp.l.upper;
4902
}
4903

  
4904
floatx80 cpu_set_fp80(uint64_t mant, uint16_t upper)
4905
{
4906
    CPU_LDoubleU temp;
4907

  
4908
    temp.l.upper = upper;
4909
    temp.l.lower = mant;
4910
    return temp.d;
4911
}
4912

  
4913
#ifdef TARGET_X86_64
4914
static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
4915
{
4916
    *plow += a;
4917
    /* carry test */
4918
    if (*plow < a) {
4919
        (*phigh)++;
4920
    }
4921
    *phigh += b;
4922
}
4923

  
4924
static void neg128(uint64_t *plow, uint64_t *phigh)
4925
{
4926
    *plow = ~*plow;
4927
    *phigh = ~*phigh;
4928
    add128(plow, phigh, 1, 0);
4929
}
4930

  
4931
/* return TRUE if overflow */
4932
static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
4933
{
4934
    uint64_t q, r, a1, a0;
4935
    int i, qb, ab;
4936

  
4937
    a0 = *plow;
4938
    a1 = *phigh;
4939
    if (a1 == 0) {
4940
        q = a0 / b;
4941
        r = a0 % b;
4942
        *plow = q;
4943
        *phigh = r;
4944
    } else {
4945
        if (a1 >= b) {
4946
            return 1;
4947
        }
4948
        /* XXX: use a better algorithm */
4949
        for (i = 0; i < 64; i++) {
4950
            ab = a1 >> 63;
4951
            a1 = (a1 << 1) | (a0 >> 63);
4952
            if (ab || a1 >= b) {
4953
                a1 -= b;
4954
                qb = 1;
4955
            } else {
4956
                qb = 0;
4957
            }
4958
            a0 = (a0 << 1) | qb;
4959
        }
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff