Merge remote branch 'arm/for-anthony' into staging

This commit is contained in:
Anthony Liguori 2010-12-17 08:25:17 -06:00
commit 9d861fa595
6 changed files with 315 additions and 45 deletions

View File

@ -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

View File

@ -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)
{ {

View File

@ -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)

View File

@ -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;

View File

@ -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)); \
} }

View File

@ -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);