aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--target/hppa/translate.c302
1 files changed, 159 insertions, 143 deletions
diff --git a/target/hppa/translate.c b/target/hppa/translate.c
index 993438a60b..b6e2652341 100644
--- a/target/hppa/translate.c
+++ b/target/hppa/translate.c
@@ -3729,185 +3729,201 @@ static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn)
return gen_illegal(ctx);
}
-void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
+static int hppa_tr_init_disas_context(DisasContextBase *dcbase,
+ CPUState *cs, int max_insns)
{
- CPUHPPAState *env = cs->env_ptr;
- DisasContext ctx;
- DisasJumpType ret;
- int num_insns, max_insns, i;
+ DisasContext *ctx = container_of(dcbase, DisasContext, base);
+ TranslationBlock *tb = ctx->base.tb;
+ int i, bound;
- ctx.base.tb = tb;
- ctx.base.singlestep_enabled = cs->singlestep_enabled;
- ctx.cs = cs;
- ctx.iaoq_f = tb->pc;
- ctx.iaoq_b = tb->cs_base;
+ ctx->cs = cs;
+ ctx->iaoq_f = tb->pc;
+ ctx->iaoq_b = tb->cs_base;
+ ctx->iaoq_n = -1;
+ TCGV_UNUSED(ctx->iaoq_n_var);
- ctx.ntemps = 0;
- for (i = 0; i < ARRAY_SIZE(ctx.temps); ++i) {
- TCGV_UNUSED(ctx.temps[i]);
+ ctx->ntemps = 0;
+ for (i = 0; i < ARRAY_SIZE(ctx->temps); ++i) {
+ TCGV_UNUSED(ctx->temps[i]);
}
- /* Compute the maximum number of insns to execute, as bounded by
- (1) icount, (2) single-stepping, (3) branch delay slots, or
- (4) the number of insns remaining on the current page. */
- max_insns = tb->cflags & CF_COUNT_MASK;
- if (max_insns == 0) {
- max_insns = CF_COUNT_MASK;
- }
- if (ctx.base.singlestep_enabled || singlestep) {
- max_insns = 1;
- } else if (max_insns > TCG_MAX_INSNS) {
- max_insns = TCG_MAX_INSNS;
- }
+ bound = -(tb->pc | TARGET_PAGE_MASK) / 4;
+ return MIN(max_insns, bound);
+}
- num_insns = 0;
- gen_tb_start(tb);
+static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs)
+{
+ DisasContext *ctx = container_of(dcbase, DisasContext, base);
/* Seed the nullification status from PSW[N], as shown in TB->FLAGS. */
- ctx.null_cond = cond_make_f();
- ctx.psw_n_nonzero = false;
- if (tb->flags & 1) {
- ctx.null_cond.c = TCG_COND_ALWAYS;
- ctx.psw_n_nonzero = true;
+ ctx->null_cond = cond_make_f();
+ ctx->psw_n_nonzero = false;
+ if (ctx->base.tb->flags & 1) {
+ ctx->null_cond.c = TCG_COND_ALWAYS;
+ ctx->psw_n_nonzero = true;
}
- ctx.null_lab = NULL;
+ ctx->null_lab = NULL;
+}
- do {
- tcg_gen_insn_start(ctx.iaoq_f, ctx.iaoq_b);
- num_insns++;
+static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
+{
+ DisasContext *ctx = container_of(dcbase, DisasContext, base);
- if (unlikely(cpu_breakpoint_test(cs, ctx.iaoq_f, BP_ANY))) {
- ret = gen_excp(&ctx, EXCP_DEBUG);
- break;
- }
- if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
- gen_io_start();
- }
+ tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b);
+}
+
+static bool hppa_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs,
+ const CPUBreakpoint *bp)
+{
+ DisasContext *ctx = container_of(dcbase, DisasContext, base);
- if (ctx.iaoq_f < TARGET_PAGE_SIZE) {
- ret = do_page_zero(&ctx);
- assert(ret != DISAS_NEXT);
+ ctx->base.is_jmp = gen_excp(ctx, EXCP_DEBUG);
+ ctx->base.pc_next = ctx->iaoq_f + 4;
+ return true;
+}
+
+static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
+{
+ DisasContext *ctx = container_of(dcbase, DisasContext, base);
+ CPUHPPAState *env = cs->env_ptr;
+ DisasJumpType ret;
+ int i, n;
+
+ /* Execute one insn. */
+ if (ctx->iaoq_f < TARGET_PAGE_SIZE) {
+ ret = do_page_zero(ctx);
+ assert(ret != DISAS_NEXT);
+ } else {
+ /* Always fetch the insn, even if nullified, so that we check
+ the page permissions for execute. */
+ uint32_t insn = cpu_ldl_code(env, ctx->iaoq_f);
+
+ /* Set up the IA queue for the next insn.
+ This will be overwritten by a branch. */
+ if (ctx->iaoq_b == -1) {
+ ctx->iaoq_n = -1;
+ ctx->iaoq_n_var = get_temp(ctx);
+ tcg_gen_addi_tl(ctx->iaoq_n_var, cpu_iaoq_b, 4);
} else {
- /* Always fetch the insn, even if nullified, so that we check
- the page permissions for execute. */
- uint32_t insn = cpu_ldl_code(env, ctx.iaoq_f);
-
- /* Set up the IA queue for the next insn.
- This will be overwritten by a branch. */
- if (ctx.iaoq_b == -1) {
- ctx.iaoq_n = -1;
- ctx.iaoq_n_var = get_temp(&ctx);
- tcg_gen_addi_tl(ctx.iaoq_n_var, cpu_iaoq_b, 4);
- } else {
- ctx.iaoq_n = ctx.iaoq_b + 4;
- TCGV_UNUSED(ctx.iaoq_n_var);
- }
-
- if (unlikely(ctx.null_cond.c == TCG_COND_ALWAYS)) {
- ctx.null_cond.c = TCG_COND_NEVER;
- ret = DISAS_NEXT;
- } else {
- ret = translate_one(&ctx, insn);
- assert(ctx.null_lab == NULL);
- }
+ ctx->iaoq_n = ctx->iaoq_b + 4;
+ TCGV_UNUSED(ctx->iaoq_n_var);
}
- for (i = 0; i < ctx.ntemps; ++i) {
- tcg_temp_free(ctx.temps[i]);
- TCGV_UNUSED(ctx.temps[i]);
- }
- ctx.ntemps = 0;
-
- /* If we see non-linear instructions, exhaust instruction count,
- or run out of buffer space, stop generation. */
- /* ??? The non-linear instruction restriction is purely due to
- the debugging dump. Otherwise we *could* follow unconditional
- branches within the same page. */
- if (ret == DISAS_NEXT
- && (ctx.iaoq_b != ctx.iaoq_f + 4
- || num_insns >= max_insns
- || tcg_op_buf_full())) {
- if (ctx.null_cond.c == TCG_COND_NEVER
- || ctx.null_cond.c == TCG_COND_ALWAYS) {
- nullify_set(&ctx, ctx.null_cond.c == TCG_COND_ALWAYS);
- gen_goto_tb(&ctx, 0, ctx.iaoq_b, ctx.iaoq_n);
- ret = DISAS_NORETURN;
- } else {
- ret = DISAS_IAQ_N_STALE;
- }
+ if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) {
+ ctx->null_cond.c = TCG_COND_NEVER;
+ ret = DISAS_NEXT;
+ } else {
+ ret = translate_one(ctx, insn);
+ assert(ctx->null_lab == NULL);
}
+ }
- ctx.iaoq_f = ctx.iaoq_b;
- ctx.iaoq_b = ctx.iaoq_n;
- if (ret == DISAS_NORETURN || ret == DISAS_IAQ_N_UPDATED) {
- break;
- }
- if (ctx.iaoq_f == -1) {
- tcg_gen_mov_tl(cpu_iaoq_f, cpu_iaoq_b);
- copy_iaoq_entry(cpu_iaoq_b, ctx.iaoq_n, ctx.iaoq_n_var);
- nullify_save(&ctx);
- ret = DISAS_IAQ_N_UPDATED;
- break;
- }
- if (ctx.iaoq_b == -1) {
- tcg_gen_mov_tl(cpu_iaoq_b, ctx.iaoq_n_var);
- }
- } while (ret == DISAS_NEXT);
+ /* Free any temporaries allocated. */
+ for (i = 0, n = ctx->ntemps; i < n; ++i) {
+ tcg_temp_free(ctx->temps[i]);
+ TCGV_UNUSED(ctx->temps[i]);
+ }
+ ctx->ntemps = 0;
- if (tb->cflags & CF_LAST_IO) {
- gen_io_end();
+ /* Advance the insn queue. */
+ /* ??? The non-linear instruction restriction is purely due to
+ the debugging dump. Otherwise we *could* follow unconditional
+ branches within the same page. */
+ if (ret == DISAS_NEXT && ctx->iaoq_b != ctx->iaoq_f + 4) {
+ if (ctx->null_cond.c == TCG_COND_NEVER
+ || ctx->null_cond.c == TCG_COND_ALWAYS) {
+ nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS);
+ gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n);
+ ret = DISAS_NORETURN;
+ } else {
+ ret = DISAS_IAQ_N_STALE;
+ }
}
+ ctx->iaoq_f = ctx->iaoq_b;
+ ctx->iaoq_b = ctx->iaoq_n;
+ ctx->base.is_jmp = ret;
+
+ if (ret == DISAS_NORETURN || ret == DISAS_IAQ_N_UPDATED) {
+ return;
+ }
+ if (ctx->iaoq_f == -1) {
+ tcg_gen_mov_tl(cpu_iaoq_f, cpu_iaoq_b);
+ copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var);
+ nullify_save(ctx);
+ ctx->base.is_jmp = DISAS_IAQ_N_UPDATED;
+ } else if (ctx->iaoq_b == -1) {
+ tcg_gen_mov_tl(cpu_iaoq_b, ctx->iaoq_n_var);
+ }
+}
+
+static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
+{
+ DisasContext *ctx = container_of(dcbase, DisasContext, base);
- switch (ret) {
+ switch (ctx->base.is_jmp) {
case DISAS_NORETURN:
break;
+ case DISAS_TOO_MANY:
case DISAS_IAQ_N_STALE:
- copy_iaoq_entry(cpu_iaoq_f, ctx.iaoq_f, cpu_iaoq_f);
- copy_iaoq_entry(cpu_iaoq_b, ctx.iaoq_b, cpu_iaoq_b);
- nullify_save(&ctx);
+ copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
+ copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
+ nullify_save(ctx);
/* FALLTHRU */
case DISAS_IAQ_N_UPDATED:
- if (ctx.base.singlestep_enabled) {
+ if (ctx->base.singlestep_enabled) {
gen_excp_1(EXCP_DEBUG);
} else {
tcg_gen_lookup_and_goto_ptr(cpu_iaoq_f);
}
break;
default:
- abort();
+ g_assert_not_reached();
}
- gen_tb_end(tb, num_insns);
+ /* We don't actually use this during normal translation,
+ but we should interact with the generic main loop. */
+ ctx->base.pc_next = ctx->base.tb->pc + 4 * ctx->base.num_insns;
+}
- tb->size = num_insns * 4;
- tb->icount = num_insns;
+static void hppa_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs)
+{
+ TranslationBlock *tb = dcbase->tb;
-#ifdef DEBUG_DISAS
- if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
- && qemu_log_in_addr_range(tb->pc)) {
- qemu_log_lock();
- switch (tb->pc) {
- case 0x00:
- qemu_log("IN:\n0x00000000: (null)\n\n");
- break;
- case 0xb0:
- qemu_log("IN:\n0x000000b0: light-weight-syscall\n\n");
- break;
- case 0xe0:
- qemu_log("IN:\n0x000000e0: set-thread-pointer-syscall\n\n");
- break;
- case 0x100:
- qemu_log("IN:\n0x00000100: syscall\n\n");
- break;
- default:
- qemu_log("IN: %s\n", lookup_symbol(tb->pc));
- log_target_disas(cs, tb->pc, tb->size, 1);
- qemu_log("\n");
- break;
- }
- qemu_log_unlock();
+ switch (tb->pc) {
+ case 0x00:
+ qemu_log("IN:\n0x00000000: (null)\n");
+ break;
+ case 0xb0:
+ qemu_log("IN:\n0x000000b0: light-weight-syscall\n");
+ break;
+ case 0xe0:
+ qemu_log("IN:\n0x000000e0: set-thread-pointer-syscall\n");
+ break;
+ case 0x100:
+ qemu_log("IN:\n0x00000100: syscall\n");
+ break;
+ default:
+ qemu_log("IN: %s\n", lookup_symbol(tb->pc));
+ log_target_disas(cs, tb->pc, tb->size, 1);
+ break;
}
-#endif
+}
+
+static const TranslatorOps hppa_tr_ops = {
+ .init_disas_context = hppa_tr_init_disas_context,
+ .tb_start = hppa_tr_tb_start,
+ .insn_start = hppa_tr_insn_start,
+ .breakpoint_check = hppa_tr_breakpoint_check,
+ .translate_insn = hppa_tr_translate_insn,
+ .tb_stop = hppa_tr_tb_stop,
+ .disas_log = hppa_tr_disas_log,
+};
+
+void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb)
+
+{
+ DisasContext ctx;
+ translator_loop(&hppa_tr_ops, &ctx.base, cs, tb);
}
void restore_state_to_opc(CPUHPPAState *env, TranslationBlock *tb,