target/alpha: Convert to TranslatorOps

Signed-off-by: Richard Henderson <rth@twiddle.net>
master
Richard Henderson 2017-07-14 13:47:59 -10:00 committed by Richard Henderson
parent c5f806579f
commit 99a92b9459
1 changed files with 85 additions and 98 deletions

View File

@ -2929,33 +2929,23 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn)
return ret; return ret;
} }
void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) static int alpha_tr_init_disas_context(DisasContextBase *dcbase,
CPUState *cpu, int max_insns)
{ {
CPUAlphaState *env = cs->env_ptr; DisasContext *ctx = container_of(dcbase, DisasContext, base);
DisasContext ctx, *ctxp = &ctx; CPUAlphaState *env = cpu->env_ptr;
target_ulong pc_start; int64_t bound, mask;
target_ulong pc_mask;
uint32_t insn;
DisasJumpType ret;
int num_insns;
int max_insns;
pc_start = tb->pc; ctx->tbflags = ctx->base.tb->flags;
ctx->mem_idx = cpu_mmu_index(env, false);
ctx.base.tb = tb; ctx->implver = env->implver;
ctx.base.pc_next = pc_start; ctx->amask = env->amask;
ctx.base.singlestep_enabled = cs->singlestep_enabled;
ctx.tbflags = tb->flags;
ctx.mem_idx = cpu_mmu_index(env, false);
ctx.implver = env->implver;
ctx.amask = env->amask;
#ifdef CONFIG_USER_ONLY #ifdef CONFIG_USER_ONLY
ctx.ir = cpu_std_ir; ctx->ir = cpu_std_ir;
#else #else
ctx.palbr = env->palbr; ctx->palbr = env->palbr;
ctx.ir = (ctx.tbflags & ENV_FLAG_PAL_MODE ? cpu_pal_ir : cpu_std_ir); ctx->ir = (ctx->tbflags & ENV_FLAG_PAL_MODE ? cpu_pal_ir : cpu_std_ir);
#endif #endif
/* ??? Every TB begins with unset rounding mode, to be initialized on /* ??? Every TB begins with unset rounding mode, to be initialized on
@ -2964,96 +2954,87 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
to reset the FP_STATUS to that default at the end of any TB that to reset the FP_STATUS to that default at the end of any TB that
changes the default. We could even (gasp) dynamiclly figure out changes the default. We could even (gasp) dynamiclly figure out
what default would be most efficient given the running program. */ what default would be most efficient given the running program. */
ctx.tb_rm = -1; ctx->tb_rm = -1;
/* Similarly for flush-to-zero. */ /* Similarly for flush-to-zero. */
ctx.tb_ftz = -1; ctx->tb_ftz = -1;
TCGV_UNUSED_I64(ctx.zero); TCGV_UNUSED_I64(ctx->zero);
TCGV_UNUSED_I64(ctx.sink); TCGV_UNUSED_I64(ctx->sink);
TCGV_UNUSED_I64(ctx.lit); TCGV_UNUSED_I64(ctx->lit);
num_insns = 0; /* Bound the number of insns to execute to those left on the page. */
max_insns = tb->cflags & CF_COUNT_MASK; if (in_superpage(ctx, ctx->base.pc_first)) {
if (max_insns == 0) { mask = -1ULL << 41;
max_insns = CF_COUNT_MASK;
}
if (max_insns > TCG_MAX_INSNS) {
max_insns = TCG_MAX_INSNS;
}
if (in_superpage(&ctx, pc_start)) {
pc_mask = (1ULL << 41) - 1;
} else { } else {
pc_mask = ~TARGET_PAGE_MASK; mask = TARGET_PAGE_MASK;
} }
bound = -(ctx->base.pc_first | mask) / 4;
gen_tb_start(tb); return MIN(max_insns, bound);
tcg_clear_temp_count(); }
do { static void alpha_tr_tb_start(DisasContextBase *db, CPUState *cpu)
tcg_gen_insn_start(ctx.base.pc_next); {
num_insns++; }
if (unlikely(cpu_breakpoint_test(cs, ctx.base.pc_next, BP_ANY))) { static void alpha_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
ret = gen_excp(&ctx, EXCP_DEBUG, 0); {
/* The address covered by the breakpoint must be included in tcg_gen_insn_start(dcbase->pc_next);
[tb->pc, tb->pc + tb->size) in order to for it to be }
properly cleared -- thus we increment the PC here so that
the logic setting tb->size below does the right thing. */
ctx.base.pc_next += 4;
break;
}
if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
gen_io_start();
}
insn = cpu_ldl_code(env, ctx.base.pc_next);
ctx.base.pc_next += 4; static bool alpha_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu,
ret = translate_one(ctxp, insn); const CPUBreakpoint *bp)
free_context_temps(ctxp); {
DisasContext *ctx = container_of(dcbase, DisasContext, base);
if (tcg_check_temp_count()) { ctx->base.is_jmp = gen_excp(ctx, EXCP_DEBUG, 0);
qemu_log("TCG temporary leak before "TARGET_FMT_lx"\n",
ctx.base.pc_next);
}
/* If we reach a page boundary, are single stepping, /* The address covered by the breakpoint must be included in
or exhaust instruction count, stop generation. */ [tb->pc, tb->pc + tb->size) in order to for it to be
if (ret == DISAS_NEXT properly cleared -- thus we increment the PC here so that
&& ((ctx.base.pc_next & pc_mask) == 0 the logic setting tb->size below does the right thing. */
|| tcg_op_buf_full() ctx->base.pc_next += 4;
|| num_insns >= max_insns return true;
|| singlestep }
|| ctx.base.singlestep_enabled)) {
ret = DISAS_TOO_MANY;
}
} while (ret == DISAS_NEXT);
if (tb->cflags & CF_LAST_IO) { static void alpha_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
gen_io_end(); {
} DisasContext *ctx = container_of(dcbase, DisasContext, base);
CPUAlphaState *env = cpu->env_ptr;
uint32_t insn = cpu_ldl_code(env, ctx->base.pc_next);
switch (ret) { ctx->base.pc_next += 4;
ctx->base.is_jmp = translate_one(ctx, insn);
free_context_temps(ctx);
translator_loop_temp_check(&ctx->base);
}
static void alpha_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
{
DisasContext *ctx = container_of(dcbase, DisasContext, base);
switch (ctx->base.is_jmp) {
case DISAS_NORETURN: case DISAS_NORETURN:
break; break;
case DISAS_TOO_MANY: case DISAS_TOO_MANY:
if (use_goto_tb(&ctx, ctx.base.pc_next)) { if (use_goto_tb(ctx, ctx->base.pc_next)) {
tcg_gen_goto_tb(0); tcg_gen_goto_tb(0);
tcg_gen_movi_i64(cpu_pc, ctx.base.pc_next); tcg_gen_movi_i64(cpu_pc, ctx->base.pc_next);
tcg_gen_exit_tb((uintptr_t)ctx.base.tb); tcg_gen_exit_tb((uintptr_t)ctx->base.tb);
} }
/* FALLTHRU */ /* FALLTHRU */
case DISAS_PC_STALE: case DISAS_PC_STALE:
tcg_gen_movi_i64(cpu_pc, ctx.base.pc_next); tcg_gen_movi_i64(cpu_pc, ctx->base.pc_next);
/* FALLTHRU */ /* FALLTHRU */
case DISAS_PC_UPDATED: case DISAS_PC_UPDATED:
if (!use_exit_tb(&ctx)) { if (!use_exit_tb(ctx)) {
tcg_gen_lookup_and_goto_ptr(cpu_pc); tcg_gen_lookup_and_goto_ptr(cpu_pc);
break; break;
} }
/* FALLTHRU */ /* FALLTHRU */
case DISAS_PC_UPDATED_NOCHAIN: case DISAS_PC_UPDATED_NOCHAIN:
if (ctx.base.singlestep_enabled) { if (ctx->base.singlestep_enabled) {
gen_excp_1(EXCP_DEBUG, 0); gen_excp_1(EXCP_DEBUG, 0);
} else { } else {
tcg_gen_exit_tb(0); tcg_gen_exit_tb(0);
@ -3062,22 +3043,28 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
default: default:
g_assert_not_reached(); g_assert_not_reached();
} }
}
gen_tb_end(tb, num_insns); static void alpha_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu)
{
qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first));
log_target_disas(cpu, dcbase->pc_first, dcbase->tb->size, 1);
}
tb->size = ctx.base.pc_next - pc_start; static const TranslatorOps alpha_tr_ops = {
tb->icount = num_insns; .init_disas_context = alpha_tr_init_disas_context,
.tb_start = alpha_tr_tb_start,
.insn_start = alpha_tr_insn_start,
.breakpoint_check = alpha_tr_breakpoint_check,
.translate_insn = alpha_tr_translate_insn,
.tb_stop = alpha_tr_tb_stop,
.disas_log = alpha_tr_disas_log,
};
#ifdef DEBUG_DISAS void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) {
&& qemu_log_in_addr_range(pc_start)) { DisasContext dc;
qemu_log_lock(); translator_loop(&alpha_tr_ops, &dc.base, cpu, tb);
qemu_log("IN: %s\n", lookup_symbol(pc_start));
log_target_disas(cs, pc_start, ctx.base.pc_next - pc_start, 1);
qemu_log("\n");
qemu_log_unlock();
}
#endif
} }
void restore_state_to_opc(CPUAlphaState *env, TranslationBlock *tb, void restore_state_to_opc(CPUAlphaState *env, TranslationBlock *tb,