mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2024-12-23 08:45:37 +00:00
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:
parent
3a25695841
commit
eec264526e
|
@ -4417,12 +4417,10 @@ sparc_symbols = (
|
||||||
'helper_fsubs',
|
'helper_fsubs',
|
||||||
'helper_ld_asi',
|
'helper_ld_asi',
|
||||||
'helper_ldfsr',
|
'helper_ldfsr',
|
||||||
'helper_ldqf',
|
|
||||||
'helper_restore',
|
'helper_restore',
|
||||||
'helper_save',
|
'helper_save',
|
||||||
'helper_sdiv_cc',
|
'helper_sdiv_cc',
|
||||||
'helper_st_asi',
|
'helper_st_asi',
|
||||||
'helper_stqf',
|
|
||||||
'helper_taddcctv',
|
'helper_taddcctv',
|
||||||
'helper_tsubcctv',
|
'helper_tsubcctv',
|
||||||
'helper_udiv_cc',
|
'helper_udiv_cc',
|
||||||
|
|
|
@ -3403,12 +3403,10 @@
|
||||||
#define helper_fsubs helper_fsubs_sparc
|
#define helper_fsubs helper_fsubs_sparc
|
||||||
#define helper_ld_asi helper_ld_asi_sparc
|
#define helper_ld_asi helper_ld_asi_sparc
|
||||||
#define helper_ldfsr helper_ldfsr_sparc
|
#define helper_ldfsr helper_ldfsr_sparc
|
||||||
#define helper_ldqf helper_ldqf_sparc
|
|
||||||
#define helper_restore helper_restore_sparc
|
#define helper_restore helper_restore_sparc
|
||||||
#define helper_save helper_save_sparc
|
#define helper_save helper_save_sparc
|
||||||
#define helper_sdiv_cc helper_sdiv_cc_sparc
|
#define helper_sdiv_cc helper_sdiv_cc_sparc
|
||||||
#define helper_st_asi helper_st_asi_sparc
|
#define helper_st_asi helper_st_asi_sparc
|
||||||
#define helper_stqf helper_stqf_sparc
|
|
||||||
#define helper_taddcctv helper_taddcctv_sparc
|
#define helper_taddcctv helper_taddcctv_sparc
|
||||||
#define helper_tsubcctv helper_tsubcctv_sparc
|
#define helper_tsubcctv helper_tsubcctv_sparc
|
||||||
#define helper_udiv_cc helper_udiv_cc_sparc
|
#define helper_udiv_cc helper_udiv_cc_sparc
|
||||||
|
|
|
@ -3403,12 +3403,10 @@
|
||||||
#define helper_fsubs helper_fsubs_sparc64
|
#define helper_fsubs helper_fsubs_sparc64
|
||||||
#define helper_ld_asi helper_ld_asi_sparc64
|
#define helper_ld_asi helper_ld_asi_sparc64
|
||||||
#define helper_ldfsr helper_ldfsr_sparc64
|
#define helper_ldfsr helper_ldfsr_sparc64
|
||||||
#define helper_ldqf helper_ldqf_sparc64
|
|
||||||
#define helper_restore helper_restore_sparc64
|
#define helper_restore helper_restore_sparc64
|
||||||
#define helper_save helper_save_sparc64
|
#define helper_save helper_save_sparc64
|
||||||
#define helper_sdiv_cc helper_sdiv_cc_sparc64
|
#define helper_sdiv_cc helper_sdiv_cc_sparc64
|
||||||
#define helper_st_asi helper_st_asi_sparc64
|
#define helper_st_asi helper_st_asi_sparc64
|
||||||
#define helper_stqf helper_stqf_sparc64
|
|
||||||
#define helper_taddcctv helper_taddcctv_sparc64
|
#define helper_taddcctv helper_taddcctv_sparc64
|
||||||
#define helper_tsubcctv helper_tsubcctv_sparc64
|
#define helper_tsubcctv helper_tsubcctv_sparc64
|
||||||
#define helper_udiv_cc helper_udiv_cc_sparc64
|
#define helper_udiv_cc helper_udiv_cc_sparc64
|
||||||
|
|
|
@ -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(sdivx, TCG_CALL_NO_WG, s64, env, s64, s64)
|
||||||
DEF_HELPER_FLAGS_3(udivx, TCG_CALL_NO_WG, i64, env, i64, i64)
|
DEF_HELPER_FLAGS_3(udivx, TCG_CALL_NO_WG, i64, env, i64, i64)
|
||||||
#endif
|
#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)
|
#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_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)
|
DEF_HELPER_FLAGS_5(st_asi, TCG_CALL_NO_WG, void, env, tl, i64, int, i32)
|
||||||
|
|
|
@ -977,11 +977,9 @@ static inline int is_translating_asi(int asi)
|
||||||
|
|
||||||
static inline target_ulong address_mask(CPUSPARCState *env1, target_ulong addr)
|
static inline target_ulong address_mask(CPUSPARCState *env1, target_ulong addr)
|
||||||
{
|
{
|
||||||
#ifdef TARGET_SPARC64
|
|
||||||
if (AM_CHECK(env1)) {
|
if (AM_CHECK(env1)) {
|
||||||
addr &= 0xffffffffULL;
|
addr &= 0xffffffffULL;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -989,10 +987,9 @@ static inline target_ulong asi_address_mask(CPUSPARCState *env,
|
||||||
int asi, target_ulong addr)
|
int asi, target_ulong addr)
|
||||||
{
|
{
|
||||||
if (is_translating_asi(asi)) {
|
if (is_translating_asi(asi)) {
|
||||||
return address_mask(env, addr);
|
addr = address_mask(env, addr);
|
||||||
} else {
|
|
||||||
return addr;
|
|
||||||
}
|
}
|
||||||
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_USER_ONLY
|
#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 /* CONFIG_USER_ONLY */
|
||||||
#endif /* TARGET_SPARC64 */
|
#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)
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
#ifndef TARGET_SPARC64
|
#ifndef TARGET_SPARC64
|
||||||
void sparc_cpu_unassigned_access(CPUState *cs, hwaddr addr,
|
void sparc_cpu_unassigned_access(CPUState *cs, hwaddr addr,
|
||||||
|
|
|
@ -225,7 +225,32 @@ static void gen_op_store_QT0_fpr(DisasContext *dc, unsigned int dst)
|
||||||
offsetof(CPU_QuadU, ll.lower));
|
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
|
#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)
|
static void gen_move_Q(DisasContext *dc, unsigned int rd, unsigned int rs)
|
||||||
{
|
{
|
||||||
TCGContext *tcg_ctx = dc->uc->tcg_ctx;
|
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);
|
tcg_gen_qemu_st_i32(dc->uc, d32, addr, da.mem_idx, da.memop);
|
||||||
break;
|
break;
|
||||||
case 8:
|
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);
|
tcg_gen_qemu_st_i64(dc->uc, tcg_ctx->cpu_fpr[rd / 2], addr, da.mem_idx, da.memop);
|
||||||
break;
|
break;
|
||||||
case 16:
|
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_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);
|
tcg_gen_qemu_st_i64(dc->uc, tcg_ctx->cpu_fpr[rd/2+1], addr, da.mem_idx, da.memop);
|
||||||
break;
|
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);
|
gen_helper_ldfsr(tcg_ctx, tcg_ctx->cpu_fsr, tcg_ctx->cpu_env, tcg_ctx->cpu_fsr, cpu_dst_32);
|
||||||
break;
|
break;
|
||||||
case 0x22: /* ldqf, load quad fpreg */
|
case 0x22: /* ldqf, load quad fpreg */
|
||||||
{
|
CHECK_FPU_FEATURE(dc, FLOAT128);
|
||||||
TCGv_i32 r_const;
|
gen_address_mask(dc, cpu_addr);
|
||||||
|
cpu_src1_64 = tcg_temp_new_i64(tcg_ctx);
|
||||||
CHECK_FPU_FEATURE(dc, FLOAT128);
|
tcg_gen_qemu_ld64(dc->uc, cpu_src1_64, cpu_addr, dc->mem_idx);
|
||||||
r_const = tcg_const_i32(tcg_ctx, dc->mem_idx);
|
tcg_gen_addi_tl(tcg_ctx, cpu_addr, cpu_addr, 8);
|
||||||
gen_address_mask(dc, cpu_addr);
|
cpu_src2_64 = tcg_temp_new_i64(tcg_ctx);
|
||||||
gen_helper_ldqf(tcg_ctx, tcg_ctx->cpu_env, cpu_addr, r_const);
|
tcg_gen_qemu_ld64(dc->uc, cpu_src2_64, cpu_addr, dc->mem_idx);
|
||||||
tcg_temp_free_i32(tcg_ctx, r_const);
|
gen_store_fpr_Q(dc, rd, cpu_src1_64, cpu_src2_64);
|
||||||
gen_op_store_QT0_fpr(dc, QFPREG(rd));
|
tcg_temp_free_i64(tcg_ctx, cpu_src1_64);
|
||||||
gen_update_fprs_dirty(dc, QFPREG(rd));
|
tcg_temp_free_i64(tcg_ctx, cpu_src2_64);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 0x23: /* lddf, load double fpreg */
|
case 0x23: /* lddf, load double fpreg */
|
||||||
gen_address_mask(dc, cpu_addr);
|
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:
|
case 0x26:
|
||||||
#ifdef TARGET_SPARC64
|
#ifdef TARGET_SPARC64
|
||||||
/* V9 stqf, store quad fpreg */
|
/* V9 stqf, store quad fpreg */
|
||||||
{
|
CHECK_FPU_FEATURE(dc, FLOAT128);
|
||||||
TCGv_i32 r_const;
|
gen_address_mask(dc, cpu_addr);
|
||||||
|
/* ??? While stqf only requires 4-byte alignment, it is
|
||||||
CHECK_FPU_FEATURE(dc, FLOAT128);
|
legal for the cpu to signal the unaligned exception.
|
||||||
gen_op_load_fpr_QT0(dc, QFPREG(rd));
|
The OS trap handler is then required to fix it up.
|
||||||
r_const = tcg_const_i32(tcg_ctx, dc->mem_idx);
|
For qemu, this avoids having to probe the second page
|
||||||
gen_address_mask(dc, cpu_addr);
|
before performing the first write. */
|
||||||
gen_helper_stqf(tcg_ctx, tcg_ctx->cpu_env, cpu_addr, r_const);
|
cpu_src1_64 = gen_load_fpr_Q0(dc, rd);
|
||||||
tcg_temp_free_i32(tcg_ctx, r_const);
|
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;
|
break;
|
||||||
#else /* !TARGET_SPARC64 */
|
#else /* !TARGET_SPARC64 */
|
||||||
/* stdfq, store floating point queue */
|
/* stdfq, store floating point queue */
|
||||||
|
@ -5742,6 +5777,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn, bool hook_ins
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
case 0x27: /* stdf, store double fpreg */
|
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);
|
gen_address_mask(dc, cpu_addr);
|
||||||
cpu_src1_64 = gen_load_fpr_D(dc, rd);
|
cpu_src1_64 = gen_load_fpr_D(dc, rd);
|
||||||
tcg_gen_qemu_st64(dc->uc, cpu_src1_64, cpu_addr, dc->mem_idx);
|
tcg_gen_qemu_st64(dc->uc, cpu_src1_64, cpu_addr, dc->mem_idx);
|
||||||
|
|
Loading…
Reference in a new issue