diff options
-rw-r--r-- | target-sparc/cpu.h | 1 | ||||
-rw-r--r-- | target-sparc/helper.c | 28 | ||||
-rw-r--r-- | target-sparc/helper.h | 4 | ||||
-rw-r--r-- | target-sparc/ldst_helper.c | 4 | ||||
-rw-r--r-- | target-sparc/translate.c | 52 |
5 files changed, 37 insertions, 52 deletions
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index e16b7b3515..214d01dd71 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -714,6 +714,7 @@ trap_state* cpu_tsptr(CPUSPARCState* env); void QEMU_NORETURN do_unaligned_access(CPUSPARCState *env, target_ulong addr, int is_write, int is_user, uintptr_t retaddr); +void cpu_restore_state2(CPUSPARCState *env, uintptr_t retaddr); #define TB_FLAG_FPU_ENABLED (1 << 4) #define TB_FLAG_AM_ENABLED (1 << 5) diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 65e1740e19..4555d2bfc0 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -75,6 +75,7 @@ static target_ulong helper_udiv_common(CPUSPARCState *env, target_ulong a, x1 = (b & 0xffffffff); if (x1 == 0) { + cpu_restore_state2(env, GETPC()); helper_raise_exception(env, TT_DIV_ZERO); } @@ -113,6 +114,7 @@ static target_ulong helper_sdiv_common(CPUSPARCState *env, target_ulong a, x1 = (b & 0xffffffff); if (x1 == 0) { + cpu_restore_state2(env, GETPC()); helper_raise_exception(env, TT_DIV_ZERO); } @@ -139,3 +141,29 @@ target_ulong helper_sdiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b) { return helper_sdiv_common(env, a, b, 1); } + +#ifdef TARGET_SPARC64 +int64_t helper_sdivx(CPUSPARCState *env, int64_t a, int64_t b) +{ + if (b == 0) { + /* Raise divide by zero trap. */ + cpu_restore_state2(env, GETPC()); + helper_raise_exception(env, TT_DIV_ZERO); + } else if (b == -1) { + /* Avoid overflow trap with i386 divide insn. */ + return -a; + } else { + return a / b; + } +} + +uint64_t helper_udivx(CPUSPARCState *env, uint64_t a, uint64_t b) +{ + if (b == 0) { + /* Raise divide by zero trap. */ + cpu_restore_state2(env, GETPC()); + helper_raise_exception(env, TT_DIV_ZERO); + } + return a / b; +} +#endif diff --git a/target-sparc/helper.h b/target-sparc/helper.h index e3c7fddbe8..827df67cc2 100644 --- a/target-sparc/helper.h +++ b/target-sparc/helper.h @@ -38,6 +38,10 @@ DEF_HELPER_3(udiv, tl, env, tl, tl) DEF_HELPER_3(udiv_cc, tl, env, tl, tl) DEF_HELPER_3(sdiv, tl, env, tl, tl) DEF_HELPER_3(sdiv_cc, tl, env, tl, tl) +#ifdef TARGET_SPARC64 +DEF_HELPER_3(sdivx, s64, env, s64, s64) +DEF_HELPER_3(udivx, i64, env, i64, i64) +#endif DEF_HELPER_3(ldqf, void, env, tl, int) DEF_HELPER_3(stqf, void, env, tl, int) #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c index 9bec7a92f7..2ca9a5c4a9 100644 --- a/target-sparc/ldst_helper.c +++ b/target-sparc/ldst_helper.c @@ -2390,9 +2390,8 @@ void cpu_unassigned_access(CPUSPARCState *env, target_phys_addr_t addr, #endif #endif -#if !defined(CONFIG_USER_ONLY) /* XXX: make it generic ? */ -static void cpu_restore_state2(CPUSPARCState *env, uintptr_t retaddr) +void cpu_restore_state2(CPUSPARCState *env, uintptr_t retaddr) { TranslationBlock *tb; @@ -2407,6 +2406,7 @@ static void cpu_restore_state2(CPUSPARCState *env, uintptr_t retaddr) } } +#if !defined(CONFIG_USER_ONLY) void do_unaligned_access(CPUSPARCState *env, target_ulong addr, int is_write, int is_user, uintptr_t retaddr) { diff --git a/target-sparc/translate.c b/target-sparc/translate.c index c1a1dc4808..1628cf355b 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -768,44 +768,6 @@ static inline void gen_op_smul(TCGv dst, TCGv src1, TCGv src2) gen_op_multiply(dst, src1, src2, 1); } -#ifdef TARGET_SPARC64 -static inline void gen_trap_ifdivzero_tl(TCGv divisor) -{ - TCGv_i32 r_const; - int l1; - - l1 = gen_new_label(); - tcg_gen_brcondi_tl(TCG_COND_NE, divisor, 0, l1); - r_const = tcg_const_i32(TT_DIV_ZERO); - gen_helper_raise_exception(cpu_env, r_const); - tcg_temp_free_i32(r_const); - gen_set_label(l1); -} - -static inline void gen_op_sdivx(TCGv dst, TCGv src1, TCGv src2) -{ - int l1, l2; - TCGv r_temp1, r_temp2; - - l1 = gen_new_label(); - l2 = gen_new_label(); - r_temp1 = tcg_temp_local_new(); - r_temp2 = tcg_temp_local_new(); - tcg_gen_mov_tl(r_temp1, src1); - tcg_gen_mov_tl(r_temp2, src2); - gen_trap_ifdivzero_tl(r_temp2); - tcg_gen_brcondi_tl(TCG_COND_NE, r_temp1, INT64_MIN, l1); - tcg_gen_brcondi_tl(TCG_COND_NE, r_temp2, -1, l1); - tcg_gen_movi_i64(dst, INT64_MIN); - tcg_gen_br(l2); - gen_set_label(l1); - tcg_gen_div_i64(dst, r_temp1, r_temp2); - gen_set_label(l2); - tcg_temp_free(r_temp1); - tcg_temp_free(r_temp2); -} -#endif - // 1 static inline void gen_op_eval_ba(TCGv dst) { @@ -3591,17 +3553,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) break; #ifdef TARGET_SPARC64 case 0xd: /* V9 udivx */ - { - TCGv r_temp1, r_temp2; - r_temp1 = tcg_temp_local_new(); - r_temp2 = tcg_temp_local_new(); - tcg_gen_mov_tl(r_temp1, cpu_src1); - tcg_gen_mov_tl(r_temp2, cpu_src2); - gen_trap_ifdivzero_tl(r_temp2); - tcg_gen_divu_i64(cpu_dst, r_temp1, r_temp2); - tcg_temp_free(r_temp1); - tcg_temp_free(r_temp2); - } + gen_helper_udivx(cpu_dst, cpu_env, cpu_src1, cpu_src2); break; #endif case 0xe: /* udiv */ @@ -4102,7 +4054,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) break; } case 0x2d: /* V9 sdivx */ - gen_op_sdivx(cpu_dst, cpu_src1, cpu_src2); + gen_helper_sdivx(cpu_dst, cpu_env, cpu_src1, cpu_src2); gen_movl_TN_reg(rd, cpu_dst); break; case 0x2e: /* V9 popc */ |