DEF_HELPER_1(neon_narrow_u8, i32, i64)
DEF_HELPER_1(neon_narrow_u16, i32, i64)
+DEF_HELPER_2(neon_unarrow_sat8, i32, env, i64)
DEF_HELPER_2(neon_narrow_sat_u8, i32, env, i64)
DEF_HELPER_2(neon_narrow_sat_s8, i32, env, i64)
+DEF_HELPER_2(neon_unarrow_sat16, i32, env, i64)
DEF_HELPER_2(neon_narrow_sat_u16, i32, env, i64)
DEF_HELPER_2(neon_narrow_sat_s16, i32, env, i64)
+DEF_HELPER_2(neon_unarrow_sat32, i32, env, i64)
DEF_HELPER_2(neon_narrow_sat_u32, i32, env, i64)
DEF_HELPER_2(neon_narrow_sat_s32, i32, env, i64)
DEF_HELPER_1(neon_narrow_high_u8, i32, i64)
return ((x >> 16) & 0xffff) | ((x >> 32) & 0xffff0000);
}
+uint32_t HELPER(neon_unarrow_sat8)(CPUState *env, uint64_t x)
+{
+ uint16_t s;
+ uint8_t d;
+ uint32_t res = 0;
+#define SAT8(n) \
+ s = x >> n; \
+ if (s & 0x8000) { \
+ SET_QC(); \
+ } else { \
+ if (s > 0xff) { \
+ d = 0xff; \
+ SET_QC(); \
+ } else { \
+ d = s; \
+ } \
+ res |= (uint32_t)d << (n / 2); \
+ }
+
+ SAT8(0);
+ SAT8(16);
+ SAT8(32);
+ SAT8(48);
+#undef SAT8
+ return res;
+}
+
uint32_t HELPER(neon_narrow_sat_u8)(CPUState *env, uint64_t x)
{
uint16_t s;
return res;
}
+uint32_t HELPER(neon_unarrow_sat16)(CPUState *env, uint64_t x)
+{
+ uint32_t high;
+ uint32_t low;
+ low = x;
+ if (low & 0x80000000) {
+ low = 0;
+ SET_QC();
+ } else if (low > 0xffff) {
+ low = 0xffff;
+ SET_QC();
+ }
+ high = x >> 32;
+ if (high & 0x80000000) {
+ high = 0;
+ SET_QC();
+ } else if (high > 0xffff) {
+ high = 0xffff;
+ SET_QC();
+ }
+ return low | (high << 16);
+}
+
uint32_t HELPER(neon_narrow_sat_u16)(CPUState *env, uint64_t x)
{
uint32_t high;
return (uint16_t)low | (high << 16);
}
+uint32_t HELPER(neon_unarrow_sat32)(CPUState *env, uint64_t x)
+{
+ if (x & 0x8000000000000000ull) {
+ SET_QC();
+ return 0;
+ }
+ if (x > 0xffffffffu) {
+ SET_QC();
+ return 0xffffffffu;
+ }
+ return x;
+}
+
uint32_t HELPER(neon_narrow_sat_u32)(CPUState *env, uint64_t x)
{
if (x > 0xffffffffu) {
{
if ((int64_t)x != (int32_t)x) {
SET_QC();
- return (x >> 63) ^ 0x7fffffff;
+ return ((int64_t)x >> 63) ^ 0x7fffffff;
}
return x;
}
}
}
+static inline void gen_neon_unarrow_sats(int size, TCGv dest, TCGv_i64 src)
+{
+ switch (size) {
+ case 0: gen_helper_neon_unarrow_sat8(dest, cpu_env, src); break;
+ case 1: gen_helper_neon_unarrow_sat16(dest, cpu_env, src); break;
+ case 2: gen_helper_neon_unarrow_sat32(dest, cpu_env, src); break;
+ default: abort();
+ }
+}
+
static inline void gen_neon_shift_narrow(int size, TCGv var, TCGv shift,
int q, int u)
{
tcg_gen_add_i64(cpu_V0, cpu_V0, cpu_V1);
} else if (op == 4 || (op == 5 && u)) {
/* Insert */
- cpu_abort(env, "VS[LR]I.64 not implemented");
+ neon_load_reg64(cpu_V1, rd + pass);
+ uint64_t mask;
+ if (shift < -63 || shift > 63) {
+ mask = 0;
+ } else {
+ if (op == 4) {
+ mask = 0xffffffffffffffffull >> -shift;
+ } else {
+ mask = 0xffffffffffffffffull << shift;
+ }
+ }
+ tcg_gen_andi_i64(cpu_V1, cpu_V1, ~mask);
+ tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);
}
neon_store_reg64(cpu_V0, rd + pass);
} else { /* size < 3 */
/* The shift is less than the width of the source
type, so we can just shift the whole register. */
tcg_gen_shli_i64(cpu_V0, cpu_V0, shift);
+ /* Widen the result of shift: we need to clear
+ * the potential overflow bits resulting from
+ * left bits of the narrow input appearing as
+ * right bits of left the neighbour narrow
+ * input. */
if (size < 2 || !u) {
uint64_t imm64;
if (size == 0) {
imm = (0xffu >> (8 - shift));
imm |= imm << 16;
- } else {
+ } else if (size == 1) {
imm = 0xffff >> (16 - shift);
+ } else {
+ /* size == 2 */
+ imm = 0xffffffff >> (32 - shift);
+ }
+ if (size < 2) {
+ imm64 = imm | (((uint64_t)imm) << 32);
+ } else {
+ imm64 = imm;
}
- imm64 = imm | (((uint64_t)imm) << 32);
- tcg_gen_andi_i64(cpu_V0, cpu_V0, imm64);
+ tcg_gen_andi_i64(cpu_V0, cpu_V0, ~imm64);
}
}
neon_store_reg64(cpu_V0, rd + pass);
for (pass = 0; pass < 2; pass++) {
neon_load_reg64(cpu_V0, rm + pass);
tmp = new_tmp();
- if (op == 36 && q == 0) {
- gen_neon_narrow(size, tmp, cpu_V0);
- } else if (q) {
- gen_neon_narrow_satu(size, tmp, cpu_V0);
- } else {
- gen_neon_narrow_sats(size, tmp, cpu_V0);
+ if (op == 36) {
+ if (q) { /* VQMOVUN */
+ gen_neon_unarrow_sats(size, tmp, cpu_V0);
+ } else { /* VMOVN */
+ gen_neon_narrow(size, tmp, cpu_V0);
+ }
+ } else { /* VQMOVN */
+ if (q) {
+ gen_neon_narrow_satu(size, tmp, cpu_V0);
+ } else {
+ gen_neon_narrow_sats(size, tmp, cpu_V0);
+ }
}
if (pass == 0) {
tmp2 = tmp;
{
uint64_t dt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
RESTORE_ROUNDING_MODE;
{
uint64_t dt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
RESTORE_ROUNDING_MODE;
{
uint32_t wt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
RESTORE_ROUNDING_MODE;
{
uint32_t wt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
RESTORE_ROUNDING_MODE;
{
uint64_t dt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
update_fcr31();
if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
{
uint64_t dt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
update_fcr31();
if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
{
uint32_t wt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
update_fcr31();
if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
{
uint32_t wt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
update_fcr31();
if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
{
uint64_t dt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
RESTORE_ROUNDING_MODE;
{
uint64_t dt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
RESTORE_ROUNDING_MODE;
{
uint32_t wt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
RESTORE_ROUNDING_MODE;
{
uint32_t wt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
RESTORE_ROUNDING_MODE;
{
uint64_t dt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
RESTORE_ROUNDING_MODE;
{
uint64_t dt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
RESTORE_ROUNDING_MODE;
{
uint32_t wt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
RESTORE_ROUNDING_MODE;
{
uint32_t wt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
RESTORE_ROUNDING_MODE;