Emilio G Cota writes: > On Mon, Jun 12, 2017 at 17:54:09 +0300, Lluís Vilanova wrote: >> Signed-off-by: Lluís Vilanova <vilan...@ac.upc.edu> >> --- >> include/exec/gen-icount.h | 2 >> include/exec/translate-all_template.h | 73 ++++++++++++ >> include/qom/cpu.h | 22 ++++ >> translate-all_template.h | 204 >> +++++++++++++++++++++++++++++++++
> I think this concept of "template" is quite painful. > Find appended something that I find more palatable: it embeds > DisasContextBase in DisasContext, so that we can have a standalone > object with all generic code; I don't get it. Isn't that what my series is already doing? Or do you mean explicitly passing DisasContextBase to all the generic translator functions below? I kind of dislike it every time I see container_of, and it makes type checking from the compiler a bit more fragile. > target-specific code is called via > an "ops" struct with function pointers that targets fill in. > The target-specific DisasContext struct can then be retrieved from > the base struct with container_of(). I seem to remember we discussed this at some point before I sent the first version, to allow multiple targets on the same binary, but decided against it. Still, I can leave the ops struct in place without even trying to support multiple targets. It should be a little bit slower (using function pointers instead of a "template"), but I don't think performance will suffer that much since we're at the translation path. Any other opinions on this and the point above? > I'll send as a separate, proper patch the gen-icount changes; really > having cpu_env there as a global seems wrong to me. That's an orthogonal issue that can he handled in a separate series. Thanks! Lluis > What do you think? > Emilio > PS. Apply with `git am --scissors'. > --- 8< --- > Warning: INCOMPLETE, do not even think of merging! > This is just to show an alternative approach to including C > code from the target translators (ugh!). Only arm and aarch64 > have been converted. > This applies on top of this series: > https://lists.gnu.org/archive/html/qemu-devel/2017-06/msg02833.html > Signed-off-by: Emilio G. Cota <c...@braap.org> > --- > Makefile.target | 2 +- > include/exec/exec-all.h | 2 +- > include/exec/gen-icount.h | 6 +- > include/exec/translator.h | 74 +++++++++++++++++++ > target/arm/translate-a64.c | 130 ++++++++++++++++++---------------- > target/arm/translate.c | 173 > +++++++++++++++++++++++---------------------- > target/arm/translate.h | 11 +-- > translator.c | 170 ++++++++++++++++++++++++++++++++++++++++++++ > 8 files changed, 411 insertions(+), 157 deletions(-) > create mode 100644 include/exec/translator.h > create mode 100644 translator.c > diff --git a/Makefile.target b/Makefile.target > index ce8dfe4..ef2d538 100644 > --- a/Makefile.target > +++ b/Makefile.target > @@ -88,7 +88,7 @@ all: $(PROGS) stap > ######################################################### > # cpu emulator library > -obj-y = exec.o translate-all.o cpu-exec.o > +obj-y = exec.o translate-all.o cpu-exec.o translator.o > obj-y += translate-common.o > obj-y += cpu-exec-common.o > obj-y += tcg/tcg.o tcg/tcg-op.o tcg/optimize.o > diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h > index 6ad31a8..d376546 100644 > --- a/include/exec/exec-all.h > +++ b/include/exec/exec-all.h > @@ -22,6 +22,7 @@ > #include "qemu-common.h" > #include "exec/tb-context.h" > +#include "exec/translator.h" > /* allow to see translation results - the slowdown should be negligible, so > we leave it */ > #define DEBUG_DISAS > @@ -37,7 +38,6 @@ typedef ram_addr_t tb_page_addr_t; > /* is_jmp field values */ > /* TODO: delete after all targets are transitioned to generic translation */ > -#include "exec/translate-all_template.h" > #define DISAS_NEXT DJ_NEXT /* next instruction can be analyzed > */ > #define DISAS_JUMP (DJ_TARGET + 0) /* only pc was modified dynamically > */ > #define DISAS_UPDATE (DJ_TARGET + 1) /* cpu state was modified > dynamically */ > diff --git a/include/exec/gen-icount.h b/include/exec/gen-icount.h > index 547c979..f4ad610 100644 > --- a/include/exec/gen-icount.h > +++ b/include/exec/gen-icount.h > @@ -8,7 +8,7 @@ > static int icount_start_insn_idx; > static TCGLabel *exitreq_label; > -static inline void gen_tb_start(TranslationBlock *tb) > +static inline void gen_tb_start(TranslationBlock *tb, TCGv_env cpu_env) > { > TCGv_i32 count, imm; > @@ -59,14 +59,14 @@ static inline void gen_tb_end(TranslationBlock *tb, int > num_insns) > tcg_ctx.gen_op_buf[tcg_ctx.gen_op_buf[0].prev].next = 0; > } > -static inline void gen_io_start(void) > +static inline void gen_io_start(TCGv_env cpu_env) > { > TCGv_i32 tmp = tcg_const_i32(1); > tcg_gen_st_i32(tmp, cpu_env, -ENV_OFFSET + offsetof(CPUState, > can_do_io)); > tcg_temp_free_i32(tmp); > } > -static inline void gen_io_end(void) > +static inline void gen_io_end(TCGv_env cpu_env) > { > TCGv_i32 tmp = tcg_const_i32(0); > tcg_gen_st_i32(tmp, cpu_env, -ENV_OFFSET + offsetof(CPUState, > can_do_io)); > diff --git a/include/exec/translator.h b/include/exec/translator.h > new file mode 100644 > index 0000000..f2da424 > --- /dev/null > +++ b/include/exec/translator.h > @@ -0,0 +1,74 @@ > +#ifndef EXEC_TRANSLATOR_H > +#define EXEC_TRANSLATOR_H > + > +#include "exec/exec-all.h" > +#include "tcg.h" > + > +/** > + * BreakpointHitType: > + * @BH_MISS: No hit > + * @BH_HIT_INSN: Hit, but continue translating instruction > + * @BH_HIT_TB: Hit, stop translating TB > + * > + * How to react to a breakpoint hit. > + */ > +typedef enum BreakpointHitType { > + BH_MISS, > + BH_HIT_INSN, > + BH_HIT_TB, > +} BreakpointHitType; > + > +/** > + * DisasJumpType: > + * @DJ_NEXT: Next instruction in program order > + * @DJ_TOO_MANY: Too many instructions executed > + * @DJ_TARGET: Start of target-specific conditions > + * > + * What instruction to disassemble next. > + */ > +typedef enum DisasJumpType { > + DJ_NEXT, > + DJ_TOO_MANY, > + DJ_TARGET, > +} DisasJumpType; > + > +/** > + * DisasContextBase: > + * @tb: Translation block for this disassembly. > + * @pc_first: Address of first guest instruction in this TB. > + * @pc_next: Address of next guest instruction in this TB (current during > + * disassembly). > + * @num_insns: Number of translated instructions (including current). > + * @singlestep_enabled: "Hardware" single stepping enabled. > + * > + * Architecture-agnostic disassembly context. > + */ > +typedef struct DisasContextBase { > + TranslationBlock *tb; > + target_ulong pc_first; > + target_ulong pc_next; > + DisasJumpType jmp_type; > + unsigned int num_insns; > + bool singlestep_enabled; > +} DisasContextBase; > + > +/* all void-returning ops are optional, i.e. can be NULL */ > +struct translator_ops { > + void (*init_context)(DisasContextBase *, CPUArchState *); > + void (*init_globals)(DisasContextBase *, CPUArchState *); > + void (*tb_start)(DisasContextBase *, CPUArchState *); > + void (*insn_start)(DisasContextBase *, CPUArchState *); > + BreakpointHitType (*breakpoint_hit)(DisasContextBase *, CPUArchState *, > + const CPUBreakpoint *); > + target_ulong (*disas_insn)(DisasContextBase *, CPUArchState *); > + DisasJumpType (*stop_check)(DisasContextBase *, CPUArchState *); > + void (*stop)(DisasContextBase *, CPUArchState *); > + int (*disas_flags)(const DisasContextBase *); > +}; > + > +typedef struct translator_ops TranslatorOps; > + > +void translator_gen(const TranslatorOps *tr, DisasContextBase *base, > + CPUState *cpu, TranslationBlock *tb, TCGv_env cpu_env); > + > +#endif /* EXEC_TRANSLATOR_H */ > diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c > index 508a016..c486d04 100644 > --- a/target/arm/translate-a64.c > +++ b/target/arm/translate-a64.c > @@ -1561,7 +1561,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, > bool isread, > } > if ((s->base.tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) { > - gen_io_start(); > + gen_io_start(cpu_env); > } > tcg_rt = cpu_reg(s, rt); > @@ -1593,7 +1593,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, > bool isread, > if ((s->base.tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) { > /* I/O operations must end the TB here (whether read or write) */ > - gen_io_end(); > + gen_io_end(cpu_env); s-> base.jmp_type = DJ_UPDATE; > } else if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) { > /* We default to ending the TB on a coprocessor register write, > @@ -11191,16 +11191,10 @@ static void disas_a64_insn(CPUARMState *env, > DisasContext *s) > free_tmp_a64(s); > } > - > - > -/* Use separate top-level templates for each architecture */ > -#define gen_intermediate_code gen_intermediate_code_aarch64 > -#include "translate-all_template.h" > -#undef gen_intermediate_code > - > -static void gen_intermediate_code_target_init_disas_context( > - DisasContext *dc, CPUArchState *env) > +static void a64_tr_init_dc(DisasContextBase *base, CPUArchState *env) > { > + DisasContext *dc = container_of(base, DisasContext, base); > + dc-> condjmp = 0; dc-> aarch64 = 1; > @@ -11211,17 +11205,17 @@ static void > gen_intermediate_code_target_init_disas_context( > !arm_el_is_aa64(env, 3); dc-> thumb = 0; dc-> sctlr_b = 0; > - dc->be_data = ARM_TBFLAG_BE_DATA(dc->base.tb->flags) ? MO_BE : MO_LE; > + dc->be_data = ARM_TBFLAG_BE_DATA(base->tb->flags) ? MO_BE : MO_LE; dc-> condexec_mask = 0; dc-> condexec_cond = 0; > - dc->mmu_idx = core_to_arm_mmu_idx(env, > ARM_TBFLAG_MMUIDX(dc->base.tb->flags)); > - dc->tbi0 = ARM_TBFLAG_TBI0(dc->base.tb->flags); > - dc->tbi1 = ARM_TBFLAG_TBI1(dc->base.tb->flags); > + dc->mmu_idx = core_to_arm_mmu_idx(env, > ARM_TBFLAG_MMUIDX(base->tb->flags)); > + dc->tbi0 = ARM_TBFLAG_TBI0(base->tb->flags); > + dc->tbi1 = ARM_TBFLAG_TBI1(base->tb->flags); dc-> current_el = arm_mmu_idx_to_el(dc->mmu_idx); > #if !defined(CONFIG_USER_ONLY) dc-> user = (dc->current_el == 0); > #endif > - dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(dc->base.tb->flags); > + dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(base->tb->flags); dc-> vec_len = 0; dc-> vec_stride = 0; dc-> cp_regs = arm_env_get_cpu(env)->cp_regs; > @@ -11242,43 +11236,35 @@ static void > gen_intermediate_code_target_init_disas_context( > * emit code to generate a software step exception > * end the TB > */ > - dc->ss_active = ARM_TBFLAG_SS_ACTIVE(dc->base.tb->flags); > - dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(dc->base.tb->flags); > + dc->ss_active = ARM_TBFLAG_SS_ACTIVE(base->tb->flags); > + dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(base->tb->flags); dc-> is_ldex = false; dc-> ss_same_el = (arm_debug_target_el(env) == dc->current_el); > init_tmp_a64_array(dc); dc-> next_page_start = > - (dc->base.pc_first & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; > -} > - > -static void gen_intermediate_code_target_init_globals( > - DisasContext *dc, CPUArchState *env) > -{ > + (base->pc_first & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; > } > -static void gen_intermediate_code_target_tb_start( > - DisasContext *dc, CPUArchState *env) > +static void a64_tr_insn_start(DisasContextBase *base, CPUArchState *env) > { > -} > + DisasContext *dc = container_of(base, DisasContext, base); > -static void gen_intermediate_code_target_insn_start( > - DisasContext *dc, CPUArchState *env) > -{ dc-> insn_start_idx = tcg_op_buf_count(); > - tcg_gen_insn_start(dc->base.pc_next, 0, 0); > + tcg_gen_insn_start(base->pc_next, 0, 0); > } > -static BreakpointHitType gen_intermediate_code_target_breakpoint_hit( > - DisasContext *dc, CPUArchState *env, > - const CPUBreakpoint *bp) > +static BreakpointHitType > +a64_tr_bp_hit(DisasContextBase *b, CPUArchState *env, const CPUBreakpoint > *bp) > { > + DisasContext *dc = container_of(b, DisasContext, base); > + > if (bp->flags & BP_CPU) { > - gen_a64_set_pc_im(dc->base.pc_next); > + gen_a64_set_pc_im(b->pc_next); > gen_helper_check_breakpoints(cpu_env); > /* End the TB early; it likely won't be executed */ > - dc->base.jmp_type = DJ_UPDATE; > + b->jmp_type = DJ_UPDATE; > return BH_HIT_INSN; > } else { > gen_exception_internal_insn(dc, 0, EXCP_DEBUG); > @@ -11287,14 +11273,15 @@ static BreakpointHitType > gen_intermediate_code_target_breakpoint_hit( > 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->base.pc_next += 4; > + b->pc_next += 4; > return BH_HIT_TB; > } > } > -static target_ulong gen_intermediate_code_target_disas_insn( > - DisasContext *dc, CPUArchState *env) > +static target_ulong a64_tr_disas_insn(DisasContextBase *base, CPUArchState > *env) > { > + DisasContext *dc = container_of(base, DisasContext, base); > + > if (dc->ss_active && !dc->pstate_ss) { > /* Singlestep state is Active-pending. > * If we're in this state at the start of a TB then either > @@ -11306,19 +11293,21 @@ static target_ulong > gen_intermediate_code_target_disas_insn( > * "did not step an insn" case, and so the syndrome ISV and EX > * bits should be zero. > */ > - assert(dc->base.num_insns == 1); > + assert(base->num_insns == 1); > gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0), > default_exception_el(dc)); > - dc->base.jmp_type = DJ_EXC; > + base->jmp_type = DJ_EXC; > } else { > disas_a64_insn(env, dc); > } > - return dc->base.pc_next; > + return base->pc_next; > } > -static DisasJumpType gen_intermediate_code_target_stop_check( > - DisasContext *dc, CPUArchState *env) > +static DisasJumpType > +a64_tr_stop_check(DisasContextBase *base, CPUArchState *env) > { > + DisasContext *dc = container_of(base, DisasContext, base); > + > /* Translation stops when a conditional branch is encountered. > * Otherwise the subsequent code could get translated several times. > * Also stop translation when a page boundary is reached. This > @@ -11327,41 +11316,42 @@ static DisasJumpType > gen_intermediate_code_target_stop_check( > if (dc->ss_active) { > return DJ_SS; > } else { > - return dc->base.jmp_type; > + return base->jmp_type; > } > } > -static void gen_intermediate_code_target_stop( > - DisasContext *dc, CPUArchState *env) > +static void a64_tr_stop(DisasContextBase *base, CPUArchState *env) > { > - if (unlikely(dc->base.singlestep_enabled || dc->ss_active) > - && dc->base.jmp_type != DJ_EXC) { > + DisasContext *dc = container_of(base, DisasContext, base); > + > + if (unlikely(base->singlestep_enabled || dc->ss_active) > + && base->jmp_type != DJ_EXC) { > /* Note that this means single stepping WFI doesn't halt the CPU. > * For conditional branch insns this is harmless unreachable code as > * gen_goto_tb() has already handled emitting the debug exception > * (and thus a tb-jump is not possible when singlestepping). > */ > - assert(dc->base.jmp_type != DJ_TB_JUMP); > - if (dc->base.jmp_type != DJ_JUMP) { > - gen_a64_set_pc_im(dc->base.pc_next); > + assert(base->jmp_type != DJ_TB_JUMP); > + if (base->jmp_type != DJ_JUMP) { > + gen_a64_set_pc_im(base->pc_next); > } > - if (dc->base.singlestep_enabled) { > + if (base->singlestep_enabled) { > gen_exception_internal(EXCP_DEBUG); > } else { > gen_step_complete_exception(dc); > } > } else { > /* Cast because target-specific values are not in generic enum */ > - unsigned int jt = (unsigned int)dc->base.jmp_type; > + unsigned int jt = (unsigned int)base->jmp_type; > switch (jt) { > case DJ_NEXT: > case DJ_TOO_MANY: /* target set DJ_NEXT */ > - gen_goto_tb(dc, 1, dc->base.pc_next); > + gen_goto_tb(dc, 1, base->pc_next); > break; > default: > case DJ_UPDATE: > - gen_a64_set_pc_im(dc->base.pc_next); > + gen_a64_set_pc_im(base->pc_next); > /* fall through */ > case DJ_JUMP: > tcg_gen_lookup_and_goto_ptr(cpu_pc); > @@ -11375,18 +11365,18 @@ static void gen_intermediate_code_target_stop( > /* nothing to generate */ > break; > case DJ_WFE: > - gen_a64_set_pc_im(dc->base.pc_next); > + gen_a64_set_pc_im(base->pc_next); > gen_helper_wfe(cpu_env); > break; > case DJ_YIELD: > - gen_a64_set_pc_im(dc->base.pc_next); > + gen_a64_set_pc_im(base->pc_next); > gen_helper_yield(cpu_env); > break; > case DJ_WFI: > /* This is a special case because we don't want to just halt the > CPU > * if trying to debug across a WFI. > */ > - gen_a64_set_pc_im(dc->base.pc_next); > + gen_a64_set_pc_im(base->pc_next); > gen_helper_wfi(cpu_env); > /* The helper doesn't necessarily throw an exception, but we > * must go back to the main loop to check for interrupts anyway. > @@ -11397,8 +11387,26 @@ static void gen_intermediate_code_target_stop( > } > } > -static int gen_intermediate_code_target_get_disas_flags( > - const DisasContext *dc) > +static int a64_tr_disas_flags(const DisasContextBase *base) > { > + DisasContext *dc = container_of(base, DisasContext, base); > + > return 4 | (bswap_code(dc->sctlr_b) ? 2 : 0); > } > + > +static const TranslatorOps a64_tr = { > + .init_context = a64_tr_init_dc, > + .insn_start = a64_tr_insn_start, > + .breakpoint_hit = a64_tr_bp_hit, > + .disas_insn = a64_tr_disas_insn, > + .stop_check = a64_tr_stop_check, > + .stop = a64_tr_stop, > + .disas_flags = a64_tr_disas_flags, > +}; > + > +void gen_intermediate_code_a64(CPUState *cpu, struct TranslationBlock *tb) > +{ > + DisasContext dc; > + > + translator_gen(&a64_tr, &dc.base, cpu, tb, cpu_env); > +} > diff --git a/target/arm/translate.c b/target/arm/translate.c > index 06f207a..5ea9952 100644 > --- a/target/arm/translate.c > +++ b/target/arm/translate.c > @@ -7655,7 +7655,7 @@ static int disas_coproc_insn(DisasContext *s, uint32_t > insn) > } > if ((s->base.tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) { > - gen_io_start(); > + gen_io_start(cpu_env); > } > if (isread) { > @@ -7747,7 +7747,7 @@ static int disas_coproc_insn(DisasContext *s, uint32_t > insn) > if ((s->base.tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) { > /* I/O operations must end the TB here (whether read or write) */ > - gen_io_end(); > + gen_io_end(cpu_env); > gen_lookup_tb(s); > } else if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) { > /* We default to ending the TB on a coprocessor register write, > @@ -11864,31 +11864,10 @@ void restore_state_to_opc(CPUARMState *env, > TranslationBlock *tb, > } > } > - > - > -/* Use separate top-level templates for each architecture */ > -#define gen_intermediate_code gen_intermediate_code_arm > -#include "translate-all_template.h" > -#undef gen_intermediate_code > - > -#if !defined(TARGET_AARCH64) > -void gen_intermediate_code_aarch64(CPUState *cpu, struct TranslationBlock > *tb) > -{ > -} > -#endif > - > -void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb) > +static void arm_tr_init_dc(DisasContextBase *base, CPUARMState *env) > { > - if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) { > - gen_intermediate_code_aarch64(cpu, tb); > - } else { > - gen_intermediate_code_arm(cpu, tb); > - } > -} > + DisasContext *dc = container_of(base, DisasContext, base); > -static void gen_intermediate_code_target_init_disas_context( > - DisasContext *dc, CPUARMState *env) > -{ dc-> condjmp = 0; dc-> aarch64 = 0; > @@ -11897,23 +11876,23 @@ static void > gen_intermediate_code_target_init_disas_context( > */ dc-> secure_routed_to_el3 = arm_feature(env, ARM_FEATURE_EL3) && > !arm_el_is_aa64(env, 3); > - dc->thumb = ARM_TBFLAG_THUMB(dc->base.tb->flags); > - dc->sctlr_b = ARM_TBFLAG_SCTLR_B(dc->base.tb->flags); > - dc->be_data = ARM_TBFLAG_BE_DATA(dc->base.tb->flags) ? MO_BE : MO_LE; > - dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(dc->base.tb->flags) & 0xf) << 1; > - dc->condexec_cond = ARM_TBFLAG_CONDEXEC(dc->base.tb->flags) >> 4; > - dc->mmu_idx = core_to_arm_mmu_idx(env, > ARM_TBFLAG_MMUIDX(dc->base.tb->flags)); > + dc->thumb = ARM_TBFLAG_THUMB(base->tb->flags); > + dc->sctlr_b = ARM_TBFLAG_SCTLR_B(base->tb->flags); > + dc->be_data = ARM_TBFLAG_BE_DATA(base->tb->flags) ? MO_BE : MO_LE; > + dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(base->tb->flags) & 0xf) << 1; > + dc->condexec_cond = ARM_TBFLAG_CONDEXEC(base->tb->flags) >> 4; > + dc->mmu_idx = core_to_arm_mmu_idx(env, > ARM_TBFLAG_MMUIDX(base->tb->flags)); dc-> current_el = arm_mmu_idx_to_el(dc->mmu_idx); > #if !defined(CONFIG_USER_ONLY) dc-> user = (dc->current_el == 0); > #endif > - dc->ns = ARM_TBFLAG_NS(dc->base.tb->flags); > - dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(dc->base.tb->flags); > - dc->vfp_enabled = ARM_TBFLAG_VFPEN(dc->base.tb->flags); > - dc->vec_len = ARM_TBFLAG_VECLEN(dc->base.tb->flags); > - dc->vec_stride = ARM_TBFLAG_VECSTRIDE(dc->base.tb->flags); > - dc->c15_cpar = ARM_TBFLAG_XSCALE_CPAR(dc->base.tb->flags); > - dc->v7m_handler_mode = ARM_TBFLAG_HANDLER(dc->base.tb->flags); > + dc->ns = ARM_TBFLAG_NS(base->tb->flags); > + dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(base->tb->flags); > + dc->vfp_enabled = ARM_TBFLAG_VFPEN(base->tb->flags); > + dc->vec_len = ARM_TBFLAG_VECLEN(base->tb->flags); > + dc->vec_stride = ARM_TBFLAG_VECSTRIDE(base->tb->flags); > + dc->c15_cpar = ARM_TBFLAG_XSCALE_CPAR(base->tb->flags); > + dc->v7m_handler_mode = ARM_TBFLAG_HANDLER(base->tb->flags); dc-> cp_regs = arm_env_get_cpu(env)->cp_regs; dc-> features = env->features; > @@ -11932,17 +11911,16 @@ static void > gen_intermediate_code_target_init_disas_context( > * emit code to generate a software step exception > * end the TB > */ > - dc->ss_active = ARM_TBFLAG_SS_ACTIVE(dc->base.tb->flags); > - dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(dc->base.tb->flags); > + dc->ss_active = ARM_TBFLAG_SS_ACTIVE(base->tb->flags); > + dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(base->tb->flags); dc-> is_ldex = false; dc-> ss_same_el = false; /* Can't be true since EL_d must be AArch64 */ dc-> next_page_start = > - (dc->base.pc_first & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; > + (base->pc_first & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; > } > -static void gen_intermediate_code_target_init_globals( > - DisasContext *dc, CPUARMState *env) > +static void arm_tr_init_globals(DisasContextBase *base, CPUARMState *env) > { > cpu_F0s = tcg_temp_new_i32(); > cpu_F1s = tcg_temp_new_i32(); > @@ -11954,8 +11932,7 @@ static void gen_intermediate_code_target_init_globals( > cpu_M0 = tcg_temp_new_i64(); > } > -static void gen_intermediate_code_target_tb_start( > - DisasContext *dc, CPUARMState *env) > +static void arm_tr_tb_start(DisasContextBase *base, CPUARMState *env) > { > /* A note on handling of the condexec (IT) bits: > * > @@ -11986,6 +11963,7 @@ static void gen_intermediate_code_target_tb_start( > * we don't need to care about whether CPUARMState is correct in the > * middle of a TB. > */ > + DisasContext *dc = container_of(base, DisasContext, base); > /* > * Reset the conditional execution bits immediately. This avoids > @@ -11998,43 +11976,45 @@ static void gen_intermediate_code_target_tb_start( > } > } > -static void gen_intermediate_code_target_insn_start( > - DisasContext *dc, CPUARMState *env) > +static void arm_tr_insn_start(DisasContextBase *base, CPUARMState *env) > { > + DisasContext *dc = container_of(base, DisasContext, base); > + dc-> insn_start_idx = tcg_op_buf_count(); > - tcg_gen_insn_start(dc->base.pc_next, > + tcg_gen_insn_start(base->pc_next, > (dc->condexec_cond << 4) | (dc->condexec_mask >> 1), > 0); > #ifdef CONFIG_USER_ONLY > /* Intercept jump to the magic kernel page. */ > - if (dc->base.pc_next >= 0xffff0000) { > + if (base->pc_next >= 0xffff0000) { > /* We always get here via a jump, so know we are not in a > conditional execution block. */ > gen_exception_internal(EXCP_KERNEL_TRAP); > - dc->base.jmp_type = DJ_EXC; > + base->jmp_type = DJ_EXC; > } > #else > - if (dc->base.pc_next >= 0xfffffff0 && arm_dc_feature(dc, ARM_FEATURE_M)) > { > + if (base->pc_next >= 0xfffffff0 && arm_dc_feature(dc, ARM_FEATURE_M)) { > /* We always get here via a jump, so know we are not in a > conditional execution block. */ > gen_exception_internal(EXCP_EXCEPTION_EXIT); > - dc->base.jmp_type = DJ_EXC; > + base->jmp_type = DJ_EXC; > } > #endif > } > -static BreakpointHitType gen_intermediate_code_target_breakpoint_hit( > - DisasContext *dc, CPUARMState *env, > - const CPUBreakpoint *bp) > +static BreakpointHitType > +arm_tr_bp_hit(DisasContextBase *base, CPUARMState *env, const CPUBreakpoint > *bp) > { > + DisasContext *dc = container_of(base, DisasContext, base); > + > if (bp->flags & BP_CPU) { > gen_set_condexec(dc); > - gen_set_pc_im(dc, dc->base.pc_next); > + gen_set_pc_im(dc, base->pc_next); > gen_helper_check_breakpoints(cpu_env); > /* End the TB early; it's likely not going to be executed */ > - dc->base.jmp_type = DJ_UPDATE; > + base->jmp_type = DJ_UPDATE; > return BH_HIT_INSN; > } else { > gen_exception_internal_insn(dc, 0, EXCP_DEBUG); > @@ -12045,14 +12025,15 @@ static BreakpointHitType > gen_intermediate_code_target_breakpoint_hit( tb-> size below does the right thing. */ > /* TODO: Advance PC by correct instruction length to avoid > * disassembler error messages */ > - dc->base.pc_next += 2; > + base->pc_next += 2; > return BH_HIT_TB; > } > } > -static target_ulong gen_intermediate_code_target_disas_insn( > - DisasContext *dc, CPUArchState *env) > +static target_ulong arm_tr_disas_insn(DisasContextBase *base, CPUArchState > *env) > { > + DisasContext *dc = container_of(base, DisasContext, base); > + > if (dc->ss_active && !dc->pstate_ss) { > /* Singlestep state is Active-pending. > * If we're in this state at the start of a TB then either > @@ -12064,11 +12045,11 @@ static target_ulong > gen_intermediate_code_target_disas_insn( > * "did not step an insn" case, and so the syndrome ISV and EX > * bits should be zero. > */ > - assert(dc->base.num_insns == 1); > + assert(base->num_insns == 1); > gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0), > default_exception_el(dc)); > - dc->base.jmp_type = DJ_SKIP; > - return dc->base.pc_next; > + base->jmp_type = DJ_SKIP; > + return base->pc_next; > } > if (dc->thumb) { > @@ -12082,30 +12063,32 @@ static target_ulong > gen_intermediate_code_target_disas_insn( > } > } > } else { > - unsigned int insn = arm_ldl_code(env, dc->base.pc_next, dc->sctlr_b); > - dc->base.pc_next += 4; > + unsigned int insn = arm_ldl_code(env, base->pc_next, dc->sctlr_b); > + base->pc_next += 4; > disas_arm_insn(dc, insn); > } > - if (dc->condjmp && !dc->base.jmp_type) { > + if (dc->condjmp && !base->jmp_type) { > gen_set_label(dc->condlabel); dc-> condjmp = 0; > } > - return dc->base.pc_next; > + return base->pc_next; > } > -static DisasJumpType gen_intermediate_code_target_stop_check( > - DisasContext *dc, CPUARMState *env) > +static DisasJumpType arm_tr_stop_check(DisasContextBase *base, CPUARMState > *env) > { > + DisasContext *dc = container_of(base, DisasContext, base); > + > /* Translation stops when a conditional branch is encountered. > * Otherwise the subsequent code could get translated several times. > * Also stop translation when a page boundary is reached. This > * ensures prefetch aborts occur at the right place. */ > + dc = container_of(base, DisasContext, base); > if (is_singlestepping(dc)) { > return DJ_SS; > - } else if ((dc->base.pc_next >= dc->next_page_start - 3) > + } else if ((base->pc_next >= dc->next_page_start - 3) > && insn_crosses_page(env, dc)) { > /* > * Generic code already checked if the next insn starts in a new > @@ -12122,21 +12105,21 @@ static DisasJumpType > gen_intermediate_code_target_stop_check( > */ > return DJ_PAGE_CROSS; > } else { > - return dc->base.jmp_type; > + return base->jmp_type; > } > } > -static void gen_intermediate_code_target_stop( > - DisasContext *dc, CPUARMState *env) > +static void arm_tr_stop(DisasContextBase *base, CPUARMState *env) > { > + DisasContext *dc = container_of(base, DisasContext, base); > /* Cast because target-specific values are not in generic enum */ > - unsigned int jt = (unsigned int)dc->base.jmp_type; > + unsigned int jt = (unsigned int)base->jmp_type; > if (jt == DJ_SKIP) { > return; > } > - if ((dc->base.tb->cflags & CF_LAST_IO) && dc->condjmp) { > + if ((base->tb->cflags & CF_LAST_IO) && dc->condjmp) { > /* FIXME: This can theoretically happen with self-modifying code. */ > cpu_abort(ENV_GET_CPU(env), "IO on conditional branch instruction"); > } > @@ -12145,7 +12128,7 @@ static void gen_intermediate_code_target_stop( > instruction was a conditional branch or trap, and the PC has > already been written. */ > gen_set_condexec(dc); > - if (dc->base.jmp_type == DJ_BX_EXCRET) { > + if (base->jmp_type == DJ_BX_EXCRET) { > /* Exception return branches need some special case code at the > * end of the TB, which is complex enough that it has to > * handle the single-step vs not and the condition-failed > @@ -12171,7 +12154,7 @@ static void gen_intermediate_code_target_stop( > case DJ_NEXT: > case DJ_TOO_MANY: /* target set DJ_NEXT */ > case DJ_UPDATE: > - gen_set_pc_im(dc, dc->base.pc_next); > + gen_set_pc_im(dc, base->pc_next); > /* fall through */ > default: > /* FIXME: Single stepping a WFI insn will not halt the CPU. */ > @@ -12191,10 +12174,10 @@ static void gen_intermediate_code_target_stop( > switch (jt) { > case DJ_NEXT: > case DJ_TOO_MANY: /* target set DJ_NEXT */ > - gen_goto_tb(dc, 1, dc->base.pc_next); > + gen_goto_tb(dc, 1, base->pc_next); > break; > case DJ_UPDATE: > - gen_set_pc_im(dc, dc->base.pc_next); > + gen_set_pc_im(dc, base->pc_next); > /* fall through */ > case DJ_JUMP: > gen_goto_ptr(); > @@ -12238,16 +12221,40 @@ static void gen_intermediate_code_target_stop( > gen_set_label(dc->condlabel); > gen_set_condexec(dc); > if (unlikely(is_singlestepping(dc))) { > - gen_set_pc_im(dc, dc->base.pc_next); > + gen_set_pc_im(dc, base->pc_next); > gen_singlestep_exception(dc); > } else { > - gen_goto_tb(dc, 1, dc->base.pc_next); > + gen_goto_tb(dc, 1, base->pc_next); > } > } > } > -static int gen_intermediate_code_target_get_disas_flags( > - const DisasContext *dc) > +static int arm_tr_disas_flags(const DisasContextBase *base) > { > + DisasContext *dc = container_of(base, DisasContext, base); > + > return dc->thumb | (dc->sctlr_b << 1); > } > + > +static const TranslatorOps arm_tr = { > + .init_context = arm_tr_init_dc, > + .init_globals = arm_tr_init_globals, > + .tb_start = arm_tr_tb_start, > + .insn_start = arm_tr_insn_start, > + .breakpoint_hit = arm_tr_bp_hit, > + .disas_insn = arm_tr_disas_insn, > + .stop_check = arm_tr_stop_check, > + .stop = arm_tr_stop, > + .disas_flags = arm_tr_disas_flags, > +}; > + > +void gen_intermediate_code(CPUState *cpu, struct TranslationBlock *tb) > +{ > + DisasContext dc; > + > + if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) { > + gen_intermediate_code_a64(cpu, tb); > + } else { > + translator_gen(&arm_tr, &dc.base, cpu, tb, cpu_env); > + } > +} > diff --git a/target/arm/translate.h b/target/arm/translate.h > index 5473994..1aa5d49 100644 > --- a/target/arm/translate.h > +++ b/target/arm/translate.h > @@ -1,8 +1,7 @@ > #ifndef TARGET_ARM_TRANSLATE_H > #define TARGET_ARM_TRANSLATE_H > -#include "exec/translate-all_template.h" > - > +#include "exec/translator.h" > /* internal defines */ > typedef struct DisasContext { > @@ -122,7 +121,6 @@ static void disas_set_insn_syndrome(DisasContext *s, > uint32_t syn) > } > /* Target-specific values for DisasContextBase::jmp_type */ > -#include "exec/translate-all_template.h" > #define DJ_JUMP (DJ_TARGET + 0) > #define DJ_UPDATE (DJ_TARGET + 1) > #define DJ_TB_JUMP (DJ_TARGET + 2) > @@ -153,13 +151,10 @@ static void disas_set_insn_syndrome(DisasContext *s, > uint32_t syn) > #define DJ_PAGE_CROSS (DJ_TARGET + 13) > #define DJ_SKIP (DJ_TARGET + 14) > -void gen_intermediate_code_arm(CPUState *cpu, struct TranslationBlock *tb); > -void gen_intermediate_code_aarch64(CPUState *cpu, struct TranslationBlock > *tb); > - > #ifdef TARGET_AARCH64 > void init_tmp_a64_array(DisasContext *s); > void a64_translate_init(void); > -void gen_intermediate_code_a64(ARMCPU *cpu, TranslationBlock *tb); > +void gen_intermediate_code_a64(CPUState *cpu, TranslationBlock *tb); > void gen_a64_set_pc_im(uint64_t val); > void aarch64_cpu_dump_state(CPUState *cs, FILE *f, > fprintf_function cpu_fprintf, int flags); > @@ -172,7 +167,7 @@ static inline void a64_translate_init(void) > { > } > -static inline void gen_intermediate_code_a64(ARMCPU *cpu, TranslationBlock > *tb) > +static inline void gen_intermediate_code_a64(CPUState *cpu, TranslationBlock > *tb) > { > } > diff --git a/translator.c b/translator.c > new file mode 100644 > index 0000000..2248b52 > --- /dev/null > +++ b/translator.c > @@ -0,0 +1,170 @@ > +#include "qemu/osdep.h" > +#include "qemu-common.h" > +#include "qemu/error-report.h" > +#include "disas/disas.h" > +#include "cpu.h" > +#include "tcg.h" > +#include "tcg-op.h" > +#include "exec/exec-all.h" > +#include "exec/translator.h" > +#include "exec/gen-icount.h" > +#include "exec/log.h" > + > +static inline void check_tcg(const DisasContextBase *base) > +{ > + if (tcg_check_temp_count()) { > + error_report("warning: TCG temporary leaks before "TARGET_FMT_lx, > + base->pc_next); > + } > +} > + > +void translator_gen(const TranslatorOps *tr, DisasContextBase *base, > + CPUState *cpu, TranslationBlock *tb, TCGv_env cpu_env) > +{ > + CPUArchState *env = cpu->env_ptr; > + int max_insns; > + > + /* Initialize DisasContextBase */ > + base->tb = tb; > + base->singlestep_enabled = cpu->singlestep_enabled; > + base->pc_first = tb->pc; > + base->pc_next = base->pc_first; > + base->jmp_type = DJ_NEXT; > + base->num_insns = 0; > + if (tr->init_context) { > + tr->init_context(base, env); > + } > + > + /* Initialize globals */ > + if (tr->init_globals) { > + tr->init_globals(base, env); > + } > + tcg_clear_temp_count(); > + > + /* Instruction counting */ > + max_insns = base->tb->cflags & CF_COUNT_MASK; > + if (max_insns == 0) { > + max_insns = CF_COUNT_MASK; > + } > + if (max_insns > TCG_MAX_INSNS) { > + max_insns = TCG_MAX_INSNS; > + } > + if (base->singlestep_enabled || singlestep) { > + max_insns = 1; > + } > + > + /* Start translating */ > + gen_tb_start(base->tb, cpu_env); > + if (tr->tb_start) { > + tr->tb_start(base, env); > + } > + > + while (true) { > + CPUBreakpoint *bp; > + > + base->num_insns++; > + if (tr->insn_start) { > + tr->insn_start(base, env); > + } > + > + /* Early exit before breakpoint checks */ > + if (unlikely(base->jmp_type != DJ_NEXT)) { > + break; > + } > + > + /* Pass breakpoint hits to target for further processing */ > + bp = NULL; > + do { > + bp = cpu_breakpoint_get(cpu, base->pc_next, bp); > + if (unlikely(bp)) { > + BreakpointHitType bh = tr->breakpoint_hit(base, env, bp); > + if (bh == BH_HIT_INSN) { > + /* Hit, keep translating */ > + /* > + * TODO: if we're never going to have more than one BP > in a > + * single address, we can simply use a bool here. > + */ > + break; > + } else if (bh == BH_HIT_TB) { > + goto done_generating; > + } > + } > + } while (bp != NULL); > + > + /* Accept I/O on last instruction */ > + if (base->num_insns == max_insns && > + (base->tb->cflags & CF_LAST_IO)) { > + gen_io_start(cpu_env); > + } > + > + /* Disassemble one instruction */ > + base->pc_next = tr->disas_insn(base, env); > + > + /**************************************************/ > + /* Conditions to stop translation */ > + /**************************************************/ > + > + /* Disassembly already set a stop condition */ > + if (base->jmp_type >= DJ_TARGET) { > + break; > + } > + > + /* Target-specific conditions */ > + base->jmp_type = tr->stop_check(base, env); > + if (base->jmp_type >= DJ_TARGET) { > + break; > + } > + > + /* Too many instructions */ > + if (tcg_op_buf_full() || base->num_insns >= max_insns) { > + base->jmp_type = DJ_TOO_MANY; > + break; > + } > + > + /* > + * Check if next instruction is on next page, which can cause an > + * exception. > + * > + * NOTE: Target-specific code must check a single instruction does > not > + * cross page boundaries; the first in the TB is always > allowed to > + * cross pages (never goes through this check). > + */ > + if ((base->pc_first & TARGET_PAGE_MASK) > + != (base->pc_next & TARGET_PAGE_MASK)) { > + base->jmp_type = DJ_TOO_MANY; > + break; > + } > + > + check_tcg(base); > + } > + > + if (tr->stop) { > + tr->stop(base, env); > + } > + > + if (base->tb->cflags & CF_LAST_IO) { > + gen_io_end(cpu_env); > + } > + > + done_generating: > + gen_tb_end(base->tb, base->num_insns); > + > + check_tcg(base); > + > +#ifdef DEBUG_DISAS > + if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) && > + qemu_log_in_addr_range(base->pc_first)) { > + qemu_log_lock(); > + qemu_log("----------------\n"); > + qemu_log("IN: %s\n", lookup_symbol(base->pc_first)); > + log_target_disas(cpu, base->pc_first, > + base->pc_next - base->pc_first, > + tr->disas_flags(base)); > + qemu_log("\n"); > + qemu_log_unlock(); > + } > +#endif > + > + base->tb->size = base->pc_next - base->pc_first; > + base->tb->icount = base->num_insns; > +} > -- > 2.7.4