diff --git a/cpu-all.h b/cpu-all.h index f4db59234e..6b78435093 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -135,6 +135,36 @@ typedef union { uint64_t ll; } CPU_DoubleU; +#ifdef TARGET_SPARC +typedef union { + float128 q; +#if defined(WORDS_BIGENDIAN) \ + || (defined(__arm__) && !defined(__VFP_FP__) && !defined(CONFIG_SOFTFLOAT)) + struct { + uint32_t upmost; + uint32_t upper; + uint32_t lower; + uint32_t lowest; + } l; + struct { + uint64_t upper; + uint64_t lower; + } ll; +#else + struct { + uint32_t lowest; + uint32_t lower; + uint32_t upper; + uint32_t upmost; + } l; + struct { + uint64_t lower; + uint64_t upper; + } ll; +#endif +} CPU_QuadU; +#endif + /* CPU memory access without any memory or io remapping */ /* diff --git a/fpu/softfloat.c b/fpu/softfloat.c index e30f22f918..3ec1e0de18 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -5421,6 +5421,50 @@ int float ## s ## _compare_quiet( float ## s a, float ## s b STATUS_PARAM ) \ COMPARE(32, 0xff) COMPARE(64, 0x7ff) +INLINE int float128_compare_internal( float128 a, float128 b, + int is_quiet STATUS_PARAM ) +{ + flag aSign, bSign; + + if (( ( extractFloat128Exp( a ) == 0x7fff ) && + ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) || + ( ( extractFloat128Exp( b ) == 0x7fff ) && + ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )) { + if (!is_quiet || + float128_is_signaling_nan( a ) || + float128_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return float_relation_unordered; + } + aSign = extractFloat128Sign( a ); + bSign = extractFloat128Sign( b ); + if ( aSign != bSign ) { + if ( ( ( ( a.high | b.high )<<1 ) | a.low | b.low ) == 0 ) { + /* zero case */ + return float_relation_equal; + } else { + return 1 - (2 * aSign); + } + } else { + if (a.low == b.low && a.high == b.high) { + return float_relation_equal; + } else { + return 1 - 2 * (aSign ^ ( lt128( a.high, a.low, b.high, b.low ) )); + } + } +} + +int float128_compare( float128 a, float128 b STATUS_PARAM ) +{ + return float128_compare_internal(a, b, 0 STATUS_VAR); +} + +int float128_compare_quiet( float128 a, float128 b STATUS_PARAM ) +{ + return float128_compare_internal(a, b, 1 STATUS_VAR); +} + /* Multiply A by 2 raised to the power N. */ float32 float32_scalbn( float32 a, int n STATUS_PARAM ) { diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 84cffdd5d5..5f95d061e5 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -415,6 +415,8 @@ int float128_lt( float128, float128 STATUS_PARAM ); int float128_eq_signaling( float128, float128 STATUS_PARAM ); int float128_le_quiet( float128, float128 STATUS_PARAM ); int float128_lt_quiet( float128, float128 STATUS_PARAM ); +int float128_compare( float128, float128 STATUS_PARAM ); +int float128_compare_quiet( float128, float128 STATUS_PARAM ); int float128_is_nan( float128 ); int float128_is_signaling_nan( float128 ); float128 float128_scalbn( float128, int STATUS_PARAM ); diff --git a/qemu-tech.texi b/qemu-tech.texi index 9147096d93..cc027cf6a5 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -212,8 +212,7 @@ Current QEMU limitations: @item IPC syscalls are missing. -@item 128-bit floating point operations are not supported, though none of the -real CPUs implement them either. Floating point exception support is untested. +@item Floating point exception support is buggy. @item Atomic instructions are not correctly implemented. diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 319e6e896a..783a850c64 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -222,6 +222,9 @@ typedef struct CPUSPARCState { /* temporary float registers */ float32 ft0, ft1; float64 dt0, dt1; +#if defined(CONFIG_USER_ONLY) + float128 qt0, qt1; +#endif float_status fp_status; #if defined(TARGET_SPARC64) #define MAXTL 4 diff --git a/target-sparc/exec.h b/target-sparc/exec.h index 81c4741be3..db19da6f66 100644 --- a/target-sparc/exec.h +++ b/target-sparc/exec.h @@ -41,6 +41,10 @@ register uint32_t T2 asm(AREG3); #define FT1 (env->ft1) #define DT0 (env->dt0) #define DT1 (env->dt1) +#if defined(CONFIG_USER_ONLY) +#define QT0 (env->qt0) +#define QT1 (env->qt1) +#endif #include "cpu.h" #include "exec-all.h" @@ -65,6 +69,13 @@ void do_fcmps(void); void do_fcmpd(void); void do_fcmpes(void); void do_fcmped(void); +#if defined(CONFIG_USER_ONLY) +void do_fitoq(void); +void do_fabsq(void); +void do_fsqrtq(void); +void do_fcmpq(void); +void do_fcmpeq(void); +#endif #ifdef TARGET_SPARC64 void do_fabsd(void); void do_fcmps_fcc1(void); @@ -79,6 +90,14 @@ void do_fcmpes_fcc2(void); void do_fcmped_fcc2(void); void do_fcmpes_fcc3(void); void do_fcmped_fcc3(void); +#if defined(CONFIG_USER_ONLY) +void do_fcmpq_fcc1(void); +void do_fcmpq_fcc2(void); +void do_fcmpq_fcc3(void); +void do_fcmpeq_fcc1(void); +void do_fcmpeq_fcc2(void); +void do_fcmpeq_fcc3(void); +#endif void do_popc(); void do_wrpstate(); void do_done(); diff --git a/target-sparc/fop_template.h b/target-sparc/fop_template.h index 0598b30208..0c045b8355 100644 --- a/target-sparc/fop_template.h +++ b/target-sparc/fop_template.h @@ -77,5 +77,52 @@ void OPPROTO glue(op_store_DT1_fpr_fpr, REGNAME)(void) *p = u.l.upper; } +#if defined(CONFIG_USER_ONLY) +/* quad floating point registers moves */ +void OPPROTO glue(op_load_fpr_QT0_fpr, REGNAME)(void) +{ + CPU_QuadU u; + uint32_t *p = (uint32_t *)® + u.l.lowest = *(p + 3); + u.l.lower = *(p + 2); + u.l.upper = *(p + 1); + u.l.upmost = *p; + QT0 = u.q; +} + +void OPPROTO glue(op_store_QT0_fpr_fpr, REGNAME)(void) +{ + CPU_QuadU u; + uint32_t *p = (uint32_t *)® + u.q = QT0; + *(p + 3) = u.l.lowest; + *(p + 2) = u.l.lower; + *(p + 1) = u.l.upper; + *p = u.l.upmost; +} + +void OPPROTO glue(op_load_fpr_QT1_fpr, REGNAME)(void) +{ + CPU_QuadU u; + uint32_t *p = (uint32_t *)® + u.l.lowest = *(p + 3); + u.l.lower = *(p + 2); + u.l.upper = *(p + 1); + u.l.upmost = *p; + QT1 = u.q; +} + +void OPPROTO glue(op_store_QT1_fpr_fpr, REGNAME)(void) +{ + CPU_QuadU u; + uint32_t *p = (uint32_t *)® + u.q = QT1; + *(p + 3) = u.l.lowest; + *(p + 2) = u.l.lower; + *(p + 1) = u.l.upper; + *p = u.l.upmost; +} +#endif + #undef REG #undef REGNAME diff --git a/target-sparc/op.c b/target-sparc/op.c index 55ea2b9fe4..1fb48cfd6c 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -1581,6 +1581,27 @@ void OPPROTO op_clear_ieee_excp_and_FTT(void) #define F_OP(name, p) void OPPROTO op_f##name##p(void) +#if defined(CONFIG_USER_ONLY) +#define F_BINOP(name) \ + F_OP(name, s) \ + { \ + set_float_exception_flags(0, &env->fp_status); \ + FT0 = float32_ ## name (FT0, FT1, &env->fp_status); \ + check_ieee_exceptions(); \ + } \ + F_OP(name, d) \ + { \ + set_float_exception_flags(0, &env->fp_status); \ + DT0 = float64_ ## name (DT0, DT1, &env->fp_status); \ + check_ieee_exceptions(); \ + } \ + F_OP(name, q) \ + { \ + set_float_exception_flags(0, &env->fp_status); \ + QT0 = float128_ ## name (QT0, QT1, &env->fp_status); \ + check_ieee_exceptions(); \ + } +#else #define F_BINOP(name) \ F_OP(name, s) \ { \ @@ -1594,6 +1615,7 @@ void OPPROTO op_clear_ieee_excp_and_FTT(void) DT0 = float64_ ## name (DT0, DT1, &env->fp_status); \ check_ieee_exceptions(); \ } +#endif F_BINOP(add); F_BINOP(sub); @@ -1610,6 +1632,32 @@ void OPPROTO op_fsmuld(void) check_ieee_exceptions(); } +#if defined(CONFIG_USER_ONLY) +void OPPROTO op_fdmulq(void) +{ + set_float_exception_flags(0, &env->fp_status); + QT0 = float128_mul(float64_to_float128(DT0, &env->fp_status), + float64_to_float128(DT1, &env->fp_status), + &env->fp_status); + check_ieee_exceptions(); +} +#endif + +#if defined(CONFIG_USER_ONLY) +#define F_HELPER(name) \ + F_OP(name, s) \ + { \ + do_f##name##s(); \ + } \ + F_OP(name, d) \ + { \ + do_f##name##d(); \ + } \ + F_OP(name, q) \ + { \ + do_f##name##q(); \ + } +#else #define F_HELPER(name) \ F_OP(name, s) \ { \ @@ -1619,6 +1667,7 @@ void OPPROTO op_fsmuld(void) { \ do_f##name##d(); \ } +#endif F_HELPER(sqrt); @@ -1646,6 +1695,18 @@ F_OP(abs, d) do_fabsd(); } +#if defined(CONFIG_USER_ONLY) +F_OP(neg, q) +{ + QT0 = float128_chs(QT1); +} + +F_OP(abs, q) +{ + do_fabsd(); +} +#endif + void OPPROTO op_fcmps_fcc1(void) { do_fcmps_fcc1(); @@ -1706,6 +1767,38 @@ void OPPROTO op_fcmped_fcc3(void) do_fcmped_fcc3(); } +#if defined(CONFIG_USER_ONLY) +void OPPROTO op_fcmpq_fcc1(void) +{ + do_fcmpq_fcc1(); +} + +void OPPROTO op_fcmpq_fcc2(void) +{ + do_fcmpq_fcc2(); +} + +void OPPROTO op_fcmpq_fcc3(void) +{ + do_fcmpq_fcc3(); +} + +void OPPROTO op_fcmpeq_fcc1(void) +{ + do_fcmpeq_fcc1(); +} + +void OPPROTO op_fcmpeq_fcc2(void) +{ + do_fcmpeq_fcc2(); +} + +void OPPROTO op_fcmpeq_fcc3(void) +{ + do_fcmpeq_fcc3(); +} +#endif + #endif /* Integer to float conversion. */ @@ -1729,6 +1822,15 @@ F_OP(ito, d) check_ieee_exceptions(); } +#if defined(CONFIG_USER_ONLY) +F_OP(ito, q) +{ + set_float_exception_flags(0, &env->fp_status); + QT0 = int32_to_float128(*((int32_t *)&FT1), &env->fp_status); + check_ieee_exceptions(); +} +#endif + #ifdef TARGET_SPARC64 F_OP(xto, s) { @@ -1743,6 +1845,14 @@ F_OP(xto, d) DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status); check_ieee_exceptions(); } +#if defined(CONFIG_USER_ONLY) +F_OP(xto, q) +{ + set_float_exception_flags(0, &env->fp_status); + QT0 = int64_to_float128(*((int64_t *)&DT1), &env->fp_status); + check_ieee_exceptions(); +} +#endif #endif #endif #undef F_HELPER @@ -1762,6 +1872,36 @@ void OPPROTO op_fstod(void) check_ieee_exceptions(); } +#if defined(CONFIG_USER_ONLY) +void OPPROTO op_fqtos(void) +{ + set_float_exception_flags(0, &env->fp_status); + FT0 = float128_to_float32(QT1, &env->fp_status); + check_ieee_exceptions(); +} + +void OPPROTO op_fstoq(void) +{ + set_float_exception_flags(0, &env->fp_status); + QT0 = float32_to_float128(FT1, &env->fp_status); + check_ieee_exceptions(); +} + +void OPPROTO op_fqtod(void) +{ + set_float_exception_flags(0, &env->fp_status); + DT0 = float128_to_float64(QT1, &env->fp_status); + check_ieee_exceptions(); +} + +void OPPROTO op_fdtoq(void) +{ + set_float_exception_flags(0, &env->fp_status); + QT0 = float64_to_float128(DT1, &env->fp_status); + check_ieee_exceptions(); +} +#endif + /* Float to integer conversion. */ void OPPROTO op_fstoi(void) { @@ -1777,6 +1917,15 @@ void OPPROTO op_fdtoi(void) check_ieee_exceptions(); } +#if defined(CONFIG_USER_ONLY) +void OPPROTO op_fqtoi(void) +{ + set_float_exception_flags(0, &env->fp_status); + *((int32_t *)&FT0) = float128_to_int32_round_to_zero(QT1, &env->fp_status); + check_ieee_exceptions(); +} +#endif + #ifdef TARGET_SPARC64 void OPPROTO op_fstox(void) { @@ -1792,6 +1941,15 @@ void OPPROTO op_fdtox(void) check_ieee_exceptions(); } +#if defined(CONFIG_USER_ONLY) +void OPPROTO op_fqtox(void) +{ + set_float_exception_flags(0, &env->fp_status); + *((int64_t *)&DT0) = float128_to_int64_round_to_zero(QT1, &env->fp_status); + check_ieee_exceptions(); +} +#endif + void OPPROTO op_fmovs_cc(void) { if (T2) @@ -1804,6 +1962,14 @@ void OPPROTO op_fmovd_cc(void) DT0 = DT1; } +#if defined(CONFIG_USER_ONLY) +void OPPROTO op_fmovq_cc(void) +{ + if (T2) + QT0 = QT1; +} +#endif + void OPPROTO op_mov_cc(void) { if (T2) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index c643bdb364..48f5fc6004 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -97,6 +97,13 @@ void do_fabsd(void) { DT0 = float64_abs(DT1); } + +#if defined(CONFIG_USER_ONLY) +void do_fabsq(void) +{ + QT0 = float128_abs(QT1); +} +#endif #endif void do_fsqrts(void) @@ -113,6 +120,15 @@ void do_fsqrtd(void) check_ieee_exceptions(); } +#if defined(CONFIG_USER_ONLY) +void do_fsqrtq(void) +{ + set_float_exception_flags(0, &env->fp_status); + QT0 = float128_sqrt(QT1, &env->fp_status); + check_ieee_exceptions(); +} +#endif + #define GEN_FCMP(name, size, reg1, reg2, FS, TRAP) \ void glue(do_, name) (void) \ { \ @@ -148,6 +164,11 @@ GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0); GEN_FCMP(fcmpes, float32, FT0, FT1, 0, 1); GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1); +#ifdef CONFIG_USER_ONLY +GEN_FCMP(fcmpq, float128, QT0, QT1, 0, 0); +GEN_FCMP(fcmpeq, float128, QT0, QT1, 0, 1); +#endif + #ifdef TARGET_SPARC64 GEN_FCMP(fcmps_fcc1, float32, FT0, FT1, 22, 0); GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0); @@ -166,6 +187,14 @@ GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1); GEN_FCMP(fcmpes_fcc3, float32, FT0, FT1, 26, 1); GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1); +#ifdef CONFIG_USER_ONLY +GEN_FCMP(fcmpq_fcc1, float128, QT0, QT1, 22, 0); +GEN_FCMP(fcmpq_fcc2, float128, QT0, QT1, 24, 0); +GEN_FCMP(fcmpq_fcc3, float128, QT0, QT1, 26, 0); +GEN_FCMP(fcmpeq_fcc1, float128, QT0, QT1, 22, 1); +GEN_FCMP(fcmpeq_fcc2, float128, QT0, QT1, 24, 1); +GEN_FCMP(fcmpeq_fcc3, float128, QT0, QT1, 26, 1); +#endif #endif #ifndef TARGET_SPARC64 @@ -1374,6 +1403,11 @@ void helper_ldf_asi(int asi, int size, int rd) case 8: *((int64_t *)&DT0) = T1; break; +#if defined(CONFIG_USER_ONLY) + case 16: + // XXX + break; +#endif } T1 = tmp_T1; } @@ -1417,6 +1451,11 @@ void helper_stf_asi(int asi, int size, int rd) case 8: T1 = *((int64_t *)&DT0); break; +#if defined(CONFIG_USER_ONLY) + case 16: + // XXX + break; +#endif } helper_st_asi(asi, size); T1 = tmp_T1; diff --git a/target-sparc/op_mem.h b/target-sparc/op_mem.h index 4af00b3711..894fc36660 100644 --- a/target-sparc/op_mem.h +++ b/target-sparc/op_mem.h @@ -85,6 +85,28 @@ void OPPROTO glue(op_lddf, MEMSUFFIX) (void) DT0 = glue(ldfq, MEMSUFFIX)(ADDR(T0)); } +#if defined(CONFIG_USER_ONLY) +void OPPROTO glue(op_ldqf, MEMSUFFIX) (void) +{ + // XXX add 128 bit load + CPU_QuadU u; + + u.ll.upper = glue(ldq, MEMSUFFIX)(ADDR(T0)); + u.ll.lower = glue(ldq, MEMSUFFIX)(ADDR(T0 + 8)); + QT0 = u.q; +} + +void OPPROTO glue(op_stqf, MEMSUFFIX) (void) +{ + // XXX add 128 bit store + CPU_QuadU u; + + u.q = QT0; + glue(stq, MEMSUFFIX)(ADDR(T0), u.ll.upper); + glue(stq, MEMSUFFIX)(ADDR(T0 + 8), u.ll.lower); +} +#endif + #ifdef TARGET_SPARC64 void OPPROTO glue(op_lduw, MEMSUFFIX)(void) { diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 1e373cea39..7dee0adb18 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -25,7 +25,6 @@ Rest of V9 instructions, VIS instructions NPC/PC static optimisations (use JUMP_TB when possible) Optimize synthetic instructions - 128-bit float */ #include @@ -93,8 +92,10 @@ enum { #ifdef TARGET_SPARC64 #define DFPREG(r) (((r & 1) << 5) | (r & 0x1e)) +#define QFPREG(r) (((r & 1) << 5) | (r & 0x1c)) #else #define DFPREG(r) (r & 0x1e) +#define QFPREG(r) (r & 0x1c) #endif #ifdef USE_DIRECT_JUMP @@ -351,6 +352,13 @@ GEN32(gen_op_load_fpr_DT1, gen_op_load_fpr_DT1_fprf); GEN32(gen_op_store_DT0_fpr, gen_op_store_DT0_fpr_fprf); GEN32(gen_op_store_DT1_fpr, gen_op_store_DT1_fpr_fprf); +#if defined(CONFIG_USER_ONLY) +GEN32(gen_op_load_fpr_QT0, gen_op_load_fpr_QT0_fprf); +GEN32(gen_op_load_fpr_QT1, gen_op_load_fpr_QT1_fprf); +GEN32(gen_op_store_QT0_fpr, gen_op_store_QT0_fpr_fprf); +GEN32(gen_op_store_QT1_fpr, gen_op_store_QT1_fpr_fprf); +#endif + /* moves */ #ifdef CONFIG_USER_ONLY #define supervisor(dc) 0 @@ -1060,6 +1068,15 @@ static GenOpFunc * const gen_fcmpd[4] = { gen_op_fcmpd_fcc3, }; +#if defined(CONFIG_USER_ONLY) +static GenOpFunc * const gen_fcmpq[4] = { + gen_op_fcmpq, + gen_op_fcmpq_fcc1, + gen_op_fcmpq_fcc2, + gen_op_fcmpq_fcc3, +}; +#endif + static GenOpFunc * const gen_fcmpes[4] = { gen_op_fcmpes, gen_op_fcmpes_fcc1, @@ -1074,6 +1091,14 @@ static GenOpFunc * const gen_fcmped[4] = { gen_op_fcmped_fcc3, }; +#if defined(CONFIG_USER_ONLY) +static GenOpFunc * const gen_fcmpeq[4] = { + gen_op_fcmpeq, + gen_op_fcmpeq_fcc1, + gen_op_fcmpeq_fcc2, + gen_op_fcmpeq_fcc3, +}; +#endif #endif static int gen_trap_ifnofpu(DisasContext * dc) @@ -1484,7 +1509,14 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x2b: /* fsqrtq */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_QT1(QFPREG(rs2)); + gen_op_fsqrtq(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else goto nfpu_insn; +#endif case 0x41: gen_op_load_fpr_FT0(rs1); gen_op_load_fpr_FT1(rs2); @@ -1498,7 +1530,15 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x43: /* faddq */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_QT0(QFPREG(rs1)); + gen_op_load_fpr_QT1(QFPREG(rs2)); + gen_op_faddq(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else goto nfpu_insn; +#endif case 0x45: gen_op_load_fpr_FT0(rs1); gen_op_load_fpr_FT1(rs2); @@ -1512,7 +1552,15 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x47: /* fsubq */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_QT0(QFPREG(rs1)); + gen_op_load_fpr_QT1(QFPREG(rs2)); + gen_op_fsubq(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else goto nfpu_insn; +#endif case 0x49: gen_op_load_fpr_FT0(rs1); gen_op_load_fpr_FT1(rs2); @@ -1526,7 +1574,15 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_DT0_fpr(rd); break; case 0x4b: /* fmulq */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_QT0(QFPREG(rs1)); + gen_op_load_fpr_QT1(QFPREG(rs2)); + gen_op_fmulq(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else goto nfpu_insn; +#endif case 0x4d: gen_op_load_fpr_FT0(rs1); gen_op_load_fpr_FT1(rs2); @@ -1540,7 +1596,15 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x4f: /* fdivq */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_QT0(QFPREG(rs1)); + gen_op_load_fpr_QT1(QFPREG(rs2)); + gen_op_fdivq(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else goto nfpu_insn; +#endif case 0x69: gen_op_load_fpr_FT0(rs1); gen_op_load_fpr_FT1(rs2); @@ -1548,7 +1612,15 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0x6e: /* fdmulq */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_DT0(DFPREG(rs1)); + gen_op_load_fpr_DT1(DFPREG(rs2)); + gen_op_fdmulq(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else goto nfpu_insn; +#endif case 0xc4: gen_op_load_fpr_FT1(rs2); gen_op_fitos(); @@ -1560,7 +1632,14 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_FT0_fpr(rd); break; case 0xc7: /* fqtos */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_QT1(QFPREG(rs2)); + gen_op_fqtos(); + gen_op_store_FT0_fpr(rd); + break; +#else goto nfpu_insn; +#endif case 0xc8: gen_op_load_fpr_FT1(rs2); gen_op_fitod(); @@ -1572,13 +1651,41 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_DT0_fpr(DFPREG(rd)); break; case 0xcb: /* fqtod */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_QT1(QFPREG(rs2)); + gen_op_fqtod(); + gen_op_store_DT0_fpr(DFPREG(rd)); + break; +#else goto nfpu_insn; +#endif case 0xcc: /* fitoq */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_FT1(rs2); + gen_op_fitoq(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else goto nfpu_insn; +#endif case 0xcd: /* fstoq */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_FT1(rs2); + gen_op_fstoq(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else goto nfpu_insn; +#endif case 0xce: /* fdtoq */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_DT1(DFPREG(rs2)); + gen_op_fdtoq(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else goto nfpu_insn; +#endif case 0xd1: gen_op_load_fpr_FT1(rs2); gen_op_fstoi(); @@ -1590,22 +1697,55 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_FT0_fpr(rd); break; case 0xd3: /* fqtoi */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_QT1(QFPREG(rs2)); + gen_op_fqtoi(); + gen_op_store_FT0_fpr(rd); + break; +#else goto nfpu_insn; +#endif #ifdef TARGET_SPARC64 case 0x2: /* V9 fmovd */ gen_op_load_fpr_DT0(DFPREG(rs2)); gen_op_store_DT0_fpr(DFPREG(rd)); break; + case 0x3: /* V9 fmovq */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_QT0(QFPREG(rs2)); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else + goto nfpu_insn; +#endif case 0x6: /* V9 fnegd */ gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fnegd(); gen_op_store_DT0_fpr(DFPREG(rd)); break; + case 0x7: /* V9 fnegq */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_QT1(QFPREG(rs2)); + gen_op_fnegq(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else + goto nfpu_insn; +#endif case 0xa: /* V9 fabsd */ gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fabsd(); gen_op_store_DT0_fpr(DFPREG(rd)); break; + case 0xb: /* V9 fabsq */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_QT1(QFPREG(rs2)); + gen_op_fabsq(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else + goto nfpu_insn; +#endif case 0x81: /* V9 fstox */ gen_op_load_fpr_FT1(rs2); gen_op_fstox(); @@ -1616,6 +1756,15 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_fdtox(); gen_op_store_DT0_fpr(DFPREG(rd)); break; + case 0x83: /* V9 fqtox */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_QT1(QFPREG(rs2)); + gen_op_fqtox(); + gen_op_store_DT0_fpr(DFPREG(rd)); + break; +#else + goto nfpu_insn; +#endif case 0x84: /* V9 fxtos */ gen_op_load_fpr_DT1(DFPREG(rs2)); gen_op_fxtos(); @@ -1626,12 +1775,15 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_fxtod(); gen_op_store_DT0_fpr(DFPREG(rd)); break; - case 0x3: /* V9 fmovq */ - case 0x7: /* V9 fnegq */ - case 0xb: /* V9 fabsq */ - case 0x83: /* V9 fqtox */ case 0x8c: /* V9 fxtoq */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_DT1(DFPREG(rs2)); + gen_op_fxtoq(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else goto nfpu_insn; +#endif #endif default: goto illegal_insn; @@ -1670,7 +1822,20 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_DT0_fpr(rd); break; } else if ((xop & 0x11f) == 0x007) { // V9 fmovqr +#if defined(CONFIG_USER_ONLY) + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_QT0(QFPREG(rd)); + gen_op_load_fpr_QT1(QFPREG(rs2)); + flush_T2(dc); + rs1 = GET_FIELD(insn, 13, 17); + gen_movl_reg_T0(rs1); + gen_cond_reg(cond); + gen_op_fmovq_cc(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else goto nfpu_insn; +#endif } #endif switch (xop) { @@ -1694,7 +1859,18 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_DT0_fpr(rd); break; case 0x003: /* V9 fmovqcc %fcc0 */ +#if defined(CONFIG_USER_ONLY) + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_QT0(QFPREG(rd)); + gen_op_load_fpr_QT1(QFPREG(rs2)); + flush_T2(dc); + gen_fcond[0][cond](); + gen_op_fmovq_cc(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else goto nfpu_insn; +#endif case 0x041: /* V9 fmovscc %fcc1 */ cond = GET_FIELD_SP(insn, 14, 17); gen_op_load_fpr_FT0(rd); @@ -1714,7 +1890,18 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_DT0_fpr(rd); break; case 0x043: /* V9 fmovqcc %fcc1 */ +#if defined(CONFIG_USER_ONLY) + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_QT0(QFPREG(rd)); + gen_op_load_fpr_QT1(QFPREG(rs2)); + flush_T2(dc); + gen_fcond[1][cond](); + gen_op_fmovq_cc(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else goto nfpu_insn; +#endif case 0x081: /* V9 fmovscc %fcc2 */ cond = GET_FIELD_SP(insn, 14, 17); gen_op_load_fpr_FT0(rd); @@ -1734,7 +1921,18 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_DT0_fpr(rd); break; case 0x083: /* V9 fmovqcc %fcc2 */ +#if defined(CONFIG_USER_ONLY) + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_QT0(rd); + gen_op_load_fpr_QT1(rs2); + flush_T2(dc); + gen_fcond[2][cond](); + gen_op_fmovq_cc(); + gen_op_store_QT0_fpr(rd); + break; +#else goto nfpu_insn; +#endif case 0x0c1: /* V9 fmovscc %fcc3 */ cond = GET_FIELD_SP(insn, 14, 17); gen_op_load_fpr_FT0(rd); @@ -1754,7 +1952,18 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_DT0_fpr(rd); break; case 0x0c3: /* V9 fmovqcc %fcc3 */ +#if defined(CONFIG_USER_ONLY) + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_QT0(QFPREG(rd)); + gen_op_load_fpr_QT1(QFPREG(rs2)); + flush_T2(dc); + gen_fcond[3][cond](); + gen_op_fmovq_cc(); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else goto nfpu_insn; +#endif case 0x101: /* V9 fmovscc %icc */ cond = GET_FIELD_SP(insn, 14, 17); gen_op_load_fpr_FT0(rd); @@ -1774,7 +1983,18 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_DT0_fpr(rd); break; case 0x103: /* V9 fmovqcc %icc */ +#if defined(CONFIG_USER_ONLY) + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_QT0(rd); + gen_op_load_fpr_QT1(rs2); + flush_T2(dc); + gen_cond[0][cond](); + gen_op_fmovq_cc(); + gen_op_store_QT0_fpr(rd); + break; +#else goto nfpu_insn; +#endif case 0x181: /* V9 fmovscc %xcc */ cond = GET_FIELD_SP(insn, 14, 17); gen_op_load_fpr_FT0(rd); @@ -1794,9 +2014,20 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_store_DT0_fpr(rd); break; case 0x183: /* V9 fmovqcc %xcc */ +#if defined(CONFIG_USER_ONLY) + cond = GET_FIELD_SP(insn, 14, 17); + gen_op_load_fpr_QT0(rd); + gen_op_load_fpr_QT1(rs2); + flush_T2(dc); + gen_cond[1][cond](); + gen_op_fmovq_cc(); + gen_op_store_QT0_fpr(rd); + break; +#else goto nfpu_insn; #endif - case 0x51: /* V9 %fcc */ +#endif + case 0x51: /* fcmps, V9 %fcc */ gen_op_load_fpr_FT0(rs1); gen_op_load_fpr_FT1(rs2); #ifdef TARGET_SPARC64 @@ -1805,7 +2036,7 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_fcmps(); #endif break; - case 0x52: /* V9 %fcc */ + case 0x52: /* fcmpd, V9 %fcc */ gen_op_load_fpr_DT0(DFPREG(rs1)); gen_op_load_fpr_DT1(DFPREG(rs2)); #ifdef TARGET_SPARC64 @@ -1814,8 +2045,19 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_fcmpd(); #endif break; - case 0x53: /* fcmpq */ + case 0x53: /* fcmpq, V9 %fcc */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_QT0(QFPREG(rs1)); + gen_op_load_fpr_QT1(QFPREG(rs2)); +#ifdef TARGET_SPARC64 + gen_fcmpq[rd & 3](); +#else + gen_op_fcmpq(); +#endif + break; +#else /* !defined(CONFIG_USER_ONLY) */ goto nfpu_insn; +#endif case 0x55: /* fcmpes, V9 %fcc */ gen_op_load_fpr_FT0(rs1); gen_op_load_fpr_FT1(rs2); @@ -1834,8 +2076,19 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_fcmped(); #endif break; - case 0x57: /* fcmpeq */ + case 0x57: /* fcmpeq, V9 %fcc */ +#if defined(CONFIG_USER_ONLY) + gen_op_load_fpr_QT0(QFPREG(rs1)); + gen_op_load_fpr_QT1(QFPREG(rs2)); +#ifdef TARGET_SPARC64 + gen_fcmpeq[rd & 3](); +#else + gen_op_fcmpeq(); +#endif + break; +#else/* !defined(CONFIG_USER_ONLY) */ goto nfpu_insn; +#endif default: goto illegal_insn; } @@ -3095,7 +3348,13 @@ static void disas_sparc_insn(DisasContext * dc) case 0x3d: /* V9 prefetcha, no effect */ goto skip_move; case 0x32: /* V9 ldqfa */ +#if defined(CONFIG_USER_ONLY) + gen_op_check_align_T0_3(); + gen_ldf_asi(insn, 16); + goto skip_move; +#else goto nfpu_insn; +#endif #endif default: goto illegal_insn; @@ -3119,7 +3378,14 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_ldfsr(); break; case 0x22: /* load quad fpreg */ +#if defined(CONFIG_USER_ONLY) + gen_op_check_align_T0_7(); + gen_op_ldst(ldqf); + gen_op_store_QT0_fpr(QFPREG(rd)); + break; +#else goto nfpu_insn; +#endif case 0x23: /* load double fpreg */ gen_op_check_align_T0_7(); gen_op_ldst(lddf); @@ -3225,13 +3491,28 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_stfsr(); gen_op_ldst(stf); break; -#if !defined(CONFIG_USER_ONLY) - case 0x26: /* stdfq */ + case 0x26: +#ifdef TARGET_SPARC64 +#if defined(CONFIG_USER_ONLY) + /* V9 stqf, store quad fpreg */ + gen_op_check_align_T0_7(); + gen_op_load_fpr_QT0(QFPREG(rd)); + gen_op_ldst(stqf); + break; +#else + goto nfpu_insn; +#endif +#else /* !TARGET_SPARC64 */ + /* stdfq, store floating point queue */ +#if defined(CONFIG_USER_ONLY) + goto illegal_insn; +#else if (!supervisor(dc)) goto priv_insn; if (gen_trap_ifnofpu(dc)) goto jmp_insn; goto nfq_insn; +#endif #endif case 0x27: gen_op_check_align_T0_7(); @@ -3249,6 +3530,15 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_load_fpr_FT0(rd); gen_stf_asi(insn, 4); break; + case 0x36: /* V9 stqfa */ +#if defined(CONFIG_USER_ONLY) + gen_op_check_align_T0_7(); + gen_op_load_fpr_QT0(QFPREG(rd)); + gen_stf_asi(insn, 16); + break; +#else + goto nfpu_insn; +#endif case 0x37: /* V9 stdfa */ gen_op_check_align_T0_3(); gen_op_load_fpr_DT0(DFPREG(rd)); @@ -3268,8 +3558,6 @@ static void disas_sparc_insn(DisasContext * dc) gen_casx_asi(insn); gen_movl_T1_reg(rd); break; - case 0x36: /* V9 stqfa */ - goto nfpu_insn; #else case 0x34: /* stc */ case 0x35: /* stcsr */ @@ -3311,19 +3599,19 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_exception(TT_PRIV_INSN); dc->is_br = 1; return; -#endif nfpu_insn: save_state(dc); gen_op_fpexception_im(FSR_FTT_UNIMPFPOP); dc->is_br = 1; return; -#if !defined(CONFIG_USER_ONLY) +#ifndef TARGET_SPARC64 nfq_insn: save_state(dc); gen_op_fpexception_im(FSR_FTT_SEQ_ERROR); dc->is_br = 1; return; #endif +#endif #ifndef TARGET_SPARC64 ncp_insn: save_state(dc);