mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-04 00:03:54 -06:00
ARM TCG conversion 10/16.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4147 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
b010980544
commit
4373f3ceeb
9 changed files with 676 additions and 683 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue