target-sparc: Implement ldqf and stqf inline

At the same time, fix a problem with stqf_asi, when
a write might access two pages.

Backports commit f939ffe5a022a8798824e2720ed5a14186fca6b6 from qemu
This commit is contained in:
Richard Henderson 2018-03-01 08:15:30 -05:00 committed by Lioncash
parent 3a25695841
commit eec264526e
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
6 changed files with 62 additions and 107 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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