qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH] translator mega-patch


From: Emilio G. Cota
Subject: [Qemu-devel] [PATCH] translator mega-patch
Date: Thu, 15 Jun 2017 18:05:02 -0400
User-agent: Mutt/1.5.24 (2015-08-30)

On Mon, Jun 12, 2017 at 17:54:09 +0300, Lluís Vilanova wrote:
> Signed-off-by: Lluís Vilanova <address@hidden>
> ---
>  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; 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'll send as a separate, proper patch the gen-icount changes; really
having cpu_env there as a global seems wrong to me.

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 <address@hidden>
---
 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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]