Reviewed-by: Michael Rolnik <mrol...@gmail.com> Tested-by: Michael Rolnik <mrol...@gmail.com>
On Mon, Jun 21, 2021 at 12:50 AM Richard Henderson < richard.hender...@linaro.org> wrote: > Signed-off-by: Richard Henderson <richard.hender...@linaro.org> > --- > target/avr/translate.c | 234 ++++++++++++++++++++++------------------- > 1 file changed, 128 insertions(+), 106 deletions(-) > > diff --git a/target/avr/translate.c b/target/avr/translate.c > index 66e9882422..c06ce45bc7 100644 > --- a/target/avr/translate.c > +++ b/target/avr/translate.c > @@ -2897,113 +2897,131 @@ static bool canonicalize_skip(DisasContext *ctx) > return true; > } > > -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int > max_insns) > +static void gen_breakpoint(DisasContext *ctx) > { > + canonicalize_skip(ctx); > + tcg_gen_movi_tl(cpu_pc, ctx->npc); > + gen_helper_debug(cpu_env); > + ctx->base.is_jmp = DISAS_NORETURN; > +} > + > +static void avr_tr_init_disas_context(DisasContextBase *dcbase, CPUState > *cs) > +{ > + DisasContext *ctx = container_of(dcbase, DisasContext, base); > CPUAVRState *env = cs->env_ptr; > - DisasContext ctx1 = { > - .base.tb = tb, > - .base.is_jmp = DISAS_NEXT, > - .base.pc_first = tb->pc, > - .base.pc_next = tb->pc, > - .base.singlestep_enabled = cs->singlestep_enabled, > - .cs = cs, > - .env = env, > - .memidx = 0, > - .skip_cond = TCG_COND_NEVER, > - }; > - DisasContext *ctx = &ctx1; > - target_ulong pc_start = tb->pc / 2; > - int num_insns = 0; > + uint32_t tb_flags = ctx->base.tb->flags; > > - if (tb->flags & TB_FLAGS_FULL_ACCESS) { > - /* > - * This flag is set by ST/LD instruction we will regenerate it > ONLY > - * with mem/cpu memory access instead of mem access > - */ > - max_insns = 1; > - } > - if (ctx->base.singlestep_enabled) { > - max_insns = 1; > - } > + ctx->cs = cs; > + ctx->env = env; > + ctx->npc = ctx->base.pc_first / 2; > > - gen_tb_start(tb); > - > - ctx->npc = pc_start; > - if (tb->flags & TB_FLAGS_SKIP) { > + ctx->skip_cond = TCG_COND_NEVER; > + if (tb_flags & TB_FLAGS_SKIP) { > ctx->skip_cond = TCG_COND_ALWAYS; > ctx->skip_var0 = cpu_skip; > } > > - do { > - TCGLabel *skip_label = NULL; > - > - /* translate current instruction */ > - tcg_gen_insn_start(ctx->npc); > - num_insns++; > - > + if (tb_flags & TB_FLAGS_FULL_ACCESS) { > /* > - * this is due to some strange GDB behavior > - * let's assume main has address 0x100 > - * b main - sets breakpoint at address 0x00000100 (code) > - * b *0x100 - sets breakpoint at address 0x00800100 (data) > + * This flag is set by ST/LD instruction we will regenerate it > ONLY > + * with mem/cpu memory access instead of mem access > */ > - if (unlikely(!ctx->base.singlestep_enabled && > - (cpu_breakpoint_test(cs, OFFSET_CODE + ctx->npc * 2, BP_ANY) > || > - cpu_breakpoint_test(cs, OFFSET_DATA + ctx->npc * 2, > BP_ANY)))) { > - canonicalize_skip(ctx); > - tcg_gen_movi_tl(cpu_pc, ctx->npc); > - gen_helper_debug(cpu_env); > - goto done_generating; > - } > + ctx->base.max_insns = 1; > + } > +} > > - /* Conditionally skip the next instruction, if indicated. */ > - if (ctx->skip_cond != TCG_COND_NEVER) { > - skip_label = gen_new_label(); > - if (ctx->skip_var0 == cpu_skip) { > - /* > - * Copy cpu_skip so that we may zero it before the branch. > - * This ensures that cpu_skip is non-zero after the label > - * if and only if the skipped insn itself sets a skip. > - */ > - ctx->free_skip_var0 = true; > - ctx->skip_var0 = tcg_temp_new(); > - tcg_gen_mov_tl(ctx->skip_var0, cpu_skip); > - tcg_gen_movi_tl(cpu_skip, 0); > - } > - if (ctx->skip_var1 == NULL) { > - tcg_gen_brcondi_tl(ctx->skip_cond, ctx->skip_var0, > - 0, skip_label); > - } else { > - tcg_gen_brcond_tl(ctx->skip_cond, ctx->skip_var0, > - ctx->skip_var1, skip_label); > - ctx->skip_var1 = NULL; > - } > - if (ctx->free_skip_var0) { > - tcg_temp_free(ctx->skip_var0); > - ctx->free_skip_var0 = false; > - } > - ctx->skip_cond = TCG_COND_NEVER; > - ctx->skip_var0 = NULL; > - } > +static void avr_tr_tb_start(DisasContextBase *db, CPUState *cs) > +{ > +} > > - translate(ctx); > +static void avr_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) > +{ > + DisasContext *ctx = container_of(dcbase, DisasContext, base); > > - if (skip_label) { > - canonicalize_skip(ctx); > - gen_set_label(skip_label); > - if (ctx->base.is_jmp == DISAS_NORETURN) { > - ctx->base.is_jmp = DISAS_CHAIN; > - } > - } > - } while (ctx->base.is_jmp == DISAS_NEXT > - && num_insns < max_insns > - && (ctx->npc - pc_start) * 2 < TARGET_PAGE_SIZE - 4 > - && !tcg_op_buf_full()); > + tcg_gen_insn_start(ctx->npc); > +} > > - if (tb->cflags & CF_LAST_IO) { > - gen_io_end(); > +static bool avr_tr_breakpoint_check(DisasContextBase *dcbase, CPUState > *cs, > + const CPUBreakpoint *bp) > +{ > + DisasContext *ctx = container_of(dcbase, DisasContext, base); > + > + gen_breakpoint(ctx); > + return true; > +} > + > +static void avr_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) > +{ > + DisasContext *ctx = container_of(dcbase, DisasContext, base); > + TCGLabel *skip_label = NULL; > + > + /* > + * This is due to some strange GDB behavior > + * Let's assume main has address 0x100: > + * b main - sets breakpoint at address 0x00000100 (code) > + * b *0x100 - sets breakpoint at address 0x00800100 (data) > + * > + * The translator driver has already taken care of the code pointer. > + */ > + if (!ctx->base.singlestep_enabled && > + cpu_breakpoint_test(cs, OFFSET_DATA + ctx->base.pc_next, BP_ANY)) > { > + gen_breakpoint(ctx); > + return; > } > > + /* Conditionally skip the next instruction, if indicated. */ > + if (ctx->skip_cond != TCG_COND_NEVER) { > + skip_label = gen_new_label(); > + if (ctx->skip_var0 == cpu_skip) { > + /* > + * Copy cpu_skip so that we may zero it before the branch. > + * This ensures that cpu_skip is non-zero after the label > + * if and only if the skipped insn itself sets a skip. > + */ > + ctx->free_skip_var0 = true; > + ctx->skip_var0 = tcg_temp_new(); > + tcg_gen_mov_tl(ctx->skip_var0, cpu_skip); > + tcg_gen_movi_tl(cpu_skip, 0); > + } > + if (ctx->skip_var1 == NULL) { > + tcg_gen_brcondi_tl(ctx->skip_cond, ctx->skip_var0, 0, > skip_label); > + } else { > + tcg_gen_brcond_tl(ctx->skip_cond, ctx->skip_var0, > + ctx->skip_var1, skip_label); > + ctx->skip_var1 = NULL; > + } > + if (ctx->free_skip_var0) { > + tcg_temp_free(ctx->skip_var0); > + ctx->free_skip_var0 = false; > + } > + ctx->skip_cond = TCG_COND_NEVER; > + ctx->skip_var0 = NULL; > + } > + > + translate(ctx); > + > + ctx->base.pc_next = ctx->npc * 2; > + > + if (skip_label) { > + canonicalize_skip(ctx); > + gen_set_label(skip_label); > + if (ctx->base.is_jmp == DISAS_NORETURN) { > + ctx->base.is_jmp = DISAS_CHAIN; > + } > + } > + > + if (ctx->base.is_jmp == DISAS_NEXT) { > + target_ulong page_first = ctx->base.pc_first & TARGET_PAGE_MASK; > + > + if ((ctx->base.pc_next - page_first) >= TARGET_PAGE_SIZE - 4) { > + ctx->base.is_jmp = DISAS_TOO_MANY; > + } > + } > +} > + > +static void avr_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) > +{ > + DisasContext *ctx = container_of(dcbase, DisasContext, base); > bool nonconst_skip = canonicalize_skip(ctx); > > switch (ctx->base.is_jmp) { > @@ -3036,24 +3054,28 @@ void gen_intermediate_code(CPUState *cs, > TranslationBlock *tb, int max_insns) > default: > g_assert_not_reached(); > } > +} > > -done_generating: > - gen_tb_end(tb, num_insns); > +static void avr_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs) > +{ > + qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first)); > + log_target_disas(cs, dcbase->pc_first, dcbase->tb->size); > +} > > - tb->size = (ctx->npc - pc_start) * 2; > - tb->icount = num_insns; > +static const TranslatorOps avr_tr_ops = { > + .init_disas_context = avr_tr_init_disas_context, > + .tb_start = avr_tr_tb_start, > + .insn_start = avr_tr_insn_start, > + .breakpoint_check = avr_tr_breakpoint_check, > + .translate_insn = avr_tr_translate_insn, > + .tb_stop = avr_tr_tb_stop, > + .disas_log = avr_tr_disas_log, > +}; > > -#ifdef DEBUG_DISAS > - if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) > - && qemu_log_in_addr_range(tb->pc)) { > - FILE *fd; > - fd = qemu_log_lock(); > - qemu_log("IN: %s\n", lookup_symbol(tb->pc)); > - log_target_disas(cs, tb->pc, tb->size); > - qemu_log("\n"); > - qemu_log_unlock(fd); > - } > -#endif > +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int > max_insns) > +{ > + DisasContext dc = { }; > + translator_loop(&avr_tr_ops, &dc.base, cs, tb, max_insns); > } > > void restore_state_to_opc(CPUAVRState *env, TranslationBlock *tb, > -- > 2.25.1 > > -- Best Regards, Michael Rolnik