diff options
author | pbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162> | 2008-03-31 03:47:19 +0000 |
---|---|---|
committer | pbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162> | 2008-03-31 03:47:19 +0000 |
commit | 4373f3ceeb419263d63109408b86f398564c9536 (patch) | |
tree | a8e7239898fd97ad3535f72f21efe2f55ccaf00a | |
parent | b010980544b543d421b3f514bba3cafc59b3a3db (diff) | |
download | qemu-4373f3ceeb419263d63109408b86f398564c9536.tar.gz qemu-4373f3ceeb419263d63109408b86f398564c9536.tar.bz2 qemu-4373f3ceeb419263d63109408b86f398564c9536.zip |
ARM TCG conversion 10/16.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4147 c046a42c-6fe2-441c-8c8c-71466251a162
-rw-r--r-- | target-arm/cpu.h | 3 | ||||
-rw-r--r-- | target-arm/exec.h | 25 | ||||
-rw-r--r-- | target-arm/helper.c | 363 | ||||
-rw-r--r-- | target-arm/helpers.h | 63 | ||||
-rw-r--r-- | target-arm/op.c | 313 | ||||
-rw-r--r-- | target-arm/op_helper.c | 188 | ||||
-rw-r--r-- | target-arm/op_mem.h | 18 | ||||
-rw-r--r-- | target-arm/op_neon.h | 56 | ||||
-rw-r--r-- | target-arm/translate.c | 334 |
9 files changed, 678 insertions, 685 deletions
diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 275733e9c1..1feec83300 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -168,9 +168,6 @@ typedef struct CPUARMState { int vec_len; int vec_stride; - /* Temporary variables if we don't have spare fp regs. */ - float32 tmp0s, tmp1s; - float64 tmp0d, tmp1d; /* scratch space when Tn are not sufficient. */ uint32_t scratch[8]; diff --git a/target-arm/exec.h b/target-arm/exec.h index 9b284f2872..d95309811d 100644 --- a/target-arm/exec.h +++ b/target-arm/exec.h @@ -25,13 +25,6 @@ register uint32_t T0 asm(AREG1); register uint32_t T1 asm(AREG2); register uint32_t T2 asm(AREG3); -/* TODO: Put these in FP regs on targets that have such things. */ -/* It is ok for FT0s and FT0d to overlap. Likewise FT1s and FT1d. */ -#define FT0s env->vfp.tmp0s -#define FT1s env->vfp.tmp1s -#define FT0d env->vfp.tmp0d -#define FT1d env->vfp.tmp1d - #define M0 env->iwmmxt.val #include "cpu.h" @@ -83,23 +76,5 @@ void cpu_loop_exit(void); void raise_exception(int); -void do_vfp_abss(void); -void do_vfp_absd(void); -void do_vfp_negs(void); -void do_vfp_negd(void); -void do_vfp_sqrts(void); -void do_vfp_sqrtd(void); -void do_vfp_cmps(void); -void do_vfp_cmpd(void); -void do_vfp_cmpes(void); -void do_vfp_cmped(void); -void do_vfp_set_fpscr(void); -void do_vfp_get_fpscr(void); -float32 helper_recps_f32(float32, float32); -float32 helper_rsqrts_f32(float32, float32); -uint32_t helper_recpe_u32(uint32_t); -uint32_t helper_rsqrte_u32(uint32_t); -float32 helper_recpe_f32(float32); -float32 helper_rsqrte_f32(float32); void helper_neon_tbl(int rn, int maxindex); uint32_t helper_neon_mul_p8(uint32_t op1, uint32_t op2); diff --git a/target-arm/helper.c b/target-arm/helper.c index 8985c8855a..8e737a8916 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -2167,3 +2167,366 @@ uint32_t HELPER(sel_flags)(uint32_t flags, uint32_t a, uint32_t b) return (a & mask) | (b & ~mask); } + +/* VFP support. We follow the convention used for VFP instrunctions: + Single precition routines have a "s" suffix, double precision a + "d" suffix. */ + +/* Convert host exception flags to vfp form. */ +static inline int vfp_exceptbits_from_host(int host_bits) +{ + int target_bits = 0; + + if (host_bits & float_flag_invalid) + target_bits |= 1; + if (host_bits & float_flag_divbyzero) + target_bits |= 2; + if (host_bits & float_flag_overflow) + target_bits |= 4; + if (host_bits & float_flag_underflow) + target_bits |= 8; + if (host_bits & float_flag_inexact) + target_bits |= 0x10; + return target_bits; +} + +uint32_t HELPER(vfp_get_fpscr)(CPUState *env) +{ + int i; + uint32_t fpscr; + + fpscr = (env->vfp.xregs[ARM_VFP_FPSCR] & 0xffc8ffff) + | (env->vfp.vec_len << 16) + | (env->vfp.vec_stride << 20); + i = get_float_exception_flags(&env->vfp.fp_status); + fpscr |= vfp_exceptbits_from_host(i); + return fpscr; +} + +/* Convert vfp exception flags to target form. */ +static inline int vfp_exceptbits_to_host(int target_bits) +{ + int host_bits = 0; + + if (target_bits & 1) + host_bits |= float_flag_invalid; + if (target_bits & 2) + host_bits |= float_flag_divbyzero; + if (target_bits & 4) + host_bits |= float_flag_overflow; + if (target_bits & 8) + host_bits |= float_flag_underflow; + if (target_bits & 0x10) + host_bits |= float_flag_inexact; + return host_bits; +} + +void HELPER(vfp_set_fpscr)(CPUState *env, uint32_t val) +{ + int i; + uint32_t changed; + + changed = env->vfp.xregs[ARM_VFP_FPSCR]; + env->vfp.xregs[ARM_VFP_FPSCR] = (val & 0xffc8ffff); + env->vfp.vec_len = (val >> 16) & 7; + env->vfp.vec_stride = (val >> 20) & 3; + + changed ^= val; + if (changed & (3 << 22)) { + i = (val >> 22) & 3; + switch (i) { + case 0: + i = float_round_nearest_even; + break; + case 1: + i = float_round_up; + break; + case 2: + i = float_round_down; + break; + case 3: + i = float_round_to_zero; + break; + } + set_float_rounding_mode(i, &env->vfp.fp_status); + } + + i = vfp_exceptbits_to_host((val >> 8) & 0x1f); + set_float_exception_flags(i, &env->vfp.fp_status); + /* XXX: FZ and DN are not implemented. */ +} + +#define VFP_HELPER(name, p) HELPER(glue(glue(vfp_,name),p)) + +#define VFP_BINOP(name) \ +float32 VFP_HELPER(name, s)(float32 a, float32 b, CPUState *env) \ +{ \ + return float32_ ## name (a, b, &env->vfp.fp_status); \ +} \ +float64 VFP_HELPER(name, d)(float64 a, float64 b, CPUState *env) \ +{ \ + return float64_ ## name (a, b, &env->vfp.fp_status); \ +} +VFP_BINOP(add) +VFP_BINOP(sub) +VFP_BINOP(mul) +VFP_BINOP(div) +#undef VFP_BINOP + +float32 VFP_HELPER(neg, s)(float32 a) +{ + return float32_chs(a); +} + +float64 VFP_HELPER(neg, d)(float64 a) +{ + return float32_chs(a); +} + +float32 VFP_HELPER(abs, s)(float32 a) +{ + return float32_abs(a); +} + +float64 VFP_HELPER(abs, d)(float64 a) +{ + return float32_abs(a); +} + +float32 VFP_HELPER(sqrt, s)(float32 a, CPUState *env) +{ + return float32_sqrt(a, &env->vfp.fp_status); +} + +float64 VFP_HELPER(sqrt, d)(float64 a, CPUState *env) +{ + return float64_sqrt(a, &env->vfp.fp_status); +} + +/* XXX: check quiet/signaling case */ +#define DO_VFP_cmp(p, type) \ +void VFP_HELPER(cmp, p)(type a, type b, CPUState *env) \ +{ \ + uint32_t flags; \ + switch(type ## _compare_quiet(a, b, &env->vfp.fp_status)) { \ + case 0: flags = 0x6; break; \ + case -1: flags = 0x8; break; \ + case 1: flags = 0x2; break; \ + default: case 2: flags = 0x3; break; \ + } \ + env->vfp.xregs[ARM_VFP_FPSCR] = (flags << 28) \ + | (env->vfp.xregs[ARM_VFP_FPSCR] & 0x0fffffff); \ +} \ +void VFP_HELPER(cmpe, p)(type a, type b, CPUState *env) \ +{ \ + uint32_t flags; \ + switch(type ## _compare(a, b, &env->vfp.fp_status)) { \ + case 0: flags = 0x6; break; \ + case -1: flags = 0x8; break; \ + case 1: flags = 0x2; break; \ + default: case 2: flags = 0x3; break; \ + } \ + env->vfp.xregs[ARM_VFP_FPSCR] = (flags << 28) \ + | (env->vfp.xregs[ARM_VFP_FPSCR] & 0x0fffffff); \ +} +DO_VFP_cmp(s, float32) +DO_VFP_cmp(d, float64) +#undef DO_VFP_cmp + +/* Helper routines to perform bitwise copies between float and int. */ +static inline float32 vfp_itos(uint32_t i) +{ + union { + uint32_t i; + float32 s; + } v; + + v.i = i; + return v.s; +} + +static inline uint32_t vfp_stoi(float32 s) +{ + union { + uint32_t i; + float32 s; + } v; + + v.s = s; + return v.i; +} + +static inline float64 vfp_itod(uint64_t i) +{ + union { + uint64_t i; + float64 d; + } v; + + v.i = i; + return v.d; +} + +static inline uint64_t vfp_dtoi(float64 d) +{ + union { + uint64_t i; + float64 d; + } v; + + v.d = d; + return v.i; +} + +/* Integer to float conversion. */ +float32 VFP_HELPER(uito, s)(float32 x, CPUState *env) +{ + return uint32_to_float32(vfp_stoi(x), &env->vfp.fp_status); +} + +float64 VFP_HELPER(uito, d)(float32 x, CPUState *env) +{ + return uint32_to_float64(vfp_stoi(x), &env->vfp.fp_status); +} + +float32 VFP_HELPER(sito, s)(float32 x, CPUState *env) +{ + return int32_to_float32(vfp_stoi(x), &env->vfp.fp_status); +} + +float64 VFP_HELPER(sito, d)(float32 x, CPUState *env) +{ + return int32_to_float64(vfp_stoi(x), &env->vfp.fp_status); +} + +/* Float to integer conversion. */ +float32 VFP_HELPER(toui, s)(float32 x, CPUState *env) +{ + return vfp_itos(float32_to_uint32(x, &env->vfp.fp_status)); +} + +float32 VFP_HELPER(toui, d)(float64 x, CPUState *env) +{ + return vfp_itos(float64_to_uint32(x, &env->vfp.fp_status)); +} + +float32 VFP_HELPER(tosi, s)(float32 x, CPUState *env) +{ + return vfp_itos(float32_to_int32(x, &env->vfp.fp_status)); +} + +float32 VFP_HELPER(tosi, d)(float64 x, CPUState *env) +{ + return vfp_itos(float64_to_int32(x, &env->vfp.fp_status)); +} + +float32 VFP_HELPER(touiz, s)(float32 x, CPUState *env) +{ + return vfp_itos(float32_to_uint32_round_to_zero(x, &env->vfp.fp_status)); +} + +float32 VFP_HELPER(touiz, d)(float64 x, CPUState *env) +{ + return vfp_itos(float64_to_uint32_round_to_zero(x, &env->vfp.fp_status)); +} + +float32 VFP_HELPER(tosiz, s)(float32 x, CPUState *env) +{ + return vfp_itos(float32_to_int32_round_to_zero(x, &env->vfp.fp_status)); +} + +float32 VFP_HELPER(tosiz, d)(float64 x, CPUState *env) +{ + return vfp_itos(float64_to_int32_round_to_zero(x, &env->vfp.fp_status)); +} + +/* floating point conversion */ +float64 VFP_HELPER(fcvtd, s)(float32 x, CPUState *env) +{ + return float32_to_float64(x, &env->vfp.fp_status); +} + +float32 VFP_HELPER(fcvts, d)(float64 x, CPUState *env) +{ + return float64_to_float32(x, &env->vfp.fp_status); +} + +/* VFP3 fixed point conversion. */ +#define VFP_CONV_FIX(name, p, ftype, itype, sign) \ +ftype VFP_HELPER(name##to, p)(ftype x, uint32_t shift, CPUState *env) \ +{ \ + ftype tmp; \ + tmp = sign##int32_to_##ftype ((itype)vfp_##p##toi(x), \ + &env->vfp.fp_status); \ + return ftype##_scalbn(tmp, shift, &env->vfp.fp_status); \ +} \ +ftype VFP_HELPER(to##name, p)(ftype x, uint32_t shift, CPUState *env) \ +{ \ + ftype tmp; \ + tmp = ftype##_scalbn(x, shift, &env->vfp.fp_status); \ + return vfp_ito##p((itype)ftype##_to_##sign##int32_round_to_zero(tmp, \ + &env->vfp.fp_status)); \ +} + +VFP_CONV_FIX(sh, d, float64, int16, ) +VFP_CONV_FIX(sl, d, float64, int32, ) +VFP_CONV_FIX(uh, d, float64, uint16, u) +VFP_CONV_FIX(ul, d, float64, uint32, u) +VFP_CONV_FIX(sh, s, float32, int16, ) +VFP_CONV_FIX(sl, s, float32, int32, ) +VFP_CONV_FIX(uh, s, float32, uint16, u) +VFP_CONV_FIX(ul, s, float32, uint32, u) +#undef VFP_CONV_FIX + +float32 HELPER(recps_f32)(float32 a, float32 b, CPUState *env) +{ + float_status *s = &env->vfp.fp_status; + float32 two = int32_to_float32(2, s); + return float32_sub(two, float32_mul(a, b, s), s); +} + +float32 HELPER(rsqrts_f32)(float32 a, float32 b, CPUState *env) +{ + float_status *s = &env->vfp.fp_status; + float32 three = int32_to_float32(3, s); + return float32_sub(three, float32_mul(a, b, s), s); +} + +/* TODO: The architecture specifies the value that the estimate functions + should return. We return the exact reciprocal/root instead. */ +float32 HELPER(recpe_f32)(float32 a, CPUState *env) +{ + float_status *s = &env->vfp.fp_status; + float32 one = int32_to_float32(1, s); + return float32_div(one, a, s); +} + +float32 HELPER(rsqrte_f32)(float32 a, CPUState *env) +{ + float_status *s = &env->vfp.fp_status; + float32 one = int32_to_float32(1, s); + return float32_div(one, float32_sqrt(a, s), s); +} + +uint32_t HELPER(recpe_u32)(uint32_t a, CPUState *env) +{ + float_status *s = &env->vfp.fp_status; + float32 tmp; + tmp = int32_to_float32(a, s); + tmp = float32_scalbn(tmp, -32, s); + tmp = helper_recpe_f32(tmp, env); + tmp = float32_scalbn(tmp, 31, s); + return float32_to_int32(tmp, s); +} + +uint32_t HELPER(rsqrte_u32)(uint32_t a, CPUState *env) +{ + float_status *s = &env->vfp.fp_status; + float32 tmp; + tmp = int32_to_float32(a, s); + tmp = float32_scalbn(tmp, -32, s); + tmp = helper_rsqrte_f32(tmp, env); + tmp = float32_scalbn(tmp, 31, s); + return float32_to_int32(tmp, s); +} + diff --git a/target-arm/helpers.h b/target-arm/helpers.h index 12c9343f98..e4c50c6894 100644 --- a/target-arm/helpers.h +++ b/target-arm/helpers.h @@ -122,6 +122,69 @@ DEF_HELPER_0_3(set_r13_banked, void, (CPUState *, uint32_t, uint32_t)) DEF_HELPER_1_1(get_user_reg, uint32_t, (uint32_t)) DEF_HELPER_0_2(set_user_reg, void, (uint32_t, uint32_t)) +DEF_HELPER_1_1(vfp_get_fpscr, uint32_t, (CPUState *)) +DEF_HELPER_0_2(vfp_set_fpscr, void, (CPUState *, uint32_t)) + +DEF_HELPER_1_3(vfp_adds, float32, (float32, float32, CPUState *)) +DEF_HELPER_1_3(vfp_addd, float64, (float64, float64, CPUState *)) +DEF_HELPER_1_3(vfp_subs, float32, (float32, float32, CPUState *)) +DEF_HELPER_1_3(vfp_subd, float64, (float64, float64, CPUState *)) +DEF_HELPER_1_3(vfp_muls, float32, (float32, float32, CPUState *)) +DEF_HELPER_1_3(vfp_muld, float64, (float64, float64, CPUState *)) +DEF_HELPER_1_3(vfp_divs, float32, (float32, float32, CPUState *)) +DEF_HELPER_1_3(vfp_divd, float64, (float64, float64, CPUState *)) +DEF_HELPER_1_1(vfp_negs, float32, (float32)) +DEF_HELPER_1_1(vfp_negd, float64, (float64)) +DEF_HELPER_1_1(vfp_abss, float32, (float32)) +DEF_HELPER_1_1(vfp_absd, float64, (float64)) +DEF_HELPER_1_2(vfp_sqrts, float32, (float32, CPUState *)) +DEF_HELPER_1_2(vfp_sqrtd, float64, (float64, CPUState *)) +DEF_HELPER_0_3(vfp_cmps, void, (float32, float32, CPUState *)) +DEF_HELPER_0_3(vfp_cmpd, void, (float64, float64, CPUState *)) +DEF_HELPER_0_3(vfp_cmpes, void, (float32, float32, CPUState *)) +DEF_HELPER_0_3(vfp_cmped, void, (float64, float64, CPUState *)) + +DEF_HELPER_1_2(vfp_fcvtds, float64, (float32, CPUState *)) +DEF_HELPER_1_2(vfp_fcvtsd, float32, (float64, CPUState *)) + +DEF_HELPER_1_2(vfp_uitos, float32, (float32, CPUState *)) +DEF_HELPER_1_2(vfp_uitod, float64, (float32, CPUState *)) +DEF_HELPER_1_2(vfp_sitos, float32, (float32, CPUState *)) +DEF_HELPER_1_2(vfp_sitod, float64, (float32, CPUState *)) + +DEF_HELPER_1_2(vfp_touis, float32, (float32, CPUState *)) +DEF_HELPER_1_2(vfp_touid, float32, (float64, CPUState *)) +DEF_HELPER_1_2(vfp_touizs, float32, (float32, CPUState *)) +DEF_HELPER_1_2(vfp_touizd, float32, (float64, CPUState *)) +DEF_HELPER_1_2(vfp_tosis, float32, (float32, CPUState *)) +DEF_HELPER_1_2(vfp_tosid, float32, (float64, CPUState *)) +DEF_HELPER_1_2(vfp_tosizs, float32, (float32, CPUState *)) +DEF_HELPER_1_2(vfp_tosizd, float32, (float64, CPUState *)) + +DEF_HELPER_1_3(vfp_toshs, float32, (float32, uint32_t, CPUState *)) +DEF_HELPER_1_3(vfp_tosls, float32, (float32, uint32_t, CPUState *)) +DEF_HELPER_1_3(vfp_touhs, float32, (float32, uint32_t, CPUState *)) +DEF_HELPER_1_3(vfp_touls, float32, (float32, uint32_t, CPUState *)) +DEF_HELPER_1_3(vfp_toshd, float64, (float64, uint32_t, CPUState *)) +DEF_HELPER_1_3(vfp_tosld, float64, (float64, uint32_t, CPUState *)) +DEF_HELPER_1_3(vfp_touhd, float64, (float64, uint32_t, CPUState *)) +DEF_HELPER_1_3(vfp_tould, float64, (float64, uint32_t, CPUState *)) +DEF_HELPER_1_3(vfp_shtos, float32, (float32, uint32_t, CPUState *)) +DEF_HELPER_1_3(vfp_sltos, float32, (float32, uint32_t, CPUState *)) +DEF_HELPER_1_3(vfp_uhtos, float32, (float32, uint32_t, CPUState *)) +DEF_HELPER_1_3(vfp_ultos, float32, (float32, uint32_t, CPUState *)) +DEF_HELPER_1_3(vfp_shtod, float64, (float64, uint32_t, CPUState *)) +DEF_HELPER_1_3(vfp_sltod, float64, (float64, uint32_t, CPUState *)) +DEF_HELPER_1_3(vfp_uhtod, float64, (float64, uint32_t, CPUState *)) +DEF_HELPER_1_3(vfp_ultod, float64, (float64, uint32_t, CPUState *)) + +DEF_HELPER_1_3(recps_f32, float32, (float32, float32, CPUState *)) +DEF_HELPER_1_3(rsqrts_f32, float32, (float32, float32, CPUState *)) +DEF_HELPER_1_2(recpe_f32, float32, (float32, CPUState *)) +DEF_HELPER_1_2(rsqrte_f32, float32, (float32, CPUState *)) +DEF_HELPER_1_2(recpe_u32, uint32_t, (uint32_t, CPUState *)) +DEF_HELPER_1_2(rsqrte_u32, uint32_t, (uint32_t, CPUState *)) + #undef DEF_HELPER #undef DEF_HELPER_0_0 #undef DEF_HELPER_0_1 diff --git a/target-arm/op.c b/target-arm/op.c index 74bf62b723..66dc7375c0 100644 --- a/target-arm/op.c +++ b/target-arm/op.c @@ -252,319 +252,6 @@ void OPPROTO op_rorl_T1_T0_cc(void) FORCE_RET(); } -/* VFP support. We follow the convention used for VFP instrunctions: - Single precition routines have a "s" suffix, double precision a - "d" suffix. */ - -#define VFP_OP(name, p) void OPPROTO op_vfp_##name##p(void) - -#define VFP_BINOP(name) \ -VFP_OP(name, s) \ -{ \ - FT0s = float32_ ## name (FT0s, FT1s, &env->vfp.fp_status); \ -} \ -VFP_OP(name, d) \ -{ \ - FT0d = float64_ ## name (FT0d, FT1d, &env->vfp.fp_status); \ -} -VFP_BINOP(add) -VFP_BINOP(sub) -VFP_BINOP(mul) -VFP_BINOP(div) -#undef VFP_BINOP - -#define VFP_HELPER(name) \ -VFP_OP(name, s) \ -{ \ - do_vfp_##name##s(); \ -} \ -VFP_OP(name, d) \ -{ \ - do_vfp_##name##d(); \ -} -VFP_HELPER(abs) -VFP_HELPER(sqrt) -VFP_HELPER(cmp) -VFP_HELPER(cmpe) -#undef VFP_HELPER - -/* XXX: Will this do the right thing for NANs. Should invert the signbit - without looking at the rest of the value. */ -VFP_OP(neg, s) -{ - FT0s = float32_chs(FT0s); -} - -VFP_OP(neg, d) -{ - FT0d = float64_chs(FT0d); -} - -VFP_OP(F1_ld0, s) -{ - union { - uint32_t i; - float32 s; - } v; - v.i = 0; - FT1s = v.s; -} - -VFP_OP(F1_ld0, d) -{ - union { - uint64_t i; - float64 d; - } v; - v.i = 0; - FT1d = v.d; -} - -/* Helper routines to perform bitwise copies between float and int. */ -static inline float32 vfp_itos(uint32_t i) -{ - union { - uint32_t i; - float32 s; - } v; - - v.i = i; - return v.s; -} - -static inline uint32_t vfp_stoi(float32 s) -{ - union { - uint32_t i; - float32 s; - } v; - - v.s = s; - return v.i; -} - -static inline float64 vfp_itod(uint64_t i) -{ - union { - uint64_t i; - float64 d; - } v; - - v.i = i; - return v.d; -} - -static inline uint64_t vfp_dtoi(float64 d) -{ - union { - uint64_t i; - float64 d; - } v; - - v.d = d; - return v.i; -} - -/* Integer to float conversion. */ -VFP_OP(uito, s) -{ - FT0s = uint32_to_float32(vfp_stoi(FT0s), &env->vfp.fp_status); -} - -VFP_OP(uito, d) -{ - FT0d = uint32_to_float64(vfp_stoi(FT0s), &env->vfp.fp_status); -} - -VFP_OP(sito, s) -{ - FT0s = int32_to_float32(vfp_stoi(FT0s), &env->vfp.fp_status); -} - -VFP_OP(sito, d) -{ - FT0d = int32_to_float64(vfp_stoi(FT0s), &env->vfp.fp_status); -} - -/* Float to integer conversion. */ -VFP_OP(toui, s) -{ - FT0s = vfp_itos(float32_to_uint32(FT0s, &env->vfp.fp_status)); -} - -VFP_OP(toui, d) -{ - FT0s = vfp_itos(float64_to_uint32(FT0d, &env->vfp.fp_status)); -} - -VFP_OP(tosi, s) -{ - FT0s = vfp_itos(float32_to_int32(FT0s, &env->vfp.fp_status)); -} - -VFP_OP(tosi, d) -{ - FT0s = vfp_itos(float64_to_int32(FT0d, &env->vfp.fp_status)); -} - -/* TODO: Set rounding mode properly. */ -VFP_OP(touiz, s) -{ - FT0s = vfp_itos(float32_to_uint32_round_to_zero(FT0s, &env->vfp.fp_status)); -} - -VFP_OP(touiz, d) -{ - FT0s = vfp_itos(float64_to_uint32_round_to_zero(FT0d, &env->vfp.fp_status)); -} - -VFP_OP(tosiz, s) -{ - FT0s = vfp_itos(float32_to_int32_round_to_zero(FT0s, &env->vfp.fp_status)); -} - -VFP_OP(tosiz, d) -{ - FT0s = vfp_itos(float64_to_int32_round_to_zero(FT0d, &env->vfp.fp_status)); -} - -/* floating point conversion */ -VFP_OP(fcvtd, s) -{ - FT0d = float32_to_float64(FT0s, &env->vfp.fp_status); -} - -VFP_OP(fcvts, d) -{ - FT0s = float64_to_float32(FT0d, &env->vfp.fp_status); -} - -/* VFP3 fixed point conversion. */ -#define VFP_CONV_FIX(name, p, ftype, itype, sign) \ -VFP_OP(name##to, p) \ -{ \ - ftype tmp; \ - tmp = sign##int32_to_##ftype ((itype)vfp_##p##toi(FT0##p), \ - &env->vfp.fp_status); \ - FT0##p = ftype##_scalbn(tmp, PARAM1, &env->vfp.fp_status); \ -} \ -VFP_OP(to##name, p) \ -{ \ - ftype tmp; \ - tmp = ftype##_scalbn(FT0##p, PARAM1, &env->vfp.fp_status); \ - FT0##p = vfp_ito##p((itype)ftype##_to_##sign##int32_round_to_zero(tmp, \ - &env->vfp.fp_status)); \ -} - -VFP_CONV_FIX(sh, d, float64, int16, ) -VFP_CONV_FIX(sl, d, float64, int32, ) -VFP_CONV_FIX(uh, d, float64, uint16, u) -VFP_CONV_FIX(ul, d, float64, uint32, u) -VFP_CONV_FIX(sh, s, float32, int16, ) -VFP_CONV_FIX(sl, s, float32, int32, ) -VFP_CONV_FIX(uh, s, float32, uint16, u) -VFP_CONV_FIX(ul, s, float32, uint32, u) - -/* Get and Put values from registers. */ -VFP_OP(getreg_F0, d) -{ - FT0d = *(float64 *)((char *) env + PARAM1); -} - -VFP_OP(getreg_F0, s) -{ - FT0s = *(float32 *)((char *) env + PARAM1); -} - -VFP_OP(getreg_F1, d) -{ - FT1d = *(float64 *)((char *) env + PARAM1); -} - -VFP_OP(getreg_F1, s) -{ - FT1s = *(float32 *)((char *) env + PARAM1); -} - -VFP_OP(setreg_F0, d) -{ - *(float64 *)((char *) env + PARAM1) = FT0d; -} - -VFP_OP(setreg_F0, s) -{ - *(float32 *)((char *) env + PARAM1) = FT0s; -} - -void OPPROTO op_vfp_movl_T0_fpscr(void) -{ - do_vfp_get_fpscr (); -} - -void OPPROTO op_vfp_movl_T0_fpscr_flags(void) -{ - T0 = env->vfp.xregs[ARM_VFP_FPSCR] & (0xf << 28); -} - -void OPPROTO op_vfp_movl_fpscr_T0(void) -{ - do_vfp_set_fpscr(); -} - -void OPPROTO op_vfp_movl_T0_xreg(void) -{ - T0 = env->vfp.xregs[PARAM1]; -} - -void OPPROTO op_vfp_movl_xreg_T0(void) -{ - env->vfp.xregs[PARAM1] = T0; -} - -/* Move between FT0s to T0 */ -void OPPROTO op_vfp_mrs(void) -{ - T0 = vfp_stoi(FT0s); -} - -void OPPROTO op_vfp_msr(void) -{ - FT0s = vfp_itos(T0); -} - -/* Move between FT0d and {T0,T1} */ -void OPPROTO op_vfp_mrrd(void) -{ - CPU_DoubleU u; - - u.d = FT0d; - T0 = u.l.lower; - T1 = u.l.upper; -} - -void OPPROTO op_vfp_mdrr(void) -{ - CPU_DoubleU u; - - u.l.lower = T0; - u.l.upper = T1; - FT0d = u.d; -} - -/* Load immediate. PARAM1 is the 32 most significant bits of the value. */ -void OPPROTO op_vfp_fconstd(void) -{ - CPU_DoubleU u; - u.l.upper = PARAM1; - u.l.lower = 0; - FT0d = u.d; -} - -void OPPROTO op_vfp_fconsts(void) -{ - FT0s = vfp_itos(PARAM1); -} - void OPPROTO op_movl_cp_T0(void) { helper_set_cp(env, PARAM1, T0); diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index 939aebfe6c..6748b06058 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -40,194 +40,6 @@ void cpu_unlock(void) spin_unlock(&global_cpu_lock); } -/* VFP support. */ - -void do_vfp_abss(void) -{ - FT0s = float32_abs(FT0s); -} - -void do_vfp_absd(void) -{ - FT0d = float64_abs(FT0d); -} - -void do_vfp_sqrts(void) -{ - FT0s = float32_sqrt(FT0s, &env->vfp.fp_status); -} - -void do_vfp_sqrtd(void) -{ - FT0d = float64_sqrt(FT0d, &env->vfp.fp_status); -} - -/* XXX: check quiet/signaling case */ -#define DO_VFP_cmp(p, size) \ -void do_vfp_cmp##p(void) \ -{ \ - uint32_t flags; \ - switch(float ## size ## _compare_quiet(FT0##p, FT1##p, &env->vfp.fp_status)) {\ - case 0: flags = 0x6; break;\ - case -1: flags = 0x8; break;\ - case 1: flags = 0x2; break;\ - default: case 2: flags = 0x3; break;\ - }\ - env->vfp.xregs[ARM_VFP_FPSCR] = (flags << 28)\ - | (env->vfp.xregs[ARM_VFP_FPSCR] & 0x0fffffff); \ - FORCE_RET(); \ -}\ -\ -void do_vfp_cmpe##p(void) \ -{ \ - uint32_t flags; \ - switch(float ## size ## _compare(FT0##p, FT1##p, &env->vfp.fp_status)) {\ - case 0: flags = 0x6; break;\ - case -1: flags = 0x8; break;\ - case 1: flags = 0x2; break;\ - default: case 2: flags = 0x3; break;\ - }\ - env->vfp.xregs[ARM_VFP_FPSCR] = (flags << 28)\ - | (env->vfp.xregs[ARM_VFP_FPSCR] & 0x0fffffff); \ - FORCE_RET(); \ -} -DO_VFP_cmp(s, 32) -DO_VFP_cmp(d, 64) -#undef DO_VFP_cmp - -/* Convert host exception flags to vfp form. */ -static inline int vfp_exceptbits_from_host(int host_bits) -{ - int target_bits = 0; - - if (host_bits & float_flag_invalid) - target_bits |= 1; - if (host_bits & float_flag_divbyzero) - target_bits |= 2; - if (host_bits & float_flag_overflow) - target_bits |= 4; - if (host_bits & float_flag_underflow) - target_bits |= 8; - if (host_bits & float_flag_inexact) - target_bits |= 0x10; - return target_bits; -} - -/* Convert vfp exception flags to target form. */ -static inline int vfp_exceptbits_to_host(int target_bits) -{ - int host_bits = 0; - - if (target_bits & 1) - host_bits |= float_flag_invalid; - if (target_bits & 2) - host_bits |= float_flag_divbyzero; - if (target_bits & 4) - host_bits |= float_flag_overflow; - if (target_bits & 8) - host_bits |= float_flag_underflow; - if (target_bits & 0x10) - host_bits |= float_flag_inexact; - return host_bits; -} - -void do_vfp_set_fpscr(void) -{ - int i; - uint32_t changed; - - changed = env->vfp.xregs[ARM_VFP_FPSCR]; - env->vfp.xregs[ARM_VFP_FPSCR] = (T0 & 0xffc8ffff); - env->vfp.vec_len = (T0 >> 16) & 7; - env->vfp.vec_stride = (T0 >> 20) & 3; - - changed ^= T0; - if (changed & (3 << 22)) { - i = (T0 >> 22) & 3; - switch (i) { - case 0: - i = float_round_nearest_even; - break; - case 1: - i = float_round_up; - break; - case 2: - i = float_round_down; - break; - case 3: - i = float_round_to_zero; - break; - } - set_float_rounding_mode(i, &env->vfp.fp_status); - } - - i = vfp_exceptbits_to_host((T0 >> 8) & 0x1f); - set_float_exception_flags(i, &env->vfp.fp_status); - /* XXX: FZ and DN are not implemented. */ -} - -void do_vfp_get_fpscr(void) -{ - int i; - - T0 = (env->vfp.xregs[ARM_VFP_FPSCR] & 0xffc8ffff) | (env->vfp.vec_len << 16) - | (env->vfp.vec_stride << 20); - i = get_float_exception_flags(&env->vfp.fp_status); - T0 |= vfp_exceptbits_from_host(i); -} - -float32 helper_recps_f32(float32 a, float32 b) -{ - float_status *s = &env->vfp.fp_status; - float32 two = int32_to_float32(2, s); - return float32_sub(two, float32_mul(a, b, s), s); -} - -float32 helper_rsqrts_f32(float32 a, float32 b) -{ - float_status *s = &env->vfp.fp_status; - float32 three = int32_to_float32(3, s); - return float32_sub(three, float32_mul(a, b, s), s); -} - -/* TODO: The architecture specifies the value that the estimate functions - should return. We return the exact reciprocal/root instead. */ -float32 helper_recpe_f32(float32 a) -{ - float_status *s = &env->vfp.fp_status; - float32 one = int32_to_float32(1, s); - return float32_div(one, a, s); -} - -float32 helper_rsqrte_f32(float32 a) -{ - float_status *s = &env->vfp.fp_status; - float32 one = int32_to_float32(1, s); - return float32_div(one, float32_sqrt(a, s), s); -} - -uint32_t helper_recpe_u32(uint32_t a) -{ - float_status *s = &env->vfp.fp_status; - float32 tmp; - tmp = int32_to_float32(a, s); - tmp = float32_scalbn(tmp, -32, s); - tmp = helper_recpe_f32(tmp); - tmp = float32_scalbn(tmp, 31, s); - return float32_to_int32(tmp, s); -} - -uint32_t helper_rsqrte_u32(uint32_t a) -{ - float_status *s = &env->vfp.fp_status; - float32 tmp; - tmp = int32_to_float32(a, s); - tmp = float32_scalbn(tmp, -32, s); - tmp = helper_rsqrte_f32(tmp); - tmp = float32_scalbn(tmp, 31, s); - return float32_to_int32(tmp, s); -} - void helper_neon_tbl(int rn, int maxindex) { uint32_t val; diff --git a/target-arm/op_mem.h b/target-arm/op_mem.h index f11c498213..0e2e7b65ef 100644 --- a/target-arm/op_mem.h +++ b/target-arm/op_mem.h @@ -77,24 +77,6 @@ void OPPROTO glue(op_stqex,MEMSUFFIX)(void) FORCE_RET(); } -/* Floating point load/store. Address is in T1 */ -#define VFP_MEM_OP(p, w) \ -void OPPROTO glue(op_vfp_ld##p,MEMSUFFIX)(void) \ -{ \ - FT0##p = glue(ldf##w,MEMSUFFIX)(T1); \ - FORCE_RET(); \ -} \ -void OPPROTO glue(op_vfp_st##p,MEMSUFFIX)(void) \ -{ \ - glue(stf##w,MEMSUFFIX)(T1, FT0##p); \ - FORCE_RET(); \ -} - -VFP_MEM_OP(s,l) -VFP_MEM_OP(d,q) - -#undef VFP_MEM_OP - /* iwMMXt load/store. Address is in T1 */ #define MMX_MEM_OP(name, ldname) \ void OPPROTO glue(op_iwmmxt_ld##name,MEMSUFFIX)(void) \ diff --git a/target-arm/op_neon.h b/target-arm/op_neon.h index e91dcc5278..095165ede5 100644 --- a/target-arm/op_neon.h +++ b/target-arm/op_neon.h @@ -14,6 +14,29 @@ #define NFS &env->vfp.fp_status #define NEON_OP(name) void OPPROTO op_neon_##name (void) +/* Helper routines to perform bitwise copies between float and int. */ +static inline float32 vfp_itos(uint32_t i) +{ + union { + uint32_t i; + float32 s; + } v; + + v.i = i; + return v.s; +} + +static inline uint32_t vfp_stoi(float32 s) +{ + union { + uint32_t i; + float32 s; + } v; + + v.s = s; + return v.i; +} + NEON_OP(getreg_T0) { T0 = *(uint32_t *)((char *) env + PARAM1); @@ -754,18 +777,6 @@ NEON_VOP(qrdmulh_s32, neon_s32, 1) #undef NEON_FN #undef NEON_QDMULH32 -NEON_OP(recps_f32) -{ - T0 = vfp_stoi(helper_recps_f32(vfp_itos(T0), vfp_itos(T1))); - FORCE_RET(); -} - -NEON_OP(rsqrts_f32) -{ - T0 = vfp_stoi(helper_rsqrts_f32(vfp_itos(T0), vfp_itos(T1))); - FORCE_RET(); -} - /* Floating point comparisons produce an integer result. */ #define NEON_VOP_FCMP(name, cmp) \ NEON_OP(name) \ @@ -1702,27 +1713,6 @@ NEON_OP(zip_u16) FORCE_RET(); } -/* Reciprocal/root estimate. */ -NEON_OP(recpe_u32) -{ - T0 = helper_recpe_u32(T0); -} - -NEON_OP(rsqrte_u32) -{ - T0 = helper_rsqrte_u32(T0); -} - -NEON_OP(recpe_f32) -{ - FT0s = helper_recpe_f32(FT0s); -} - -NEON_OP(rsqrte_f32) -{ - FT0s = helper_rsqrte_f32(FT0s); -} - /* Table lookup. This accessed the register file directly. */ NEON_OP(tbl) { diff --git a/target-arm/translate.c b/target-arm/translate.c index 89515cc819..3e7cbe81b6 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -79,6 +79,7 @@ extern int loglevel; static TCGv cpu_env; /* FIXME: These should be removed. */ static TCGv cpu_T[3]; +static TCGv cpu_F0s, cpu_F1s, cpu_F0d, cpu_F1d; /* initialize TCG globals. */ void arm_translate_init(void) @@ -959,16 +960,16 @@ static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn, } } -#define VFP_OP(name) \ -static inline void gen_vfp_##name(int dp) \ -{ \ - if (dp) \ - gen_op_vfp_##name##d(); \ - else \ - gen_op_vfp_##name##s(); \ +#define VFP_OP2(name) \ +static inline void gen_vfp_##name(int dp) \ +{ \ + if (dp) \ + gen_helper_vfp_##name##d(cpu_F0d, cpu_F0d, cpu_F1d, cpu_env); \ + else \ + gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, cpu_F1s, cpu_env); \ } -#define VFP_OP1(name) \ +#define VFP_OP1i(name) \ static inline void gen_vfp_##name(int dp, int arg) \ { \ if (dp) \ @@ -977,55 +978,141 @@ static inline void gen_vfp_##name(int dp, int arg) \ gen_op_vfp_##name##s(arg); \ } -VFP_OP(add) -VFP_OP(sub) -VFP_OP(mul) -VFP_OP(div) -VFP_OP(neg) -VFP_OP(abs) -VFP_OP(sqrt) -VFP_OP(cmp) -VFP_OP(cmpe) -VFP_OP(F1_ld0) -VFP_OP(uito) -VFP_OP(sito) -VFP_OP(toui) -VFP_OP(touiz) -VFP_OP(tosi) -VFP_OP(tosiz) -VFP_OP1(tosh) -VFP_OP1(tosl) -VFP_OP1(touh) -VFP_OP1(toul) -VFP_OP1(shto) -VFP_OP1(slto) -VFP_OP1(uhto) -VFP_OP1(ulto) - -#undef VFP_OP - -static inline void gen_vfp_fconst(int dp, uint32_t val) +VFP_OP2(add) +VFP_OP2(sub) +VFP_OP2(mul) +VFP_OP2(div) + +#undef VFP_OP2 + +static inline void gen_vfp_abs(int dp) +{ + if (dp) + gen_helper_vfp_absd(cpu_F0d, cpu_F0d); + else + gen_helper_vfp_abss(cpu_F0s, cpu_F0s); +} + +static inline void gen_vfp_neg(int dp) +{ + if (dp) + gen_helper_vfp_negd(cpu_F0d, cpu_F0d); + else + gen_helper_vfp_negs(cpu_F0s, cpu_F0s); +} + +static inline void gen_vfp_sqrt(int dp) +{ + if (dp) + gen_helper_vfp_sqrtd(cpu_F0d, cpu_F0d, cpu_env); + else + gen_helper_vfp_sqrts(cpu_F0s, cpu_F0s, cpu_env); +} + +static inline void gen_vfp_cmp(int dp) +{ + if (dp) + gen_helper_vfp_cmpd(cpu_F0d, cpu_F1d, cpu_env); + else + gen_helper_vfp_cmps(cpu_F0s, cpu_F1s, cpu_env); +} + +static inline void gen_vfp_cmpe(int dp) +{ + if (dp) + gen_helper_vfp_cmped(cpu_F0d, cpu_F1d, cpu_env); + else + gen_helper_vfp_cmpes(cpu_F0s, cpu_F1s, cpu_env); +} + +static inline void gen_vfp_F1_ld0(int dp) +{ + if (dp) + tcg_gen_movi_i64(cpu_F0d, 0); + else + tcg_gen_movi_i32(cpu_F0s, 0); +} + +static inline void gen_vfp_uito(int dp) +{ + if (dp) + gen_helper_vfp_uitod(cpu_F0d, cpu_F0s, cpu_env); + else + gen_helper_vfp_uitos(cpu_F0s, cpu_F0s, cpu_env); +} + +static inline void gen_vfp_sito(int dp) +{ + if (dp) + gen_helper_vfp_uitod(cpu_F0d, cpu_F0s, cpu_env); + else + gen_helper_vfp_uitos(cpu_F0s, cpu_F0s, cpu_env); +} + +static inline void gen_vfp_toui(int dp) +{ + if (dp) + gen_helper_vfp_touid(cpu_F0s, cpu_F0d, cpu_env); + else + gen_helper_vfp_touis(cpu_F0s, cpu_F0s, cpu_env); +} + +static inline void gen_vfp_touiz(int dp) +{ + if (dp) + gen_helper_vfp_touizd(cpu_F0s, cpu_F0d, cpu_env); + else + gen_helper_vfp_touizs(cpu_F0s, cpu_F0s, cpu_env); +} + +static inline void gen_vfp_tosi(int dp) +{ + if (dp) + gen_helper_vfp_tosid(cpu_F0s, cpu_F0d, cpu_env); + else + gen_helper_vfp_tosis(cpu_F0s, cpu_F0s, cpu_env); +} + +static inline void gen_vfp_tosiz(int dp) { if (dp) - gen_op_vfp_fconstd(val); + gen_helper_vfp_tosizd(cpu_F0s, cpu_F0d, cpu_env); else - gen_op_vfp_fconsts(val); + gen_helper_vfp_tosizs(cpu_F0s, cpu_F0s, cpu_env); +} + +#define VFP_GEN_FIX(name) \ +static inline void gen_vfp_##name(int dp, int shift) \ +{ \ + if (dp) \ + gen_helper_vfp_##name##d(cpu_F0d, cpu_F0d, tcg_const_i32(shift), cpu_env);\ + else \ + gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, tcg_const_i32(shift), cpu_env);\ } +VFP_GEN_FIX(tosh) +VFP_GEN_FIX(tosl) +VFP_GEN_FIX(touh) +VFP_GEN_FIX(toul) +VFP_GEN_FIX(shto) +VFP_GEN_FIX(slto) +VFP_GEN_FIX(uhto) +VFP_GEN_FIX(ulto) +#undef VFP_GEN_FIX static inline void gen_vfp_ld(DisasContext *s, int dp) { if (dp) - gen_ldst(vfp_ldd, s); + tcg_gen_qemu_ld64(cpu_F0d, cpu_T[1], IS_USER(s)); else - gen_ldst(vfp_lds, s); + tcg_gen_qemu_ld32u(cpu_F0s, cpu_T[1], IS_USER(s)); } static inline void gen_vfp_st(DisasContext *s, int dp) { if (dp) - gen_ldst(vfp_std, s); + tcg_gen_qemu_st64(cpu_F0d, cpu_T[1], IS_USER(s)); else - gen_ldst(vfp_sts, s); + tcg_gen_qemu_st32(cpu_F0s, cpu_T[1], IS_USER(s)); } static inline long @@ -1055,28 +1142,33 @@ neon_reg_offset (int reg, int n) #define NEON_GET_REG(T, reg, n) gen_op_neon_getreg_##T(neon_reg_offset(reg, n)) #define NEON_SET_REG(T, reg, n) gen_op_neon_setreg_##T(neon_reg_offset(reg, n)) +#define tcg_gen_ld_f32 tcg_gen_ld_i32 +#define tcg_gen_ld_f64 tcg_gen_ld_i64 +#define tcg_gen_st_f32 tcg_gen_st_i32 +#define tcg_gen_st_f64 tcg_gen_st_i64 + static inline void gen_mov_F0_vreg(int dp, int reg) { if (dp) - gen_op_vfp_getreg_F0d(vfp_reg_offset(dp, reg)); + tcg_gen_ld_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg)); else - gen_op_vfp_getreg_F0s(vfp_reg_offset(dp, reg)); + tcg_gen_ld_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg)); } static inline void gen_mov_F1_vreg(int dp, int reg) { if (dp) - gen_op_vfp_getreg_F1d(vfp_reg_offset(dp, reg)); + tcg_gen_ld_f64(cpu_F1d, cpu_env, vfp_reg_offset(dp, reg)); else - gen_op_vfp_getreg_F1s(vfp_reg_offset(dp, reg)); + tcg_gen_ld_f32(cpu_F1s, cpu_env, vfp_reg_offset(dp, reg)); } static inline void gen_mov_vreg_F0(int dp, int reg) { if (dp) - gen_op_vfp_setreg_F0d(vfp_reg_offset(dp, reg)); + tcg_gen_st_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg)); else - gen_op_vfp_setreg_F0s(vfp_reg_offset(dp, reg)); + tcg_gen_st_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg)); } #define ARM_CP_RW_BIT (1 << 20) @@ -2262,6 +2354,20 @@ static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn) #define VFP_SREG_M(insn) VFP_SREG(insn, 0, 5) #define VFP_DREG_M(reg, insn) VFP_DREG(reg, insn, 0, 5) +/* Move between integer and VFP cores. */ +static TCGv gen_vfp_mrs(void) +{ + TCGv tmp = new_tmp(); + tcg_gen_mov_i32(tmp, cpu_F0s); + return tmp; +} + +static void gen_vfp_msr(TCGv tmp) +{ + tcg_gen_mov_i32(cpu_F0s, tmp); + dead_tmp(tmp); +} + static inline int vfp_enabled(CPUState * env) { @@ -2274,6 +2380,7 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) { uint32_t rd, rn, rm, op, i, n, offset, delta_d, delta_m, bank_mask; int dp, veclen; + TCGv tmp; if (!arm_feature(env, ARM_FEATURE_VFP)) return 1; @@ -2396,18 +2503,18 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) switch (rn) { case ARM_VFP_FPSID: - /* VFP2 allows access for FSID from userspace. + /* VFP2 allows access to FSID from userspace. VFP3 restricts all id registers to privileged accesses. */ if (IS_USER(s) && arm_feature(env, ARM_FEATURE_VFP3)) return 1; - gen_op_vfp_movl_T0_xreg(rn); + tmp = load_cpu_field(vfp.xregs[rn]); break; case ARM_VFP_FPEXC: if (IS_USER(s)) return 1; - gen_op_vfp_movl_T0_xreg(rn); + tmp = load_cpu_field(vfp.xregs[rn]); break; case ARM_VFP_FPINST: case ARM_VFP_FPINST2: @@ -2415,36 +2522,41 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) if (IS_USER(s) || arm_feature(env, ARM_FEATURE_VFP3)) return 1; - gen_op_vfp_movl_T0_xreg(rn); + tmp = load_cpu_field(vfp.xregs[rn]); break; case ARM_VFP_FPSCR: - if (rd == 15) - gen_op_vfp_movl_T0_fpscr_flags(); - else - gen_op_vfp_movl_T0_fpscr(); + if (rd == 15) { + tmp = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]); + tcg_gen_andi_i32(tmp, tmp, 0xf0000000); + } else { + tmp = new_tmp(); + gen_helper_vfp_get_fpscr(tmp, cpu_env); + } break; case ARM_VFP_MVFR0: case ARM_VFP_MVFR1: if (IS_USER(s) || !arm_feature(env, ARM_FEATURE_VFP3)) return 1; - gen_op_vfp_movl_T0_xreg(rn); + tmp = load_cpu_field(vfp.xregs[rn]); break; default: return 1; } } else { gen_mov_F0_vreg(0, rn); - gen_op_vfp_mrs(); + tmp = gen_vfp_mrs(); } if (rd == 15) { /* Set the 4 flag bits in the CPSR. */ - gen_set_nzcv(cpu_T[0]); - } else - gen_movl_reg_T0(s, rd); + gen_set_nzcv(tmp); + dead_tmp(tmp); + } else { + store_reg(s, rd, tmp); + } } else { /* arm->vfp */ - gen_movl_T0_reg(s, rd); + tmp = load_reg(s, rd); if (insn & (1 << 21)) { rn >>= 1; /* system register */ @@ -2455,24 +2567,25 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) /* Writes are ignored. */ break; case ARM_VFP_FPSCR: - gen_op_vfp_movl_fpscr_T0(); + gen_helper_vfp_set_fpscr(cpu_env, tmp); + dead_tmp(tmp); gen_lookup_tb(s); break; case ARM_VFP_FPEXC: if (IS_USER(s)) return 1; - gen_op_vfp_movl_xreg_T0(rn); + store_cpu_field(tmp, vfp.xregs[rn]); gen_lookup_tb(s); break; case ARM_VFP_FPINST: case ARM_VFP_FPINST2: - gen_op_vfp_movl_xreg_T0(rn); + store_cpu_field(tmp, vfp.xregs[rn]); break; default: return 1; } } else { - gen_op_vfp_msr(); + gen_vfp_msr(tmp); gen_mov_vreg_F0(0, rn); } } @@ -2640,14 +2753,15 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) else i |= 0x4000; n |= i << 16; + tcg_gen_movi_i64(cpu_F0d, ((uint64_t)n) << 32); } else { if (i & 0x40) i |= 0x780; else i |= 0x800; n |= i << 19; + tcg_gen_movi_i32(cpu_F0d, ((uint64_t)n) << 32); } - gen_vfp_fconst(dp, n); break; case 15: /* extension space */ switch (rn) { @@ -2678,9 +2792,9 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) break; case 15: /* single<->double conversion */ if (dp) - gen_op_vfp_fcvtsd(); + gen_helper_vfp_fcvtsd(cpu_F0s, cpu_F0d, cpu_env); else - gen_op_vfp_fcvtds(); + gen_helper_vfp_fcvtds(cpu_F0d, cpu_F0s, cpu_env); break; case 16: /* fuito */ gen_vfp_uito(dp); @@ -2814,31 +2928,35 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) if (insn & ARM_CP_RW_BIT) { /* vfp->arm */ if (dp) { - gen_mov_F0_vreg(1, rm); - gen_op_vfp_mrrd(); - gen_movl_reg_T0(s, rd); - gen_movl_reg_T1(s, rn); + gen_mov_F0_vreg(0, rm * 2); + tmp = gen_vfp_mrs(); + store_reg(s, rd, tmp); + gen_mov_F0_vreg(0, rm * 2 + 1); + tmp = gen_vfp_mrs(); + store_reg(s, rn, tmp); } else { gen_mov_F0_vreg(0, rm); - gen_op_vfp_mrs(); - gen_movl_reg_T0(s, rn); + tmp = gen_vfp_mrs(); + store_reg(s, rn, tmp); gen_mov_F0_vreg(0, rm + 1); - gen_op_vfp_mrs(); - gen_movl_reg_T0(s, rd); + tmp = gen_vfp_mrs(); + store_reg(s, rd, tmp); } } else { /* arm->vfp */ if (dp) { - gen_movl_T0_reg(s, rd); - gen_movl_T1_reg(s, rn); - gen_op_vfp_mdrr(); - gen_mov_vreg_F0(1, rm); + tmp = load_reg(s, rd); + gen_vfp_msr(tmp); + gen_mov_vreg_F0(0, rm * 2); + tmp = load_reg(s, rn); + gen_vfp_msr(tmp); + gen_mov_vreg_F0(0, rm * 2 + 1); } else { - gen_movl_T0_reg(s, rn); - gen_op_vfp_msr(); + tmp = load_reg(s, rn); + gen_vfp_msr(tmp); gen_mov_vreg_F0(0, rm); - gen_movl_T0_reg(s, rd); - gen_op_vfp_msr(); + tmp = load_reg(s, rd); + gen_vfp_msr(tmp); gen_mov_vreg_F0(0, rm + 1); } } @@ -3993,9 +4111,9 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) break; case 31: if (size == 0) - gen_op_neon_recps_f32(); + gen_helper_recps_f32(cpu_T[0], cpu_T[0], cpu_T[1], cpu_env); else - gen_op_neon_rsqrts_f32(); + gen_helper_rsqrts_f32(cpu_T[0], cpu_T[0], cpu_T[1], cpu_env); break; default: abort(); @@ -4242,19 +4360,19 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) } else if (op == 15 || op == 16) { /* VCVT fixed-point. */ for (pass = 0; pass < (q ? 4 : 2); pass++) { - gen_op_vfp_getreg_F0s(neon_reg_offset(rm, pass)); + tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, pass)); if (op & 1) { if (u) - gen_op_vfp_ultos(shift); + gen_vfp_ulto(0, shift); else - gen_op_vfp_sltos(shift); + gen_vfp_slto(0, shift); } else { if (u) - gen_op_vfp_touls(shift); + gen_vfp_toul(0, shift); else - gen_op_vfp_tosls(shift); + gen_vfp_tosl(0, shift); } - gen_op_vfp_setreg_F0s(neon_reg_offset(rd, pass)); + tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, pass)); } } else { return 1; @@ -4898,7 +5016,8 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) elementwise: for (pass = 0; pass < (q ? 4 : 2); pass++) { if (op == 30 || op == 31 || op >= 58) { - gen_op_vfp_getreg_F0s(neon_reg_offset(rm, pass)); + tcg_gen_ld_f32(cpu_F0s, cpu_env, + neon_reg_offset(rm, pass)); } else { NEON_GET_REG(T0, rm, pass); } @@ -5041,10 +5160,10 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) gen_op_neon_ceq_f32(); break; case 30: /* Float VABS */ - gen_op_vfp_abss(); + gen_vfp_abs(0); break; case 31: /* Float VNEG */ - gen_op_vfp_negs(); + gen_vfp_neg(0); break; case 32: /* VSWP */ NEON_GET_REG(T1, rd, pass); @@ -5061,35 +5180,36 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) NEON_SET_REG(T1, rm, pass); break; case 56: /* Integer VRECPE */ - gen_op_neon_recpe_u32(); + gen_helper_recpe_u32(cpu_T[0], cpu_T[0], cpu_env); break; case 57: /* Integer VRSQRTE */ - gen_op_neon_rsqrte_u32(); + gen_helper_rsqrte_u32(cpu_T[0], cpu_T[0], cpu_env); break; case 58: /* Float VRECPE */ - gen_op_neon_recpe_f32(); + gen_helper_recpe_f32(cpu_F0s, cpu_F0s, cpu_env); break; case 59: /* Float VRSQRTE */ - gen_op_neon_rsqrte_f32(); + gen_helper_rsqrte_f32(cpu_F0s, cpu_F0s, cpu_env); break; case 60: /* VCVT.F32.S32 */ - gen_op_vfp_tosizs(); + gen_vfp_tosiz(0); break; case 61: /* VCVT.F32.U32 */ - gen_op_vfp_touizs(); + gen_vfp_touiz(0); break; case 62: /* VCVT.S32.F32 */ - gen_op_vfp_sitos(); + gen_vfp_sito(0); break; case 63: /* VCVT.U32.F32 */ - gen_op_vfp_uitos(); + gen_vfp_uito(0); break; default: /* Reserved: 21, 29, 39-56 */ return 1; } if (op == 30 || op == 31 || op >= 58) { - gen_op_vfp_setreg_F0s(neon_reg_offset(rm, pass)); + tcg_gen_st_f32(cpu_F0s, cpu_env, + neon_reg_offset(rd, pass)); } else { NEON_SET_REG(T0, rd, pass); } @@ -8062,6 +8182,10 @@ static inline int gen_intermediate_code_internal(CPUState *env, dc->user = (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_USR; } #endif + cpu_F0s = tcg_temp_new(TCG_TYPE_I32); + cpu_F1s = tcg_temp_new(TCG_TYPE_I32); + cpu_F0d = tcg_temp_new(TCG_TYPE_I64); + cpu_F1d = tcg_temp_new(TCG_TYPE_I64); next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; lj = -1; /* Reset the conditional execution bits immediately. This avoids |