mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2024-12-23 08:05:36 +00:00
target/mips: reimplement SC instruction emulation and use cmpxchg
Completely rewrite conditional stores handling. Use cmpxchg. This eliminates need for separate implementations of SC instruction emulation for user and system emulation. Backports commit 33a07fa2db66376e6ee780d4a8b064dc5118cf34 from qemu
This commit is contained in:
parent
df67716ed5
commit
6099733fc5
|
@ -875,10 +875,8 @@ struct CPUMIPSState {
|
|||
/* XXX: Maybe make LLAddr per-TC? */
|
||||
target_ulong lladdr; /* LL virtual address compared against SC */
|
||||
target_ulong llval;
|
||||
target_ulong llnewval;
|
||||
uint64_t llval_wp;
|
||||
uint32_t llnewval_wp;
|
||||
target_ulong llreg;
|
||||
uint64_t CP0_LLAddr_rw_bitmask;
|
||||
int CP0_LLAddr_shift;
|
||||
/*
|
||||
|
@ -1158,8 +1156,6 @@ enum {
|
|||
|
||||
EXCP_LAST = EXCP_TLBRI,
|
||||
};
|
||||
/* Dummy exception for conditional stores. */
|
||||
#define EXCP_SC 0x100
|
||||
|
||||
/*
|
||||
* This is an internally generated WAKE request line.
|
||||
|
|
|
@ -1452,10 +1452,8 @@ void QEMU_NORETURN do_raise_exception_err(CPUMIPSState *env,
|
|||
{
|
||||
CPUState *cs = CPU(mips_env_get_cpu(env));
|
||||
|
||||
if (exception < EXCP_SC) {
|
||||
qemu_log_mask(CPU_LOG_INT, "%s: %d %d\n",
|
||||
__func__, exception, error_code);
|
||||
}
|
||||
qemu_log_mask(CPU_LOG_INT, "%s: %d %d\n",
|
||||
__func__, exception, error_code);
|
||||
cs->exception_index = exception;
|
||||
env->error_code = error_code;
|
||||
|
||||
|
|
|
@ -13,10 +13,8 @@ DEF_HELPER_4(swr, void, env, tl, tl, int)
|
|||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
DEF_HELPER_3(ll, tl, env, tl, int)
|
||||
DEF_HELPER_4(sc, tl, env, tl, tl, int)
|
||||
#ifdef TARGET_MIPS64
|
||||
DEF_HELPER_3(lld, tl, env, tl, int)
|
||||
DEF_HELPER_4(scd, tl, env, tl, tl, int)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
|
@ -376,31 +376,6 @@ HELPER_LD_ATOMIC(ll, lw, 0x3)
|
|||
HELPER_LD_ATOMIC(lld, ld, 0x7)
|
||||
#endif
|
||||
#undef HELPER_LD_ATOMIC
|
||||
|
||||
#define HELPER_ST_ATOMIC(name, ld_insn, st_insn, almask) \
|
||||
target_ulong helper_##name(CPUMIPSState *env, target_ulong arg1, \
|
||||
target_ulong arg2, int mem_idx) \
|
||||
{ \
|
||||
target_long tmp; \
|
||||
\
|
||||
if (arg2 & almask) { \
|
||||
env->CP0_BadVAddr = arg2; \
|
||||
do_raise_exception(env, EXCP_AdES, GETPC()); \
|
||||
} \
|
||||
if (arg2 == env->lladdr) { \
|
||||
tmp = do_##ld_insn(env, arg2, mem_idx, GETPC()); \
|
||||
if (tmp == env->llval) { \
|
||||
do_##st_insn(env, arg2, arg1, mem_idx, GETPC()); \
|
||||
return 1; \
|
||||
} \
|
||||
} \
|
||||
return 0; \
|
||||
}
|
||||
HELPER_ST_ATOMIC(sc, lw, sw, 0x3)
|
||||
#ifdef TARGET_MIPS64
|
||||
HELPER_ST_ATOMIC(scd, ld, sd, 0x7)
|
||||
#endif
|
||||
#undef HELPER_ST_ATOMIC
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
|
|
|
@ -3333,50 +3333,6 @@ OP_LD_ATOMIC(lld,ld64);
|
|||
#endif
|
||||
#undef OP_LD_ATOMIC
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
#define OP_ST_ATOMIC(insn,fname,ldname,almask) \
|
||||
static inline void op_st_##insn(TCGv arg1, TCGv arg2, int rt, int mem_idx, \
|
||||
DisasContext *ctx) \
|
||||
{ \
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx; \
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx); \
|
||||
TCGLabel *l1 = gen_new_label(tcg_ctx); \
|
||||
TCGLabel *l2 = gen_new_label(tcg_ctx); \
|
||||
\
|
||||
tcg_gen_andi_tl(tcg_ctx, t0, arg2, almask); \
|
||||
tcg_gen_brcondi_tl(tcg_ctx, TCG_COND_EQ, t0, 0, l1); \
|
||||
tcg_gen_st_tl(tcg_ctx, arg2, tcg_ctx->cpu_env, offsetof(CPUMIPSState, CP0_BadVAddr)); \
|
||||
generate_exception(ctx, EXCP_AdES); \
|
||||
gen_set_label(tcg_ctx, l1); \
|
||||
tcg_gen_ld_tl(tcg_ctx, t0, tcg_ctx->cpu_env, offsetof(CPUMIPSState, lladdr)); \
|
||||
tcg_gen_brcond_tl(tcg_ctx, TCG_COND_NE, arg2, t0, l2); \
|
||||
tcg_gen_movi_tl(tcg_ctx, t0, rt | ((almask << 3) & 0x20)); \
|
||||
tcg_gen_st_tl(tcg_ctx, t0, tcg_ctx->cpu_env, offsetof(CPUMIPSState, llreg)); \
|
||||
tcg_gen_st_tl(tcg_ctx, arg1, tcg_ctx->cpu_env, offsetof(CPUMIPSState, llnewval)); \
|
||||
generate_exception_end(ctx, EXCP_SC); \
|
||||
gen_set_label(tcg_ctx, l2); \
|
||||
tcg_gen_movi_tl(tcg_ctx, t0, 0); \
|
||||
gen_store_gpr(ctx, t0, rt); \
|
||||
tcg_temp_free(tcg_ctx, t0); \
|
||||
}
|
||||
#else
|
||||
#define OP_ST_ATOMIC(insn,fname,ldname,almask) \
|
||||
static inline void op_st_##insn(TCGv arg1, TCGv arg2, int rt, int mem_idx, \
|
||||
DisasContext *ctx) \
|
||||
{ \
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx; \
|
||||
TCGv t0 = tcg_temp_new(tcg_ctx); \
|
||||
gen_helper_1e2i(tcg_ctx, insn, t0, arg1, arg2, ctx->mem_idx); \
|
||||
gen_store_gpr(ctx, t0, rt); \
|
||||
tcg_temp_free(tcg_ctx, t0); \
|
||||
}
|
||||
#endif
|
||||
OP_ST_ATOMIC(sc,st32,ld32s,0x3);
|
||||
#if defined(TARGET_MIPS64)
|
||||
OP_ST_ATOMIC(scd,st64,ld64,0x7);
|
||||
#endif
|
||||
#undef OP_ST_ATOMIC
|
||||
|
||||
static void gen_base_offset_addr (DisasContext *ctx, TCGv addr,
|
||||
int base, int offset)
|
||||
{
|
||||
|
@ -3693,41 +3649,39 @@ static void gen_st (DisasContext *ctx, uint32_t opc, int rt,
|
|||
|
||||
|
||||
/* Store conditional */
|
||||
static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt,
|
||||
int base, int16_t offset)
|
||||
static void gen_st_cond(DisasContext *ctx, int rt, int base, int offset,
|
||||
TCGMemOp tcg_mo, bool eva)
|
||||
{
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
TCGv t0, t1;
|
||||
int mem_idx = ctx->mem_idx;
|
||||
TCGv addr, t0, val;
|
||||
TCGLabel *l1 = gen_new_label(tcg_ctx);
|
||||
TCGLabel *done = gen_new_label(tcg_ctx);
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
t0 = tcg_temp_local_new(tcg_ctx);
|
||||
t1 = tcg_temp_local_new(tcg_ctx);
|
||||
#else
|
||||
t0 = tcg_temp_new(tcg_ctx);
|
||||
t1 = tcg_temp_new(tcg_ctx);
|
||||
#endif
|
||||
gen_base_offset_addr(ctx, t0, base, offset);
|
||||
gen_load_gpr(ctx, t1, rt);
|
||||
switch (opc) {
|
||||
#if defined(TARGET_MIPS64)
|
||||
case OPC_SCD:
|
||||
case R6_OPC_SCD:
|
||||
op_st_scd(t1, t0, rt, mem_idx, ctx);
|
||||
break;
|
||||
#endif
|
||||
case OPC_SCE:
|
||||
mem_idx = MIPS_HFLAG_UM;
|
||||
/* fall through */
|
||||
case OPC_SC:
|
||||
case R6_OPC_SC:
|
||||
op_st_sc(t1, t0, rt, mem_idx, ctx);
|
||||
break;
|
||||
}
|
||||
tcg_temp_free(tcg_ctx, t1);
|
||||
addr = tcg_temp_new(tcg_ctx);
|
||||
/* compare the address against that of the preceeding LL */
|
||||
gen_base_offset_addr(ctx, addr, base, offset);
|
||||
tcg_gen_brcond_tl(tcg_ctx, TCG_COND_EQ, addr, tcg_ctx->cpu_lladdr, l1);
|
||||
tcg_temp_free(tcg_ctx, addr);
|
||||
tcg_gen_movi_tl(tcg_ctx, t0, 0);
|
||||
gen_store_gpr(ctx, t0, rt);
|
||||
tcg_gen_br(tcg_ctx, done);
|
||||
|
||||
gen_set_label(tcg_ctx, l1);
|
||||
/* generate cmpxchg */
|
||||
val = tcg_temp_new(tcg_ctx);
|
||||
gen_load_gpr(ctx, val, rt);
|
||||
tcg_gen_atomic_cmpxchg_tl(tcg_ctx, t0, tcg_ctx->cpu_lladdr, tcg_ctx->cpu_llval, val,
|
||||
eva ? MIPS_HFLAG_UM : ctx->mem_idx, tcg_mo);
|
||||
tcg_gen_setcond_tl(tcg_ctx, TCG_COND_EQ, t0, t0, tcg_ctx->cpu_llval);
|
||||
gen_store_gpr(ctx, t0, rt);
|
||||
tcg_temp_free(tcg_ctx, val);
|
||||
|
||||
gen_set_label(tcg_ctx, done);
|
||||
tcg_temp_free(tcg_ctx, t0);
|
||||
}
|
||||
|
||||
|
||||
static void gen_scwp(DisasContext *ctx, uint32_t base, int16_t offset,
|
||||
uint32_t reg1, uint32_t reg2, bool eva)
|
||||
{
|
||||
|
@ -16967,13 +16921,13 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx)
|
|||
gen_st(ctx, mips32_op, rt, rs, offset);
|
||||
break;
|
||||
case SC:
|
||||
gen_st_cond(ctx, OPC_SC, rt, rs, offset);
|
||||
gen_st_cond(ctx, rt, rs, offset, MO_TESL, false);
|
||||
break;
|
||||
#if defined(TARGET_MIPS64)
|
||||
case SCD:
|
||||
check_insn(ctx, ISA_MIPS3);
|
||||
check_mips_64(ctx);
|
||||
gen_st_cond(ctx, OPC_SCD, rt, rs, offset);
|
||||
gen_st_cond(ctx, rt, rs, offset, MO_TEQ, false);
|
||||
break;
|
||||
#endif
|
||||
case LD_EVA:
|
||||
|
@ -17054,7 +17008,7 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx)
|
|||
mips32_op = OPC_SHE;
|
||||
goto do_st_lr;
|
||||
case SCE:
|
||||
gen_st_cond(ctx, OPC_SCE, rt, rs, offset);
|
||||
gen_st_cond(ctx, rt, rs, offset, MO_TESL, true);
|
||||
break;
|
||||
case SWE:
|
||||
mips32_op = OPC_SWE;
|
||||
|
@ -21691,7 +21645,7 @@ static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx)
|
|||
case NM_P_SC:
|
||||
switch (ctx->opcode & 0x03) {
|
||||
case NM_SC:
|
||||
gen_st_cond(ctx, OPC_SC, rt, rs, s);
|
||||
gen_st_cond(ctx, rt, rs, s, MO_TESL, false);
|
||||
break;
|
||||
case NM_SCWP:
|
||||
check_xnp(ctx);
|
||||
|
@ -21794,7 +21748,7 @@ static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx)
|
|||
check_xnp(ctx);
|
||||
check_eva(ctx);
|
||||
check_cp0_enabled(ctx);
|
||||
gen_st_cond(ctx, OPC_SCE, rt, rs, s);
|
||||
gen_st_cond(ctx, rt, rs, s, MO_TESL, true);
|
||||
break;
|
||||
case NM_SCWPE:
|
||||
check_xnp(ctx);
|
||||
|
@ -26852,7 +26806,7 @@ static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx)
|
|||
}
|
||||
break;
|
||||
case R6_OPC_SC:
|
||||
gen_st_cond(ctx, op1, rt, rs, imm);
|
||||
gen_st_cond(ctx, rt, rs, imm, MO_TESL, false);
|
||||
break;
|
||||
case R6_OPC_LL:
|
||||
gen_ld(ctx, op1, rt, rs, imm);
|
||||
|
@ -26879,7 +26833,7 @@ static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx)
|
|||
break;
|
||||
#if defined(TARGET_MIPS64)
|
||||
case R6_OPC_SCD:
|
||||
gen_st_cond(ctx, op1, rt, rs, imm);
|
||||
gen_st_cond(ctx, rt, rs, imm, MO_TEQ, false);
|
||||
break;
|
||||
case R6_OPC_LLD:
|
||||
gen_ld(ctx, op1, rt, rs, imm);
|
||||
|
@ -27737,7 +27691,7 @@ static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx)
|
|||
return;
|
||||
case OPC_SCE:
|
||||
check_cp0_enabled(ctx);
|
||||
gen_st_cond(ctx, op1, rt, rs, imm);
|
||||
gen_st_cond(ctx, rt, rs, imm, MO_TESL, true);
|
||||
return;
|
||||
case OPC_CACHEE:
|
||||
check_cp0_enabled(ctx);
|
||||
|
@ -29359,8 +29313,8 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx, bool *insn_need_pat
|
|||
if (ctx->insn_flags & INSN_R5900) {
|
||||
check_insn_opc_user_only(ctx, INSN_R5900);
|
||||
}
|
||||
gen_st_cond(ctx, op, rt, rs, imm);
|
||||
break;
|
||||
gen_st_cond(ctx, rt, rs, imm, MO_TESL, false);
|
||||
break;
|
||||
case OPC_CACHE:
|
||||
check_insn_opc_removed(ctx, ISA_MIPS32R6);
|
||||
check_cp0_enabled(ctx);
|
||||
|
@ -29659,7 +29613,7 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx, bool *insn_need_pat
|
|||
check_insn_opc_user_only(ctx, INSN_R5900);
|
||||
}
|
||||
check_mips_64(ctx);
|
||||
gen_st_cond(ctx, op, rt, rs, imm);
|
||||
gen_st_cond(ctx, rt, rs, imm, MO_TEQ, false);
|
||||
break;
|
||||
case OPC_BNVC: /* OPC_BNEZALC, OPC_BNEC, OPC_DADDI */
|
||||
if (ctx->insn_flags & ISA_MIPS32R6) {
|
||||
|
@ -30037,6 +29991,11 @@ void mips_tcg_init(struct uc_struct *uc)
|
|||
offsetof(CPUMIPSState, active_fpu.fcr31),
|
||||
"fcr31");
|
||||
|
||||
tcg_ctx->cpu_lladdr = tcg_global_mem_new(tcg_ctx, tcg_ctx->cpu_env, offsetof(CPUMIPSState, lladdr),
|
||||
"lladdr");
|
||||
tcg_ctx->cpu_llval = tcg_global_mem_new(tcg_ctx, tcg_ctx->cpu_env, offsetof(CPUMIPSState, llval),
|
||||
"llval");
|
||||
|
||||
#if defined(TARGET_MIPS64)
|
||||
tcg_ctx->cpu_mmr[0] = NULL;
|
||||
for (i = 1; i < 32; i++) {
|
||||
|
|
|
@ -903,6 +903,7 @@ struct TCGContext {
|
|||
TCGv cpu_PC;
|
||||
TCGv cpu_HI[4], cpu_LO[4]; // MIPS_DSP_ACC = 4 in qemu/target-mips/cpu.h
|
||||
TCGv cpu_dspctrl;
|
||||
TCGv cpu_lladdr, cpu_llval;
|
||||
TCGv btarget;
|
||||
TCGv bcond;
|
||||
TCGv_i32 hflags;
|
||||
|
|
Loading…
Reference in a new issue