diff --git a/qemu/header_gen.py b/qemu/header_gen.py index b17ca86b..66e0ce55 100644 --- a/qemu/header_gen.py +++ b/qemu/header_gen.py @@ -4417,12 +4417,10 @@ sparc_symbols = ( 'helper_fsubs', 'helper_ld_asi', 'helper_ldfsr', - 'helper_ldqf', 'helper_restore', 'helper_save', 'helper_sdiv_cc', 'helper_st_asi', - 'helper_stqf', 'helper_taddcctv', 'helper_tsubcctv', 'helper_udiv_cc', diff --git a/qemu/sparc.h b/qemu/sparc.h index 3bc48337..e192c7ae 100644 --- a/qemu/sparc.h +++ b/qemu/sparc.h @@ -3403,12 +3403,10 @@ #define helper_fsubs helper_fsubs_sparc #define helper_ld_asi helper_ld_asi_sparc #define helper_ldfsr helper_ldfsr_sparc -#define helper_ldqf helper_ldqf_sparc #define helper_restore helper_restore_sparc #define helper_save helper_save_sparc #define helper_sdiv_cc helper_sdiv_cc_sparc #define helper_st_asi helper_st_asi_sparc -#define helper_stqf helper_stqf_sparc #define helper_taddcctv helper_taddcctv_sparc #define helper_tsubcctv helper_tsubcctv_sparc #define helper_udiv_cc helper_udiv_cc_sparc diff --git a/qemu/sparc64.h b/qemu/sparc64.h index aa44f725..62cf3d59 100644 --- a/qemu/sparc64.h +++ b/qemu/sparc64.h @@ -3403,12 +3403,10 @@ #define helper_fsubs helper_fsubs_sparc64 #define helper_ld_asi helper_ld_asi_sparc64 #define helper_ldfsr helper_ldfsr_sparc64 -#define helper_ldqf helper_ldqf_sparc64 #define helper_restore helper_restore_sparc64 #define helper_save helper_save_sparc64 #define helper_sdiv_cc helper_sdiv_cc_sparc64 #define helper_st_asi helper_st_asi_sparc64 -#define helper_stqf helper_stqf_sparc64 #define helper_taddcctv helper_taddcctv_sparc64 #define helper_tsubcctv helper_tsubcctv_sparc64 #define helper_udiv_cc helper_udiv_cc_sparc64 diff --git a/qemu/target-sparc/helper.h b/qemu/target-sparc/helper.h index d174c90c..e1897752 100644 --- a/qemu/target-sparc/helper.h +++ b/qemu/target-sparc/helper.h @@ -40,8 +40,6 @@ DEF_HELPER_3(tsubcctv, tl, env, tl, tl) DEF_HELPER_FLAGS_3(sdivx, TCG_CALL_NO_WG, s64, env, s64, s64) DEF_HELPER_FLAGS_3(udivx, TCG_CALL_NO_WG, i64, env, i64, i64) #endif -DEF_HELPER_FLAGS_3(ldqf, TCG_CALL_NO_WG, void, env, tl, int) -DEF_HELPER_FLAGS_3(stqf, TCG_CALL_NO_WG, void, env, tl, int) #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) DEF_HELPER_FLAGS_4(ld_asi, TCG_CALL_NO_WG, i64, env, tl, int, i32) DEF_HELPER_FLAGS_5(st_asi, TCG_CALL_NO_WG, void, env, tl, i64, int, i32) diff --git a/qemu/target-sparc/ldst_helper.c b/qemu/target-sparc/ldst_helper.c index b1831d93..0338f9f2 100644 --- a/qemu/target-sparc/ldst_helper.c +++ b/qemu/target-sparc/ldst_helper.c @@ -977,11 +977,9 @@ static inline int is_translating_asi(int asi) static inline target_ulong address_mask(CPUSPARCState *env1, target_ulong addr) { -#ifdef TARGET_SPARC64 if (AM_CHECK(env1)) { addr &= 0xffffffffULL; } -#endif return addr; } @@ -989,10 +987,9 @@ static inline target_ulong asi_address_mask(CPUSPARCState *env, int asi, target_ulong addr) { if (is_translating_asi(asi)) { - return address_mask(env, addr); - } else { - return addr; + addr = address_mask(env, addr); } + return addr; } #ifdef CONFIG_USER_ONLY @@ -1610,78 +1607,6 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val, #endif /* CONFIG_USER_ONLY */ #endif /* TARGET_SPARC64 */ -void helper_ldqf(CPUSPARCState *env, target_ulong addr, int mem_idx) -{ - /* XXX add 128 bit load */ - CPU_QuadU u; - - do_check_align(env, addr, 7, GETPC()); -#if !defined(CONFIG_USER_ONLY) - switch (mem_idx) { - case MMU_USER_IDX: - u.ll.upper = cpu_ldq_user(env, addr); - u.ll.lower = cpu_ldq_user(env, addr + 8); - QT0 = u.q; - break; - case MMU_KERNEL_IDX: - u.ll.upper = cpu_ldq_kernel(env, addr); - u.ll.lower = cpu_ldq_kernel(env, addr + 8); - QT0 = u.q; - break; -#ifdef TARGET_SPARC64 - case MMU_HYPV_IDX: - u.ll.upper = cpu_ldq_hypv(env, addr); - u.ll.lower = cpu_ldq_hypv(env, addr + 8); - QT0 = u.q; - break; -#endif - default: - DPRINTF_MMU("helper_ldqf: need to check MMU idx %d\n", mem_idx); - break; - } -#else - u.ll.upper = ldq_raw(address_mask(env, addr)); - u.ll.lower = ldq_raw(address_mask(env, addr + 8)); - QT0 = u.q; -#endif -} - -void helper_stqf(CPUSPARCState *env, target_ulong addr, int mem_idx) -{ - /* XXX add 128 bit store */ - CPU_QuadU u; - - do_check_align(env, addr, 7, GETPC()); -#if !defined(CONFIG_USER_ONLY) - switch (mem_idx) { - case MMU_USER_IDX: - u.q = QT0; - cpu_stq_user(env, addr, u.ll.upper); - cpu_stq_user(env, addr + 8, u.ll.lower); - break; - case MMU_KERNEL_IDX: - u.q = QT0; - cpu_stq_kernel(env, addr, u.ll.upper); - cpu_stq_kernel(env, addr + 8, u.ll.lower); - break; -#ifdef TARGET_SPARC64 - case MMU_HYPV_IDX: - u.q = QT0; - cpu_stq_hypv(env, addr, u.ll.upper); - cpu_stq_hypv(env, addr + 8, u.ll.lower); - break; -#endif - default: - DPRINTF_MMU("helper_stqf: need to check MMU idx %d\n", mem_idx); - break; - } -#else - u.q = QT0; - stq_raw(address_mask(env, addr), u.ll.upper); - stq_raw(address_mask(env, addr + 8), u.ll.lower); -#endif -} - #if !defined(CONFIG_USER_ONLY) #ifndef TARGET_SPARC64 void sparc_cpu_unassigned_access(CPUState *cs, hwaddr addr, diff --git a/qemu/target-sparc/translate.c b/qemu/target-sparc/translate.c index 18cfdf6d..06467bec 100644 --- a/qemu/target-sparc/translate.c +++ b/qemu/target-sparc/translate.c @@ -225,7 +225,32 @@ static void gen_op_store_QT0_fpr(DisasContext *dc, unsigned int dst) offsetof(CPU_QuadU, ll.lower)); } +static void gen_store_fpr_Q(DisasContext *dc, unsigned int dst, + TCGv_i64 v1, TCGv_i64 v2) +{ + TCGContext *tcg_ctx = dc->uc->tcg_ctx; + dst = QFPREG(dst); + + tcg_gen_mov_i64(tcg_ctx, tcg_ctx->cpu_fpr[dst / 2], v1); + tcg_gen_mov_i64(tcg_ctx, tcg_ctx->cpu_fpr[dst / 2 + 1], v2); + gen_update_fprs_dirty(dc, dst); +} + #ifdef TARGET_SPARC64 +static TCGv_i64 gen_load_fpr_Q0(DisasContext *dc, unsigned int src) +{ + TCGContext *tcg_ctx = dc->uc->tcg_ctx; + src = QFPREG(src); + return tcg_ctx->cpu_fpr[src / 2]; +} + +static TCGv_i64 gen_load_fpr_Q1(DisasContext *dc, unsigned int src) +{ + TCGContext *tcg_ctx = dc->uc->tcg_ctx; + src = QFPREG(src); + return tcg_ctx->cpu_fpr[src / 2 + 1]; +} + static void gen_move_Q(DisasContext *dc, unsigned int rd, unsigned int rs) { TCGContext *tcg_ctx = dc->uc->tcg_ctx; @@ -2753,10 +2778,17 @@ static void gen_stf_asi(DisasContext *dc, TCGv addr, tcg_gen_qemu_st_i32(dc->uc, d32, addr, da.mem_idx, da.memop); break; case 8: + /* ??? Only 4-byte alignment required. However, it is legal + for the cpu to signal the alignment fault, and the OS trap + handler is required to fix it up. */ tcg_gen_qemu_st_i64(dc->uc, tcg_ctx->cpu_fpr[rd / 2], addr, da.mem_idx, da.memop); break; case 16: - tcg_gen_qemu_st_i64(dc->uc, tcg_ctx->cpu_fpr[rd / 2], addr, da.mem_idx, da.memop); + /* Only 4-byte alignment required. See above. Requiring + 16-byte alignment here avoids having to probe the second + page before performing the first write. */ + tcg_gen_qemu_st_i64(dc->uc, tcg_ctx->cpu_fpr[rd / 2], addr, da.mem_idx, + da.memop | MO_ALIGN_16); tcg_gen_addi_tl(tcg_ctx, addr, addr, 8); tcg_gen_qemu_st_i64(dc->uc, tcg_ctx->cpu_fpr[rd/2+1], addr, da.mem_idx, da.memop); break; @@ -5605,17 +5637,16 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn, bool hook_ins gen_helper_ldfsr(tcg_ctx, tcg_ctx->cpu_fsr, tcg_ctx->cpu_env, tcg_ctx->cpu_fsr, cpu_dst_32); break; case 0x22: /* ldqf, load quad fpreg */ - { - TCGv_i32 r_const; - - CHECK_FPU_FEATURE(dc, FLOAT128); - r_const = tcg_const_i32(tcg_ctx, dc->mem_idx); - gen_address_mask(dc, cpu_addr); - gen_helper_ldqf(tcg_ctx, tcg_ctx->cpu_env, cpu_addr, r_const); - tcg_temp_free_i32(tcg_ctx, r_const); - gen_op_store_QT0_fpr(dc, QFPREG(rd)); - gen_update_fprs_dirty(dc, QFPREG(rd)); - } + CHECK_FPU_FEATURE(dc, FLOAT128); + gen_address_mask(dc, cpu_addr); + cpu_src1_64 = tcg_temp_new_i64(tcg_ctx); + tcg_gen_qemu_ld64(dc->uc, cpu_src1_64, cpu_addr, dc->mem_idx); + tcg_gen_addi_tl(tcg_ctx, cpu_addr, cpu_addr, 8); + cpu_src2_64 = tcg_temp_new_i64(tcg_ctx); + tcg_gen_qemu_ld64(dc->uc, cpu_src2_64, cpu_addr, dc->mem_idx); + gen_store_fpr_Q(dc, rd, cpu_src1_64, cpu_src2_64); + tcg_temp_free_i64(tcg_ctx, cpu_src1_64); + tcg_temp_free_i64(tcg_ctx, cpu_src2_64); break; case 0x23: /* lddf, load double fpreg */ gen_address_mask(dc, cpu_addr); @@ -5717,16 +5748,20 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn, bool hook_ins case 0x26: #ifdef TARGET_SPARC64 /* V9 stqf, store quad fpreg */ - { - TCGv_i32 r_const; - - CHECK_FPU_FEATURE(dc, FLOAT128); - gen_op_load_fpr_QT0(dc, QFPREG(rd)); - r_const = tcg_const_i32(tcg_ctx, dc->mem_idx); - gen_address_mask(dc, cpu_addr); - gen_helper_stqf(tcg_ctx, tcg_ctx->cpu_env, cpu_addr, r_const); - tcg_temp_free_i32(tcg_ctx, r_const); - } + CHECK_FPU_FEATURE(dc, FLOAT128); + gen_address_mask(dc, cpu_addr); + /* ??? While stqf only requires 4-byte alignment, it is + legal for the cpu to signal the unaligned exception. + The OS trap handler is then required to fix it up. + For qemu, this avoids having to probe the second page + before performing the first write. */ + cpu_src1_64 = gen_load_fpr_Q0(dc, rd); + tcg_gen_qemu_st_i64(dc->uc, cpu_src1_64, cpu_addr, + dc->mem_idx, MO_TEQ | MO_ALIGN_16); + tcg_gen_addi_tl(tcg_ctx, cpu_addr, cpu_addr, 8); + cpu_src2_64 = gen_load_fpr_Q1(dc, rd); + tcg_gen_qemu_st_i64(dc->uc, cpu_src1_64, cpu_addr, + dc->mem_idx, MO_TEQ); break; #else /* !TARGET_SPARC64 */ /* stdfq, store floating point queue */ @@ -5742,6 +5777,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn, bool hook_ins #endif #endif case 0x27: /* stdf, store double fpreg */ + /* ??? Only 4-byte alignment required. However, it is + legal for the cpu to signal the alignment fault, and + the OS trap handler is required to fix it up. */ gen_address_mask(dc, cpu_addr); cpu_src1_64 = gen_load_fpr_D(dc, rd); tcg_gen_qemu_st64(dc->uc, cpu_src1_64, cpu_addr, dc->mem_idx);