mirror of https://github.com/xemu-project/xemu.git
target/sparc: Implement check_align inline
Emit the exception at the end of the translation block, so that the non-exception case can fall through. Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
930f1865cc
commit
186e78905a
|
@ -24,7 +24,6 @@ DEF_HELPER_FLAGS_2(tick_set_count, TCG_CALL_NO_RWG, void, ptr, i64)
|
|||
DEF_HELPER_FLAGS_3(tick_get_count, TCG_CALL_NO_WG, i64, env, ptr, int)
|
||||
DEF_HELPER_FLAGS_2(tick_set_limit, TCG_CALL_NO_RWG, void, ptr, i64)
|
||||
#endif
|
||||
DEF_HELPER_FLAGS_3(check_align, TCG_CALL_NO_WG, void, env, tl, i32)
|
||||
DEF_HELPER_1(debug, void, env)
|
||||
DEF_HELPER_1(save, void, env)
|
||||
DEF_HELPER_1(restore, void, env)
|
||||
|
|
|
@ -360,6 +360,7 @@ static inline void do_check_asi(CPUSPARCState *env, int asi, uintptr_t ra)
|
|||
#endif /* !CONFIG_USER_ONLY */
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_SPARC64) || !defined(CONFIG_USER_ONLY)
|
||||
static void do_check_align(CPUSPARCState *env, target_ulong addr,
|
||||
uint32_t align, uintptr_t ra)
|
||||
{
|
||||
|
@ -367,11 +368,7 @@ static void do_check_align(CPUSPARCState *env, target_ulong addr,
|
|||
cpu_raise_exception_ra(env, TT_UNALIGNED, ra);
|
||||
}
|
||||
}
|
||||
|
||||
void helper_check_align(CPUSPARCState *env, target_ulong addr, uint32_t align)
|
||||
{
|
||||
do_check_align(env, addr, align, GETPC());
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) && \
|
||||
defined(DEBUG_MXCC)
|
||||
|
|
|
@ -68,6 +68,15 @@ static TCGv cpu_wim;
|
|||
/* Floating point registers */
|
||||
static TCGv_i64 cpu_fpr[TARGET_DPREGS];
|
||||
|
||||
typedef struct DisasDelayException {
|
||||
struct DisasDelayException *next;
|
||||
TCGLabel *lab;
|
||||
TCGv_i32 excp;
|
||||
/* Saved state at parent insn. */
|
||||
target_ulong pc;
|
||||
target_ulong npc;
|
||||
} DisasDelayException;
|
||||
|
||||
typedef struct DisasContext {
|
||||
DisasContextBase base;
|
||||
target_ulong pc; /* current Program Counter: integer or DYNAMIC_PC */
|
||||
|
@ -89,6 +98,7 @@ typedef struct DisasContext {
|
|||
int fprs_dirty;
|
||||
int asi;
|
||||
#endif
|
||||
DisasDelayException *delay_excp_list;
|
||||
} DisasContext;
|
||||
|
||||
typedef struct {
|
||||
|
@ -984,9 +994,38 @@ static void gen_exception(DisasContext *dc, int which)
|
|||
dc->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
|
||||
static void gen_check_align(TCGv addr, int mask)
|
||||
static TCGLabel *delay_exceptionv(DisasContext *dc, TCGv_i32 excp)
|
||||
{
|
||||
gen_helper_check_align(tcg_env, addr, tcg_constant_i32(mask));
|
||||
DisasDelayException *e = g_new0(DisasDelayException, 1);
|
||||
|
||||
e->next = dc->delay_excp_list;
|
||||
dc->delay_excp_list = e;
|
||||
|
||||
e->lab = gen_new_label();
|
||||
e->excp = excp;
|
||||
e->pc = dc->pc;
|
||||
/* Caller must have used flush_cond before branch. */
|
||||
assert(e->npc != JUMP_PC);
|
||||
e->npc = dc->npc;
|
||||
|
||||
return e->lab;
|
||||
}
|
||||
|
||||
static TCGLabel *delay_exception(DisasContext *dc, int excp)
|
||||
{
|
||||
return delay_exceptionv(dc, tcg_constant_i32(excp));
|
||||
}
|
||||
|
||||
static void gen_check_align(DisasContext *dc, TCGv addr, int mask)
|
||||
{
|
||||
TCGv t = tcg_temp_new();
|
||||
TCGLabel *lab;
|
||||
|
||||
tcg_gen_andi_tl(t, addr, mask);
|
||||
|
||||
flush_cond(dc);
|
||||
lab = delay_exception(dc, TT_UNALIGNED);
|
||||
tcg_gen_brcondi_tl(TCG_COND_NE, t, 0, lab);
|
||||
}
|
||||
|
||||
static void gen_mov_pc_npc(DisasContext *dc)
|
||||
|
@ -5019,9 +5058,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
|
|||
tcg_gen_mov_tl(cpu_tmp0, cpu_src1);
|
||||
}
|
||||
}
|
||||
gen_check_align(dc, cpu_tmp0, 3);
|
||||
gen_helper_restore(tcg_env);
|
||||
gen_mov_pc_npc(dc);
|
||||
gen_check_align(cpu_tmp0, 3);
|
||||
tcg_gen_mov_tl(cpu_npc, cpu_tmp0);
|
||||
dc->npc = DYNAMIC_PC_LOOKUP;
|
||||
goto jmp_insn;
|
||||
|
@ -5044,12 +5083,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
|
|||
switch (xop) {
|
||||
case 0x38: /* jmpl */
|
||||
{
|
||||
TCGv t = gen_dest_gpr(dc, rd);
|
||||
tcg_gen_movi_tl(t, dc->pc);
|
||||
gen_store_gpr(dc, rd, t);
|
||||
|
||||
gen_check_align(dc, cpu_tmp0, 3);
|
||||
gen_store_gpr(dc, rd, tcg_constant_tl(dc->pc));
|
||||
gen_mov_pc_npc(dc);
|
||||
gen_check_align(cpu_tmp0, 3);
|
||||
gen_address_mask(dc, cpu_tmp0);
|
||||
tcg_gen_mov_tl(cpu_npc, cpu_tmp0);
|
||||
dc->npc = DYNAMIC_PC_LOOKUP;
|
||||
|
@ -5060,8 +5096,8 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
|
|||
{
|
||||
if (!supervisor(dc))
|
||||
goto priv_insn;
|
||||
gen_check_align(dc, cpu_tmp0, 3);
|
||||
gen_mov_pc_npc(dc);
|
||||
gen_check_align(cpu_tmp0, 3);
|
||||
tcg_gen_mov_tl(cpu_npc, cpu_tmp0);
|
||||
dc->npc = DYNAMIC_PC;
|
||||
gen_helper_rett(tcg_env);
|
||||
|
@ -5643,6 +5679,7 @@ static void sparc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
|
|||
static void sparc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
DisasDelayException *e, *e_next;
|
||||
bool may_lookup;
|
||||
|
||||
switch (dc->base.is_jmp) {
|
||||
|
@ -5704,6 +5741,19 @@ static void sparc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
|
|||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
for (e = dc->delay_excp_list; e ; e = e_next) {
|
||||
gen_set_label(e->lab);
|
||||
|
||||
tcg_gen_movi_tl(cpu_pc, e->pc);
|
||||
if (e->npc % 4 == 0) {
|
||||
tcg_gen_movi_tl(cpu_npc, e->npc);
|
||||
}
|
||||
gen_helper_raise_exception(tcg_env, e->excp);
|
||||
|
||||
e_next = e->next;
|
||||
g_free(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void sparc_tr_disas_log(const DisasContextBase *dcbase,
|
||||
|
|
Loading…
Reference in New Issue