Signed-off-by: Richard Henderson <r...@twiddle.net> --- linux-user/main.c | 84 +++++++---------------------------------------- target-tilegx/cpu.h | 4 ++- target-tilegx/translate.c | 80 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 94 insertions(+), 74 deletions(-)
diff --git a/linux-user/main.c b/linux-user/main.c index 4fe18c0..04e5bbe 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -3433,51 +3433,26 @@ static void gen_sigill_reg(CPUTLGState *env) queue_signal(env, info.si_signo, &info); } -static int get_regval(CPUTLGState *env, uint8_t reg, target_ulong *val) -{ - if (likely(reg < TILEGX_R_COUNT)) { - *val = env->regs[reg]; - return 0; - } - - switch (reg) { - case TILEGX_R_SN: - case TILEGX_R_ZERO: - *val = 0; - return 0; - case TILEGX_R_IDN0: - case TILEGX_R_IDN1: - case TILEGX_R_UDN0: - case TILEGX_R_UDN1: - case TILEGX_R_UDN2: - case TILEGX_R_UDN3: - return -1; - default: - g_assert_not_reached(); - } -} - -static int set_regval(CPUTLGState *env, uint8_t reg, uint64_t val) +static void set_regval(CPUTLGState *env, uint8_t reg, uint64_t val) { if (unlikely(reg >= TILEGX_R_COUNT)) { switch (reg) { case TILEGX_R_SN: case TILEGX_R_ZERO: - return 0; + return; case TILEGX_R_IDN0: case TILEGX_R_IDN1: case TILEGX_R_UDN0: case TILEGX_R_UDN1: case TILEGX_R_UDN2: case TILEGX_R_UDN3: - return -1; + gen_sigill_reg(env); + return; default: g_assert_not_reached(); } } - env->regs[reg] = val; - return 0; } /* @@ -3508,19 +3483,12 @@ static int set_regval(CPUTLGState *env, uint8_t reg, uint64_t val) */ static void do_exch(CPUTLGState *env, bool quad, bool cmp) { - uint8_t rdst, rsrc, rsrcb; target_ulong addr; target_long val, sprval; start_exclusive(); - rdst = extract32(env->excparam, 16, 8); - rsrc = extract32(env->excparam, 8, 8); - rsrcb = extract32(env->excparam, 0, 8); - - if (get_regval(env, rsrc, &addr)) { - goto sigill_reg; - } + addr = env->atomic_srca; if (quad ? get_user_s64(val, addr) : get_user_s32(val, addr)) { goto sigsegv_mapper; } @@ -3534,56 +3502,35 @@ static void do_exch(CPUTLGState *env, bool quad, bool cmp) } if (!cmp || val == sprval) { - target_long valb; - - if (get_regval(env, rsrcb, (target_ulong *)&valb)) { - goto sigill_reg; - } + target_long valb = env->atomic_srcb; if (quad ? put_user_u64(valb, addr) : put_user_u32(valb, addr)) { goto sigsegv_mapper; } } - if (set_regval(env, rdst, val)) { - goto sigill_reg; - } + set_regval(env, env->atomic_dstr, val); end_exclusive(); return; -sigill_reg: - end_exclusive(); - gen_sigill_reg(env); - return; - -sigsegv_mapper: + sigsegv_mapper: end_exclusive(); gen_sigsegv_mapper(env, addr); } static void do_fetch(CPUTLGState *env, int trapnr, bool quad) { - uint8_t rdst, rsrc, rsrcb; int8_t write = 1; target_ulong addr; target_long val, valb; start_exclusive(); - rdst = extract32(env->excparam, 16, 8); - rsrc = extract32(env->excparam, 8, 8); - rsrcb = extract32(env->excparam, 0, 8); - - - if (get_regval(env, rsrc, &addr)) { - goto sigill_reg; - } + addr = env->atomic_srca; + valb = env->atomic_srcb; if (quad ? get_user_s64(val, addr) : get_user_s32(val, addr)) { goto sigsegv_mapper; } - if (get_regval(env, rsrcb, (target_ulong *)&valb)) { - goto sigill_reg; - } switch (trapnr) { case TILEGX_EXCP_OPCODE_FETCHADD: case TILEGX_EXCP_OPCODE_FETCHADD4: @@ -3619,18 +3566,11 @@ static void do_fetch(CPUTLGState *env, int trapnr, bool quad) } } - if (set_regval(env, rdst, val)) { - goto sigill_reg; - } - end_exclusive(); - return; - -sigill_reg: + set_regval(env, env->atomic_dstr, val); end_exclusive(); - gen_sigill_reg(env); return; -sigsegv_mapper: + sigsegv_mapper: end_exclusive(); gen_sigsegv_mapper(env, addr); } diff --git a/target-tilegx/cpu.h b/target-tilegx/cpu.h index 3a62d20..b9f5082 100644 --- a/target-tilegx/cpu.h +++ b/target-tilegx/cpu.h @@ -87,7 +87,9 @@ typedef struct CPUTLGState { uint64_t pc; /* Current pc */ #if defined(CONFIG_USER_ONLY) - uint32_t excparam; /* exception parameter */ + uint64_t atomic_srca; /* Arguments to atomic "exceptions" */ + uint64_t atomic_srcb; + uint32_t atomic_dstr; uint64_t excaddr; /* exception address */ #endif diff --git a/target-tilegx/translate.c b/target-tilegx/translate.c index 9418799..702289e 100644 --- a/target-tilegx/translate.c +++ b/target-tilegx/translate.c @@ -61,6 +61,7 @@ typedef struct { int num_wb; int mmuidx; bool exit_tb; + TileExcp atomic_excp; struct { TCGCond cond; /* branch condition */ @@ -180,6 +181,32 @@ static void gen_saturate_op(TCGv tdest, TCGv tsrca, TCGv tsrcb, tcg_temp_free(t0); } +static void gen_atomic_excp(DisasContext *dc, unsigned dest, TCGv tdest, + TCGv tsrca, TCGv tsrcb, TileExcp excp) +{ +#ifdef CONFIG_USER_ONLY + TCGv_i32 t; + + tcg_gen_st_tl(tsrca, cpu_env, offsetof(CPUTLGState, atomic_srca)); + tcg_gen_st_tl(tsrcb, cpu_env, offsetof(CPUTLGState, atomic_srcb)); + t = tcg_const_i32(dest); + tcg_gen_st_i32(t, cpu_env, offsetof(CPUTLGState, atomic_dstr)); + tcg_temp_free_i32(t); + + /* We're going to write the real result in the exception. But in + the meantime we've already created a writeback register, and + we don't want that to remain uninitialized. */ + tcg_gen_movi_tl(tdest, 0); + + /* Note that we need to delay issuing the exception that implements + the atomic operation until after writing back the results of the + instruction occupying the X0 pipe. */ + dc->atomic_excp = excp; +#else + gen_exception(dc, TILEGX_EXCP_OPCODE_UNIMPLEMENTED); +#endif +} + /* Shift the 128-bit value TSRCA:TSRCD riht by the number of bytes specified by the bottom 3 bits of TSRCB, and set TDEST to the low 64 bits of the resulting value. */ @@ -591,8 +618,15 @@ static TileExcp gen_rrr_opcode(DisasContext *dc, unsigned opext, mnemonic = "cmpeq"; break; case OE_RRR(CMPEXCH4, 0, X1): + gen_atomic_excp(dc, dest, tdest, tsrca, tsrcb, + TILEGX_EXCP_OPCODE_CMPEXCH4); + mnemonic = "cmpexch4"; + break; case OE_RRR(CMPEXCH, 0, X1): - return TILEGX_EXCP_OPCODE_UNIMPLEMENTED; + gen_atomic_excp(dc, dest, tdest, tsrca, tsrcb, + TILEGX_EXCP_OPCODE_CMPEXCH); + mnemonic = "cmpexch"; + break; case OE_RRR(CMPLES, 0, X0): case OE_RRR(CMPLES, 0, X1): case OE_RRR(CMPLES, 2, Y0): @@ -658,7 +692,15 @@ static TileExcp gen_rrr_opcode(DisasContext *dc, unsigned opext, mnemonic = "dblalign"; break; case OE_RRR(EXCH4, 0, X1): + gen_atomic_excp(dc, dest, tdest, tsrca, tsrcb, + TILEGX_EXCP_OPCODE_EXCH4); + mnemonic = "exch4"; + break; case OE_RRR(EXCH, 0, X1): + gen_atomic_excp(dc, dest, tdest, tsrca, tsrcb, + TILEGX_EXCP_OPCODE_EXCH); + mnemonic = "exch"; + break; case OE_RRR(FDOUBLE_ADDSUB, 0, X0): case OE_RRR(FDOUBLE_ADD_FLAGS, 0, X0): case OE_RRR(FDOUBLE_MUL_FLAGS, 0, X0): @@ -667,14 +709,47 @@ static TileExcp gen_rrr_opcode(DisasContext *dc, unsigned opext, case OE_RRR(FDOUBLE_SUB_FLAGS, 0, X0): case OE_RRR(FDOUBLE_UNPACK_MAX, 0, X0): case OE_RRR(FDOUBLE_UNPACK_MIN, 0, X0): + return TILEGX_EXCP_OPCODE_UNIMPLEMENTED; case OE_RRR(FETCHADD4, 0, X1): + gen_atomic_excp(dc, dest, tdest, tsrca, tsrcb, + TILEGX_EXCP_OPCODE_FETCHADD4); + mnemonic = "fetchadd4"; + break; case OE_RRR(FETCHADDGEZ4, 0, X1): + gen_atomic_excp(dc, dest, tdest, tsrca, tsrcb, + TILEGX_EXCP_OPCODE_FETCHADDGEZ4); + mnemonic = "fetchaddgez4"; + break; case OE_RRR(FETCHADDGEZ, 0, X1): + gen_atomic_excp(dc, dest, tdest, tsrca, tsrcb, + TILEGX_EXCP_OPCODE_FETCHADDGEZ); + mnemonic = "fetchaddgez"; + break; case OE_RRR(FETCHADD, 0, X1): + gen_atomic_excp(dc, dest, tdest, tsrca, tsrcb, + TILEGX_EXCP_OPCODE_FETCHADD); + mnemonic = "fetchadd"; + break; case OE_RRR(FETCHAND4, 0, X1): + gen_atomic_excp(dc, dest, tdest, tsrca, tsrcb, + TILEGX_EXCP_OPCODE_FETCHAND4); + mnemonic = "fetchand4"; + break; case OE_RRR(FETCHAND, 0, X1): + gen_atomic_excp(dc, dest, tdest, tsrca, tsrcb, + TILEGX_EXCP_OPCODE_FETCHAND); + mnemonic = "fetchand"; + break; case OE_RRR(FETCHOR4, 0, X1): + gen_atomic_excp(dc, dest, tdest, tsrca, tsrcb, + TILEGX_EXCP_OPCODE_FETCHOR4); + mnemonic = "fetchor4"; + break; case OE_RRR(FETCHOR, 0, X1): + gen_atomic_excp(dc, dest, tdest, tsrca, tsrcb, + TILEGX_EXCP_OPCODE_FETCHOR); + mnemonic = "fetchor"; + break; case OE_RRR(FSINGLE_ADD1, 0, X0): case OE_RRR(FSINGLE_ADDSUB2, 0, X0): case OE_RRR(FSINGLE_MUL1, 0, X0): @@ -1936,6 +2011,8 @@ static void translate_one_bundle(DisasContext *dc, uint64_t bundle) tcg_temp_free_i64(dc->jmp.dest); tcg_gen_exit_tb(0); dc->exit_tb = true; + } else if (dc->atomic_excp != TILEGX_EXCP_NONE) { + gen_exception(dc, dc->atomic_excp); } } @@ -1956,6 +2033,7 @@ static inline void gen_intermediate_code_internal(TileGXCPU *cpu, dc->pc = pc_start; dc->mmuidx = 0; dc->exit_tb = false; + dc->atomic_excp = TILEGX_EXCP_NONE; dc->jmp.cond = TCG_COND_NEVER; TCGV_UNUSED_I64(dc->jmp.dest); TCGV_UNUSED_I64(dc->jmp.val1); -- 2.4.3