Loading target/hppa/translate.c +159 −143 Original line number Diff line number Diff line Loading @@ -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; tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b); } if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) { gen_io_start(); static bool hppa_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs, const CPUBreakpoint *bp) { DisasContext *ctx = container_of(dcbase, DisasContext, base); ctx->base.is_jmp = gen_excp(ctx, EXCP_DEBUG); ctx->base.pc_next = ctx->iaoq_f + 4; return true; } if (ctx.iaoq_f < TARGET_PAGE_SIZE) { ret = do_page_zero(&ctx); 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); 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); 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); 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; 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); ret = translate_one(ctx, insn); assert(ctx->null_lab == NULL); } } for (i = 0; i < ctx.ntemps; ++i) { tcg_temp_free(ctx.temps[i]); TCGV_UNUSED(ctx.temps[i]); /* 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; ctx->ntemps = 0; /* If we see non-linear instructions, exhaust instruction count, or run out of buffer space, stop generation. */ /* 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 || 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); 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; ctx.iaoq_f = ctx.iaoq_b; ctx.iaoq_b = ctx.iaoq_n; if (ret == DISAS_NORETURN || ret == DISAS_IAQ_N_UPDATED) { break; return; } if (ctx.iaoq_f == -1) { 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; 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); } if (ctx.iaoq_b == -1) { tcg_gen_mov_tl(cpu_iaoq_b, ctx.iaoq_n_var); } } while (ret == DISAS_NEXT); if (tb->cflags & CF_LAST_IO) { gen_io_end(); } 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"); qemu_log("IN:\n0x00000000: (null)\n"); break; case 0xb0: qemu_log("IN:\n0x000000b0: light-weight-syscall\n\n"); qemu_log("IN:\n0x000000b0: light-weight-syscall\n"); break; case 0xe0: qemu_log("IN:\n0x000000e0: set-thread-pointer-syscall\n\n"); qemu_log("IN:\n0x000000e0: set-thread-pointer-syscall\n"); break; case 0x100: qemu_log("IN:\n0x00000100: syscall\n\n"); 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); qemu_log("\n"); break; } qemu_log_unlock(); } #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, Loading Loading
target/hppa/translate.c +159 −143 Original line number Diff line number Diff line Loading @@ -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; tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b); } if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) { gen_io_start(); static bool hppa_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs, const CPUBreakpoint *bp) { DisasContext *ctx = container_of(dcbase, DisasContext, base); ctx->base.is_jmp = gen_excp(ctx, EXCP_DEBUG); ctx->base.pc_next = ctx->iaoq_f + 4; return true; } if (ctx.iaoq_f < TARGET_PAGE_SIZE) { ret = do_page_zero(&ctx); 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); 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); 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); 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; 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); ret = translate_one(ctx, insn); assert(ctx->null_lab == NULL); } } for (i = 0; i < ctx.ntemps; ++i) { tcg_temp_free(ctx.temps[i]); TCGV_UNUSED(ctx.temps[i]); /* 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; ctx->ntemps = 0; /* If we see non-linear instructions, exhaust instruction count, or run out of buffer space, stop generation. */ /* 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 || 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); 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; ctx.iaoq_f = ctx.iaoq_b; ctx.iaoq_b = ctx.iaoq_n; if (ret == DISAS_NORETURN || ret == DISAS_IAQ_N_UPDATED) { break; return; } if (ctx.iaoq_f == -1) { 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; 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); } if (ctx.iaoq_b == -1) { tcg_gen_mov_tl(cpu_iaoq_b, ctx.iaoq_n_var); } } while (ret == DISAS_NEXT); if (tb->cflags & CF_LAST_IO) { gen_io_end(); } 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"); qemu_log("IN:\n0x00000000: (null)\n"); break; case 0xb0: qemu_log("IN:\n0x000000b0: light-weight-syscall\n\n"); qemu_log("IN:\n0x000000b0: light-weight-syscall\n"); break; case 0xe0: qemu_log("IN:\n0x000000e0: set-thread-pointer-syscall\n\n"); qemu_log("IN:\n0x000000e0: set-thread-pointer-syscall\n"); break; case 0x100: qemu_log("IN:\n0x00000100: syscall\n\n"); 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); qemu_log("\n"); break; } qemu_log_unlock(); } #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, Loading