Merge remote branch 'arm/for-anthony' into staging
This commit is contained in:
commit
9d861fa595
@ -101,6 +101,25 @@ int float32_is_signaling_nan( float32 a_ )
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------
|
||||||
|
| Returns a quiet NaN if the single-precision floating point value `a' is a
|
||||||
|
| signaling NaN; otherwise returns `a'.
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
float32 float32_maybe_silence_nan( float32 a_ )
|
||||||
|
{
|
||||||
|
if (float32_is_signaling_nan(a_)) {
|
||||||
|
uint32_t a = float32_val(a_);
|
||||||
|
#if SNAN_BIT_IS_ONE
|
||||||
|
a &= ~(1 << 22);
|
||||||
|
#else
|
||||||
|
a |= (1 << 22);
|
||||||
|
#endif
|
||||||
|
return make_float32(a);
|
||||||
|
}
|
||||||
|
return a_;
|
||||||
|
}
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------
|
/*----------------------------------------------------------------------------
|
||||||
| Returns the result of converting the single-precision floating-point NaN
|
| Returns the result of converting the single-precision floating-point NaN
|
||||||
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
|
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
|
||||||
@ -233,6 +252,25 @@ int float64_is_signaling_nan( float64 a_ )
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------
|
||||||
|
| Returns a quiet NaN if the double-precision floating point value `a' is a
|
||||||
|
| signaling NaN; otherwise returns `a'.
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
float64 float64_maybe_silence_nan( float64 a_ )
|
||||||
|
{
|
||||||
|
if (float64_is_signaling_nan(a_)) {
|
||||||
|
bits64 a = float64_val(a_);
|
||||||
|
#if SNAN_BIT_IS_ONE
|
||||||
|
a &= ~LIT64( 0x0008000000000000 );
|
||||||
|
#else
|
||||||
|
a |= LIT64( 0x0008000000000000 );
|
||||||
|
#endif
|
||||||
|
return make_float64(a);
|
||||||
|
}
|
||||||
|
return a_;
|
||||||
|
}
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------
|
/*----------------------------------------------------------------------------
|
||||||
| Returns the result of converting the double-precision floating-point NaN
|
| Returns the result of converting the double-precision floating-point NaN
|
||||||
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
|
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
|
||||||
|
136
fpu/softfloat.c
136
fpu/softfloat.c
@ -1353,6 +1353,55 @@ int32 float32_to_int32_round_to_zero( float32 a STATUS_PARAM )
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------
|
||||||
|
| Returns the result of converting the single-precision floating-point value
|
||||||
|
| `a' to the 16-bit two's complement integer format. The conversion is
|
||||||
|
| performed according to the IEC/IEEE Standard for Binary Floating-Point
|
||||||
|
| Arithmetic, except that the conversion is always rounded toward zero.
|
||||||
|
| If `a' is a NaN, the largest positive integer is returned. Otherwise, if
|
||||||
|
| the conversion overflows, the largest integer with the same sign as `a' is
|
||||||
|
| returned.
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
int16 float32_to_int16_round_to_zero( float32 a STATUS_PARAM )
|
||||||
|
{
|
||||||
|
flag aSign;
|
||||||
|
int16 aExp, shiftCount;
|
||||||
|
bits32 aSig;
|
||||||
|
int32 z;
|
||||||
|
|
||||||
|
aSig = extractFloat32Frac( a );
|
||||||
|
aExp = extractFloat32Exp( a );
|
||||||
|
aSign = extractFloat32Sign( a );
|
||||||
|
shiftCount = aExp - 0x8E;
|
||||||
|
if ( 0 <= shiftCount ) {
|
||||||
|
if ( float32_val(a) != 0xC7000000 ) {
|
||||||
|
float_raise( float_flag_invalid STATUS_VAR);
|
||||||
|
if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) {
|
||||||
|
return 0x7FFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (sbits32) 0xffff8000;
|
||||||
|
}
|
||||||
|
else if ( aExp <= 0x7E ) {
|
||||||
|
if ( aExp | aSig ) {
|
||||||
|
STATUS(float_exception_flags) |= float_flag_inexact;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
shiftCount -= 0x10;
|
||||||
|
aSig = ( aSig | 0x00800000 )<<8;
|
||||||
|
z = aSig>>( - shiftCount );
|
||||||
|
if ( (bits32) ( aSig<<( shiftCount & 31 ) ) ) {
|
||||||
|
STATUS(float_exception_flags) |= float_flag_inexact;
|
||||||
|
}
|
||||||
|
if ( aSign ) {
|
||||||
|
z = - z;
|
||||||
|
}
|
||||||
|
return z;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------
|
/*----------------------------------------------------------------------------
|
||||||
| Returns the result of converting the single-precision floating-point value
|
| Returns the result of converting the single-precision floating-point value
|
||||||
| `a' to the 64-bit two's complement integer format. The conversion is
|
| `a' to the 64-bit two's complement integer format. The conversion is
|
||||||
@ -2410,6 +2459,57 @@ int32 float64_to_int32_round_to_zero( float64 a STATUS_PARAM )
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------
|
||||||
|
| Returns the result of converting the double-precision floating-point value
|
||||||
|
| `a' to the 16-bit two's complement integer format. The conversion is
|
||||||
|
| performed according to the IEC/IEEE Standard for Binary Floating-Point
|
||||||
|
| Arithmetic, except that the conversion is always rounded toward zero.
|
||||||
|
| If `a' is a NaN, the largest positive integer is returned. Otherwise, if
|
||||||
|
| the conversion overflows, the largest integer with the same sign as `a' is
|
||||||
|
| returned.
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
int16 float64_to_int16_round_to_zero( float64 a STATUS_PARAM )
|
||||||
|
{
|
||||||
|
flag aSign;
|
||||||
|
int16 aExp, shiftCount;
|
||||||
|
bits64 aSig, savedASig;
|
||||||
|
int32 z;
|
||||||
|
|
||||||
|
aSig = extractFloat64Frac( a );
|
||||||
|
aExp = extractFloat64Exp( a );
|
||||||
|
aSign = extractFloat64Sign( a );
|
||||||
|
if ( 0x40E < aExp ) {
|
||||||
|
if ( ( aExp == 0x7FF ) && aSig ) {
|
||||||
|
aSign = 0;
|
||||||
|
}
|
||||||
|
goto invalid;
|
||||||
|
}
|
||||||
|
else if ( aExp < 0x3FF ) {
|
||||||
|
if ( aExp || aSig ) {
|
||||||
|
STATUS(float_exception_flags) |= float_flag_inexact;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
aSig |= LIT64( 0x0010000000000000 );
|
||||||
|
shiftCount = 0x433 - aExp;
|
||||||
|
savedASig = aSig;
|
||||||
|
aSig >>= shiftCount;
|
||||||
|
z = aSig;
|
||||||
|
if ( aSign ) {
|
||||||
|
z = - z;
|
||||||
|
}
|
||||||
|
if ( ( (int16_t)z < 0 ) ^ aSign ) {
|
||||||
|
invalid:
|
||||||
|
float_raise( float_flag_invalid STATUS_VAR);
|
||||||
|
return aSign ? (sbits32) 0xffff8000 : 0x7FFF;
|
||||||
|
}
|
||||||
|
if ( ( aSig<<shiftCount ) != savedASig ) {
|
||||||
|
STATUS(float_exception_flags) |= float_flag_inexact;
|
||||||
|
}
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------
|
/*----------------------------------------------------------------------------
|
||||||
| Returns the result of converting the double-precision floating-point value
|
| Returns the result of converting the double-precision floating-point value
|
||||||
| `a' to the 64-bit two's complement integer format. The conversion is
|
| `a' to the 64-bit two's complement integer format. The conversion is
|
||||||
@ -5632,6 +5732,24 @@ unsigned int float32_to_uint32_round_to_zero( float32 a STATUS_PARAM )
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int float32_to_uint16_round_to_zero( float32 a STATUS_PARAM )
|
||||||
|
{
|
||||||
|
int64_t v;
|
||||||
|
unsigned int res;
|
||||||
|
|
||||||
|
v = float32_to_int64_round_to_zero(a STATUS_VAR);
|
||||||
|
if (v < 0) {
|
||||||
|
res = 0;
|
||||||
|
float_raise( float_flag_invalid STATUS_VAR);
|
||||||
|
} else if (v > 0xffff) {
|
||||||
|
res = 0xffff;
|
||||||
|
float_raise( float_flag_invalid STATUS_VAR);
|
||||||
|
} else {
|
||||||
|
res = v;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int float64_to_uint32( float64 a STATUS_PARAM )
|
unsigned int float64_to_uint32( float64 a STATUS_PARAM )
|
||||||
{
|
{
|
||||||
int64_t v;
|
int64_t v;
|
||||||
@ -5668,6 +5786,24 @@ unsigned int float64_to_uint32_round_to_zero( float64 a STATUS_PARAM )
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int float64_to_uint16_round_to_zero( float64 a STATUS_PARAM )
|
||||||
|
{
|
||||||
|
int64_t v;
|
||||||
|
unsigned int res;
|
||||||
|
|
||||||
|
v = float64_to_int64_round_to_zero(a STATUS_VAR);
|
||||||
|
if (v < 0) {
|
||||||
|
res = 0;
|
||||||
|
float_raise( float_flag_invalid STATUS_VAR);
|
||||||
|
} else if (v > 0xffff) {
|
||||||
|
res = 0xffff;
|
||||||
|
float_raise( float_flag_invalid STATUS_VAR);
|
||||||
|
} else {
|
||||||
|
res = v;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/* FIXME: This looks broken. */
|
/* FIXME: This looks broken. */
|
||||||
uint64_t float64_to_uint64 (float64 a STATUS_PARAM)
|
uint64_t float64_to_uint64 (float64 a STATUS_PARAM)
|
||||||
{
|
{
|
||||||
|
@ -251,6 +251,8 @@ float32 float16_to_float32( bits16, flag STATUS_PARAM );
|
|||||||
/*----------------------------------------------------------------------------
|
/*----------------------------------------------------------------------------
|
||||||
| Software IEC/IEEE single-precision conversion routines.
|
| Software IEC/IEEE single-precision conversion routines.
|
||||||
*----------------------------------------------------------------------------*/
|
*----------------------------------------------------------------------------*/
|
||||||
|
int float32_to_int16_round_to_zero( float32 STATUS_PARAM );
|
||||||
|
unsigned int float32_to_uint16_round_to_zero( float32 STATUS_PARAM );
|
||||||
int float32_to_int32( float32 STATUS_PARAM );
|
int float32_to_int32( float32 STATUS_PARAM );
|
||||||
int float32_to_int32_round_to_zero( float32 STATUS_PARAM );
|
int float32_to_int32_round_to_zero( float32 STATUS_PARAM );
|
||||||
unsigned int float32_to_uint32( float32 STATUS_PARAM );
|
unsigned int float32_to_uint32( float32 STATUS_PARAM );
|
||||||
@ -287,6 +289,7 @@ int float32_compare( float32, float32 STATUS_PARAM );
|
|||||||
int float32_compare_quiet( float32, float32 STATUS_PARAM );
|
int float32_compare_quiet( float32, float32 STATUS_PARAM );
|
||||||
int float32_is_nan( float32 );
|
int float32_is_nan( float32 );
|
||||||
int float32_is_signaling_nan( float32 );
|
int float32_is_signaling_nan( float32 );
|
||||||
|
float32 float32_maybe_silence_nan( float32 );
|
||||||
float32 float32_scalbn( float32, int STATUS_PARAM );
|
float32 float32_scalbn( float32, int STATUS_PARAM );
|
||||||
|
|
||||||
INLINE float32 float32_abs(float32 a)
|
INLINE float32 float32_abs(float32 a)
|
||||||
@ -314,6 +317,11 @@ INLINE int float32_is_zero(float32 a)
|
|||||||
return (float32_val(a) & 0x7fffffff) == 0;
|
return (float32_val(a) & 0x7fffffff) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INLINE int float32_is_any_nan(float32 a)
|
||||||
|
{
|
||||||
|
return ((float32_val(a) & ~(1 << 31)) > 0x7f800000UL);
|
||||||
|
}
|
||||||
|
|
||||||
#define float32_zero make_float32(0)
|
#define float32_zero make_float32(0)
|
||||||
#define float32_one make_float32(0x3f800000)
|
#define float32_one make_float32(0x3f800000)
|
||||||
#define float32_ln2 make_float32(0x3f317218)
|
#define float32_ln2 make_float32(0x3f317218)
|
||||||
@ -321,6 +329,8 @@ INLINE int float32_is_zero(float32 a)
|
|||||||
/*----------------------------------------------------------------------------
|
/*----------------------------------------------------------------------------
|
||||||
| Software IEC/IEEE double-precision conversion routines.
|
| Software IEC/IEEE double-precision conversion routines.
|
||||||
*----------------------------------------------------------------------------*/
|
*----------------------------------------------------------------------------*/
|
||||||
|
int float64_to_int16_round_to_zero( float64 STATUS_PARAM );
|
||||||
|
unsigned int float64_to_uint16_round_to_zero( float64 STATUS_PARAM );
|
||||||
int float64_to_int32( float64 STATUS_PARAM );
|
int float64_to_int32( float64 STATUS_PARAM );
|
||||||
int float64_to_int32_round_to_zero( float64 STATUS_PARAM );
|
int float64_to_int32_round_to_zero( float64 STATUS_PARAM );
|
||||||
unsigned int float64_to_uint32( float64 STATUS_PARAM );
|
unsigned int float64_to_uint32( float64 STATUS_PARAM );
|
||||||
@ -359,6 +369,7 @@ int float64_compare( float64, float64 STATUS_PARAM );
|
|||||||
int float64_compare_quiet( float64, float64 STATUS_PARAM );
|
int float64_compare_quiet( float64, float64 STATUS_PARAM );
|
||||||
int float64_is_nan( float64 a );
|
int float64_is_nan( float64 a );
|
||||||
int float64_is_signaling_nan( float64 );
|
int float64_is_signaling_nan( float64 );
|
||||||
|
float64 float64_maybe_silence_nan( float64 );
|
||||||
float64 float64_scalbn( float64, int STATUS_PARAM );
|
float64 float64_scalbn( float64, int STATUS_PARAM );
|
||||||
|
|
||||||
INLINE float64 float64_abs(float64 a)
|
INLINE float64 float64_abs(float64 a)
|
||||||
@ -386,6 +397,11 @@ INLINE int float64_is_zero(float64 a)
|
|||||||
return (float64_val(a) & 0x7fffffffffffffffLL) == 0;
|
return (float64_val(a) & 0x7fffffffffffffffLL) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INLINE int float64_is_any_nan(float64 a)
|
||||||
|
{
|
||||||
|
return ((float64_val(a) & ~(1ULL << 63)) > 0x7ff0000000000000ULL);
|
||||||
|
}
|
||||||
|
|
||||||
#define float64_zero make_float64(0)
|
#define float64_zero make_float64(0)
|
||||||
#define float64_one make_float64(0x3ff0000000000000LL)
|
#define float64_one make_float64(0x3ff0000000000000LL)
|
||||||
#define float64_ln2 make_float64(0x3fe62e42fefa39efLL)
|
#define float64_ln2 make_float64(0x3fe62e42fefa39efLL)
|
||||||
|
@ -589,7 +589,7 @@ static int do_strex(CPUARMState *env)
|
|||||||
}
|
}
|
||||||
if (size == 3) {
|
if (size == 3) {
|
||||||
val = env->regs[(env->exclusive_info >> 12) & 0xf];
|
val = env->regs[(env->exclusive_info >> 12) & 0xf];
|
||||||
segv = put_user_u32(val, addr);
|
segv = put_user_u32(val, addr + 4);
|
||||||
if (segv) {
|
if (segv) {
|
||||||
env->cp15.c6_data = addr + 4;
|
env->cp15.c6_data = addr + 4;
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -2463,53 +2463,85 @@ float64 VFP_HELPER(sito, d)(float32 x, CPUState *env)
|
|||||||
/* Float to integer conversion. */
|
/* Float to integer conversion. */
|
||||||
float32 VFP_HELPER(toui, s)(float32 x, CPUState *env)
|
float32 VFP_HELPER(toui, s)(float32 x, CPUState *env)
|
||||||
{
|
{
|
||||||
|
if (float32_is_any_nan(x)) {
|
||||||
|
return float32_zero;
|
||||||
|
}
|
||||||
return vfp_itos(float32_to_uint32(x, &env->vfp.fp_status));
|
return vfp_itos(float32_to_uint32(x, &env->vfp.fp_status));
|
||||||
}
|
}
|
||||||
|
|
||||||
float32 VFP_HELPER(toui, d)(float64 x, CPUState *env)
|
float32 VFP_HELPER(toui, d)(float64 x, CPUState *env)
|
||||||
{
|
{
|
||||||
|
if (float64_is_any_nan(x)) {
|
||||||
|
return float32_zero;
|
||||||
|
}
|
||||||
return vfp_itos(float64_to_uint32(x, &env->vfp.fp_status));
|
return vfp_itos(float64_to_uint32(x, &env->vfp.fp_status));
|
||||||
}
|
}
|
||||||
|
|
||||||
float32 VFP_HELPER(tosi, s)(float32 x, CPUState *env)
|
float32 VFP_HELPER(tosi, s)(float32 x, CPUState *env)
|
||||||
{
|
{
|
||||||
|
if (float32_is_any_nan(x)) {
|
||||||
|
return float32_zero;
|
||||||
|
}
|
||||||
return vfp_itos(float32_to_int32(x, &env->vfp.fp_status));
|
return vfp_itos(float32_to_int32(x, &env->vfp.fp_status));
|
||||||
}
|
}
|
||||||
|
|
||||||
float32 VFP_HELPER(tosi, d)(float64 x, CPUState *env)
|
float32 VFP_HELPER(tosi, d)(float64 x, CPUState *env)
|
||||||
{
|
{
|
||||||
|
if (float64_is_any_nan(x)) {
|
||||||
|
return float32_zero;
|
||||||
|
}
|
||||||
return vfp_itos(float64_to_int32(x, &env->vfp.fp_status));
|
return vfp_itos(float64_to_int32(x, &env->vfp.fp_status));
|
||||||
}
|
}
|
||||||
|
|
||||||
float32 VFP_HELPER(touiz, s)(float32 x, CPUState *env)
|
float32 VFP_HELPER(touiz, s)(float32 x, CPUState *env)
|
||||||
{
|
{
|
||||||
|
if (float32_is_any_nan(x)) {
|
||||||
|
return float32_zero;
|
||||||
|
}
|
||||||
return vfp_itos(float32_to_uint32_round_to_zero(x, &env->vfp.fp_status));
|
return vfp_itos(float32_to_uint32_round_to_zero(x, &env->vfp.fp_status));
|
||||||
}
|
}
|
||||||
|
|
||||||
float32 VFP_HELPER(touiz, d)(float64 x, CPUState *env)
|
float32 VFP_HELPER(touiz, d)(float64 x, CPUState *env)
|
||||||
{
|
{
|
||||||
|
if (float64_is_any_nan(x)) {
|
||||||
|
return float32_zero;
|
||||||
|
}
|
||||||
return vfp_itos(float64_to_uint32_round_to_zero(x, &env->vfp.fp_status));
|
return vfp_itos(float64_to_uint32_round_to_zero(x, &env->vfp.fp_status));
|
||||||
}
|
}
|
||||||
|
|
||||||
float32 VFP_HELPER(tosiz, s)(float32 x, CPUState *env)
|
float32 VFP_HELPER(tosiz, s)(float32 x, CPUState *env)
|
||||||
{
|
{
|
||||||
|
if (float32_is_any_nan(x)) {
|
||||||
|
return float32_zero;
|
||||||
|
}
|
||||||
return vfp_itos(float32_to_int32_round_to_zero(x, &env->vfp.fp_status));
|
return vfp_itos(float32_to_int32_round_to_zero(x, &env->vfp.fp_status));
|
||||||
}
|
}
|
||||||
|
|
||||||
float32 VFP_HELPER(tosiz, d)(float64 x, CPUState *env)
|
float32 VFP_HELPER(tosiz, d)(float64 x, CPUState *env)
|
||||||
{
|
{
|
||||||
|
if (float64_is_any_nan(x)) {
|
||||||
|
return float32_zero;
|
||||||
|
}
|
||||||
return vfp_itos(float64_to_int32_round_to_zero(x, &env->vfp.fp_status));
|
return vfp_itos(float64_to_int32_round_to_zero(x, &env->vfp.fp_status));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* floating point conversion */
|
/* floating point conversion */
|
||||||
float64 VFP_HELPER(fcvtd, s)(float32 x, CPUState *env)
|
float64 VFP_HELPER(fcvtd, s)(float32 x, CPUState *env)
|
||||||
{
|
{
|
||||||
return float32_to_float64(x, &env->vfp.fp_status);
|
float64 r = float32_to_float64(x, &env->vfp.fp_status);
|
||||||
|
/* ARM requires that S<->D conversion of any kind of NaN generates
|
||||||
|
* a quiet NaN by forcing the most significant frac bit to 1.
|
||||||
|
*/
|
||||||
|
return float64_maybe_silence_nan(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
float32 VFP_HELPER(fcvts, d)(float64 x, CPUState *env)
|
float32 VFP_HELPER(fcvts, d)(float64 x, CPUState *env)
|
||||||
{
|
{
|
||||||
return float64_to_float32(x, &env->vfp.fp_status);
|
float32 r = float64_to_float32(x, &env->vfp.fp_status);
|
||||||
|
/* ARM requires that S<->D conversion of any kind of NaN generates
|
||||||
|
* a quiet NaN by forcing the most significant frac bit to 1.
|
||||||
|
*/
|
||||||
|
return float32_maybe_silence_nan(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* VFP3 fixed point conversion. */
|
/* VFP3 fixed point conversion. */
|
||||||
@ -2517,15 +2549,18 @@ float32 VFP_HELPER(fcvts, d)(float64 x, CPUState *env)
|
|||||||
ftype VFP_HELPER(name##to, p)(ftype x, uint32_t shift, CPUState *env) \
|
ftype VFP_HELPER(name##to, p)(ftype x, uint32_t shift, CPUState *env) \
|
||||||
{ \
|
{ \
|
||||||
ftype tmp; \
|
ftype tmp; \
|
||||||
tmp = sign##int32_to_##ftype ((itype)vfp_##p##toi(x), \
|
tmp = sign##int32_to_##ftype ((itype##_t)vfp_##p##toi(x), \
|
||||||
&env->vfp.fp_status); \
|
&env->vfp.fp_status); \
|
||||||
return ftype##_scalbn(tmp, -(int)shift, &env->vfp.fp_status); \
|
return ftype##_scalbn(tmp, -(int)shift, &env->vfp.fp_status); \
|
||||||
} \
|
} \
|
||||||
ftype VFP_HELPER(to##name, p)(ftype x, uint32_t shift, CPUState *env) \
|
ftype VFP_HELPER(to##name, p)(ftype x, uint32_t shift, CPUState *env) \
|
||||||
{ \
|
{ \
|
||||||
ftype tmp; \
|
ftype tmp; \
|
||||||
|
if (ftype##_is_any_nan(x)) { \
|
||||||
|
return ftype##_zero; \
|
||||||
|
} \
|
||||||
tmp = ftype##_scalbn(x, shift, &env->vfp.fp_status); \
|
tmp = ftype##_scalbn(x, shift, &env->vfp.fp_status); \
|
||||||
return vfp_ito##p((itype)ftype##_to_##sign##int32_round_to_zero(tmp, \
|
return vfp_ito##p(ftype##_to_##itype##_round_to_zero(tmp, \
|
||||||
&env->vfp.fp_status)); \
|
&env->vfp.fp_status)); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2870,16 +2870,18 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
|
|||||||
VFP_DREG_N(rn, insn);
|
VFP_DREG_N(rn, insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (op == 15 && (rn == 15 || rn > 17)) {
|
if (op == 15 && (rn == 15 || ((rn & 0x1c) == 0x18))) {
|
||||||
/* Integer or single precision destination. */
|
/* Integer or single precision destination. */
|
||||||
rd = VFP_SREG_D(insn);
|
rd = VFP_SREG_D(insn);
|
||||||
} else {
|
} else {
|
||||||
VFP_DREG_D(rd, insn);
|
VFP_DREG_D(rd, insn);
|
||||||
}
|
}
|
||||||
|
if (op == 15 &&
|
||||||
if (op == 15 && (rn == 16 || rn == 17)) {
|
(((rn & 0x1c) == 0x10) || ((rn & 0x14) == 0x14))) {
|
||||||
/* Integer source. */
|
/* VCVT from int is always from S reg regardless of dp bit.
|
||||||
rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1);
|
* VCVT with immediate frac_bits has same format as SREG_M
|
||||||
|
*/
|
||||||
|
rm = VFP_SREG_M(insn);
|
||||||
} else {
|
} else {
|
||||||
VFP_DREG_M(rm, insn);
|
VFP_DREG_M(rm, insn);
|
||||||
}
|
}
|
||||||
@ -2891,6 +2893,9 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
|
|||||||
} else {
|
} else {
|
||||||
rd = VFP_SREG_D(insn);
|
rd = VFP_SREG_D(insn);
|
||||||
}
|
}
|
||||||
|
/* NB that we implicitly rely on the encoding for the frac_bits
|
||||||
|
* in VCVT of fixed to float being the same as that of an SREG_M
|
||||||
|
*/
|
||||||
rm = VFP_SREG_M(insn);
|
rm = VFP_SREG_M(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3179,8 +3184,8 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
|
|||||||
/* Write back the result. */
|
/* Write back the result. */
|
||||||
if (op == 15 && (rn >= 8 && rn <= 11))
|
if (op == 15 && (rn >= 8 && rn <= 11))
|
||||||
; /* Comparison, do nothing. */
|
; /* Comparison, do nothing. */
|
||||||
else if (op == 15 && rn > 17)
|
else if (op == 15 && dp && ((rn & 0x1c) == 0x18))
|
||||||
/* Integer result. */
|
/* VCVT double to int: always integer result. */
|
||||||
gen_mov_vreg_F0(0, rd);
|
gen_mov_vreg_F0(0, rd);
|
||||||
else if (op == 15 && rn == 15)
|
else if (op == 15 && rn == 15)
|
||||||
/* conversion */
|
/* conversion */
|
||||||
@ -4845,11 +4850,15 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
|
|||||||
}
|
}
|
||||||
neon_store_reg64(cpu_V0, rd + pass);
|
neon_store_reg64(cpu_V0, rd + pass);
|
||||||
}
|
}
|
||||||
} else if (op == 15 || op == 16) {
|
} else if (op >= 14) {
|
||||||
/* VCVT fixed-point. */
|
/* VCVT fixed-point. */
|
||||||
|
/* We have already masked out the must-be-1 top bit of imm6,
|
||||||
|
* hence this 32-shift where the ARM ARM has 64-imm6.
|
||||||
|
*/
|
||||||
|
shift = 32 - shift;
|
||||||
for (pass = 0; pass < (q ? 4 : 2); pass++) {
|
for (pass = 0; pass < (q ? 4 : 2); pass++) {
|
||||||
tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, pass));
|
tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, pass));
|
||||||
if (op & 1) {
|
if (!(op & 1)) {
|
||||||
if (u)
|
if (u)
|
||||||
gen_vfp_ulto(0, shift);
|
gen_vfp_ulto(0, shift);
|
||||||
else
|
else
|
||||||
@ -5655,17 +5664,17 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
|
|||||||
gen_helper_rsqrte_f32(cpu_F0s, cpu_F0s, cpu_env);
|
gen_helper_rsqrte_f32(cpu_F0s, cpu_F0s, cpu_env);
|
||||||
break;
|
break;
|
||||||
case 60: /* VCVT.F32.S32 */
|
case 60: /* VCVT.F32.S32 */
|
||||||
gen_vfp_tosiz(0);
|
|
||||||
break;
|
|
||||||
case 61: /* VCVT.F32.U32 */
|
|
||||||
gen_vfp_touiz(0);
|
|
||||||
break;
|
|
||||||
case 62: /* VCVT.S32.F32 */
|
|
||||||
gen_vfp_sito(0);
|
gen_vfp_sito(0);
|
||||||
break;
|
break;
|
||||||
case 63: /* VCVT.U32.F32 */
|
case 61: /* VCVT.F32.U32 */
|
||||||
gen_vfp_uito(0);
|
gen_vfp_uito(0);
|
||||||
break;
|
break;
|
||||||
|
case 62: /* VCVT.S32.F32 */
|
||||||
|
gen_vfp_tosiz(0);
|
||||||
|
break;
|
||||||
|
case 63: /* VCVT.U32.F32 */
|
||||||
|
gen_vfp_touiz(0);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* Reserved: 21, 29, 39-56 */
|
/* Reserved: 21, 29, 39-56 */
|
||||||
return 1;
|
return 1;
|
||||||
@ -5926,8 +5935,10 @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
|
|||||||
tcg_gen_mov_i32(cpu_exclusive_val, tmp);
|
tcg_gen_mov_i32(cpu_exclusive_val, tmp);
|
||||||
store_reg(s, rt, tmp);
|
store_reg(s, rt, tmp);
|
||||||
if (size == 3) {
|
if (size == 3) {
|
||||||
tcg_gen_addi_i32(addr, addr, 4);
|
TCGv tmp2 = new_tmp();
|
||||||
tmp = gen_ld32(addr, IS_USER(s));
|
tcg_gen_addi_i32(tmp2, addr, 4);
|
||||||
|
tmp = gen_ld32(tmp2, IS_USER(s));
|
||||||
|
dead_tmp(tmp2);
|
||||||
tcg_gen_mov_i32(cpu_exclusive_high, tmp);
|
tcg_gen_mov_i32(cpu_exclusive_high, tmp);
|
||||||
store_reg(s, rt2, tmp);
|
store_reg(s, rt2, tmp);
|
||||||
}
|
}
|
||||||
@ -5987,7 +5998,7 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
|
|||||||
if (size == 3) {
|
if (size == 3) {
|
||||||
TCGv tmp2 = new_tmp();
|
TCGv tmp2 = new_tmp();
|
||||||
tcg_gen_addi_i32(tmp2, addr, 4);
|
tcg_gen_addi_i32(tmp2, addr, 4);
|
||||||
tmp = gen_ld32(addr, IS_USER(s));
|
tmp = gen_ld32(tmp2, IS_USER(s));
|
||||||
dead_tmp(tmp2);
|
dead_tmp(tmp2);
|
||||||
tcg_gen_brcond_i32(TCG_COND_NE, tmp, cpu_exclusive_high, fail_label);
|
tcg_gen_brcond_i32(TCG_COND_NE, tmp, cpu_exclusive_high, fail_label);
|
||||||
dead_tmp(tmp);
|
dead_tmp(tmp);
|
||||||
@ -6346,7 +6357,14 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
|
|||||||
dead_tmp(tmp2);
|
dead_tmp(tmp2);
|
||||||
store_reg(s, rd, tmp);
|
store_reg(s, rd, tmp);
|
||||||
break;
|
break;
|
||||||
case 7: /* bkpt */
|
case 7:
|
||||||
|
/* SMC instruction (op1 == 3)
|
||||||
|
and undefined instructions (op1 == 0 || op1 == 2)
|
||||||
|
will trap */
|
||||||
|
if (op1 != 1) {
|
||||||
|
goto illegal_op;
|
||||||
|
}
|
||||||
|
/* bkpt */
|
||||||
gen_set_condexec(s);
|
gen_set_condexec(s);
|
||||||
gen_set_pc_im(s->pc - 4);
|
gen_set_pc_im(s->pc - 4);
|
||||||
gen_exception(EXCP_BKPT);
|
gen_exception(EXCP_BKPT);
|
||||||
@ -7601,27 +7619,54 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 5: /* Data processing register constant shift. */
|
case 5:
|
||||||
if (rn == 15) {
|
|
||||||
tmp = new_tmp();
|
|
||||||
tcg_gen_movi_i32(tmp, 0);
|
|
||||||
} else {
|
|
||||||
tmp = load_reg(s, rn);
|
|
||||||
}
|
|
||||||
tmp2 = load_reg(s, rm);
|
|
||||||
op = (insn >> 21) & 0xf;
|
op = (insn >> 21) & 0xf;
|
||||||
shiftop = (insn >> 4) & 3;
|
if (op == 6) {
|
||||||
shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c);
|
/* Halfword pack. */
|
||||||
conds = (insn & (1 << 20)) != 0;
|
tmp = load_reg(s, rn);
|
||||||
logic_cc = (conds && thumb2_logic_op(op));
|
tmp2 = load_reg(s, rm);
|
||||||
gen_arm_shift_im(tmp2, shiftop, shift, logic_cc);
|
shift = ((insn >> 10) & 0x1c) | ((insn >> 6) & 0x3);
|
||||||
if (gen_thumb2_data_op(s, op, conds, 0, tmp, tmp2))
|
if (insn & (1 << 5)) {
|
||||||
goto illegal_op;
|
/* pkhtb */
|
||||||
dead_tmp(tmp2);
|
if (shift == 0)
|
||||||
if (rd != 15) {
|
shift = 31;
|
||||||
|
tcg_gen_sari_i32(tmp2, tmp2, shift);
|
||||||
|
tcg_gen_andi_i32(tmp, tmp, 0xffff0000);
|
||||||
|
tcg_gen_ext16u_i32(tmp2, tmp2);
|
||||||
|
} else {
|
||||||
|
/* pkhbt */
|
||||||
|
if (shift)
|
||||||
|
tcg_gen_shli_i32(tmp2, tmp2, shift);
|
||||||
|
tcg_gen_ext16u_i32(tmp, tmp);
|
||||||
|
tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);
|
||||||
|
}
|
||||||
|
tcg_gen_or_i32(tmp, tmp, tmp2);
|
||||||
|
dead_tmp(tmp2);
|
||||||
store_reg(s, rd, tmp);
|
store_reg(s, rd, tmp);
|
||||||
} else {
|
} else {
|
||||||
dead_tmp(tmp);
|
/* Data processing register constant shift. */
|
||||||
|
if (rn == 15) {
|
||||||
|
tmp = new_tmp();
|
||||||
|
tcg_gen_movi_i32(tmp, 0);
|
||||||
|
} else {
|
||||||
|
tmp = load_reg(s, rn);
|
||||||
|
}
|
||||||
|
tmp2 = load_reg(s, rm);
|
||||||
|
|
||||||
|
shiftop = (insn >> 4) & 3;
|
||||||
|
shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c);
|
||||||
|
conds = (insn & (1 << 20)) != 0;
|
||||||
|
logic_cc = (conds && thumb2_logic_op(op));
|
||||||
|
gen_arm_shift_im(tmp2, shiftop, shift, logic_cc);
|
||||||
|
if (gen_thumb2_data_op(s, op, conds, 0, tmp, tmp2))
|
||||||
|
goto illegal_op;
|
||||||
|
dead_tmp(tmp2);
|
||||||
|
if (rd != 15) {
|
||||||
|
store_reg(s, rd, tmp);
|
||||||
|
} else {
|
||||||
|
dead_tmp(tmp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 13: /* Misc data processing. */
|
case 13: /* Misc data processing. */
|
||||||
@ -7686,9 +7731,9 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
|
|||||||
/* Saturating add/subtract. */
|
/* Saturating add/subtract. */
|
||||||
tmp = load_reg(s, rn);
|
tmp = load_reg(s, rn);
|
||||||
tmp2 = load_reg(s, rm);
|
tmp2 = load_reg(s, rm);
|
||||||
if (op & 2)
|
|
||||||
gen_helper_double_saturate(tmp, tmp);
|
|
||||||
if (op & 1)
|
if (op & 1)
|
||||||
|
gen_helper_double_saturate(tmp, tmp);
|
||||||
|
if (op & 2)
|
||||||
gen_helper_sub_saturate(tmp, tmp2, tmp);
|
gen_helper_sub_saturate(tmp, tmp2, tmp);
|
||||||
else
|
else
|
||||||
gen_helper_add_saturate(tmp, tmp, tmp2);
|
gen_helper_add_saturate(tmp, tmp, tmp2);
|
||||||
|
Loading…
Reference in New Issue
Block a user