Commit 51b061fb authored by Richard Henderson's avatar Richard Henderson Committed by Richard Henderson
Browse files

target/hppa: Convert to TranslatorOps

parent d01a3625
Loading
Loading
Loading
Loading
+159 −143
Original line number Diff line number Diff line
@@ -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,