Commit 9c509ff9 authored by Richard Henderson's avatar Richard Henderson Committed by Max Filippov
Browse files

target/xtensa: Convert to TranslatorOps

parent 1d38a701
Loading
Loading
Loading
Loading
+116 −101
Original line number Diff line number Diff line
@@ -1055,84 +1055,81 @@ static void gen_ibreak_check(CPUXtensaState *env, DisasContext *dc)
    }
}

void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
static void xtensa_tr_init_disas_context(DisasContextBase *dcbase,
                                         CPUState *cpu)
{
    CPUXtensaState *env = cs->env_ptr;
    DisasContext dc1, *dc = &dc1;
    int insn_count = 0;
    int max_insns = tb_cflags(tb) & CF_COUNT_MASK;
    uint32_t pc_start = tb->pc;
    uint32_t page_start = pc_start & TARGET_PAGE_MASK;

    if (max_insns == 0) {
        max_insns = CF_COUNT_MASK;
    }
    if (max_insns > TCG_MAX_INSNS) {
        max_insns = TCG_MAX_INSNS;
    }
    DisasContext *dc = container_of(dcbase, DisasContext, base);
    CPUXtensaState *env = cpu->env_ptr;
    uint32_t tb_flags = dc->base.tb->flags;

    dc->config = env->config;
    dc->base.singlestep_enabled = cs->singlestep_enabled;
    dc->base.tb = tb;
    dc->pc = pc_start;
    dc->ring = tb->flags & XTENSA_TBFLAG_RING_MASK;
    dc->cring = (tb->flags & XTENSA_TBFLAG_EXCM) ? 0 : dc->ring;
    dc->pc = dc->base.pc_first;
    dc->ring = tb_flags & XTENSA_TBFLAG_RING_MASK;
    dc->cring = (tb_flags & XTENSA_TBFLAG_EXCM) ? 0 : dc->ring;
    dc->lbeg = env->sregs[LBEG];
    dc->lend = env->sregs[LEND];
    dc->base.is_jmp = DISAS_NEXT;
    dc->debug = tb->flags & XTENSA_TBFLAG_DEBUG;
    dc->icount = tb->flags & XTENSA_TBFLAG_ICOUNT;
    dc->cpenable = (tb->flags & XTENSA_TBFLAG_CPENABLE_MASK) >>
    dc->debug = tb_flags & XTENSA_TBFLAG_DEBUG;
    dc->icount = tb_flags & XTENSA_TBFLAG_ICOUNT;
    dc->cpenable = (tb_flags & XTENSA_TBFLAG_CPENABLE_MASK) >>
        XTENSA_TBFLAG_CPENABLE_SHIFT;
    dc->window = ((tb->flags & XTENSA_TBFLAG_WINDOW_MASK) >>
    dc->window = ((tb_flags & XTENSA_TBFLAG_WINDOW_MASK) >>
                 XTENSA_TBFLAG_WINDOW_SHIFT);

    if (dc->config->isa) {
        dc->insnbuf = xtensa_insnbuf_alloc(dc->config->isa);
        dc->slotbuf = xtensa_insnbuf_alloc(dc->config->isa);
    }

    init_sar_tracker(dc);
    if (dc->icount) {
        dc->next_icount = tcg_temp_local_new_i32();
}

    gen_tb_start(tb);
static void xtensa_tr_tb_start(DisasContextBase *dcbase, CPUState *cpu)
{
    DisasContext *dc = container_of(dcbase, DisasContext, base);

    if ((tb_cflags(tb) & CF_USE_ICOUNT) &&
        (tb->flags & XTENSA_TBFLAG_YIELD)) {
        tcg_gen_insn_start(dc->pc);
        ++insn_count;
        gen_exception(dc, EXCP_YIELD);
        dc->base.is_jmp = DISAS_NORETURN;
        goto done;
    if (dc->icount) {
        dc->next_icount = tcg_temp_local_new_i32();
    }
    if (tb->flags & XTENSA_TBFLAG_EXCEPTION) {
        tcg_gen_insn_start(dc->pc);
        ++insn_count;
        gen_exception(dc, EXCP_DEBUG);
        dc->base.is_jmp = DISAS_NORETURN;
        goto done;
}

    do {
        tcg_gen_insn_start(dc->pc);
        ++insn_count;
static void xtensa_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
{
    tcg_gen_insn_start(dcbase->pc_next);
}

        if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
            tcg_gen_movi_i32(cpu_pc, dc->pc);
static bool xtensa_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu,
                                       const CPUBreakpoint *bp)
{
    DisasContext *dc = container_of(dcbase, DisasContext, base);

    tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
    gen_exception(dc, EXCP_DEBUG);
    dc->base.is_jmp = DISAS_NORETURN;
    /* The address covered by the breakpoint must be included in
       [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.  */
            dc->pc += 2;
            break;
    dc->base.pc_next += 2;
    return true;
}

        if (insn_count == max_insns && (tb_cflags(tb) & CF_LAST_IO)) {
            gen_io_start();
static void xtensa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
{
    DisasContext *dc = container_of(dcbase, DisasContext, base);
    CPUXtensaState *env = cpu->env_ptr;
    target_ulong page_start;

    /* These two conditions only apply to the first insn in the TB,
       but this is the first TranslateOps hook that allows exiting.  */
    if ((tb_cflags(dc->base.tb) & CF_USE_ICOUNT)
        && (dc->base.tb->flags & XTENSA_TBFLAG_YIELD)) {
        gen_exception(dc, EXCP_YIELD);
        dc->base.is_jmp = DISAS_NORETURN;
        return;
    }
    if (dc->base.tb->flags & XTENSA_TBFLAG_EXCEPTION) {
        gen_exception(dc, EXCP_DEBUG);
        dc->base.is_jmp = DISAS_NORETURN;
        return;
    }

    if (dc->icount) {
@@ -1152,51 +1149,69 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
    }

    disas_xtensa_insn(env, dc);

    if (dc->icount) {
        tcg_gen_mov_i32(cpu_SR[ICOUNT], dc->next_icount);
    }
        if (dc->base.singlestep_enabled) {
            tcg_gen_movi_i32(cpu_pc, dc->pc);
            gen_exception(dc, EXCP_DEBUG);
            break;

    /* End the TB if the next insn will cross into the next page.  */
    page_start = dc->base.pc_first & TARGET_PAGE_MASK;
    if (dc->base.is_jmp == DISAS_NEXT &&
        (dc->pc - page_start >= TARGET_PAGE_SIZE ||
         dc->pc - page_start + xtensa_insn_len(env, dc) > TARGET_PAGE_SIZE)) {
        dc->base.is_jmp = DISAS_TOO_MANY;
    }
    } while (dc->base.is_jmp == DISAS_NEXT &&
             insn_count < max_insns &&
             dc->pc - page_start < TARGET_PAGE_SIZE &&
             dc->pc - page_start + xtensa_insn_len(env, dc) <= TARGET_PAGE_SIZE
             && !tcg_op_buf_full());
done:
    reset_sar_tracker(dc);
    if (dc->icount) {
        tcg_temp_free(dc->next_icount);
}

static void xtensa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
{
    DisasContext *dc = container_of(dcbase, DisasContext, base);

    reset_sar_tracker(dc);
    if (dc->config->isa) {
        xtensa_insnbuf_free(dc->config->isa, dc->insnbuf);
        xtensa_insnbuf_free(dc->config->isa, dc->slotbuf);
    }

    if (tb_cflags(tb) & CF_LAST_IO) {
        gen_io_end();
    if (dc->icount) {
        tcg_temp_free(dc->next_icount);
    }

    if (dc->base.is_jmp == DISAS_NEXT) {
    switch (dc->base.is_jmp) {
    case DISAS_NORETURN:
        break;
    case DISAS_TOO_MANY:
        if (dc->base.singlestep_enabled) {
            tcg_gen_movi_i32(cpu_pc, dc->pc);
            gen_exception(dc, EXCP_DEBUG);
        } else {
            gen_jumpi(dc, dc->pc, 0);
        }
    gen_tb_end(tb, insn_count);
        break;
    default:
        g_assert_not_reached();
    }
}

#ifdef DEBUG_DISAS
    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
        && qemu_log_in_addr_range(pc_start)) {
        qemu_log_lock();
        qemu_log("----------------\n");
        qemu_log("IN: %s\n", lookup_symbol(pc_start));
        log_target_disas(cs, pc_start, dc->pc - pc_start);
        qemu_log("\n");
        qemu_log_unlock();
static void xtensa_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);
}
#endif
    tb->size = dc->pc - pc_start;
    tb->icount = insn_count;

static const TranslatorOps xtensa_translator_ops = {
    .init_disas_context = xtensa_tr_init_disas_context,
    .tb_start           = xtensa_tr_tb_start,
    .insn_start         = xtensa_tr_insn_start,
    .breakpoint_check   = xtensa_tr_breakpoint_check,
    .translate_insn     = xtensa_tr_translate_insn,
    .tb_stop            = xtensa_tr_tb_stop,
    .disas_log          = xtensa_tr_disas_log,
};

void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
{
    DisasContext dc = {};
    translator_loop(&xtensa_translator_ops, &dc.base, cpu, tb);
}

void xtensa_cpu_dump_state(CPUState *cs, FILE *f,